// Filename: memoryUsage.h // Created by: drose (25May00) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE // Copyright (c) Carnegie Mellon University. All rights reserved. // // All use of this software is subject to the terms of the revised BSD // license. You should have received a copy of this license along // with this source code in a file named "LICENSE." // //////////////////////////////////////////////////////////////////// #ifndef MEMORYUSAGE_H #define MEMORYUSAGE_H #include "pandabase.h" #ifdef DO_MEMORY_USAGE #include "typedObject.h" #include "memoryInfo.h" #include "memoryUsagePointerCounts.h" #include "pmap.h" #include "memoryHook.h" class ReferenceCount; class MemoryUsagePointers; //////////////////////////////////////////////////////////////////// // Class : MemoryUsage // Description : This class is used strictly for debugging purposes, // specifically for tracking memory leaks of // reference-counted objects: it keeps a record of every // such object currently allocated. // // When compiled with NDEBUG set, this entire class does // nothing and compiles to nothing. //////////////////////////////////////////////////////////////////// class EXPCL_PANDAEXPRESS MemoryUsage : public MemoryHook { public: INLINE static bool get_track_memory_usage(); INLINE static void record_pointer(ReferenceCount *ptr); INLINE static void update_type(ReferenceCount *ptr, TypeHandle type); INLINE static void update_type(ReferenceCount *ptr, TypedObject *typed_ptr); INLINE static void remove_pointer(ReferenceCount *ptr); public: virtual void *heap_alloc_single(size_t size); virtual void heap_free_single(void *ptr); virtual void mark_pointer(void *ptr, size_t orig_size, ReferenceCount *ref_ptr); #if defined(WIN32_VC) && defined(_DEBUG) static int win32_malloc_hook(int alloc_type, void *ptr, size_t size, int block_use, long request, const unsigned char *filename, int line); #endif PUBLISHED: INLINE static bool is_tracking(); INLINE static bool is_counting(); INLINE static size_t get_current_cpp_size(); INLINE static size_t get_total_cpp_size(); INLINE static size_t get_panda_heap_single_size(); INLINE static size_t get_panda_heap_array_size(); INLINE static size_t get_panda_heap_overhead(); INLINE static size_t get_panda_mmap_size(); INLINE static size_t get_external_size(); INLINE static size_t get_total_size(); INLINE static int get_num_pointers(); INLINE static void get_pointers(MemoryUsagePointers &result); INLINE static void get_pointers_of_type(MemoryUsagePointers &result, TypeHandle type); INLINE static void get_pointers_of_age(MemoryUsagePointers &result, double from, double to); INLINE static void get_pointers_with_zero_count(MemoryUsagePointers &result); INLINE static void freeze(); INLINE static void show_current_types(); INLINE static void show_trend_types(); INLINE static void show_current_ages(); INLINE static void show_trend_ages(); protected: virtual void overflow_heap_size(); private: MemoryUsage(const MemoryHook ©); static MemoryUsage *get_global_ptr(); void ns_record_pointer(ReferenceCount *ptr); void ns_update_type(ReferenceCount *ptr, TypeHandle type); void ns_update_type(ReferenceCount *ptr, TypedObject *typed_ptr); void ns_remove_pointer(ReferenceCount *ptr); void ns_record_void_pointer(void *ptr, size_t size); void ns_remove_void_pointer(void *ptr); size_t ns_get_total_size(); int ns_get_num_pointers(); void ns_get_pointers(MemoryUsagePointers &result); void ns_get_pointers_of_type(MemoryUsagePointers &result, TypeHandle type); void ns_get_pointers_of_age(MemoryUsagePointers &result, double from, double to); void ns_get_pointers_with_zero_count(MemoryUsagePointers &result); void ns_freeze(); void ns_show_current_types(); void ns_show_trend_types(); void ns_show_current_ages(); void ns_show_trend_ages(); void consolidate_void_ptr(MemoryInfo *info); void refresh_info_set(); static MemoryUsage *_global_ptr; // We shouldn't use a pmap, since that would be recursive! // Actually, it turns out that it doesn't matter, since somehow the // pallocator gets used even though we don't specify it here, so we // have to make special code that handles the recursion anyway. // This table stores up to two entiries for each MemoryInfo object: // one for the void pointer (the pointer to the beginning of the // allocated memory block), and one for the ReferenceCount pointer. // For a particular object, these two pointers may be the same or // they may be different. Some objects may be stored under both // pointers, while others may be stored under only one pointer or // the other. We don't store an entry for an object's TypedObject // pointer. typedef map Table; Table _table; // This table indexes the individual MemoryInfo objects, for unique // iteration. typedef set InfoSet; InfoSet _info_set; bool _info_set_dirty; int _freeze_index; int _count; size_t _current_cpp_size; size_t _total_cpp_size; size_t _total_size; class TypeHistogram { public: void add_info(TypeHandle type, MemoryInfo *info); void show() const; void clear(); private: // Cannot use a pmap, since that would be recursive! typedef map Counts; Counts _counts; }; TypeHistogram _trend_types; class AgeHistogram { public: AgeHistogram(); void add_info(double age, MemoryInfo *info); void show() const; void clear(); private: int choose_bucket(double age) const; enum { num_buckets = 5 }; MemoryUsagePointerCounts _counts[num_buckets]; static double _cutoff[num_buckets]; }; AgeHistogram _trend_ages; bool _track_memory_usage; bool _startup_track_memory_usage; bool _count_memory_usage; bool _report_memory_usage; double _report_memory_interval; double _last_report_time; static bool _recursion_protect; }; #include "memoryUsage.I" #endif // DO_MEMORY_USAGE #endif