move some low-level mem tracking into MemoryHook, more mem tracking fixes

This commit is contained in:
David Rose 2007-06-29 01:39:09 +00:00
parent 33722a16c1
commit d52eb37b14
38 changed files with 707 additions and 822 deletions

View File

@ -152,9 +152,6 @@
#define HAVE_POSIX_THREADS 1
// Must global operator new and delete functions throw exceptions?
#define GLOBAL_OPERATOR_NEW_EXCEPTIONS 1
// Modern versions of gcc do support the latest STL allocator
// definitions.
#define USE_STL_ALLOCATOR 1

View File

@ -140,9 +140,6 @@
// Do we have RTTI (and <typeinfo>)?
#define HAVE_RTTI 1
// Must global operator new and delete functions throw exceptions?
#define GLOBAL_OPERATOR_NEW_EXCEPTIONS
// The Irix compiler doesn't support the modern STL allocator.
#define USE_STL_ALLOCATOR

View File

@ -154,9 +154,6 @@
// We need 64-bit file i/o
#define __USE_LARGEFILE64 1
// Must global operator new and delete functions throw exceptions?
#define GLOBAL_OPERATOR_NEW_EXCEPTIONS 1
// Modern versions of gcc do support the latest STL allocator
// definitions.
#define USE_STL_ALLOCATOR 1

View File

@ -154,9 +154,6 @@
// Do we have RTTI (and <typeinfo>)?
#define HAVE_RTTI 1
// Must global operator new and delete functions throw exceptions?
#define GLOBAL_OPERATOR_NEW_EXCEPTIONS 1
// Modern versions of gcc do support the latest STL allocator
// definitions.
#define USE_STL_ALLOCATOR 1

View File

@ -149,9 +149,6 @@
// Do we have RTTI (and <typeinfo>)?
#define HAVE_RTTI 1
// Must global operator new and delete functions throw exceptions?
#define GLOBAL_OPERATOR_NEW_EXCEPTIONS
// MSVC7 does support the latest STL allocator definitions.
#define USE_STL_ALLOCATOR 1

View File

@ -348,11 +348,6 @@
// available, even if it is unused.
#defer DO_MEMORY_USAGE $[<= $[OPTIMIZE], 3]
// Should we attempt to override the global new and delete operators?
// It turns out this is usually a bad idea, but may be useful for
// development.
#define REDEFINE_GLOBAL_OPERATOR_NEW
// This option compiles in support for simulating network delay via
// the min-lag and max-lag prc variables. It adds a tiny bit of
// overhead even when it is not activated, so it is typically enabled

View File

@ -309,7 +309,6 @@ $[cdefine TRACK_IN_INTERPRETER]
/* Define if we want to enable track-memory-usage. */
$[cdefine DO_MEMORY_USAGE]
$[cdefine REDEFINE_GLOBAL_OPERATOR_NEW]
/* Define if we want to enable min-lag and max-lag. */
$[cdefine SIMULATE_NETWORK_DELAY]
@ -494,9 +493,6 @@ $[cdefine USE_TAU]
/* Define if needed to have 64-bit file i/o */
$[cdefine __USE_LARGEFILE64]
/* Must global operator new and delete functions throw exceptions? */
$[cdefine GLOBAL_OPERATOR_NEW_EXCEPTIONS]
/* Which memory allocation scheme should we use? */
#define USE_MEMORY_DLMALLOC
#define USE_MEMORY_PTMALLOC2

View File

@ -14,12 +14,12 @@
atomicAdjustPosixImpl.h atomicAdjustPosixImpl.I \
atomicAdjustWin32Impl.h atomicAdjustWin32Impl.I \
cmath.I cmath.h \
dallocator.T dallocator.h \
deletedChain.h deletedChain.T \
dtoolbase.h dtoolbase_cc.h dtoolsymbols.h \
fakestringstream.h \
indent.I indent.h indent.cxx \
memoryBase.h \
memoryHook.h memoryHook.I \
mutexImpl.h \
mutexDummyImpl.h mutexDummyImpl.I \
mutexPosixImpl.h mutexPosixImpl.I \
@ -47,6 +47,7 @@
atomicAdjustWin32Impl.cxx \
dtoolbase.cxx \
memoryBase.cxx \
memoryHook.cxx \
mutexDummyImpl.cxx \
mutexPosixImpl.cxx \
mutexWin32Impl.cxx \
@ -65,11 +66,11 @@
atomicAdjustPosixImpl.h atomicAdjustPosixImpl.I \
atomicAdjustWin32Impl.h atomicAdjustWin32Impl.I \
cmath.I cmath.h \
dallocator.T dallocator.h \
deletedChain.h deletedChain.T \
dtoolbase.h dtoolbase_cc.h dtoolsymbols.h fakestringstream.h \
indent.I indent.h \
memoryBase.h \
memoryHook.h memoryHook.I \
mutexImpl.h \
mutexDummyImpl.h mutexDummyImpl.I \
mutexPosixImpl.h mutexPosixImpl.I \

View File

@ -1,35 +0,0 @@
// Filename: dallocator.T
// Created by: drose (05Jun01)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
template<class Type>
INLINE dallocator<Type>::
dallocator() throw() {
}
template<class Type>
INLINE TYPENAME dallocator<Type>::pointer dallocator<Type>::
allocate(TYPENAME dallocator<Type>::size_type n, allocator<void>::const_pointer) {
return (TYPENAME dallocator<Type>::pointer)(*global_operator_new)(n * sizeof(Type));
}
template<class Type>
INLINE void dallocator<Type>::
deallocate(TYPENAME dallocator<Type>::pointer p, TYPENAME dallocator<Type>::size_type) {
(*global_operator_delete)(p);
}

View File

@ -1,76 +0,0 @@
// Filename: dallocator.h
// Created by: drose (05Jun01)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef DALLOCATOR_H
#define DALLOCATOR_H
#include <memory>
#include "dtoolbase.h"
////////////////////////////////////////////////////////////////////
// Class : dallocator
// Description : This is similar to pallocator, but always uses the
// default new and delete handlers defined in
// dtoolbase_cc.h; it never calls the hooks assigned by
// redefining global_operator_new, etc.
//
// This is needed in those rare cases when we need to
// allocate memory for STL without going through the
// callback hooks, for instance to implement STL tables
// within the MemoryUsage class itself.
////////////////////////////////////////////////////////////////////
#ifndef USE_STL_ALLOCATOR
// If we're not trying to make custom allocators (either we don't know
// what kind of syntax this STL library wants, or we're compiling with
// OPTIMIZE 4), then simply use the standard allocator.
#define dallocator allocator
#else
template<class Type>
class dallocator : public allocator<Type> {
public:
// There seems to be a bug in VC++ 2003 that requires these typedefs
// to be made explicitly.
typedef TYPENAME allocator<Type>::pointer pointer;
typedef TYPENAME allocator<Type>::reference reference;
typedef TYPENAME allocator<Type>::const_pointer const_pointer;
typedef TYPENAME allocator<Type>::const_reference const_reference;
typedef TYPENAME allocator<Type>::size_type size_type;
INLINE dallocator() throw();
// template member functions in VC++ can only be defined in-class.
template<class U>
INLINE dallocator(const dallocator<U> &copy) throw() { }
INLINE pointer allocate(size_type n, allocator<void>::const_pointer hint = 0);
INLINE void deallocate(pointer p, size_type n);
template<class U> struct rebind {
typedef dallocator<U> other;
};
};
#include "dallocator.T"
#endif // USE_STL_ALLOCATOR
#endif

View File

@ -36,9 +36,8 @@ allocate(size_t size, TypeHandle type_handle) {
alloc_size += sizeof(PN_int32);
#endif // NDEBUG
TVOLATILE ObjectNode *obj;
ObjectNode *obj;
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
init_lock();
_lock->lock();
if (_deleted_chain != (ObjectNode *)NULL) {
@ -56,36 +55,13 @@ allocate(size_t size, TypeHandle type_handle) {
#ifdef DO_MEMORY_USAGE
type_handle.dec_memory_usage(TypeHandle::MC_deleted_chain_inactive, alloc_size);
type_handle.inc_memory_usage(TypeHandle::MC_deleted_chain_active, alloc_size);
(*global_mark_pointer)(ptr, max(size, sizeof(ObjectNode)), make_ref_ptr(ptr));
memory_hook->mark_pointer(ptr, max(size, sizeof(ObjectNode)), make_ref_ptr(ptr));
#endif // DO_MEMORY_USAGE
return ptr;
}
_lock->release();
#else // DELETED_CHAIN_USE_ATOMIC_EXCHANGE
obj = _deleted_chain;
while (obj != (ObjectNode *)NULL) {
TVOLATILE ObjectNode *next = obj->_next;
TVOLATILE ObjectNode *result = (ObjectNode *)AtomicAdjust::compare_and_exchange_ptr((void * TVOLATILE &)_deleted_chain, (void *)obj, (void *)next);
if (result == obj) {
// We got it.
#ifdef DO_MEMORY_USAGE
type_handle.dec_memory_usage(TypeHandle::MC_deleted_chain_inactive, alloc_size);
type_handle.inc_memory_usage(TypeHandle::MC_deleted_chain_active, alloc_size);
#endif // DO_MEMORY_USAGE
#ifdef USE_DELETEDCHAINFLAG
PN_int32 orig_flag = AtomicAdjust::compare_and_exchange(obj->_flag, DCF_deleted, DCF_alive);
assert(orig_flag == (PN_int32)DCF_deleted);
#endif // NDEBUG
return node_to_type(obj);
}
// Someone else grabbed the top link first. Try again.
obj = _deleted_chain;
}
#endif // DELETED_CHAIN_USE_ATOMIC_EXCHANGE
// If we get here, the deleted_chain is empty; we have to allocate a
// new object from the system pool.
@ -100,7 +76,7 @@ allocate(size_t size, TypeHandle type_handle) {
#ifdef DO_MEMORY_USAGE
type_handle.inc_memory_usage(TypeHandle::MC_deleted_chain_active, alloc_size);
(*global_mark_pointer)(ptr, max(size, sizeof(ObjectNode)), make_ref_ptr(ptr));
memory_hook->mark_pointer(ptr, max(size, sizeof(ObjectNode)), make_ref_ptr(ptr));
#endif // DO_MEMORY_USAGE
return ptr;
@ -120,7 +96,7 @@ deallocate(Type *ptr, TypeHandle type_handle) {
#ifdef DO_MEMORY_USAGE
size_t alloc_size = sizeof(Type);
(*global_mark_pointer)(ptr, 0, make_ref_ptr(ptr));
memory_hook->mark_pointer(ptr, 0, make_ref_ptr(ptr));
#ifdef USE_DELETEDCHAINFLAG
// In development mode, we also need to reserve space for _flag.
@ -131,7 +107,7 @@ deallocate(Type *ptr, TypeHandle type_handle) {
#endif // DO_MEMORY_USAGE
TVOLATILE ObjectNode *obj = type_to_node(ptr);
ObjectNode *obj = type_to_node(ptr);
#ifdef USE_DELETEDCHAINFLAG
PN_int32 orig_flag = AtomicAdjust::compare_and_exchange(obj->_flag, DCF_alive, DCF_deleted);
@ -144,7 +120,6 @@ deallocate(Type *ptr, TypeHandle type_handle) {
assert(orig_flag == (PN_int32)DCF_alive);
#endif // NDEBUG
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
// We have to test the lock again, even though we must have
// allocated this object at some point, because Windows might make
// multiple different DeletedChain instances for a particular Type,
@ -157,20 +132,6 @@ deallocate(Type *ptr, TypeHandle type_handle) {
_deleted_chain = obj;
_lock->release();
#else // DELETED_CHAIN_USE_ATOMIC_EXCHANGE
TVOLATILE ObjectNode *result;
TVOLATILE ObjectNode *next;
do {
next = _deleted_chain;
obj->_next = next;
result = type_to_node(AtomicAdjust::compare_and_exchange_ptr((void * TVOLATILE &)_deleted_chain, (void *)next, (void *)obj));
// Keep trying until no one else got to _deleted_chain first.
} while (result != next);
#endif // DELETED_CHAIN_USE_ATOMIC_EXCHANGE
}
////////////////////////////////////////////////////////////////////
@ -192,7 +153,7 @@ validate(const Type *ptr) {
}
#ifdef USE_DELETEDCHAINFLAG
TVOLATILE const ObjectNode *obj = type_to_node((Type *)ptr);
const ObjectNode *obj = type_to_node((Type *)ptr);
return AtomicAdjust::get(obj->_flag) == DCF_alive;
#else
return true;
@ -240,7 +201,7 @@ make_ref_ptr(ReferenceCount *ptr) {
////////////////////////////////////////////////////////////////////
template<class Type>
INLINE Type *DeletedChain<Type>::
node_to_type(TVOLATILE TYPENAME DeletedChain<Type>::ObjectNode *node) {
node_to_type(TYPENAME DeletedChain<Type>::ObjectNode *node) {
#ifdef USE_DELETEDCHAINFLAG
// In development mode, we increment the pointer so that the
// returned data does not overlap our _flags member.
@ -267,7 +228,6 @@ type_to_node(Type *ptr) {
#endif // NDEBUG
}
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
////////////////////////////////////////////////////////////////////
// Function: DeletedChain::init_lock
// Access: Private
@ -280,9 +240,7 @@ init_lock() {
do_init_lock(_lock);
}
}
#endif // DELETED_CHAIN_USE_ATOMIC_EXCHANGE
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
////////////////////////////////////////////////////////////////////
// Function: DeletedChain::do_init_lock
// Access: Private
@ -299,10 +257,6 @@ void DeletedChain<Type>::
do_init_lock(MutexImpl *&lock) {
MutexImpl *new_lock = new MutexImpl;
// Even though DELETED_CHAIN_USE_ATOMIC_EXCHANGE is not true, we
// will take advantage of the atomic exchange operation here, at
// startup. We have to rely on something, after all, before we have
// created the first mutex.
MutexImpl *result;
result = (MutexImpl *)AtomicAdjust::compare_and_exchange_ptr((void * TVOLATILE &)lock, (void *)NULL, (void *)new_lock);
@ -312,7 +266,6 @@ do_init_lock(MutexImpl *&lock) {
assert(lock != (MutexImpl *)NULL);
}
#endif // DELETED_CHAIN_USE_ATOMIC_EXCHANGE
////////////////////////////////////////////////////////////////////
// Function: StaticDeletedChain::allocate

View File

@ -28,15 +28,12 @@
#include "typeHandle.h"
#include <assert.h>
#ifdef HAVE_ATOMIC_COMPARE_AND_EXCHANGE_PTR
// Actually, there appears to be a (maybe fatal) flaw in our
// implementation of DeletedChain via the atomic exchange operation.
// Specifically, a pointer may be removed from the head of the chain,
// then the same pointer reinserted in the chain, while another thread
// is waiting; and that thread will not detect the change. For now,
// then, let's not use this implementation, and fall back to the mutex.
//#define DELETED_CHAIN_USE_ATOMIC_EXCHANGE
#endif
// Though it's tempting, it doesn't seem to be possible to implement
// DeletedChain via the atomic exchange operation. Specifically, a
// pointer may be removed from the head of the chain, then the same
// pointer reinserted in the chain, while another thread is waiting;
// and that thread will not detect the change. So instead, we always
// use a mutex.
#ifndef NDEBUG
// In development mode, we define USE_DELETEDCHAINFLAG, which
@ -105,21 +102,17 @@ private:
// pointer returned (unlike _flag, above). It's only used when
// the object is deleted, so there's no harm in sharing space with
// the undeleted object.
TVOLATILE ObjectNode * TVOLATILE _next;
ObjectNode *_next;
};
static INLINE Type *node_to_type(TVOLATILE ObjectNode *node);
static INLINE Type *node_to_type(ObjectNode *node);
static INLINE ObjectNode *type_to_node(Type *ptr);
TVOLATILE ObjectNode * TVOLATILE _deleted_chain;
ObjectNode *_deleted_chain;
#ifndef DELETED_CHAIN_USE_ATOMIC_EXCHANGE
// If we don't have atomic compare-and-exchange, we need to use a
// Mutex to protect the above linked list.
INLINE void init_lock();
void do_init_lock(MutexImpl *&lock);
MutexImpl *_lock;
#endif
};
////////////////////////////////////////////////////////////////////

View File

@ -17,139 +17,43 @@
////////////////////////////////////////////////////////////////////
#include "dtoolbase.h"
#include "memoryHook.h"
#if defined(USE_TAU) && defined(WIN32)
// Hack around tau's lack of DLL export declarations for Profiler class.
bool __tau_shutdown = false;
#endif
MemoryHook *memory_hook;
/////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: init_memory_hook
// Description: Any code that might need to use PANDA_MALLOC or
// PANDA_FREE, or any methods of the global memory_hook
// object, at static init time, should ensure that it
// calls init_memory_hook() first to ensure that the
// pointer has been properly initialized. There is no
// harm in calling this function more than once.
//
// Memory manager: DLMALLOC
//
// This is Doug Lea's memory manager. It is very fast,
// but it is not thread-safe.
//
/////////////////////////////////////////////////////////////////////
#if defined(USE_MEMORY_DLMALLOC)
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
#error Cannot use dlmalloc library with threading enabled!
#endif
#define USE_DL_PREFIX 1
#define NO_MALLINFO 1
#include "dlmalloc.h"
void *default_operator_new(size_t size) {
void *ptr = dlmalloc(size);
if (ptr == (void *)NULL) {
cerr << "Out of memory!\n";
abort();
// There is no need to call this function other than at
// static init time.
////////////////////////////////////////////////////////////////////
void
init_memory_hook() {
if (memory_hook == NULL) {
memory_hook = new MemoryHook;
}
return ptr;
}
void default_operator_delete(void *ptr) {
dlfree(ptr);
}
void default_mark_pointer(void *, size_t, ReferenceCount *) {
}
void *(*global_operator_new)(size_t size) = &default_operator_new;
void (*global_operator_delete)(void *ptr) = &default_operator_delete;
void (*global_mark_pointer)(void *ptr, size_t size, ReferenceCount *ref_ptr) = &default_mark_pointer;
/////////////////////////////////////////////////////////////////////
//
// Memory manager: PTMALLOC2
//
// Ptmalloc2 is a derivative of Doug Lea's memory manager that was
// made thread-safe by Wolfram Gloger, then was ported to windows by
// Niall Douglas. It is not quite as fast as dlmalloc (because the
// thread-safety constructs take a certain amount of CPU time), but
// it's still much faster than the windows allocator.
//
/////////////////////////////////////////////////////////////////////
#elif defined(USE_MEMORY_PTMALLOC2) && !defined(linux)
// This doesn't appear to work in Linux; perhaps it is clashing with
// the system library. On Linux, fall through to the next case
// instead.
#define USE_DL_PREFIX 1
#define NO_MALLINFO 1
#include "ptmalloc2_smp.c"
void *default_operator_new(size_t size) {
void *ptr = dlmalloc(size);
if (ptr == (void *)NULL) {
cerr << "Out of memory!\n";
abort();
// Here's a quick way to ensure the above function is called at least
// once at static init time.
class InitMemoryHook {
public:
InitMemoryHook() {
init_memory_hook();
}
return ptr;
}
void default_operator_delete(void *ptr) {
dlfree(ptr);
}
void default_mark_pointer(void *, size_t, ReferenceCount *) {
}
void *(*global_operator_new)(size_t size) = &default_operator_new;
void (*global_operator_delete)(void *ptr) = &default_operator_delete;
void (*global_mark_pointer)(void *ptr, size_t size, ReferenceCount *ref_ptr) = &default_mark_pointer;
/////////////////////////////////////////////////////////////////////
//
// Memory manager: MALLOC
//
// This option uses the built-in system allocator. This is a good
// choice on linux, but it's a terrible choice on windows.
//
/////////////////////////////////////////////////////////////////////
#elif defined(USE_MEMORY_MALLOC) || defined(USE_MEMORY_PTMALLOC2)
void *default_operator_new(size_t size) {
void *ptr = malloc(size);
if (ptr == (void *)NULL) {
cerr << "Out of memory!\n";
abort();
}
return ptr;
}
void default_operator_delete(void *ptr) {
free(ptr);
}
void default_mark_pointer(void *, size_t, ReferenceCount *) {
}
void *(*global_operator_new)(size_t size) = &default_operator_new;
void (*global_operator_delete)(void *ptr) = &default_operator_delete;
void (*global_mark_pointer)(void *ptr, size_t size, ReferenceCount *ref_ptr) = &default_mark_pointer;
/////////////////////////////////////////////////////////////////////
//
// Memory manager: NOWRAPPERS
//
// Not only do we use the built-in system definitions for new and
// delete, but we don't even wrap them. This removes a tiny bit of
// extra overhead from the above option, but prevents Panda's
// MemoryUsage class from being able to track memory allocations.
//
/////////////////////////////////////////////////////////////////////
#else
#endif // USE_MEMORY_*
};
static InitMemoryHook _imh_object;
#if defined(HAVE_THREADS) && defined(SIMPLE_THREADS)

View File

@ -142,59 +142,21 @@ typedef ios::seekdir ios_seekdir;
// level.
class ReferenceCount;
// Now redefine global operators new and delete so we can optionally
// provide custom handlers for them. The MemoryUsage class in Panda
// takes advantage of this to track the size of allocated pointers.
// We need a pointer to a global MemoryHook object, to manage all
// malloc and free requests from Panda. See the comments in
// MemoryHook itself.
class MemoryHook;
EXPCL_DTOOL extern MemoryHook *memory_hook;
EXPCL_DTOOL void init_memory_hook();
// Now redefine some handy macros to hook into the above MemoryHook
// object.
#ifndef USE_MEMORY_NOWRAPPERS
EXPCL_DTOOL void *default_operator_new(size_t size);
EXPCL_DTOOL void default_operator_delete(void *ptr);
EXPCL_DTOOL void default_mark_pointer(void *ptr, size_t orig_size,
ReferenceCount *ref_ptr);
extern EXPCL_DTOOL void *(*global_operator_new)(size_t size);
extern EXPCL_DTOOL void (*global_operator_delete)(void *ptr);
extern EXPCL_DTOOL void (*global_mark_pointer)(void *ptr, size_t size,
ReferenceCount *ref_ptr);
#ifdef REDEFINE_GLOBAL_OPERATOR_NEW
#ifdef GLOBAL_OPERATOR_NEW_EXCEPTIONS
// Redefinitions of operator new/delete, for O1 - O3 builds (!NDEBUG)
// only. These flavors are for modern compilers that expect these
// function prototypes to handle exceptions.
INLINE void *operator new(size_t size) throw (std::bad_alloc) {
return (*global_operator_new)(size);
}
INLINE void *operator new[](size_t size) throw (std::bad_alloc) {
return (*global_operator_new)(size);
}
INLINE void operator delete(void *ptr) throw() {
(*global_operator_delete)(ptr);
}
INLINE void operator delete[](void *ptr) throw() {
(*global_operator_delete)(ptr);
}
#else // GLOBAL_OPERATOR_NEW_EXCEPTIONS
// The same definitions as above, for compilers that don't expect
// exception handing in global operator new/delete functions.
INLINE void *operator new(size_t size) {
return (*global_operator_new)(size);
}
INLINE void *operator new[](size_t size) {
return (*global_operator_new)(size);
}
INLINE void operator delete(void *ptr) {
(*global_operator_delete)(ptr);
}
INLINE void operator delete[](void *ptr) {
(*global_operator_delete)(ptr);
}
#endif // GLOBAL_OPERATOR_NEW_EXCEPTIONS
#endif // REDEFINE_GLOBAL_OPERATOR_NEW
#define PANDA_MALLOC(size) (memory_hook->heap_alloc(size))
#define PANDA_FREE(ptr) memory_hook->heap_free(ptr)
#else
#define PANDA_MALLOC(size) malloc(size)
#define PANDA_FREE(ptr) free(ptr)
#endif // USE_MEMORY_NOWRAPPERS
#if defined(HAVE_THREADS) && defined(SIMPLE_THREADS)

View File

@ -5,4 +5,5 @@
#include "atomicAdjustWin32Impl.cxx"
#include "dtoolbase.cxx"
#include "memoryBase.cxx"
#include "memoryHook.cxx"
#include "mutexDummyImpl.cxx"

View File

@ -20,6 +20,7 @@
#define MEMORYBASE_H
#include "dtoolbase.h"
#include "memoryHook.h"
// Place this macro within a class definition to define appropriate
// operator new and delete methods that hook into the MemoryInfo class
@ -31,24 +32,24 @@
#define ALLOC_MEMORY_BASE \
inline void *operator new(size_t size) { \
return (*global_operator_new)(size); \
return PANDA_MALLOC(size); \
} \
inline void *operator new(size_t size, void *ptr) { \
return ptr; \
} \
inline void operator delete(void *ptr) { \
(*global_operator_delete)(ptr); \
PANDA_FREE(ptr); \
} \
inline void operator delete(void *ptr, void *) { \
} \
inline void *operator new[](size_t size) { \
return (*global_operator_new)(size); \
return PANDA_MALLOC(size); \
} \
inline void *operator new[](size_t size, void *ptr) { \
return ptr; \
} \
inline void operator delete[](void *ptr) { \
(*global_operator_delete)(ptr); \
PANDA_FREE(ptr); \
} \
inline void operator delete[](void *, void *) { \
}

View File

@ -0,0 +1,75 @@
// Filename: memoryHook.I
// Created by: drose (28Jun07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: MemoryHook::get_page_size
// Access: Public
// Description: Returns the operating system page size. This is the
// minimum granularity required for calls to
// mmap_alloc(). Also see round_up_to_page_size().
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryHook::
get_page_size() const {
return _page_size;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryHook::round_up_to_page_size
// Access: Public
// Description: Rounds the indicated size request up to the next
// larger multiple of page_size, to qualify it for a
// call to mmap_alloc().
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryHook::
round_up_to_page_size(size_t size) const {
return ((size + _page_size - 1) / _page_size) * _page_size;
}
#ifdef DO_MEMORY_USAGE
////////////////////////////////////////////////////////////////////
// Function: MemoryHook::alloc_to_ptr
// Access: Private
// Description: Converts an allocated pointer to a pointer returnable
// to the application. Stuffs size in the first n bytes
// of the allocated space.
////////////////////////////////////////////////////////////////////
INLINE void *MemoryHook::
alloc_to_ptr(void *alloc, size_t size) {
size_t *root = (size_t *)alloc;
root[0] = size;
return (void *)(root + 1);
}
#endif // DO_MEMORY_USAGE
#ifdef DO_MEMORY_USAGE
////////////////////////////////////////////////////////////////////
// Function: MemoryHook::ptr_to_alloc
// Access: Private
// Description: Converts an application pointer back to the original
// allocated pointer. Extracts size from the first n
// bytes of the allocated space.
////////////////////////////////////////////////////////////////////
INLINE void *MemoryHook::
ptr_to_alloc(void *ptr, size_t &size) {
size_t *root = (size_t *)ptr;
root -= 1;
size = root[0];
return (void *)root;
}
#endif // DO_MEMORY_USAGE

View File

@ -0,0 +1,294 @@
// Filename: memoryHook.cxx
// Created by: drose (28Jun07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "memoryHook.h"
#ifdef WIN32
// Windows case.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
// Posix case.
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#endif // WIN32
#if defined(USE_MEMORY_DLMALLOC)
/////////////////////////////////////////////////////////////////////
//
// Memory manager: DLMALLOC
//
// This is Doug Lea's memory manager. It is very fast,
// but it is not thread-safe.
//
/////////////////////////////////////////////////////////////////////
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
#error Cannot use dlmalloc library with threading enabled!
#endif
#define USE_DL_PREFIX 1
#define NO_MALLINFO 1
#include "dlmalloc.h"
#define call_malloc dlmalloc
#define call_free dlfree
#elif defined(USE_MEMORY_PTMALLOC2) && !defined(linux)
// This doesn't appear to work in Linux; perhaps it is clashing with
// the system library. On Linux, fall through to the next case
// instead.
/////////////////////////////////////////////////////////////////////
//
// Memory manager: PTMALLOC2
//
// Ptmalloc2 is a derivative of Doug Lea's memory manager that was
// made thread-safe by Wolfram Gloger, then was ported to windows by
// Niall Douglas. It is not quite as fast as dlmalloc (because the
// thread-safety constructs take a certain amount of CPU time), but
// it's still much faster than the windows allocator.
//
/////////////////////////////////////////////////////////////////////
#define USE_DL_PREFIX 1
#define NO_MALLINFO 1
#include "ptmalloc2_smp.c"
#define call_malloc dlmalloc
#define call_free dlfree
#else
/////////////////////////////////////////////////////////////////////
//
// Memory manager: MALLOC
//
// This option uses the built-in system allocator. This is a good
// choice on linux, but it's a terrible choice on windows.
//
/////////////////////////////////////////////////////////////////////
#define call_malloc malloc
#define call_free free
#endif // USE_MEMORY_*
////////////////////////////////////////////////////////////////////
// Function: MemoryHook::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
MemoryHook::
MemoryHook() {
#ifdef WIN32
// Windows case.
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
_page_size = (size_t)sysinfo.dwPageSize;
#else
// Posix case.
_page_size = getpagesize();
#endif // WIN32
#ifdef DO_MEMORY_USAGE
_total_heap_size = 0;
_total_mmap_size = 0;
#endif
}
////////////////////////////////////////////////////////////////////
// Function: MemoryHook::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
MemoryHook::
MemoryHook(const MemoryHook &copy) :
_page_size(copy._page_size)
{
#ifdef DO_MEMORY_USAGE
_total_heap_size = copy._total_heap_size;
_total_mmap_size = copy._total_mmap_size;
#endif
}
////////////////////////////////////////////////////////////////////
// Function: MemoryHook::heap_alloc
// Access: Public, Virtual
// Description: Allocates a block of memory from the heap, similar to
// malloc(). This will never return NULL; it will abort
// instead if memory is not available.
////////////////////////////////////////////////////////////////////
void *MemoryHook::
heap_alloc(size_t size) {
void *ptr;
#ifdef DO_MEMORY_USAGE
// In the DO_MEMORY_USAGE case, we want to track the total size of
// allocated bytes on the heap.
_total_heap_size += size;
ptr = alloc_to_ptr(call_malloc(size + sizeof(size)), size);
#else
ptr = call_malloc(size);
#endif // DO_MEMORY_USAGE
if (ptr == (void *)NULL) {
cerr << "Out of memory!\n";
abort();
}
return ptr;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryHook::heap_free
// Access: Public, Virtual
// Description: Releases a block of memory previously allocated via
// heap_alloc.
////////////////////////////////////////////////////////////////////
void MemoryHook::
heap_free(void *ptr) {
#ifdef DO_MEMORY_USAGE
// In the DO_MEMORY_USAGE case, we want to track the total size of
// allocated bytes on the heap.
size_t size;
ptr = ptr_to_alloc(ptr, size);
assert(size <= _total_heap_size);
_total_heap_size -= size;
#endif // DO_MEMORY_USAGE
call_free(ptr);
}
////////////////////////////////////////////////////////////////////
// Function: MemoryHook::mmap_alloc
// Access: Public, Virtual
// Description: Allocates a raw page or pages of memory directly from
// the OS. This will be in a different address space
// from the memory allocated by heap_alloc(), and so it
// won't contribute to fragmentation of that memory.
//
// The allocation size must be an integer multiple of
// the page size. Use round_to_page_size() if there is
// any doubt.
//
// If allow_exec is true, the memory will be flagged so
// that it is legal to execute code that has been
// written to this memory.
////////////////////////////////////////////////////////////////////
void *MemoryHook::
mmap_alloc(size_t size, bool allow_exec) {
assert((size % _page_size) == 0);
#ifdef DO_MEMORY_USAGE
_total_mmap_size += size;
#endif
#ifdef WIN32
// Windows case.
void *ptr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE,
allow_exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE);
if (ptr == (void *)NULL) {
DWORD err = GetLastError();
cerr << "Couldn't allocate memory page of size " << needed_size
<< ": ";
PVOID buffer;
DWORD length =
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, err, 0, (LPTSTR)&buffer, 0, NULL);
if (length != 0) {
cerr << (char *)buffer << "\n";
} else {
cerr << "Error code " << err << "\n";
}
LocalFree(buffer);
abort();
}
return ptr;
#else
// Posix case.
int prot = PROT_READ | PROT_WRITE;
if (allow_exec) {
prot |= PROT_EXEC;
}
void *ptr = mmap(NULL, size, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
if (ptr == (void *)-1) {
perror("mmap");
abort();
}
return ptr;
#endif // WIN32
}
////////////////////////////////////////////////////////////////////
// Function: MemoryHook::mmap_free
// Access: Public, Virtual
// Description: Frees a block of memory previously allocated via
// mmap_alloc(). You must know how large the block was.
////////////////////////////////////////////////////////////////////
void MemoryHook::
mmap_free(void *ptr, size_t size) {
assert((size % _page_size) == 0);
#ifdef DO_MEMORY_USAGE
assert(size <= _total_mmap_size);
_total_mmap_size -= size;
#endif
#ifdef WIN32
VirtualFree(ptr, 0, MEM_RELEASE);
#else
munmap(ptr, size);
#endif
}
////////////////////////////////////////////////////////////////////
// Function: MemoryHook::mark_pointer
// Access: Public, Virtual
// Description: This special method exists only to provide a callback
// hook into MemoryUsage. It indicates that the
// indicated pointer, allocated from somewhere other
// than a call to heap_alloc(), now contains a pointer
// to the indicated ReferenceCount object. If orig_size
// is 0, it indicates that the ReferenceCount object has
// been destroyed.
////////////////////////////////////////////////////////////////////
void MemoryHook::
mark_pointer(void *, size_t, ReferenceCount *) {
}

View File

@ -0,0 +1,62 @@
// Filename: memoryHook.h
// Created by: drose (28Jun07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef MEMORYHOOK_H
#define MEMORYHOOK_H
#include "dtoolbase.h"
////////////////////////////////////////////////////////////////////
// Class : MemoryHook
// Description : This class is provided to allow the MemoryUsage class
// in Panda to insert callback hooks to track the size
// of allocated pointers. Every low-level alloc and
// free operation (except in production builds) should
// vector through this class to facilitate that.
////////////////////////////////////////////////////////////////////
class EXPCL_DTOOL MemoryHook {
public:
MemoryHook();
MemoryHook(const MemoryHook &copy);
virtual void *heap_alloc(size_t size);
virtual void heap_free(void *ptr);
virtual void *mmap_alloc(size_t size, bool allow_exec);
virtual void mmap_free(void *ptr, size_t size);
INLINE size_t get_page_size() const;
INLINE size_t round_up_to_page_size(size_t size) const;
virtual void mark_pointer(void *ptr, size_t orig_size, ReferenceCount *ref_ptr);
private:
size_t _page_size;
#ifdef DO_MEMORY_USAGE
INLINE static void *alloc_to_ptr(void *alloc, size_t size);
INLINE static void *ptr_to_alloc(void *ptr, size_t &size);
protected:
size_t _total_heap_size;
size_t _total_mmap_size;
#endif
};
#include "memoryHook.I"
#endif

View File

@ -18,21 +18,7 @@
#include "neverFreeMemory.h"
#include "atomicAdjust.h"
#ifdef WIN32
// Windows case.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
// Posix case.
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#endif // WIN32
#include "memoryHook.h"
NeverFreeMemory * TVOLATILE NeverFreeMemory::_global_ptr;
@ -52,23 +38,6 @@ NeverFreeMemory::
NeverFreeMemory() {
_total_alloc = 0;
_total_used = 0;
_page_size = 1;
#ifdef WIN32
// Windows case.
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
_page_size = (size_t)sysinfo.dwPageSize;
#else
// Posix case.
_page_size = getpagesize();
#endif // WIN32
}
////////////////////////////////////////////////////////////////////
@ -100,47 +69,8 @@ ns_alloc(size_t size) {
// We have to allocate a new page. Allocate at least min_page_size
// bytes, and then round that up to the next _page_size bytes.
size_t needed_size = max(size, min_page_size);
needed_size = ((needed_size + _page_size - 1) / _page_size) * _page_size;
void *start = NULL;
#ifdef WIN32
// Windows case.
start = VirtualAlloc(NULL, needed_size, MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE);
if (start == (void *)NULL) {
DWORD err = GetLastError();
cerr << "Couldn't allocate memory page of size " << needed_size
<< ": ";
PVOID buffer;
DWORD length =
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, err, 0, (LPTSTR)&buffer, 0, NULL);
if (length != 0) {
cerr << (char *)buffer << "\n";
} else {
cerr << "Error code " << err << "\n";
}
LocalFree(buffer);
}
#else
// Posix case.
start = mmap(NULL, needed_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0);
if (start == (void *)-1) {
perror("mmap");
start = NULL;
}
#endif // WIN32
if (start == NULL) {
start = malloc(needed_size);
}
needed_size = memory_hook->round_up_to_page_size(needed_size);
void *start = memory_hook->mmap_alloc(needed_size, false);
_total_alloc += needed_size;
Page page(start, needed_size);

View File

@ -69,7 +69,6 @@ private:
typedef set<Page> Pages;
Pages _pages;
size_t _page_size;
size_t _total_alloc;
size_t _total_used;
MutexImpl _lock;

View File

@ -55,7 +55,7 @@ allocate(TYPENAME pallocator_array<Type>::size_type n, TYPENAME allocator<void>:
// We also need to store the total number of bytes we allocated.
alloc_size += sizeof(size_t);
_type_handle.inc_memory_usage(TypeHandle::MC_array, (int)alloc_size);
void *ptr = (TYPENAME pallocator_array<Type>::pointer)(*global_operator_new)(alloc_size);
void *ptr = (TYPENAME pallocator_array<Type>::pointer)PANDA_MALLOC(alloc_size);
*((size_t *)ptr) = alloc_size;
return (TYPENAME pallocator_array<Type>::pointer)(((size_t *)ptr) + 1);
#else
@ -71,7 +71,7 @@ deallocate(TYPENAME pallocator_array<Type>::pointer p, TYPENAME pallocator_array
// Now we need to recover the total number of bytes.
size_t alloc_size = *(((size_t *)p) - 1);
_type_handle.dec_memory_usage(TypeHandle::MC_array, (int)alloc_size);
(*global_operator_delete)(((size_t *)p) - 1);
PANDA_FREE(((size_t *)p) - 1);
#else
free(p);
#endif // DO_MEMORY_USAGE

View File

@ -21,6 +21,7 @@
#include <memory>
#include "dtoolbase.h"
#include "memoryHook.h"
#include "deletedChain.h"
#include "typeHandle.h"
@ -60,7 +61,7 @@ public:
typedef TYPENAME allocator<Type>::const_reference const_reference;
typedef TYPENAME allocator<Type>::size_type size_type;
INLINE pallocator_single(TypeHandle type_handle = TypeHandle::none()) throw();
INLINE pallocator_single(TypeHandle type_handle) throw();
// template member functions in VC++ can only be defined in-class.
template<class U>

View File

@ -59,6 +59,7 @@ inc_memory_usage(MemoryClass memory_class, int size) {
TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL);
assert(rnode != (TypeRegistryNode *)NULL);
AtomicAdjust::add(rnode->_memory_usage[memory_class], (PN_int32)size);
// cerr << *this << ".inc(" << memory_class << ", " << size << ") -> " << rnode->_memory_usage[memory_class] << "\n";
assert(rnode->_memory_usage[memory_class] >= 0);
}
}
@ -78,6 +79,9 @@ dec_memory_usage(MemoryClass memory_class, int size) {
TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL);
assert(rnode != (TypeRegistryNode *)NULL);
AtomicAdjust::add(rnode->_memory_usage[memory_class], -(PN_int32)size);
if (rnode->_memory_usage[memory_class] < 0) {
cerr << *this << ".dec(" << memory_class << ", " << size << ") -> " << rnode->_memory_usage[memory_class] << "\n";
}
assert(rnode->_memory_usage[memory_class] >= 0);
}
}

View File

@ -35,6 +35,7 @@ ConfigVariableManager *ConfigVariableManager::_global_ptr = NULL;
////////////////////////////////////////////////////////////////////
ConfigVariableManager::
ConfigVariableManager() {
init_memory_hook();
}
////////////////////////////////////////////////////////////////////

View File

@ -380,6 +380,7 @@ write_string(const string &str) {
Notify *Notify::
ptr() {
if (_global_ptr == (Notify *)NULL) {
init_memory_hook();
_global_ptr = new Notify;
}
return _global_ptr;

View File

@ -24,6 +24,7 @@
#include "notifySeverity.h"
#include "configVariableEnum.h"
#include "configFlags.h"
#include "memoryBase.h"
#include <vector>
@ -36,7 +37,7 @@
// created within a package if a finer grain of control
// is required.
////////////////////////////////////////////////////////////////////
class EXPCL_DTOOLCONFIG NotifyCategory : public ConfigFlags {
class EXPCL_DTOOLCONFIG NotifyCategory : public MemoryBase, public ConfigFlags {
private:
NotifyCategory(const string &fullname, const string &basename,
NotifyCategory *parent);

View File

@ -20,7 +20,6 @@
#define NOTIFY_H
#include "dtoolbase.h"
#include "notifySeverity.h"
#include <map>

View File

@ -143,6 +143,7 @@ public:
EggNamedObject::init_type();
register_type(_type_handle, "EggNode",
EggNamedObject::get_class_type());
MatrixFrame::init_type();
}
virtual TypeHandle get_type() const {
return get_class_type();

View File

@ -109,61 +109,46 @@ is_counting() {
// Function: MemoryUsage::get_current_cpp_size
// Access: Public, Static
// Description: Returns the total number of bytes of allocated memory
// via the C++ operators new and delete as counted,
// not including the memory previously frozen.
// consumed by C++ objects, not including the memory
// previously frozen.
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage::
get_current_cpp_size() {
return get_global_ptr()->ns_get_current_cpp_size();
return get_global_ptr()->_current_cpp_size;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::has_cpp_size
// Access: Public, Static
// Description: Returns true if the value returned by
// get_cpp_size() is meaningful on this particular
// system with this particular configuration, false
// otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool MemoryUsage::
has_cpp_size() {
#if defined(WIN32_VC) && defined(_DEBUG)
// Windows in debug mode can count C++ size without having to do a
// full track.
return is_counting();
#else
// Other systems require the full hammer.
return is_tracking();
#endif
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::get_cpp_size
// Function: MemoryUsage::get_total_cpp_size
// Access: Public, Static
// Description: Returns the total number of bytes of allocated memory
// via the C++ operators new and delete as counted,
// including the memory previously frozen.
// consumed by C++ objects, including the memory
// previously frozen.
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage::
get_cpp_size() {
return get_global_ptr()->ns_get_cpp_size();
get_total_cpp_size() {
return get_global_ptr()->_total_cpp_size;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::has_interpreter_size
// Function: MemoryUsage::get_panda_heap_size
// Access: Public, Static
// Description: Returns true if the value returned by
// get_interpreter_size() is meaningful on this particular
// system with this particular configuration, false
// otherwise.
// Description: Returns the total number of bytes allocated from the
// heap from code within Panda.
////////////////////////////////////////////////////////////////////
INLINE bool MemoryUsage::
has_interpreter_size() {
#ifdef TRACK_IN_INTERPRETER
return is_counting();
#else
return false;
#endif
INLINE size_t MemoryUsage::
get_panda_heap_size() {
return get_global_ptr()->_total_heap_size;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::get_panda_mmap_size
// Access: Public, Static
// Description: Returns the total number of bytes allocated from the
// virtual memory pool from code within Panda.
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage::
get_panda_mmap_size() {
return get_global_ptr()->_total_mmap_size;
}
////////////////////////////////////////////////////////////////////
@ -174,43 +159,51 @@ has_interpreter_size() {
// number is only meaningful if both Panda and the
// high-level language are single-threaded, and running
// in the same thread.
//
// This number is only available if Panda is able to
// hook into the actual heap callback.
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage::
get_interpreter_size() {
return get_global_ptr()->ns_get_interpreter_size();
return get_global_ptr()->_interpreter_size;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::has_total_size
// Function: MemoryUsage::get_external_size
// Access: Public, Static
// Description: Returns true if the value returned by
// get_total_size() is meaningful on this particular
// system with this particular configuration, false
// otherwise.
// Description: Returns the total number of bytes of allocated memory
// in the heap that Panda didn't seem to be responsible
// for. This includes a few bytes for very low-level
// objects (like ConfigVariables) that cannot use Panda
// memory tracking because they are so very low-level.
//
// This number is only available if Panda is able to
// hook into the actual heap callback.
////////////////////////////////////////////////////////////////////
INLINE bool MemoryUsage::
has_total_size() {
#if defined(WIN32_VC) && defined(_DEBUG)
// Windows in debug mode can count total size without having to do a
// full track.
return is_counting();
#else
// Other systems require the full hammer.
return is_tracking();
#endif
INLINE size_t MemoryUsage::
get_external_size() {
MemoryUsage *mu = get_global_ptr();
if (mu->_count_memory_usage) {
return mu->_total_size - mu->_total_heap_size;
} else {
return 0;
}
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::get_total_size
// Access: Public, Static
// Description: Returns the total size of the dynamic heap, as nearly
// as can be determined, including all allocated memory
// if possible, in addition to that tracked by
// get_cpp_size().
// Description: Returns the total size of allocated memory consumed
// by the process, as nearly as can be determined.
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage::
get_total_size() {
return get_global_ptr()->ns_get_total_size();
MemoryUsage *mu = get_global_ptr();
if (mu->_count_memory_usage) {
return mu->_total_size;
} else {
return mu->_total_heap_size;
}
}
////////////////////////////////////////////////////////////////////

View File

@ -33,11 +33,7 @@
#include "config_express.h"
#include <algorithm>
MemoryUsage *MemoryUsage::_global_ptr = (MemoryUsage *)NULL;
// This flag is set true in is_counting() mode to indicate that the
// malloc operation is coming from C++ operator new or delete.
bool MemoryUsage::_is_cpp_operator = false;
MemoryUsage *MemoryUsage::_global_ptr;
// This flag is used to protect the operator new/delete handlers
// against recursive entry.
@ -90,7 +86,7 @@ void MemoryUsage::TypeHistogram::
show() const {
// First, copy the relevant information to a vector so we can sort
// by counts. Don't use a pvector.
typedef vector<TypeHistogramCountSorter, dallocator<TypeHistogramCountSorter> > CountSorter;
typedef vector<TypeHistogramCountSorter> CountSorter;
CountSorter count_sorter;
Counts::const_iterator ci;
for (ci = _counts.begin(); ci != _counts.end(); ++ci) {
@ -191,20 +187,18 @@ choose_bucket(double age) const {
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::operator_new_handler
// Access: Public, Static
// Description: This is set up as a global handler function (by
// redefining a function pointer in Dtool) for the
// operator new function. If track-memory-usage is
// enabled, this function will be called whenever any
// new operator within the Panda source is invoked.
// Function: MemoryUsage::heap_alloc
// Access: Public, Virtual
// Description: Allocates a block of memory from the heap, similar to
// malloc(). This will never return NULL; it will abort
// instead if memory is not available.
////////////////////////////////////////////////////////////////////
void *MemoryUsage::
operator_new_handler(size_t size) {
heap_alloc(size_t size) {
void *ptr;
if (_recursion_protect) {
ptr = default_operator_new(size);
ptr = MemoryHook::heap_alloc(size);
if (express_cat.is_spam()) {
express_cat.spam()
<< "Allocating pointer " << (void *)ptr
@ -212,9 +206,8 @@ operator_new_handler(size_t size) {
}
} else {
MemoryUsage *mu = get_global_ptr();
if (mu->_track_memory_usage) {
ptr = default_operator_new(size);
if (_track_memory_usage) {
ptr = MemoryHook::heap_alloc(size);
/*
if (express_cat.is_spam()) {
express_cat.spam()
@ -226,9 +219,7 @@ operator_new_handler(size_t size) {
get_global_ptr()->ns_record_void_pointer(ptr, size);
} else {
_is_cpp_operator = true;
ptr = default_operator_new(size);
_is_cpp_operator = false;
ptr = MemoryHook::heap_alloc(size);
}
}
@ -236,58 +227,98 @@ operator_new_handler(size_t size) {
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::operator_delete_handler
// Access: Public, Static
// Description: This is set up as a global handler function (by
// redefining a function pointer in Dtool) for the
// operator delete function. If track-memory-usage is
// enabled, this function will be called whenever any
// delete operator within the Panda source is invoked.
// Function: MemoryUsage::heap_free
// Access: Public, Virtual
// Description: Releases a block of memory previously allocated via
// heap_alloc.
////////////////////////////////////////////////////////////////////
void MemoryUsage::
operator_delete_handler(void *ptr) {
heap_free(void *ptr) {
if (_recursion_protect) {
if (express_cat.is_spam()) {
express_cat.spam()
<< "Deleting pointer " << (void *)ptr
<< " during recursion protect.\n";
}
default_operator_delete(ptr);
MemoryHook::heap_free(ptr);
} else {
MemoryUsage *mu = get_global_ptr();
if (mu->_track_memory_usage) {
if (_track_memory_usage) {
/*
if (express_cat.is_spam()) {
express_cat.spam()
<< "Removing pointer " << (void *)ptr << "\n";
}
*/
mu->ns_remove_void_pointer(ptr);
default_operator_delete(ptr);
ns_remove_void_pointer(ptr);
MemoryHook::heap_free(ptr);
} else {
_is_cpp_operator = true;
default_operator_delete(ptr);
_is_cpp_operator = false;
MemoryHook::heap_free(ptr);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::mark_pointer_handler
// Access: Public, Static
// Description: This special function is similar to operator_new_handler,
// but instead of allocating new memory it simply marks
// existing memory as already having been allocated.
// Function: MemoryUsage::mark_pointer
// Access: Public, Virtual
// Description: This special method exists only to provide a callback
// hook into MemoryUsage. It indicates that the
// indicated pointer, allocated from somewhere other
// than a call to heap_alloc(), now contains a pointer
// to the indicated ReferenceCount object. If orig_size
// is 0, it indicates that the ReferenceCount object has
// been destroyed.
////////////////////////////////////////////////////////////////////
void MemoryUsage::
mark_pointer_handler(void *ptr, size_t size,
ReferenceCount *ref_ptr) {
if (!_recursion_protect) {
MemoryUsage *mu = get_global_ptr();
if (mu->_track_memory_usage) {
mu->ns_mark_pointer(ptr, size, ref_ptr);
mark_pointer(void *ptr, size_t size, ReferenceCount *ref_ptr) {
if (_recursion_protect || !_track_memory_usage) {
return;
}
if (express_cat.is_spam()) {
express_cat.spam()
<< "Marking pointer " << ptr << ", size " << size
<< ", ref_ptr = " << ref_ptr << "\n";
}
if (size != 0) {
// We're recording this pointer as now in use.
ns_record_void_pointer(ptr, size);
if (ref_ptr != (ReferenceCount *)NULL) {
// Make the pointer typed. This is particularly necessary in
// case the ref_ptr is a different value than the base void
// pointer; this may be our only opportunity to associate the
// two pointers.
Table::iterator ti;
ti = _table.find(ptr);
nassertv(ti != _table.end());
MemoryInfo *info = (*ti).second;
info->_ref_ptr = ref_ptr;
info->_static_type = ReferenceCount::get_class_type();
info->_dynamic_type = ReferenceCount::get_class_type();
info->_flags |= MemoryInfo::F_reconsider_dynamic_type;
if (ref_ptr != ptr) {
_recursion_protect = true;
pair<Table::iterator, bool> insert_result =
_table.insert(Table::value_type((void *)ref_ptr, info));
assert(insert_result.first != _table.end());
if (!insert_result.second) {
express_cat.warning()
<< "Attempt to mark pointer " << ptr << " as ReferenceCount "
<< ref_ptr << ", which was already allocated.\n";
}
_recursion_protect = false;
}
}
} else {
// We're removing this pointer from use.
ns_remove_void_pointer(ptr);
}
}
@ -324,13 +355,6 @@ win32_malloc_hook(int alloc_type, void *ptr,
mu->_total_size += increment;
/*
This isn't working reliably right now.
if (_is_cpp_operator) {
mu->_cpp_size += increment;
}
*/
#ifdef TRACK_IN_INTERPRETER
if (in_interpreter) {
mu->_interpreter_size += increment;
@ -351,7 +375,7 @@ win32_malloc_hook(int alloc_type, void *ptr,
// Description:
////////////////////////////////////////////////////////////////////
MemoryUsage::
MemoryUsage() {
MemoryUsage(const MemoryHook &copy) : MemoryHook(copy) {
// We must get these variables here instead of in
// config_express.cxx, because we need to know it at static init
// time, and who knows when the code in config_express will be
@ -378,20 +402,8 @@ MemoryUsage() {
#error Cannot compile MemoryUsage without malloc wrappers!
#endif
if (_track_memory_usage) {
// Redefine the global pointers for operator new and operator
// delete (these pointers are defined up in DTOOL) to vector into
// this class.
global_operator_new = &operator_new_handler;
global_operator_delete = &operator_delete_handler;
global_mark_pointer = &mark_pointer_handler;
}
#if defined(WIN32_VC) && defined(_DEBUG)
if (_count_memory_usage) {
global_operator_new = &operator_new_handler;
global_operator_delete = &operator_delete_handler;
global_mark_pointer = &mark_pointer_handler;
_CrtSetAllocHook(&win32_malloc_hook);
}
#endif
@ -400,7 +412,7 @@ MemoryUsage() {
_freeze_index = 0;
_count = 0;
_current_cpp_size = 0;
_cpp_size = 0;
_total_cpp_size = 0;
_interpreter_size = 0;
_total_size = 0;
}
@ -414,7 +426,9 @@ MemoryUsage() {
MemoryUsage *MemoryUsage::
get_global_ptr() {
if (_global_ptr == (MemoryUsage *)NULL) {
_global_ptr = new MemoryUsage;
init_memory_hook();
_global_ptr = new MemoryUsage(*memory_hook);
memory_hook = _global_ptr;
}
return _global_ptr;
@ -586,7 +600,7 @@ ns_remove_pointer(ReferenceCount *ptr) {
if (info->_void_ptr == NULL) {
// That was the last entry. Remove it altogether.
_cpp_size -= info->_size;
_total_cpp_size -= info->_size;
if (info->_freeze_index == _freeze_index) {
_current_cpp_size -= info->_size;
_count--;
@ -643,7 +657,7 @@ ns_record_void_pointer(void *ptr, size_t size) {
} else {
_current_cpp_size += size;
}
_cpp_size += size - info->_size;
_total_cpp_size += size - info->_size;
info->_void_ptr = ptr;
info->_size = size;
@ -713,7 +727,7 @@ ns_remove_void_pointer(void *ptr) {
_table.erase(ti);
_recursion_protect = false;
_cpp_size -= info->_size;
_total_cpp_size -= info->_size;
if (info->_freeze_index == _freeze_index) {
--_count;
_current_cpp_size -= info->_size;
@ -724,117 +738,6 @@ ns_remove_void_pointer(void *ptr) {
}
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::ns_mark_pointer
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void MemoryUsage::
ns_mark_pointer(void *ptr, size_t size, ReferenceCount *ref_ptr) {
if (express_cat.is_spam()) {
express_cat.spam()
<< "Marking pointer " << ptr << ", size " << size
<< ", ref_ptr = " << ref_ptr << "\n";
}
if (size != 0) {
// We're recording this pointer as now in use.
ns_record_void_pointer(ptr, size);
if (ref_ptr != (ReferenceCount *)NULL) {
// Make the pointer typed. This is particularly necessary in
// case the ref_ptr is a different value than the base void
// pointer; this may be our only opportunity to associate the
// two pointers.
Table::iterator ti;
ti = _table.find(ptr);
nassertv(ti != _table.end());
MemoryInfo *info = (*ti).second;
info->_ref_ptr = ref_ptr;
info->_static_type = ReferenceCount::get_class_type();
info->_dynamic_type = ReferenceCount::get_class_type();
info->_flags |= MemoryInfo::F_reconsider_dynamic_type;
if (ref_ptr != ptr) {
_recursion_protect = true;
pair<Table::iterator, bool> insert_result =
_table.insert(Table::value_type((void *)ref_ptr, info));
assert(insert_result.first != _table.end());
if (!insert_result.second) {
express_cat.warning()
<< "Attempt to mark pointer " << ptr << " as ReferenceCount "
<< ref_ptr << ", which was already allocated.\n";
}
_recursion_protect = false;
}
}
} else {
// We're removing this pointer from use.
ns_remove_void_pointer(ptr);
}
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::ns_get_current_cpp_size
// Access: Private
// Description: Returns the total number of bytes of allocated memory
// via the C++ operators new and delete as counted,
// not including the memory previously frozen.
////////////////////////////////////////////////////////////////////
size_t MemoryUsage::
ns_get_current_cpp_size() {
return _current_cpp_size;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::ns_get_cpp_size
// Access: Private
// Description: Returns the total number of bytes of allocated memory
// via the C++ operators new and delete as counted,
// including the memory previously frozen.
////////////////////////////////////////////////////////////////////
size_t MemoryUsage::
ns_get_cpp_size() {
return _cpp_size;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::ns_get_interpreter_size
// Access: Private
// Description: Returns the total number of bytes of allocated memory
// while the high-level languange code is running. This
// number is only meaningful if both Panda and the
// high-level language are single-threaded, and running
// in the same thread.
////////////////////////////////////////////////////////////////////
size_t MemoryUsage::
ns_get_interpreter_size() {
return _interpreter_size;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::ns_get_total_size
// Access: Private
// Description: Returns the total size of the dynamic heap, as nearly
// as can be determined, including all allocated memory
// if possible, in addition to that tracked by
// get_cpp_size().
////////////////////////////////////////////////////////////////////
size_t MemoryUsage::
ns_get_total_size() {
#if defined(WIN32_VC) && defined(_DEBUG)
return _total_size;
#else
// If we aren't tracking _total_size, report _cpp_size as the next
// best thing.
return _cpp_size;
#endif
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::ns_get_num_pointers
// Access: Private

View File

@ -27,7 +27,7 @@
#include "memoryInfo.h"
#include "memoryUsagePointerCounts.h"
#include "pmap.h"
#include "dallocator.h"
#include "memoryHook.h"
class ReferenceCount;
class MemoryUsagePointers;
@ -42,7 +42,7 @@ class MemoryUsagePointers;
// When compiled with NDEBUG set, this entire class does
// nothing and compiles to nothing.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS MemoryUsage {
class EXPCL_PANDAEXPRESS MemoryUsage : public MemoryHook {
public:
INLINE static bool get_track_memory_usage();
@ -52,10 +52,9 @@ public:
INLINE static void remove_pointer(ReferenceCount *ptr);
public:
static void *operator_new_handler(size_t size);
static void operator_delete_handler(void *ptr);
static void mark_pointer_handler(void *ptr, size_t size,
ReferenceCount *ref_ptr);
virtual void *heap_alloc(size_t size);
virtual void heap_free(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,
@ -67,11 +66,12 @@ PUBLISHED:
INLINE static bool is_tracking();
INLINE static bool is_counting();
INLINE static size_t get_current_cpp_size();
INLINE static bool has_cpp_size();
INLINE static size_t get_cpp_size();
INLINE static bool has_interpreter_size();
INLINE static size_t get_total_cpp_size();
INLINE static size_t get_panda_heap_size();
INLINE static size_t get_panda_mmap_size();
INLINE static size_t get_interpreter_size();
INLINE static bool has_total_size();
INLINE static size_t get_external_size();
INLINE static size_t get_total_size();
INLINE static int get_num_pointers();
@ -90,7 +90,7 @@ PUBLISHED:
INLINE static void show_trend_ages();
private:
MemoryUsage();
MemoryUsage(const MemoryHook &copy);
static MemoryUsage *get_global_ptr();
void ns_record_pointer(ReferenceCount *ptr);
@ -100,11 +100,7 @@ private:
void ns_record_void_pointer(void *ptr, size_t size);
void ns_remove_void_pointer(void *ptr);
void ns_mark_pointer(void *ptr, size_t size, ReferenceCount *ref_ptr);
size_t ns_get_current_cpp_size();
size_t ns_get_cpp_size();
size_t ns_get_interpreter_size();
size_t ns_get_total_size();
int ns_get_num_pointers();
void ns_get_pointers(MemoryUsagePointers &result);
@ -127,8 +123,8 @@ private:
// 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 specify dallocator here, so
// we have to make special code that handles the recursion anyway.
// 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
@ -138,19 +134,19 @@ private:
// 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<void *, MemoryInfo *, less<void *>, dallocator<pair<void * const, MemoryInfo *> > > Table;
typedef map<void *, MemoryInfo *> Table;
Table _table;
// This table indexes the individual MemoryInfo objects, for unique
// iteration.
typedef set<MemoryInfo *, less<MemoryInfo *>, dallocator<MemoryInfo *> > InfoSet;
typedef set<MemoryInfo *> InfoSet;
InfoSet _info_set;
bool _info_set_dirty;
int _freeze_index;
int _count;
size_t _current_cpp_size;
size_t _cpp_size;
size_t _total_cpp_size;
size_t _interpreter_size;
size_t _total_size;
@ -162,8 +158,7 @@ private:
private:
// Cannot use a pmap, since that would be recursive!
typedef map<TypeHandle, MemoryUsagePointerCounts,
less<TypeHandle>, dallocator<pair<const TypeHandle, MemoryUsagePointerCounts> > > Counts;
typedef map<TypeHandle, MemoryUsagePointerCounts> Counts;
Counts _counts;
};
TypeHistogram _trend_types;
@ -188,7 +183,6 @@ private:
bool _track_memory_usage;
bool _count_memory_usage;
static bool _is_cpp_operator;
static bool _recursion_protect;
};

View File

@ -22,26 +22,12 @@
#include "vertexDataBook.h"
#include "pStatTimer.h"
#include "mutexHolder.h"
#include "memoryHook.h"
#ifdef HAVE_ZLIB
#include <zlib.h>
#endif
#ifdef WIN32
// Windows case (VirtualAlloc)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
// Posix case (mmap)
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#endif
ConfigVariableInt max_resident_vertex_data
("max-resident-vertex-data", -1,
PRC_DESC("Specifies the maximum number of bytes of all vertex data "
@ -634,19 +620,7 @@ make_save_file() {
unsigned char *VertexDataPage::
alloc_page_data(size_t page_size) const {
get_class_type().inc_memory_usage(TypeHandle::MC_array, page_size);
unsigned char *buffer;
#ifdef WIN32
// Windows case.
buffer = (unsigned char *)VirtualAlloc(NULL, page_size, MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE);
#else
// Posix case.
buffer = (unsigned char *)mmap(NULL, page_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0);
#endif
return buffer;
return (unsigned char *)memory_hook->mmap_alloc(page_size, false);
}
////////////////////////////////////////////////////////////////////
@ -657,12 +631,7 @@ alloc_page_data(size_t page_size) const {
void VertexDataPage::
free_page_data(unsigned char *page_data, size_t page_size) const {
get_class_type().dec_memory_usage(TypeHandle::MC_array, page_size);
#ifdef WIN32
VirtualFree(page_data, 0, MEM_RELEASE);
#else
munmap(page_data, page_size);
#endif
memory_hook->mmap_free(page_data, page_size);
}
////////////////////////////////////////////////////////////////////

View File

@ -665,6 +665,8 @@ public:
TypedWritable::get_class_type(),
ReferenceCount::get_class_type());
CData::init_type();
Down::init_type();
Up::init_type();
}
virtual TypeHandle get_type() const {
return get_class_type();

View File

@ -24,21 +24,6 @@
#include "threadSimpleManager.h"
#include "thread.h"
#ifdef WIN32
// Windows case (VirtualAlloc)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
// Posix case (mmap)
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#endif
ThreadSimpleImpl *volatile ThreadSimpleImpl::_st_this;
////////////////////////////////////////////////////////////////////
@ -76,11 +61,7 @@ ThreadSimpleImpl::
nassertv(_status != S_running);
if (_stack != (void *)NULL) {
#ifdef WIN32
VirtualFree(_stack, 0, MEM_RELEASE);
#else
munmap(_stack, _stack_size);
#endif
memory_hook->mmap_free(_stack, _stack_size);
}
}
@ -113,17 +94,8 @@ start(ThreadPriority priority, bool joinable) {
nassertr(_status == S_new, false);
nassertr(_stack == NULL, false);
_stack_size = (size_t)thread_stack_size;
#ifdef WIN32
// Windows case.
_stack = (unsigned char *)VirtualAlloc(NULL, _stack_size, MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
#else
// Posix case.
_stack = (unsigned char *)mmap(NULL, _stack_size, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANON, -1, 0);
#endif
_stack_size = memory_hook->round_up_to_page_size((size_t)thread_stack_size);
_stack = (unsigned char *)memory_hook->mmap_alloc(_stack_size, true);
_joinable = joinable;
_status = S_running;

View File

@ -33,12 +33,14 @@
#include "clockObject.h"
#include "neverFreeMemory.h"
PStatCollector PStatClient::_nf_unused_size_pcollector("Track memory 1:NeverFree:Unused");
PStatCollector PStatClient::_nf_other_size_pcollector("Track memory 1:NeverFree:Other");
PStatCollector PStatClient::_cpp_other_size_pcollector("Track memory 1:Heap:Other");
PStatCollector PStatClient::_total_size_pcollector("Track memory 2");
PStatCollector PStatClient::_cpp_size_pcollector("Track memory 2:C++");
PStatCollector PStatClient::_interpreter_size_pcollector("Track memory 2:Interpreter");
PStatCollector PStatClient::_t1_nf_unused_size_pcollector("Track memory 1:NeverFree:Unused");
PStatCollector PStatClient::_t1_nf_other_size_pcollector("Track memory 1:NeverFree:Other");
PStatCollector PStatClient::_t1_cpp_other_size_pcollector("Track memory 1:Dynamic:Other");
PStatCollector PStatClient::_t2_total_size_pcollector("Track memory 2");
PStatCollector PStatClient::_t2_heap_size_pcollector("Track memory 2:Heap");
PStatCollector PStatClient::_t2_mmap_size_pcollector("Track memory 2:MMap");
PStatCollector PStatClient::_t2_interpreter_size_pcollector("Track memory 2:Interpreter");
PStatCollector PStatClient::_t2_external_size_pcollector("Track memory 2:External");
PStatCollector PStatClient::_pstats_pcollector("*:PStats");
PStatCollector PStatClient::_clock_wait_pcollector("Wait:Clock Wait:Sleep");
PStatCollector PStatClient::_clock_busy_wait_pcollector("Wait:Clock Wait:Spin");
@ -215,14 +217,12 @@ main_tick() {
#ifdef DO_MEMORY_USAGE
if (is_connected()) {
if (MemoryUsage::has_total_size()) {
_total_size_pcollector.set_level(MemoryUsage::get_total_size());
}
if (MemoryUsage::has_cpp_size()) {
_cpp_size_pcollector.set_level(MemoryUsage::get_cpp_size());
}
if (MemoryUsage::has_interpreter_size()) {
_interpreter_size_pcollector.set_level(MemoryUsage::get_interpreter_size());
if (MemoryUsage::is_tracking()) {
_t2_total_size_pcollector.set_level(MemoryUsage::get_total_size());
_t2_heap_size_pcollector.set_level(MemoryUsage::get_panda_heap_size());
_t2_mmap_size_pcollector.set_level(MemoryUsage::get_panda_mmap_size());
_t2_interpreter_size_pcollector.set_level(MemoryUsage::get_interpreter_size());
_t2_external_size_pcollector.set_level(MemoryUsage::get_external_size());
}
TypeRegistry *type_reg = TypeRegistry::ptr();
@ -277,7 +277,7 @@ main_tick() {
break;
default:
category = "Heap";
category = "Dynamic";
}
ostringstream strm;
strm << "Track memory 1:" << category << ":" << type << ":" << mc;
@ -298,12 +298,12 @@ main_tick() {
}
}
_nf_unused_size_pcollector.set_level(NeverFreeMemory::get_total_unused());
_t1_nf_unused_size_pcollector.set_level(NeverFreeMemory::get_total_unused());
// The remaining amount--all collectors smaller than 0.1% of the
// total--go into "other".
_nf_other_size_pcollector.set_level(nf_other_usage);
_cpp_other_size_pcollector.set_level(cpp_other_usage);
_t1_nf_other_size_pcollector.set_level(nf_other_usage);
_t1_cpp_other_size_pcollector.set_level(cpp_other_usage);
}
#endif // DO_MEMORY_USAGE

View File

@ -227,12 +227,14 @@ private:
PStatClientImpl *_impl;
static PStatCollector _nf_unused_size_pcollector;
static PStatCollector _nf_other_size_pcollector;
static PStatCollector _cpp_other_size_pcollector;
static PStatCollector _total_size_pcollector;
static PStatCollector _cpp_size_pcollector;
static PStatCollector _interpreter_size_pcollector;
static PStatCollector _t1_nf_unused_size_pcollector;
static PStatCollector _t1_nf_other_size_pcollector;
static PStatCollector _t1_cpp_other_size_pcollector;
static PStatCollector _t2_total_size_pcollector;
static PStatCollector _t2_heap_size_pcollector;
static PStatCollector _t2_mmap_size_pcollector;
static PStatCollector _t2_interpreter_size_pcollector;
static PStatCollector _t2_external_size_pcollector;
static PStatCollector _pstats_pcollector;
static PStatCollector _clock_wait_pcollector;
static PStatCollector _clock_busy_wait_pcollector;

View File

@ -197,11 +197,13 @@ static LevelCollectorProperties level_properties[] = {
{ 1, "Occlusion tests", { 0.9, 0.8, 0.3 }, "", 500.0 },
{ 1, "Occlusion results", { 0.3, 0.9, 0.8 }, "", 500.0 },
{ 1, "Track memory 1", { 0.5, 1.0, 0.5 }, "MB", 64, 1048576 },
{ 1, "Track memory 1:Heap", { 0.8, 0.2, 1.0 } },
{ 1, "Track memory 1:Dynamic", { 0.8, 0.2, 1.0 } },
{ 1, "Track memory 1:NeverFree", { 0.2, 0.5, 0.8 } },
{ 1, "Track memory 2", { 0.5, 1.0, 0.5 }, "MB", 64, 1048576 },
{ 1, "Track memory 2:C++", { 0.2, 0.2, 1.0 } },
{ 1, "Track memory 2:Heap", { 0.2, 0.2, 1.0 } },
{ 1, "Track memory 2:MMap", { 0.9, 0.4, 0.7 } },
{ 1, "Track memory 2:Interpreter", { 0.8, 0.2, 0.5 } },
{ 1, "Track memory 2:External", { 1.0, 1.0, 0.1 } },
{ 1, "Vertex Data", { 1.0, 0.4, 0.0 }, "MB", 64, 1048576 },
{ 1, "Vertex Data:Independent", { 0.9, 0.1, 0.9 } },
{ 1, "Vertex Data:Small", { 0.2, 0.3, 0.4 } },