move some low-level mem tracking into MemoryHook, more mem tracking fixes
This commit is contained in:
parent
33722a16c1
commit
d52eb37b14
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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> ©) 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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -5,4 +5,5 @@
|
|||
#include "atomicAdjustWin32Impl.cxx"
|
||||
#include "dtoolbase.cxx"
|
||||
#include "memoryBase.cxx"
|
||||
#include "memoryHook.cxx"
|
||||
#include "mutexDummyImpl.cxx"
|
||||
|
|
|
|||
|
|
@ -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 *) { \
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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 ©) :
|
||||
_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 *) {
|
||||
}
|
||||
|
|
@ -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 ©);
|
||||
|
||||
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
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ ConfigVariableManager *ConfigVariableManager::_global_ptr = NULL;
|
|||
////////////////////////////////////////////////////////////////////
|
||||
ConfigVariableManager::
|
||||
ConfigVariableManager() {
|
||||
init_memory_hook();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#define NOTIFY_H
|
||||
|
||||
#include "dtoolbase.h"
|
||||
|
||||
#include "notifySeverity.h"
|
||||
#include <map>
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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 ©) : 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
|
||||
|
|
|
|||
|
|
@ -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 ©);
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 } },
|
||||
|
|
|
|||
Loading…
Reference in New Issue