improved memory tracking tools

This commit is contained in:
David Rose 2001-06-05 21:34:36 +00:00
parent b560a14680
commit 22288e7e48
46 changed files with 1652 additions and 293 deletions

View File

@ -93,3 +93,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

View File

@ -93,3 +93,9 @@
// 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
// Do we expect the old gcc custom STL allocator?
#define GCC_STYLE_ALLOCATOR 1

View File

@ -94,8 +94,9 @@
// Do we have RTTI (and <typeinfo>)?
#define HAVE_RTTI 1
// Must global operator new and delete functions throw exceptions?
#define GLOBAL_OPERATOR_NEW_EXCEPTIONS
// can Intel C++ build this directory successfully (if not, change CC to msvc)
#define NOT_INTEL_BUILDABLE false

View File

@ -181,6 +181,12 @@ $[cdefine HAVE_SYS_SOUNDCARD_H]
/* Do we have RTTI (and <typeinfo>)? */
$[cdefine HAVE_RTTI]
/* Must global operator new and delete functions throw exceptions? */
$[cdefine GLOBAL_OPERATOR_NEW_EXCEPTIONS]
/* Do we expect the old gcc custom STL allocator? */
$[cdefine GCC_STYLE_ALLOCATOR]
#end dtool_config.h
#endif // BUILD_TYPE

View File

@ -6,8 +6,12 @@
#define SOURCES \
dtoolbase.cxx dtoolbase.h dtoolbase_cc.h dtoolsymbols.h \
fakestringstream.h
fakestringstream.h \
pallocator.T pallocator.h \
pdeque.h plist.h pmap.h pset.h pvector.h
#define INSTALL_HEADERS \
dtoolbase.h dtoolbase_cc.h dtoolsymbols.h fakestringstream.h
dtoolbase.h dtoolbase_cc.h dtoolsymbols.h fakestringstream.h \
pallocator.T pallocator.h \
pdeque.h plist.h pmap.h pset.h pvector.h
#end lib_target

View File

@ -17,3 +17,21 @@
////////////////////////////////////////////////////////////////////
#include "dtoolbase.h"
#ifndef NDEBUG
void *default_operator_new(size_t size) {
return malloc(size);
}
void default_operator_delete(void *ptr) {
free(ptr);
}
// We absolutely depend on the static initialization of these pointers
// to happen at load time, before any static constructors are called.
void *(*global_operator_new)(size_t size) = &default_operator_new;
void (*global_operator_delete)(void *ptr) = &default_operator_delete;
#endif // NDEBUG

View File

@ -95,5 +95,45 @@ using namespace std;
#endif // CPPPARSER
// 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.
#ifndef NDEBUG
EXPCL_DTOOL void *default_operator_new(size_t size);
EXPCL_DTOOL void default_operator_delete(void *ptr);
extern EXPCL_DTOOL void *(*global_operator_new)(size_t size);
extern EXPCL_DTOOL void (*global_operator_delete)(void *ptr);
#ifdef GLOBAL_OPERATOR_NEW_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
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 // NDEBUG
#endif

View File

@ -0,0 +1,51 @@
// Filename: pallocator.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 .
//
////////////////////////////////////////////////////////////////////
#ifdef GCC_STYLE_ALLOCATOR
#ifndef NDEBUG
template<class Type>
INLINE void *pallocator<Type>::
allocate(size_t n) {
return (*global_operator_new)(n);
}
template<class Type>
INLINE void pallocator<Type>::
deallocate(void *p, size_t) {
return (*global_operator_delete)(p);
}
#endif // NDEBUG
#else // GCC_STYLE_ALLOCATOR
#ifndef NDEBUG
template<class Type>
INLINE pallocator<Type>::pointer pallocator<Type>::
allocate(pallocator<Type>::size_type n, allocator<void>::const_pointer) {
return (*global_operator_new)(n * sizeof(Type));
}
template<class Type>
INLINE void pallocator<Type>::
deallocate(pallocator<Type>::pointer p, allocator<Type>::size_type) {
return (*global_operator_delete)(p);
}
#endif // NDEBUG
#endif // GCC_STYLE_ALLOCATOR

View File

@ -0,0 +1,66 @@
// Filename: pallocator.h
// 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 .
//
////////////////////////////////////////////////////////////////////
#ifndef PALLOCATOR_H
#define PALLOCATOR_H
#include "dtoolbase.h"
#include <memory>
#include <vector>
////////////////////////////////////////////////////////////////////
// Class : pallocator
// Description : This is our own Panda specialization on the default
// STL allocator. Its main purpose is to call the hooks
// for MemoryUsage to properly track STL-allocated
// memory.
//
// pvector, pmap, etc. are all defined in this directory
// to use a pallocator.
////////////////////////////////////////////////////////////////////
#ifdef GCC_STYLE_ALLOCATOR
// Early versions of gcc used its own kind of allocator, somewhat
// different from the STL standard.
template<class Type>
class pallocator : public alloc {
public:
#ifndef NDEBUG
static void *allocate(size_t n);
static void deallocate(void *p, size_t n);
#endif // NDEBUG
};
#else // GCC_STYLE_ALLOCATOR
template<class Type>
class pallocator : public allocator<Type> {
public:
#ifndef NDEBUG
INLINE pointer allocate(size_type n, allocator<void>::const_pointer hint = 0);
INLINE void deallocate(pointer p, size_type n);
#endif // NDEBUG
};
#endif // GCC_STYLE_ALLOCATOR
#include "pallocator.T"
#endif

View File

@ -0,0 +1,44 @@
// Filename: pdeque.h
// 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 .
//
////////////////////////////////////////////////////////////////////
#ifndef PDEQUE_H
#define PDEQUE_H
#include "dtoolbase.h"
#include "pallocator.h"
#include <deque>
////////////////////////////////////////////////////////////////////
// Class : pdeque
// Description : This is our own Panda specialization on the default
// STL deque. Its main purpose is to call the hooks
// for MemoryUsage to properly track STL-allocated
// memory.
////////////////////////////////////////////////////////////////////
template<class Type>
class pdeque : public deque<Type, pallocator<Type> > {
public:
pdeque() : deque<Type, pallocator<Type> >() { }
pdeque(const pdeque<Type> &copy) : deque<Type, pallocator<Type> >(copy) { }
pdeque(size_type n) : deque<Type, pallocator<Type> >(n) { }
pdeque(size_type n, const Type &value) : deque<Type, pallocator<Type> >(n, value) { }
};
#endif

View File

@ -0,0 +1,44 @@
// Filename: plist.h
// 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 .
//
////////////////////////////////////////////////////////////////////
#ifndef PLIST_H
#define PLIST_H
#include "dtoolbase.h"
#include "pallocator.h"
#include <list>
////////////////////////////////////////////////////////////////////
// Class : plist
// Description : This is our own Panda specialization on the default
// STL list. Its main purpose is to call the hooks
// for MemoryUsage to properly track STL-allocated
// memory.
////////////////////////////////////////////////////////////////////
template<class Type>
class plist : public list<Type, pallocator<Type> > {
public:
plist() : list<Type, pallocator<Type> >() { }
plist(const plist<Type> &copy) : list<Type, pallocator<Type> >(copy) { }
plist(size_type n) : list<Type, pallocator<Type> >(n) { }
plist(size_type n, const Type &value) : list<Type, pallocator<Type> >(n, value) { }
};
#endif

View File

@ -0,0 +1,56 @@
// Filename: pmap.h
// 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 .
//
////////////////////////////////////////////////////////////////////
#ifndef PMAP_H
#define PMAP_H
#include "dtoolbase.h"
#include "pallocator.h"
#include <map>
////////////////////////////////////////////////////////////////////
// Class : pmap
// Description : This is our own Panda specialization on the default
// STL map. Its main purpose is to call the hooks
// for MemoryUsage to properly track STL-allocated
// memory.
////////////////////////////////////////////////////////////////////
template<class Key, class Value, class Compare = less<Key> >
class pmap : public map<Key, Value, Compare, pallocator<pair<Key, Value> > > {
public:
pmap() : map<Key, Value, Compare, pallocator<pair<Key, Value> > >() { }
pmap(const pmap<Key> &copy) : map<Key, Value, Compare, pallocator<pair<Key, Value> > >(copy) { }
};
////////////////////////////////////////////////////////////////////
// Class : pmultimap
// Description : This is our own Panda specialization on the default
// STL multimap. Its main purpose is to call the hooks
// for MemoryUsage to properly track STL-allocated
// memory.
////////////////////////////////////////////////////////////////////
template<class Key, class Value, class Compare = less<Key> >
class pmultimap : public multimap<Key, Value, Compare, pallocator<pair<Key, Value> > > {
public:
pmultimap() : multimap<Key, Value, Compare, pallocator<pair<Key, Value> > >() { }
pmultimap(const pmultimap<Key> &copy) : multimap<Key, Value, Compare, pallocator<pair<Key, Value> > >(copy) { }
};
#endif

View File

@ -0,0 +1,56 @@
// Filename: pset.h
// 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 .
//
////////////////////////////////////////////////////////////////////
#ifndef PSET_H
#define PSET_H
#include "dtoolbase.h"
#include "pallocator.h"
#include <set>
////////////////////////////////////////////////////////////////////
// Class : pset
// Description : This is our own Panda specialization on the default
// STL set. Its main purpose is to call the hooks
// for MemoryUsage to properly track STL-allocated
// memory.
////////////////////////////////////////////////////////////////////
template<class Key, class Compare = less<Key> >
class pset : public set<Key, Compare, pallocator<Key> > {
public:
pset() : set<Key, Compare, pallocator<Key> >() { }
pset(const pset<Key> &copy) : set<Key, Compare, pallocator<Key> >(copy) { }
};
////////////////////////////////////////////////////////////////////
// Class : pmultiset
// Description : This is our own Panda specialization on the default
// STL multiset. Its main purpose is to call the hooks
// for MemoryUsage to properly track STL-allocated
// memory.
////////////////////////////////////////////////////////////////////
template<class Key, class Compare = less<Key> >
class pmultiset : public multiset<Key, Compare, pallocator<Key> > {
public:
pmultiset() : multiset<Key, Compare, pallocator<Key> >() { }
pmultiset(const pmultiset<Key> &copy) : multiset<Key, Compare, pallocator<Key> >(copy) { }
};
#endif

View File

@ -0,0 +1,44 @@
// Filename: pvector.h
// 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 .
//
////////////////////////////////////////////////////////////////////
#ifndef PVECTOR_H
#define PVECTOR_H
#include "dtoolbase.h"
#include "pallocator.h"
#include <vector>
////////////////////////////////////////////////////////////////////
// Class : pvector
// Description : This is our own Panda specialization on the default
// STL vector. Its main purpose is to call the hooks
// for MemoryUsage to properly track STL-allocated
// memory.
////////////////////////////////////////////////////////////////////
template<class Type>
class pvector : public vector<Type, pallocator<Type> > {
public:
pvector() : vector<Type, pallocator<Type> >() { }
pvector(const pvector<Type> &copy) : vector<Type, pallocator<Type> >(copy) { }
pvector(size_type n) : vector<Type, pallocator<Type> >(n) { }
pvector(size_type n, const Type &value) : vector<Type, pallocator<Type> >(n, value) { }
};
#endif

View File

@ -45,7 +45,7 @@
//
// They will automatically be undefined at the end of the file.
#include <vector>
#include "pvector.h"
#if defined(WIN32_VC) && !defined(CPPPARSER)
@ -65,7 +65,7 @@ EXPORT_TEMPLATE_CLASS(EXPCL, EXPTP, std::vector<TYPE>)
#endif
// Now make a typedef for the vector.
typedef std::vector<TYPE> NAME;
typedef pvector<TYPE> NAME;
// Finally, we must define a non-inline function that performs the
// insert operation given a range of pointers. We do this because

View File

@ -143,6 +143,35 @@ clear_bins() {
nassertv(_default_bin == (GeomBin *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: CullTraverser::clear_state
// Access: Public
// Description: Removes all the cached state information stored
// within the CullTraverser, and forces it to rebuild
// this state from scratch the next frame.
//
// This can be used to clear out state that has gone
// bad, as well as to free up memory pointers that
// otherwise may be held for another frame.
////////////////////////////////////////////////////////////////////
void CullTraverser::
clear_state() {
_states.clear();
_lookup.clear();
ToplevelBins::const_iterator tbi;
for (tbi = _toplevel_bins.begin(); tbi != _toplevel_bins.end(); ++tbi) {
(*tbi).second->clear_current_states();
}
SubBins::const_iterator sbi;
for (sbi = _sub_bins.begin(); sbi != _sub_bins.end(); ++sbi) {
(*sbi).second->clear_current_states();
}
_default_bin->clear_current_states();
_initial_state = AllAttributesWrapper();
}
////////////////////////////////////////////////////////////////////
// Function: CullTraverser::output
// Access: Public

View File

@ -59,6 +59,8 @@ PUBLISHED:
GeomBin *get_bin(const string &name) const;
void clear_bins();
void clear_state();
void output(ostream &out) const;
void write(ostream &out, int indent_level = 0) const;

View File

@ -125,6 +125,27 @@ release_all_textures() {
nassertv(_prepared_textures.empty());
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::clear_attribute
// Access: Public
// Description: Explicitly clear the indicated attribute, specified
// by the TypeHandle of its associated transition. If
// the attribute is not set already, this does nothing;
// if it is set, it resets it to its default value.
////////////////////////////////////////////////////////////////////
void GraphicsStateGuardian::
clear_attribute(TypeHandle type) {
NodeAttributes::iterator ai = _state.find(type);
if (ai != _state.end()) {
// The state is already set; get the initial value and reset it.
PT(NodeAttribute) initial = (*ai).second->make_initial();
initial->issue(this);
// Now remove the state entry from the set.
_state.erase(ai);
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::reset
// Access: Public, Virtual

View File

@ -78,10 +78,11 @@ PUBLISHED:
}
void enable_frame_clear(bool clear_color, bool clear_depth);
public:
void release_all_textures();
void clear_attribute(TypeHandle type);
public:
virtual void clear(const RenderBuffer &buffer)=0;
virtual void clear(const RenderBuffer &buffer, const DisplayRegion* region)=0;

View File

@ -16,9 +16,11 @@
//
////////////////////////////////////////////////////////////////////
#ifdef WIN32_VC
#define WINDOWS_LEAN_AND_MEAN
#include <windows.h>
#undef WINDOWS_LEAN_AND_MEAN
#endif
#include <errno.h>
#include <error_utils.h>

View File

@ -20,8 +20,11 @@
datagramOutputFile.h datagramSink.I datagramSink.h \
get_config_path.h hashGeneratorBase.I hashGeneratorBase.h \
hashVal.I hashVal.h indent.I indent.h littleEndian.h \
memoryUsage.I memoryUsage.h memoryUsagePointers.I \
memoryUsagePointers.h multifile.I multifile.h namable.I \
memoryInfo.I memoryInfo.h \
memoryUsage.I memoryUsage.h \
memoryUsagePointerCounts.I memoryUsagePointerCounts.h \
memoryUsagePointers.I memoryUsagePointers.h \
multifile.I multifile.h namable.I \
namable.h nativeNumericData.I nativeNumericData.h \
numeric_types.h pointerTo.I pointerTo.h referenceCount.I \
profileTimer.I profileTimer.h referenceCount.h \
@ -36,7 +39,8 @@
config_express.cxx datagram.cxx datagramGenerator.cxx \
datagramInputFile.cxx datagramIterator.cxx \
datagramOutputFile.cxx datagramSink.cxx get_config_path.cxx \
hashGeneratorBase.cxx hashVal.cxx indent.cxx memoryUsage.cxx \
hashGeneratorBase.cxx hashVal.cxx indent.cxx \
memoryInfo.cxx memoryUsage.cxx memoryUsagePointerCounts.cxx \
memoryUsagePointers.cxx multifile.cxx namable.cxx \
nativeNumericData.cxx profileTimer.cxx referenceCount.cxx \
reversedNumericData.cxx trueClock.cxx typeHandle.cxx \
@ -58,9 +62,11 @@
datagramGenerator.h get_config_path.h \
hashGeneratorBase.I hashGeneratorBase.h \
hashVal.I hashVal.h \
indent.I indent.h littleEndian.h \
memoryUsage.I memoryUsage.h memoryUsagePointers.I \
memoryUsagePointers.h multifile.I multifile.h \
indent.I indent.h littleEndian.h \
memoryInfo.I memoryInfo.h \
memoryUsage.I memoryUsage.h \
memoryUsagePointerCounts.I memoryUsagePointerCounts.h \
memoryUsagePointers.I memoryUsagePointers.h multifile.I multifile.h \
nativeNumericData.I nativeNumericData.h \
numeric_types.h \
pointerTo.I pointerTo.h referenceCount.I referenceCount.h \

View File

@ -0,0 +1,83 @@
// Filename: memoryInfo.I
// Created by: drose (04Jun01)
//
////////////////////////////////////////////////////////////////////
//
// 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 .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: MemoryInfo::get_void_ptr
// Access: Public
// Description: Returns the data pointer as a void pointer. This
// should always be non-NULL.
////////////////////////////////////////////////////////////////////
void *MemoryInfo::get_void_ptr() const {
return _void_ptr;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryInfo::get_ref_ptr
// Access: Public
// Description: Returns the data pointer as a ReferenceCount pointer.
// This may be NULL if the data pointer does not
// represent a ReferenceCount object.
////////////////////////////////////////////////////////////////////
ReferenceCount *MemoryInfo::get_ref_ptr() const {
return _ref_ptr;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryInfo::get_typed_ptr
// Access: Public
// Description: Returns the data pointer as a TypedObject pointer.
// This may be NULL if the data pointer does not
// represent a pointer to a TypedObject.
////////////////////////////////////////////////////////////////////
TypedObject *MemoryInfo::get_typed_ptr() const {
return _typed_ptr;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryInfo::is_size_known
// Access: Public
// Description: Returns true if the size of the memory block
// referenced by this pointer is known. Most pointers'
// sizes should be known, but some may not be.
////////////////////////////////////////////////////////////////////
bool MemoryInfo::is_size_known() const {
return (_flags & F_size_known) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryInfo::get_size
// Access: Public
// Description: Returns the size in bytes of the memory block
// referenced by this pointer, if it is known. Returns
// zero if the size is not known.
////////////////////////////////////////////////////////////////////
size_t MemoryInfo::get_size() const {
return _size;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryInfo::get_time
// Access: Public
// Description: Returns the time in seconds (based on the
// GlobalClock) at which the pointer was allocated.
////////////////////////////////////////////////////////////////////
double MemoryInfo::get_time() const {
return _time;
}

View File

@ -0,0 +1,149 @@
// Filename: memoryInfo.cxx
// Created by: drose (04Jun01)
//
////////////////////////////////////////////////////////////////////
//
// 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 .
//
////////////////////////////////////////////////////////////////////
#include "memoryInfo.h"
#include "typedReferenceCount.h"
#include "typeHandle.h"
////////////////////////////////////////////////////////////////////
// Function: MemoryInfo::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
MemoryInfo::
MemoryInfo() {
_void_ptr = (void *)NULL;
_ref_ptr = (ReferenceCount *)NULL;
_typed_ptr = (TypedObject *)NULL;
_size = 0;
_static_type = TypeHandle::none();
_dynamic_type = TypeHandle::none();
_flags = 0;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryInfo::get_type
// Access: Public
// Description: Returns the best known type, dynamic or static, of
// the pointer.
////////////////////////////////////////////////////////////////////
TypeHandle MemoryInfo::
get_type() {
// If we don't want to consider the dynamic type any further, use
// what we've got.
if ((_flags & F_reconsider_dynamic_type) == 0) {
if (_dynamic_type == TypeHandle::none()) {
return _static_type;
}
return _dynamic_type;
}
// Otherwise, examine the pointer again and make sure it's still the
// best information we have. We have to do this each time because
// if we happen to be examining the pointer from within the
// constructor or destructor, its dynamic type will appear to be
// less-specific than it actually is, so our idea of what type this
// thing is could change from time to time.
determine_dynamic_type();
// Now return the more specific of the two.
TypeHandle type = _static_type;
update_type_handle(type, _dynamic_type);
return type;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryInfo::determine_dynamic_type
// Access: Public
// Description: Tries to determine the actual type of the object to
// which this thing is pointed, if possible.
////////////////////////////////////////////////////////////////////
void MemoryInfo::
determine_dynamic_type() {
if ((_flags & F_reconsider_dynamic_type) != 0 &&
_static_type != TypeHandle::none()) {
// See if we know enough now to infer the dynamic type from the
// pointer.
if (_typed_ptr == (TypedObject *)NULL) {
// If our static type is known to inherit from
// TypedReferenceCount, then we can directly downcast to get the
// TypedObject pointer.
if (_static_type.is_derived_from(TypedReferenceCount::get_class_type())) {
_typed_ptr = (TypedReferenceCount *)_ref_ptr;
}
}
if (_typed_ptr != (TypedObject *)NULL) {
// If we have a TypedObject pointer, we can determine the type.
// This might still not return the exact type, particularly if
// we are being called within the destructor or constructor of
// this object.
TypeHandle got_type = _typed_ptr->get_type();
if (got_type == TypeHandle::none()) {
express_cat.warning()
<< "Found an unregistered type in a " << _static_type
<< " pointer:\n"
<< "Check derived types of " << _static_type
<< " and make sure that all are being initialized.\n";
_dynamic_type = _static_type;
_flags &= ~F_reconsider_dynamic_type;
return;
}
update_type_handle(_dynamic_type, got_type);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: MemoryInfo::update_type_handle
// Access: Public
// Description: Updates the given destination TypeHandle with the
// refined TypeHandle, if it is in fact more specific
// than the original value for the destination.
////////////////////////////////////////////////////////////////////
void MemoryInfo::
update_type_handle(TypeHandle &destination, TypeHandle refined) {
if (refined == TypeHandle::none()) {
express_cat.error()
<< "Attempt to update type of " << (void *)_ref_ptr
<< "(type is " << get_type()
<< ") to an undefined type!\n";
} else if (destination == refined) {
// Updating with the same type, no problem.
} else if (destination.is_derived_from(refined)) {
// Updating with a less-specific type, no problem.
} else if (refined.is_derived_from(destination)) {
// Updating with a more-specific type, no problem.
destination = refined;
} else {
express_cat.error()
<< "Pointer " << (void *)_ref_ptr << " previously indicated as type "
<< destination << " is now type " << refined << "!\n";
destination = refined;
}
}

View File

@ -0,0 +1,88 @@
// Filename: memoryInfo.h
// Created by: drose (04Jun01)
//
////////////////////////////////////////////////////////////////////
//
// 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 .
//
////////////////////////////////////////////////////////////////////
#ifndef MEMORYINFO_H
#define MEMORYINFO_H
#include <pandabase.h>
#include "typeHandle.h"
class ReferenceCount;
class TypedObject;
#ifndef NDEBUG
////////////////////////////////////////////////////////////////////
// Class : MemoryInfo
// Description : This is a supporting class for MemoryUsage. It
// records the detailed information for a particular
// pointer allocated by Panda code. This record is only
// kept if track-mem-usage is configured #t.
//
// It's not exported from the DLL, and it doesn't even
// exist if we're compiling NDEBUG.
////////////////////////////////////////////////////////////////////
class MemoryInfo {
public:
MemoryInfo();
public:
// Members to view the MemoryInfo structure.
TypeHandle get_type();
INLINE void *get_void_ptr() const;
INLINE ReferenceCount *get_ref_ptr() const;
INLINE TypedObject *get_typed_ptr() const;
INLINE bool is_size_known() const;
INLINE size_t get_size() const;
INLINE double get_time() const;
public:
// Members to set up the MemoryInfo structure.
void determine_dynamic_type();
void update_type_handle(TypeHandle &destination, TypeHandle refined);
private:
enum Flags {
F_got_ref = 0x0001,
F_got_void = 0x0002,
F_size_known = 0x0004,
F_reconsider_dynamic_type = 0x0008,
};
void *_void_ptr;
ReferenceCount *_ref_ptr;
TypedObject *_typed_ptr;
size_t _size;
TypeHandle _static_type;
TypeHandle _dynamic_type;
int _flags;
double _time;
int _freeze_index;
friend class MemoryUsage;
};
#include "memoryInfo.I"
#endif // NDEBUG
#endif

View File

@ -115,6 +115,40 @@ remove_pointer(ReferenceCount *ptr) {
#endif // __GNUC__
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::is_tracking
// Access: Public, Static
// Description: Returns true if the MemoryUsage object is currently
// tracking memory (e.g. track-memory-usage is
// configured #t).
////////////////////////////////////////////////////////////////////
INLINE bool MemoryUsage::
is_tracking() {
return get_global_ptr()->_track_memory_usage;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::get_allocated_size
// Access: Public, Static
// Description: Returns the total number of bytes of allocated memory
// as counted, excluding the memory previously frozen.
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage::
get_allocated_size() {
return get_global_ptr()->ns_get_allocated_size();
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::get_total_size
// Access: Public, Static
// Description: Returns the total number of bytes of allocated memory
// as counted, including the memory previously frozen.
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsage::
get_total_size() {
return get_global_ptr()->ns_get_total_size();
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::get_num_pointers
// Access: Public, Static

View File

@ -49,116 +49,6 @@ double MemoryUsage::AgeHistogram::_cutoff[MemoryUsage::AgeHistogram::num_buckets
60.0,
};
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::MemoryInfo::get_type
// Access: Public
// Description: Returns the best known type, dynamic or static, of
// the pointer.
////////////////////////////////////////////////////////////////////
TypeHandle MemoryUsage::MemoryInfo::
get_type() {
// If we don't want to consider the dynamic type any further, use
// what we've got.
if (!_reconsider_dynamic_type) {
if (_dynamic_type == TypeHandle::none()) {
return _static_type;
}
return _dynamic_type;
}
// Otherwise, examine the pointer again and make sure it's still the
// best information we have. We have to do this each time because
// if we happen to be examining the pointer from within the
// constructor or destructor, its dynamic type will appear to be
// less-specific than it actually is, so our idea of what type this
// thing is could change from time to time.
determine_dynamic_type();
// Now return the more specific of the two.
TypeHandle type = _static_type;
update_type_handle(type, _dynamic_type);
return type;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::MemoryInfo::determine_dynamic_type
// Access: Public
// Description: Tries to determine the actual type of the object to
// which this thing is pointed, if possible.
////////////////////////////////////////////////////////////////////
void MemoryUsage::MemoryInfo::
determine_dynamic_type() {
if (_reconsider_dynamic_type && _static_type != TypeHandle::none()) {
// See if we know enough now to infer the dynamic type from the
// pointer.
if (_typed_ptr == (TypedObject *)NULL) {
// If our static type is known to inherit from
// TypedReferenceCount, then we can directly downcast to get the
// TypedObject pointer.
if (_static_type.is_derived_from(TypedReferenceCount::get_class_type())) {
_typed_ptr = (TypedReferenceCount *)_ptr;
}
}
if (_typed_ptr != (TypedObject *)NULL) {
// If we have a TypedObject pointer, we can determine the type.
// This might still not return the exact type, particularly if
// we are being called within the destructor or constructor of
// this object.
TypeHandle got_type = _typed_ptr->get_type();
if (got_type == TypeHandle::none()) {
express_cat.warning()
<< "Found an unregistered type in a " << _static_type
<< " pointer:\n"
<< "Check derived types of " << _static_type
<< " and make sure that all are being initialized.\n";
_dynamic_type = _static_type;
_reconsider_dynamic_type = false;
return;
}
update_type_handle(_dynamic_type, got_type);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::MemoryInfo::update_type_handle
// Access: Public
// Description: Updates the given destination TypeHandle with the
// refined TypeHandle, if it is in fact more specific
// than the original value for the destination.
////////////////////////////////////////////////////////////////////
void MemoryUsage::MemoryInfo::
update_type_handle(TypeHandle &destination, TypeHandle refined) {
if (refined == TypeHandle::none()) {
express_cat.error()
<< "Attempt to update type of " << (void *)_ptr
<< "(type is " << get_type()
<< ") to an undefined type!\n";
} else if (destination == refined) {
// Updating with the same type, no problem.
} else if (destination.is_derived_from(refined)) {
// Updating with a less-specific type, no problem.
} else if (refined.is_derived_from(destination)) {
// Updating with a more-specific type, no problem.
destination = refined;
} else {
express_cat.error()
<< "Pointer " << (void *)_ptr << " previously indicated as type "
<< destination << " is now type " << refined << "!\n";
destination = refined;
}
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::TypeHistogram::add_info
@ -166,8 +56,8 @@ update_type_handle(TypeHandle &destination, TypeHandle refined) {
// Description: Adds a single entry to the histogram.
////////////////////////////////////////////////////////////////////
void MemoryUsage::TypeHistogram::
add_info(TypeHandle type) {
_counts[type]++;
add_info(TypeHandle type, MemoryInfo &info) {
_counts[type].add_info(info);
}
@ -175,14 +65,16 @@ add_info(TypeHandle type) {
// below, to sort the types in descending order by counts.
class TypeHistogramCountSorter {
public:
TypeHistogramCountSorter(int count, TypeHandle type) {
_count = count;
_type = type;
TypeHistogramCountSorter(const MemoryUsagePointerCounts &count,
TypeHandle type) :
_count(count),
_type(type)
{
}
bool operator < (const TypeHistogramCountSorter &other) const {
return _count > other._count;
}
int _count;
MemoryUsagePointerCounts _count;
TypeHandle _type;
};
@ -206,7 +98,13 @@ show() const {
vector<TypeHistogramCountSorter>::const_iterator vi;
for (vi = count_sorter.begin(); vi != count_sorter.end(); ++vi) {
nout << (*vi)._type << " : " << (*vi)._count << " pointers.\n";
TypeHandle type = (*vi)._type;
if (type == TypeHandle::none()) {
nout << "unknown";
} else {
nout << type;
}
nout << " : " << (*vi)._count << "\n";
}
}
@ -236,10 +134,10 @@ AgeHistogram() {
// Description: Adds a single entry to the histogram.
////////////////////////////////////////////////////////////////////
void MemoryUsage::AgeHistogram::
add_info(double age) {
add_info(double age, MemoryInfo &info) {
int bucket = choose_bucket(age);
nassertv(bucket >= 0 && bucket < num_buckets);
_counts[bucket]++;
_counts[bucket].add_info(info);
}
////////////////////////////////////////////////////////////////////
@ -250,11 +148,13 @@ add_info(double age) {
void MemoryUsage::AgeHistogram::
show() const {
for (int i = 0; i < num_buckets - 1; i++) {
nout << _cutoff[i] << " to " << _cutoff[i + 1] << " seconds old : "
<< _counts[i] << " pointers.\n";
nout << _cutoff[i] << " to " << _cutoff[i + 1] << " seconds old : ";
_counts[i].output(nout);
nout << "\n";
}
nout << _cutoff[num_buckets - 1] << " seconds old and up : "
<< _counts[num_buckets - 1] << " pointers.\n";
nout << _cutoff[num_buckets - 1] << " seconds old and up : ";
_counts[num_buckets - 1].output(nout);
nout << "\n";
}
////////////////////////////////////////////////////////////////////
@ -265,7 +165,7 @@ show() const {
void MemoryUsage::AgeHistogram::
clear() {
for (int i = 0; i < num_buckets; i++) {
_counts[i] = 0;
_counts[i].clear();
}
}
@ -341,6 +241,37 @@ remove_pointer(ReferenceCount *ptr) {
#endif // __GNUC__ && !NDEBUG
////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////
void *MemoryUsage::
operator_new_handler(size_t size) {
void *ptr = default_operator_new(size);
get_global_ptr()->ns_record_void_pointer(ptr, size);
return ptr;
}
////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////
void MemoryUsage::
operator_delete_handler(void *ptr) {
get_global_ptr()->ns_remove_void_pointer(ptr);
return default_operator_delete(ptr);
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::Constructor
// Access: Private
@ -354,8 +285,18 @@ MemoryUsage() {
_track_memory_usage =
config_express.GetBool("track-memory-usage", false);
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;
}
_freeze_index = 0;
_count = 0;
_allocated_size = 0;
_total_size = 0;
}
////////////////////////////////////////////////////////////////////
@ -382,24 +323,31 @@ get_global_ptr() {
void MemoryUsage::
ns_record_pointer(ReferenceCount *ptr) {
if (_track_memory_usage) {
MemoryInfo info;
info._ptr = ptr;
info._typed_ptr = (TypedObject *)NULL;
pair<Table::iterator, bool> insert_result =
_table.insert(Table::value_type((void *)ptr, MemoryInfo()));
// This shouldn't fail.
assert(insert_result.first != _table.end());
if (insert_result.second) {
_count++;
}
MemoryInfo &info = (*insert_result.first).second;
// We shouldn't already have a ReferenceCount pointer.
if ((info._flags & MemoryInfo::F_got_ref) != 0) {
express_cat.error()
<< "Pointer " << (void *)ptr << " recorded twice!\n";
}
info._void_ptr = (void *)ptr;
info._ref_ptr = ptr;
info._static_type = ReferenceCount::get_class_type();
info._dynamic_type = ReferenceCount::get_class_type();
info._time = TrueClock::get_ptr()->get_real_time();
info._freeze_index = _freeze_index;
info._reconsider_dynamic_type = true;
Table::iterator ti;
ti = _table.find(ptr);
if (ti != _table.end()) {
express_cat.error() << "Pointer " << (void *)ptr << " recorded twice!\n";
(*ti).second = info;
} else {
_table[ptr] = info;
_count++;
}
info._flags |= (MemoryInfo::F_reconsider_dynamic_type | MemoryInfo::F_got_ref);
}
}
@ -427,6 +375,8 @@ ns_update_type(ReferenceCount *ptr, TypeHandle type) {
MemoryInfo &info = (*ti).second;
info.update_type_handle(info._static_type, type);
info.determine_dynamic_type();
consolidate_void_ptr(info);
}
}
@ -456,6 +406,8 @@ ns_update_type(ReferenceCount *ptr, TypedObject *typed_ptr) {
MemoryInfo &info = (*ti).second;
info._typed_ptr = typed_ptr;
info.determine_dynamic_type();
consolidate_void_ptr(info);
}
}
@ -481,6 +433,14 @@ ns_remove_pointer(ReferenceCount *ptr) {
MemoryInfo &info = (*ti).second;
if ((info._flags & MemoryInfo::F_got_ref) == 0) {
express_cat.error()
<< "Pointer " << (void *)ptr << " deleted twice!\n";
return;
}
info._flags &= ~MemoryInfo::F_got_ref;
// Since the pointer has been destructed, we can't safely call its
// TypedObject virtual methods any more. Better clear out the
// typed_ptr for good measure.
@ -488,15 +448,143 @@ ns_remove_pointer(ReferenceCount *ptr) {
if (info._freeze_index == _freeze_index) {
double now = TrueClock::get_ptr()->get_real_time();
_count--;
_trend_types.add_info(info.get_type());
_trend_ages.add_info(now - info._time);
_trend_types.add_info(info.get_type(), info);
_trend_ages.add_info(now - info._time, info);
}
_table.erase(ti);
if ((info._flags & (MemoryInfo::F_got_ref | MemoryInfo::F_got_void)) == 0) {
// If we don't expect to call any more remove_*_pointer on this
// pointer, remove it from the table.
if (info._freeze_index == _freeze_index) {
_count--;
_allocated_size -= info._size;
}
_total_size -= info._size;
_table.erase(ti);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::ns_record_void_pointer
// Access: Private
// Description: Records a pointer that's not even necessarily a
// ReferenceCount object (but for which we know the size
// of the allocated structure).
////////////////////////////////////////////////////////////////////
void MemoryUsage::
ns_record_void_pointer(void *ptr, size_t size) {
if (_track_memory_usage) {
pair<Table::iterator, bool> insert_result =
_table.insert(Table::value_type((void *)ptr, MemoryInfo()));
// This shouldn't fail.
assert(insert_result.first != _table.end());
if (insert_result.second) {
_count++;
}
MemoryInfo &info = (*insert_result.first).second;
// We shouldn't already have a void pointer.
if ((info._flags & MemoryInfo::F_got_void) != 0) {
express_cat.error()
<< "Pointer " << (void *)ptr << " recorded twice!\n";
}
if (info._freeze_index == _freeze_index) {
_allocated_size += size - info._size;
} else {
_allocated_size += size;
}
_total_size += size - info._size;
info._void_ptr = ptr;
info._size = size;
info._time = TrueClock::get_ptr()->get_real_time();
info._freeze_index = _freeze_index;
info._flags |= (MemoryInfo::F_got_void | MemoryInfo::F_size_known);
}
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::ns_remove_void_pointer
// Access: Private
// Description: Removes a pointer previously recorded via
// record_void_pointer.
////////////////////////////////////////////////////////////////////
void MemoryUsage::
ns_remove_void_pointer(void *ptr) {
if (_track_memory_usage) {
Table::iterator ti;
ti = _table.find(ptr);
if (ti == _table.end()) {
// The pointer we tried to delete was not recorded in the table.
// We can't report this as an error, because (a) we might have
// removed the void pointer entry already when we consolidated,
// and (b) a few objects might have been created during static
// init time, before we grabbed the operator new/delete function
// handlers.
return;
}
MemoryInfo &info = (*ti).second;
if ((info._flags & MemoryInfo::F_got_void) == 0) {
express_cat.error()
<< "Pointer " << (void *)ptr << " deleted twice!\n";
return;
}
if ((info._flags & MemoryInfo::F_got_ref) != 0) {
express_cat.error()
<< "Pointer " << (void *)ptr << " did not destruct before being deleted!\n";
}
info._flags &= ~MemoryInfo::F_got_void;
if ((info._flags & (MemoryInfo::F_got_ref | MemoryInfo::F_got_void)) == 0) {
// If we don't expect to call any more remove_*_pointer on this
// pointer, remove it from the table.
if (info._freeze_index == _freeze_index) {
_count--;
_allocated_size -= info._size;
}
_total_size -= info._size;
_table.erase(ti);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::ns_get_allocated_size
// Access: Private
// Description: Returns the total number of bytes of allocated memory
// as counted, excluding the memory previously frozen.
////////////////////////////////////////////////////////////////////
size_t MemoryUsage::
ns_get_allocated_size() {
nassertr(_track_memory_usage, 0);
return _allocated_size;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::ns_get_total_size
// Access: Private
// Description: Returns the total number of bytes of allocated memory
// as counted, including the memory previously frozen.
////////////////////////////////////////////////////////////////////
size_t MemoryUsage::
ns_get_total_size() {
nassertr(_track_memory_usage, 0);
return _total_size;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::ns_get_num_pointers
// Access: Private
@ -523,8 +611,9 @@ ns_get_pointers(MemoryUsagePointers &result) {
Table::iterator ti;
for (ti = _table.begin(); ti != _table.end(); ++ti) {
MemoryInfo &info = (*ti).second;
if (info._freeze_index == _freeze_index) {
result.add_entry(info._ptr, info._typed_ptr, info.get_type(),
if (info._freeze_index == _freeze_index &&
info._ref_ptr != (ReferenceCount *)NULL) {
result.add_entry(info._ref_ptr, info._typed_ptr, info.get_type(),
now - info._time);
}
}
@ -546,11 +635,12 @@ ns_get_pointers_of_type(MemoryUsagePointers &result, TypeHandle type) {
Table::iterator ti;
for (ti = _table.begin(); ti != _table.end(); ++ti) {
MemoryInfo &info = (*ti).second;
if (info._freeze_index == _freeze_index) {
if (info._freeze_index == _freeze_index &&
info._ref_ptr != (ReferenceCount *)NULL) {
TypeHandle info_type = info.get_type();
if (info_type != TypeHandle::none() &&
info_type.is_derived_from(type)) {
result.add_entry(info._ptr, info._typed_ptr, info_type,
result.add_entry(info._ref_ptr, info._typed_ptr, info_type,
now - info._time);
}
}
@ -574,11 +664,12 @@ ns_get_pointers_of_age(MemoryUsagePointers &result,
Table::iterator ti;
for (ti = _table.begin(); ti != _table.end(); ++ti) {
MemoryInfo &info = (*ti).second;
if (info._freeze_index == _freeze_index) {
if (info._freeze_index == _freeze_index &&
info._ref_ptr != (ReferenceCount *)NULL) {
double age = now - info._time;
if ((age >= from && age <= to) ||
(age >= to && age <= from)) {
result.add_entry(info._ptr, info._typed_ptr, info.get_type(), age);
result.add_entry(info._ref_ptr, info._typed_ptr, info.get_type(), age);
}
}
}
@ -616,10 +707,11 @@ ns_get_pointers_with_zero_count(MemoryUsagePointers &result) {
Table::iterator ti;
for (ti = _table.begin(); ti != _table.end(); ++ti) {
MemoryInfo &info = (*ti).second;
if (info._freeze_index == _freeze_index) {
if ((*ti).first->get_ref_count() == 0) {
(*ti).first->ref();
result.add_entry(info._ptr, info._typed_ptr, info.get_type(),
if (info._freeze_index == _freeze_index &&
info._ref_ptr != (ReferenceCount *)NULL) {
if (info._ref_ptr->get_ref_count() == 0) {
info._ref_ptr->ref();
result.add_entry(info._ref_ptr, info._typed_ptr, info.get_type(),
now - info._time);
}
}
@ -639,6 +731,7 @@ ns_get_pointers_with_zero_count(MemoryUsagePointers &result) {
void MemoryUsage::
ns_freeze() {
_count = 0;
_allocated_size = 0;
_trend_types.clear();
_trend_ages.clear();
_freeze_index++;
@ -658,7 +751,7 @@ ns_show_current_types() {
for (ti = _table.begin(); ti != _table.end(); ++ti) {
MemoryInfo &info = (*ti).second;
if (info._freeze_index == _freeze_index) {
hist.add_info(info.get_type());
hist.add_info(info.get_type(), info);
}
}
@ -692,7 +785,7 @@ ns_show_current_ages() {
for (ti = _table.begin(); ti != _table.end(); ++ti) {
MemoryInfo &info = (*ti).second;
if (info._freeze_index == _freeze_index) {
hist.add_info(now - info._time);
hist.add_info(now - info._time, info);
}
}
@ -711,6 +804,68 @@ ns_show_trend_ages() {
_trend_ages.show();
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsage::consolidate_void_ptr
// Access: Private
// Description: If the size information has not yet been determined
// for this pointer, checks to see if it has possible
// been recorded under the TypedObject pointer (this
// will happen when the class inherits from TypedObject
// before ReferenceCount, e.g. TypedReferenceCount).
////////////////////////////////////////////////////////////////////
void MemoryUsage::
consolidate_void_ptr(MemoryInfo &info) {
if (info.is_size_known()) {
// We already know the size, so no sweat.
return;
}
if (info.get_typed_ptr() == (TypedObject *)NULL) {
// We don't have a typed pointer for this thing yet.
return;
}
void *typed_ptr = (void *)info.get_typed_ptr();
if (typed_ptr == (void *)info.get_ref_ptr()) {
// The TypedObject pointer is the same pointer as the
// ReferenceCount pointer, so there's no point in looking it up
// separately. Actually, this really shouldn't even be possible.
return;
}
Table::iterator ti;
ti = _table.find(typed_ptr);
if (ti == _table.end()) {
// No entry for the typed pointer, either.
return;
}
// We do have an entry! Copy over the relevant pieces.
MemoryInfo &typed_info = (*ti).second;
if (typed_info.is_size_known()) {
info._size = typed_info.get_size();
info._flags |= MemoryInfo::F_size_known;
if (typed_info._freeze_index == _freeze_index) {
_allocated_size += info._size;
}
}
// The typed_ptr is clearly the more accurate pointer to the
// beginning of the structure.
info._void_ptr = typed_ptr;
// Now that we've consolidated the pointers, remove the void pointer
// entry.
if (info._freeze_index == _freeze_index) {
_count--;
_allocated_size -= info._size;
}
_table.erase(ti);
}
#endif // NDEBUG

View File

@ -22,6 +22,8 @@
#include <pandabase.h>
#include "typedObject.h"
#include "memoryInfo.h"
#include "memoryUsagePointerCounts.h"
#include <map>
@ -42,7 +44,6 @@ class EXPCL_PANDAEXPRESS MemoryUsage {
public:
INLINE static bool get_track_memory_usage();
PUBLISHED:
#if defined(__GNUC__) && !defined(NDEBUG)
// There seems to be a problem with egcs-2.91.66: it gets confused
// with too many nested inline functions, and sets the wrong pointer
@ -62,7 +63,20 @@ PUBLISHED:
INLINE static void remove_pointer(ReferenceCount *ptr);
#endif // __GNUC__ && !NDEBUG
#ifndef NDEBUG
#ifdef NDEBUG
public:
INLINE static bool is_tracking() { return false; }
INLINE static size_t get_allocated_size() { return 0; }
#else // NDEBUG
public:
static void *operator_new_handler(size_t size);
static void operator_delete_handler(void *ptr);
PUBLISHED:
INLINE static bool is_tracking();
INLINE static size_t get_allocated_size();
INLINE static size_t get_total_size();
INLINE static int get_num_pointers();
INLINE static void get_pointers(MemoryUsagePointers &result);
INLINE static void get_pointers_of_type(MemoryUsagePointers &result,
@ -87,6 +101,11 @@ private:
void ns_update_type(ReferenceCount *ptr, TypedObject *typed_ptr);
void ns_remove_pointer(ReferenceCount *ptr);
void ns_record_void_pointer(void *ptr, size_t size);
void ns_remove_void_pointer(void *ptr);
size_t ns_get_allocated_size();
size_t ns_get_total_size();
int ns_get_num_pointers();
void ns_get_pointers(MemoryUsagePointers &result);
void ns_get_pointers_of_type(MemoryUsagePointers &result,
@ -101,38 +120,25 @@ private:
void ns_show_current_ages();
void ns_show_trend_ages();
void consolidate_void_ptr(MemoryInfo &info);
static MemoryUsage *_global_ptr;
class MemoryInfo {
public:
TypeHandle get_type();
void determine_dynamic_type();
void update_type_handle(TypeHandle &destination, TypeHandle refined);
ReferenceCount *_ptr;
TypedObject *_typed_ptr;
TypeHandle _static_type;
TypeHandle _dynamic_type;
double _time;
int _freeze_index;
bool _reconsider_dynamic_type;
};
typedef map<ReferenceCount *, MemoryInfo> Table;
typedef map<void *, MemoryInfo> Table;
Table _table;
int _freeze_index;
int _count;
size_t _allocated_size;
size_t _total_size;
class TypeHistogram {
public:
void add_info(TypeHandle type);
void add_info(TypeHandle type, MemoryInfo &info);
void show() const;
void clear();
private:
typedef map<TypeHandle, int> Counts;
typedef map<TypeHandle, MemoryUsagePointerCounts> Counts;
Counts _counts;
};
TypeHistogram _trend_types;
@ -140,7 +146,7 @@ private:
class AgeHistogram {
public:
AgeHistogram();
void add_info(double age);
void add_info(double age, MemoryInfo &info);
void show() const;
void clear();
@ -148,7 +154,7 @@ private:
int choose_bucket(double age) const;
enum { num_buckets = 5 };
int _counts[num_buckets];
MemoryUsagePointerCounts _counts[num_buckets];
static double _cutoff[num_buckets];
};
AgeHistogram _trend_ages;
@ -156,7 +162,7 @@ private:
bool _track_memory_usage;
#endif
#endif // NDEBUG
};
#include "memoryUsage.I"

View File

@ -0,0 +1,128 @@
// Filename: memoryUsagePointerCounts.I
// Created by: drose (04Jun01)
//
////////////////////////////////////////////////////////////////////
//
// 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 .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: MemoryUsagePointerCounts::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE MemoryUsagePointerCounts::
MemoryUsagePointerCounts() {
_count = 0;
_unknown_size_count = 0;
_size = 0;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsagePointerCounts::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE MemoryUsagePointerCounts::
MemoryUsagePointerCounts(const MemoryUsagePointerCounts &copy) :
_count(copy._count),
_unknown_size_count(copy._unknown_size_count),
_size(copy._size)
{
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsagePointerCounts::Copy Assignment
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void MemoryUsagePointerCounts::
operator = (const MemoryUsagePointerCounts &copy) {
_count = copy._count;
_unknown_size_count = copy._unknown_size_count;
_size = copy._size;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsagePointerCounts::clear
// Access: Public
// Description: Resets the counter to empty.
////////////////////////////////////////////////////////////////////
INLINE void MemoryUsagePointerCounts::
clear() {
_count = 0;
_unknown_size_count = 0;
_size = 0;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsagePointerCounts::is_size_unknown
// Access: Public
// Description: Returns true if none of the pointers in the count
// have a known size, or false if at least one of them
// does.
////////////////////////////////////////////////////////////////////
INLINE bool MemoryUsagePointerCounts::
is_size_unknown() const {
return _unknown_size_count == _count;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsagePointerCounts::get_size
// Access: Public
// Description: Returns the total allocated size of all pointers in
// the count whose size is known.
////////////////////////////////////////////////////////////////////
INLINE size_t MemoryUsagePointerCounts::
get_size() const {
return _size;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsagePointerCounts::get_count
// Access: Public
// Description: Returns the total number of pointers in the count.
////////////////////////////////////////////////////////////////////
INLINE int MemoryUsagePointerCounts::
get_count() const {
return _count;
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsagePointerCounts::Ordering Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool MemoryUsagePointerCounts::
operator < (const MemoryUsagePointerCounts &other) const {
if (is_size_unknown() != other.is_size_unknown()) {
return is_size_unknown() > other.is_size_unknown();
}
if (get_size() != other.get_size()) {
return get_size() < other.get_size();
}
if (get_count() != other.get_count()) {
return get_count() != other.get_count();
}
return false;
}
INLINE ostream &
operator << (ostream &out, const MemoryUsagePointerCounts &c) {
c.output(out);
return out;
}

View File

@ -0,0 +1,77 @@
// Filename: memoryUsagePointerCounts.cxx
// Created by: drose (04Jun01)
//
////////////////////////////////////////////////////////////////////
//
// 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 .
//
////////////////////////////////////////////////////////////////////
#include "memoryUsagePointerCounts.h"
#include "memoryInfo.h"
////////////////////////////////////////////////////////////////////
// Function: MemoryUsagePointerCounts::add_info
// Access: Public
// Description: Adds a pointer definition to the counter.
////////////////////////////////////////////////////////////////////
void MemoryUsagePointerCounts::
add_info(MemoryInfo &info) {
_count++;
if (info.is_size_known()) {
_size += info.get_size();
} else {
_unknown_size_count++;
}
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsagePointerCounts::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void MemoryUsagePointerCounts::
output(ostream &out) const {
out << _count << " pointers";
if (_unknown_size_count < _count) {
out << ", ";
output_bytes(out, _size);
out << ", ";
output_bytes(out, _size / (_count - _unknown_size_count));
out << " each";
if (_unknown_size_count != 0) {
out << " (" << _unknown_size_count << " of unknown size)";
}
}
}
////////////////////////////////////////////////////////////////////
// Function: MemoryUsagePointerCounts::output_bytes
// Access: Private, Static
// Description: Formats a size in bytes in a meaningful and concise
// way for output, with units.
////////////////////////////////////////////////////////////////////
void MemoryUsagePointerCounts::
output_bytes(ostream &out, size_t size) {
if (size < 4 * 1024) {
out << size << " bytes";
} else if (size < 4 * 1024 * 1024) {
out << size / 1024 << " Kb";
} else {
out << size / (1024 * 1024) << " Mb";
}
}

View File

@ -0,0 +1,67 @@
// Filename: memoryUsagePointerCounts.h
// Created by: drose (04Jun01)
//
////////////////////////////////////////////////////////////////////
//
// 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 .
//
////////////////////////////////////////////////////////////////////
#ifndef MEMORYUSAGEPOINTERCOUNTS_H
#define MEMORYUSAGEPOINTERCOUNTS_H
#include <pandabase.h>
class MemoryInfo;
#ifndef NDEBUG
////////////////////////////////////////////////////////////////////
// Class : MemoryUsagePointerCounts
// Description : This is a supporting class for MemoryUsage. It
// tracks the relative counts of a number of pointers of
// some type (or age), for use by TypeHistogram and
// AgeHistogram. It's not exported from the DLL, and it
// doesn't even exist if we're compiling NDEBUG.
////////////////////////////////////////////////////////////////////
class MemoryUsagePointerCounts {
public:
INLINE MemoryUsagePointerCounts();
INLINE MemoryUsagePointerCounts(const MemoryUsagePointerCounts &copy);
INLINE void operator = (const MemoryUsagePointerCounts &copy);
INLINE void clear();
void add_info(MemoryInfo &info);
void output(ostream &out) const;
INLINE bool is_size_unknown() const;
INLINE size_t get_size() const;
INLINE int get_count() const;
INLINE bool operator < (const MemoryUsagePointerCounts &other) const;
private:
static void output_bytes(ostream &out, size_t size);
private:
int _count;
int _unknown_size_count;
size_t _size;
};
INLINE ostream &operator << (ostream &out, const MemoryUsagePointerCounts &c);
#include "memoryUsagePointerCounts.I"
#endif // NDEBUG
#endif

View File

@ -22,14 +22,14 @@
// Description:
////////////////////////////////////////////////////////////////////
INLINE MemoryUsagePointers::Entry::
Entry(ReferenceCount *ptr, TypedObject *typed_ptr,
Entry(ReferenceCount *ref_ptr, TypedObject *typed_ptr,
TypeHandle type, double age) :
_ptr(ptr),
_ref_ptr(ref_ptr),
_typed_ptr(typed_ptr),
_type(type),
_age(age)
{
_ptr->ref();
_ref_ptr->ref();
}
////////////////////////////////////////////////////////////////////
@ -39,12 +39,12 @@ Entry(ReferenceCount *ptr, TypedObject *typed_ptr,
////////////////////////////////////////////////////////////////////
INLINE MemoryUsagePointers::Entry::
Entry(const Entry &copy) :
_ptr(copy._ptr),
_ref_ptr(copy._ref_ptr),
_typed_ptr(copy._typed_ptr),
_type(copy._type),
_age(copy._age)
{
_ptr->ref();
_ref_ptr->ref();
}
////////////////////////////////////////////////////////////////////
@ -54,12 +54,12 @@ Entry(const Entry &copy) :
////////////////////////////////////////////////////////////////////
INLINE void MemoryUsagePointers::Entry::
operator = (const Entry &copy) {
if (_ptr != copy._ptr) {
_ptr->unref();
_ptr = copy._ptr;
if (_ref_ptr != copy._ref_ptr) {
_ref_ptr->unref();
_ref_ptr = copy._ref_ptr;
// We can't call unref_delete(), because we don't know what kind
// of pointer it is precisely. Potential leak.
_ptr->ref();
_ref_ptr->ref();
}
_typed_ptr = copy._typed_ptr;
_type = copy._type;
@ -75,6 +75,6 @@ INLINE MemoryUsagePointers::Entry::
~Entry() {
// We can't call unref_delete(), because we don't know what kind
// of pointer it is precisely. Potential leak.
_ptr->unref();
_ref_ptr->unref();
}

View File

@ -78,7 +78,7 @@ get_num_pointers() const {
ReferenceCount *MemoryUsagePointers::
get_pointer(int n) const {
nassertr(n >= 0 && n < get_num_pointers(), NULL);
return _entries[n]._ptr;
return _entries[n]._ref_ptr;
}
////////////////////////////////////////////////////////////////////
@ -98,7 +98,7 @@ get_typed_pointer(int n) const {
return typed_ptr;
}
ReferenceCount *ptr = _entries[n]._ptr;
ReferenceCount *ref_ptr = _entries[n]._ref_ptr;
TypeHandle type = _entries[n]._type;
@ -116,7 +116,7 @@ get_typed_pointer(int n) const {
if (type != TypeHandle::none() &&
type.is_derived_from(TypedReferenceCount::get_class_type())) {
return (TypedReferenceCount *)ptr;
return (TypedReferenceCount *)ref_ptr;
}
return NULL;
}
@ -176,13 +176,13 @@ clear() {
// only by MemoryUsage.
////////////////////////////////////////////////////////////////////
void MemoryUsagePointers::
add_entry(ReferenceCount *ptr, TypedObject *typed_ptr,
add_entry(ReferenceCount *ref_ptr, TypedObject *typed_ptr,
TypeHandle type, double age) {
// We can't safly add pointers with a zero reference count. They
// might be statically-allocated or something, and if we try to add
// them they'll try to destruct when the PointerTo later goes away.
if (ptr->get_ref_count() != 0) {
_entries.push_back(Entry(ptr, typed_ptr, type, age));
if (ref_ptr->get_ref_count() != 0) {
_entries.push_back(Entry(ref_ptr, typed_ptr, type, age));
}
}

View File

@ -64,12 +64,12 @@ PUBLISHED:
void clear();
private:
void add_entry(ReferenceCount *ptr, TypedObject *typed_ptr,
void add_entry(ReferenceCount *ref_ptr, TypedObject *typed_ptr,
TypeHandle type, double age);
class Entry {
public:
INLINE Entry(ReferenceCount *ptr, TypedObject *typed_ptr,
INLINE Entry(ReferenceCount *ref_ptr, TypedObject *typed_ptr,
TypeHandle type, double age);
INLINE Entry(const Entry &copy);
INLINE void operator = (const Entry &copy);
@ -80,7 +80,7 @@ private:
// (since ReferenceCount has no public destructor). If we can't
// delete it, we can't make a PointerTo it, since PointerTo wants
// to be able to delete things.
ReferenceCount *_ptr;
ReferenceCount *_ref_ptr;
TypedObject *_typed_ptr;
TypeHandle _type;
double _age;

View File

@ -118,7 +118,7 @@ private:
// only works when the base type is, in fact, a class.
////////////////////////////////////////////////////////////////////
template<class Base>
class EXPCL_PANDAEXPRESS RefCountObj : public Base, public ReferenceCount {
class EXPCL_PANDAEXPRESS RefCountObj : public ReferenceCount, public Base {
public:
INLINE RefCountObj();
INLINE RefCountObj(const Base &copy);

View File

@ -495,9 +495,7 @@ render_frame(const AllAttributesWrapper &initial_state) {
// texture state has changed, we have to be sure to clear the
// current texture state now. A bit unfortunate, but probably not
// measurably expensive.
NodeAttributes state;
state.set_attribute(TextureTransition::get_class_type(), new TextureAttribute);
set_state(state, false);
clear_attribute(TextureTransition::get_class_type());
#endif
if (_clear_buffer_type != 0) {
@ -558,9 +556,7 @@ render_frame(const AllAttributesWrapper &initial_state) {
// Also force the lighting state to unlit, so that issue_light()
// will be guaranteed to be called next frame even if we have the
// same set of light pointers we had this frame.
NodeAttributes state;
state.set_attribute(LightTransition::get_class_type(), new LightAttribute);
set_state(state, false);
clear_attribute(LightTransition::get_class_type());
// All this work to undo the lighting state each frame doesn't seem
// ideal--there may be a better way. Maybe if the lights were just
@ -1997,15 +1993,11 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
// activate();
set_pack_alignment(1);
NodeAttributes state;
// Bug fix for RE, RE2, and VTX - need to disable texturing in order
// for glReadPixels() to work
// NOTE: reading the depth buffer is *much* slower than reading the
// color buffer
state.set_attribute(TextureTransition::get_class_type(),
new TextureAttribute);
set_state(state, false);
clear_attribute(TextureTransition::get_class_type());
int xo, yo, w, h;
dr->get_region_pixels(xo, yo, w, h);

View File

@ -77,6 +77,16 @@ insert(NodeAttributes::iterator position,
return _attributes.insert(position, x);
}
////////////////////////////////////////////////////////////////////
// Function: NodeAttributes::find
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE_GRAPH NodeAttributes::iterator NodeAttributes::
find(const key_type &k) {
return _attributes.find(k);
}
////////////////////////////////////////////////////////////////////
// Function: NodeAttributes::erase
// Access: Public

View File

@ -64,6 +64,7 @@ public:
// of PANDA.DLL.
typedef Attributes::iterator iterator;
typedef Attributes::const_iterator const_iterator;
typedef Attributes::key_type key_type;
typedef Attributes::value_type value_type;
typedef Attributes::size_type size_type;
@ -73,6 +74,7 @@ public:
INLINE_GRAPH const_iterator begin() const;
INLINE_GRAPH const_iterator end() const;
INLINE_GRAPH iterator insert(iterator position, const value_type &x);
INLINE_GRAPH iterator find(const key_type &k);
INLINE_GRAPH void erase(iterator position);
public:

View File

@ -289,6 +289,21 @@ get_last_update() const {
return _last_update;
}
////////////////////////////////////////////////////////////////////
// Function: NodeRelation::clear_wrt_cache
// Access: Public
// Description: Blows away the wrt cache information on this arc.
// This forces the wrt to be recomputed next time it is
// asked for.
////////////////////////////////////////////////////////////////////
INLINE_GRAPH void NodeRelation::
clear_wrt_cache() {
_net_transitions.clear();
_top_subtree = (Node *)NULL;
_all_verified = UpdateSeq::initial();
_last_update = ++last_graph_update(_graph_type);
}
////////////////////////////////////////////////////////////////////
// Function: NodeRelation::create_typed_arc
// Access: Public, Static

View File

@ -122,6 +122,7 @@ PUBLISHED:
INLINE_GRAPH int compare_transitions_to(const NodeRelation *arc) const;
INLINE_GRAPH UpdateSeq get_last_update() const;
INLINE_GRAPH void clear_wrt_cache();
public:
bool sub_render_trans(const AllAttributesWrapper &attrib,

View File

@ -39,6 +39,10 @@
PStatClient *PStatClient::_global_pstats = NULL;
#ifndef CPPPARSER
PStatCollector _memory_usage_pcollector("Panda memory usage");
#endif
////////////////////////////////////////////////////////////////////
// Function: PStatClient::PerThreadData::Constructor
// Access: Public
@ -363,6 +367,14 @@ make_thread(const string &name) {
////////////////////////////////////////////////////////////////////
void PStatClient::
main_tick() {
// We have code here to report the memory usage. We can't put this
// code inside the MemoryUsage class, where it fits a little better,
// simply because MemoryUsage is a very low-level class that doesn't
// know about PStatClient.
if (MemoryUsage::is_tracking()) {
_memory_usage_pcollector.set_level(MemoryUsage::get_total_size());
}
get_global_pstats()->get_main_thread().new_frame();
}

View File

@ -147,6 +147,7 @@ static LevelCollectorProperties level_properties[] = {
{ 1, "State changes", { 1.0, 0.5, 0.2 }, "", 500.0 },
{ 1, "State changes:Transforms", { 0.2, 0.2, 0.8 }, },
{ 1, "State changes:Textures", { 0.8, 0.2, 0.2 }, },
{ 1, "Panda memory usage", { 0.8, 0.2, 0.5 }, "MB", 64, 1048576 },
{ 0, NULL }
};

View File

@ -17,10 +17,10 @@
////////////////////////////////////////////////////////////////////
template<class Element>
vector<Element> PointerToArray<Element>::_empty_array;
pvector<Element> PointerToArray<Element>::_empty_array;
template<class Element>
vector<Element> ConstPointerToArray<Element>::_empty_array;
pvector<Element> ConstPointerToArray<Element>::_empty_array;
////////////////////////////////////////////////////////////////////
// Function: PointerToArray::Constructor
@ -30,7 +30,7 @@ vector<Element> ConstPointerToArray<Element>::_empty_array;
template<class Element>
INLINE PointerToArray<Element>::
PointerToArray() :
PointerToBase<RefCountObj<vector<Element> > >((RefCountObj<vector<Element> > *)NULL)
PointerToBase<RefCountObj<pvector<Element> > >((RefCountObj<pvector<Element> > *)NULL)
{
}
@ -42,7 +42,7 @@ PointerToArray() :
template<class Element>
INLINE PointerToArray<Element>::
PointerToArray(size_type n) :
PointerToBase<RefCountObj<vector<Element> > >(new RefCountObj<vector<Element> >) {
PointerToBase<RefCountObj<pvector<Element> > >(new RefCountObj<pvector<Element> >) {
_ptr->reserve(n);
insert(begin(), n, Element());
}
@ -55,7 +55,7 @@ PointerToArray(size_type n) :
template<class Element>
INLINE PointerToArray<Element>::
PointerToArray(size_type n, const Element &value) :
PointerToBase<RefCountObj<vector<Element> > >(new RefCountObj<vector<Element> >) {
PointerToBase<RefCountObj<pvector<Element> > >(new RefCountObj<pvector<Element> >) {
_ptr->reserve(n);
insert(begin(), n, value);
}
@ -68,7 +68,7 @@ PointerToArray(size_type n, const Element &value) :
template<class Element>
INLINE PointerToArray<Element>::
PointerToArray(const PointerToArray<Element> &copy) :
PointerToBase<RefCountObj<vector<Element> > >(copy)
PointerToBase<RefCountObj<pvector<Element> > >(copy)
{
}
@ -148,7 +148,7 @@ template<class Element>
INLINE PointerToArray<Element>::size_type PointerToArray<Element>::
max_size() const {
nassertd(_ptr != NULL) {
((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
}
return _ptr->max_size();
}
@ -173,7 +173,7 @@ template<class Element>
INLINE void PointerToArray<Element>::
reserve(PointerToArray<Element>::size_type n) {
if (_ptr == NULL) {
reassign(new RefCountObj<vector<Element> >);
reassign(new RefCountObj<pvector<Element> >);
}
_ptr->reserve(n);
}
@ -199,7 +199,7 @@ template<class Element>
INLINE PointerToArray<Element>::reference PointerToArray<Element>::
front() const {
nassertd(_ptr != NULL) {
((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
}
nassertd(!_ptr->empty()) {
_ptr->push_back(Element());
@ -216,7 +216,7 @@ template<class Element>
INLINE PointerToArray<Element>::reference PointerToArray<Element>::
back() const {
nassertd(_ptr != NULL) {
((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
}
nassertd(!_ptr->empty()) {
_ptr->push_back(Element());
@ -261,7 +261,7 @@ template<class Element>
INLINE void PointerToArray<Element>::
erase(iterator position) const {
nassertd(_ptr != NULL) {
((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
}
nassertv(position >= _ptr->begin() &&
position <= _ptr->end());
@ -277,7 +277,7 @@ template<class Element>
INLINE void PointerToArray<Element>::
erase(iterator first, iterator last) const {
nassertd(_ptr != NULL) {
((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
}
nassertv(first >= _ptr->begin() && first <= _ptr->end());
nassertv(last >= _ptr->begin() && last <= _ptr->end());
@ -294,7 +294,7 @@ template<class Element>
INLINE PointerToArray<Element>::reference PointerToArray<Element>::
operator [](size_type n) const {
nassertd(_ptr != NULL) {
((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
}
nassertd(!_ptr->empty()) {
_ptr->push_back(Element());
@ -313,7 +313,7 @@ template<class Element>
INLINE void PointerToArray<Element>::
push_back(const Element &x) {
if (_ptr == NULL) {
reassign(new RefCountObj<vector<Element> >);
reassign(new RefCountObj<pvector<Element> >);
}
_ptr->push_back(x);
}
@ -327,7 +327,7 @@ template<class Element>
INLINE void PointerToArray<Element>::
pop_back() {
nassertd(_ptr != NULL) {
((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
}
nassertv(!_ptr->empty());
_ptr->pop_back();
@ -344,7 +344,7 @@ template<class Element>
INLINE void PointerToArray<Element>::
make_empty() {
nassertd(_ptr != NULL) {
((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
}
nassertv(!_ptr->empty());
_ptr->clear();
@ -385,10 +385,10 @@ p() const {
// with some of the vector's esoteric functionality.
////////////////////////////////////////////////////////////////////
template<class Element>
INLINE vector<Element> &PointerToArray<Element>::
INLINE pvector<Element> &PointerToArray<Element>::
v() const {
nassertd(_ptr != NULL) {
((PointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
}
return *_ptr;
}
@ -403,7 +403,7 @@ template<class Element>
INLINE void* PointerToArray<Element>::
get_void_ptr() const
{
return PointerToBase<RefCountObj<vector<Element> > >::_ptr;
return PointerToBase<RefCountObj<pvector<Element> > >::_ptr;
}
////////////////////////////////////////////////////////////////////
@ -415,7 +415,7 @@ template<class Element>
INLINE void PointerToArray<Element>::
set_void_ptr(void* p)
{
reassign((RefCountObj<vector<Element> > *)p);
reassign((RefCountObj<pvector<Element> > *)p);
}
////////////////////////////////////////////////////////////////////
// Function: PointerToArray::get_ref_count
@ -435,7 +435,7 @@ get_ref_count() const {
////////////////////////////////////////////////////////////////////
template<class Element>
INLINE PointerToArray<Element> &PointerToArray<Element>::
operator = (RefCountObj<vector<Element> > *ptr) {
operator = (RefCountObj<pvector<Element> > *ptr) {
reassign(ptr);
return *this;
}
@ -462,7 +462,7 @@ operator = (const PointerToArray<Element> &copy) {
template<class Element>
INLINE void PointerToArray<Element>::
clear() {
reassign((RefCountObj<vector<Element> > *)NULL);
reassign((RefCountObj<pvector<Element> > *)NULL);
}
@ -475,7 +475,7 @@ clear() {
template<class Element>
INLINE ConstPointerToArray<Element>::
ConstPointerToArray() :
PointerToBase<RefCountObj<vector<Element> > >((RefCountObj<vector<Element> > *)NULL)
PointerToBase<RefCountObj<pvector<Element> > >((RefCountObj<pvector<Element> > *)NULL)
{
}
@ -487,7 +487,7 @@ ConstPointerToArray() :
template<class Element>
INLINE ConstPointerToArray<Element>::
ConstPointerToArray(const PointerToArray<Element> &copy) :
PointerToBase<RefCountObj<vector<Element> > >(copy)
PointerToBase<RefCountObj<pvector<Element> > >(copy)
{
}
@ -499,7 +499,7 @@ ConstPointerToArray(const PointerToArray<Element> &copy) :
template<class Element>
INLINE ConstPointerToArray<Element>::
ConstPointerToArray(const ConstPointerToArray<Element> &copy) :
PointerToBase<RefCountObj<vector<Element> > >(copy)
PointerToBase<RefCountObj<pvector<Element> > >(copy)
{
}
@ -579,7 +579,7 @@ template<class Element>
INLINE ConstPointerToArray<Element>::size_type ConstPointerToArray<Element>::
max_size() const {
nassertd(_ptr != NULL) {
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
}
return _ptr->max_size();
}
@ -604,7 +604,7 @@ template<class Element>
INLINE ConstPointerToArray<Element>::size_type ConstPointerToArray<Element>::
capacity() const {
nassertd(_ptr != NULL) {
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
}
return _ptr->capacity();
}
@ -619,7 +619,7 @@ template<class Element>
INLINE ConstPointerToArray<Element>::reference ConstPointerToArray<Element>::
operator[](size_type n) const {
nassertd(_ptr != NULL) {
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
}
nassertd(!_ptr->empty()) {
_ptr->push_back(Element());
@ -638,7 +638,7 @@ template<class Element>
INLINE ConstPointerToArray<Element>::reference ConstPointerToArray<Element>::
front() const {
nassertd(_ptr != NULL) {
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
}
nassertd(!_ptr->empty()) {
_ptr->push_back(Element());
@ -655,7 +655,7 @@ template<class Element>
INLINE ConstPointerToArray<Element>::reference ConstPointerToArray<Element>::
back() const {
nassertd(_ptr != NULL) {
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
}
nassertd(!_ptr->empty()) {
_ptr->push_back(Element());
@ -698,10 +698,10 @@ p() const {
// with some of the vector's esoteric functionality.
////////////////////////////////////////////////////////////////////
template<class Element>
INLINE const vector<Element> &ConstPointerToArray<Element>::
INLINE const pvector<Element> &ConstPointerToArray<Element>::
v() const {
nassertd(_ptr != NULL) {
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<vector<Element> >);
((ConstPointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
}
return *_ptr;
}
@ -724,7 +724,7 @@ get_ref_count() const {
////////////////////////////////////////////////////////////////////
template<class Element>
INLINE ConstPointerToArray<Element> &ConstPointerToArray<Element>::
operator = (RefCountObj<vector<Element> > *ptr) {
operator = (RefCountObj<pvector<Element> > *ptr) {
reassign(ptr);
return *this;
}
@ -763,6 +763,6 @@ operator = (const ConstPointerToArray<Element> &copy) {
template<class Element>
INLINE void ConstPointerToArray<Element>::
clear() {
reassign((RefCountObj<vector<Element> > *)NULL);
reassign((RefCountObj<pvector<Element> > *)NULL);
}

View File

@ -72,8 +72,7 @@
#include "referenceCount.h"
#include "pointerTo.h"
#include <vector>
#include "pvector.h"
////////////////////////////////////////////////////////////////////
// Class : PointerToArray
@ -84,17 +83,17 @@
// with a reference count.
////////////////////////////////////////////////////////////////////
template <class Element>
class PointerToArray : public PointerToBase<RefCountObj<vector<Element> > > {
class PointerToArray : public PointerToBase<RefCountObj<pvector<Element> > > {
public:
typedef vector<Element>::value_type value_type;
typedef vector<Element>::reference reference;
typedef vector<Element>::const_reference const_reference;
typedef vector<Element>::iterator iterator;
typedef vector<Element>::const_iterator const_iterator;
typedef vector<Element>::reverse_iterator reverse_iterator;
typedef vector<Element>::const_reverse_iterator const_reverse_iterator;
typedef vector<Element>::difference_type difference_type;
typedef vector<Element>::size_type size_type;
typedef pvector<Element>::value_type value_type;
typedef pvector<Element>::reference reference;
typedef pvector<Element>::const_reference const_reference;
typedef pvector<Element>::iterator iterator;
typedef pvector<Element>::const_iterator const_iterator;
typedef pvector<Element>::reverse_iterator reverse_iterator;
typedef pvector<Element>::const_reverse_iterator const_reverse_iterator;
typedef pvector<Element>::difference_type difference_type;
typedef pvector<Element>::size_type size_type;
PUBLISHED:
INLINE PointerToArray();
@ -153,7 +152,7 @@ public:
INLINE operator Element *() const;
INLINE Element *p() const;
INLINE vector<Element> &v() const;
INLINE pvector<Element> &v() const;
//These functions are only to be used in Reading through BamReader.
//They are designed to work in pairs, so that you register what is
@ -168,7 +167,7 @@ public:
// Reassignment is by pointer, not memberwise as with a vector.
INLINE PointerToArray<Element> &
operator = (RefCountObj<vector<Element> > *ptr);
operator = (RefCountObj<pvector<Element> > *ptr);
INLINE PointerToArray<Element> &
operator = (const PointerToArray<Element> &copy);
INLINE void clear();
@ -179,7 +178,7 @@ private:
// NULL pointer. It might not be shared properly between different
// .so's, since it's a static member of a template class, but we
// don't really care.
static vector<Element> _empty_array;
static pvector<Element> _empty_array;
};
////////////////////////////////////////////////////////////////////
@ -188,22 +187,22 @@ private:
// may not be modified.
////////////////////////////////////////////////////////////////////
template <class Element>
class ConstPointerToArray : public PointerToBase<RefCountObj<vector<Element> > > {
class ConstPointerToArray : public PointerToBase<RefCountObj<pvector<Element> > > {
public:
typedef vector<Element>::value_type value_type;
typedef vector<Element>::const_reference reference;
typedef vector<Element>::const_reference const_reference;
typedef vector<Element>::const_iterator iterator;
typedef vector<Element>::const_iterator const_iterator;
typedef pvector<Element>::value_type value_type;
typedef pvector<Element>::const_reference reference;
typedef pvector<Element>::const_reference const_reference;
typedef pvector<Element>::const_iterator iterator;
typedef pvector<Element>::const_iterator const_iterator;
#ifdef WIN32_VC
// VC++ seems to break the const_reverse_iterator definition somehow.
typedef vector<Element>::reverse_iterator reverse_iterator;
typedef pvector<Element>::reverse_iterator reverse_iterator;
#else
typedef vector<Element>::const_reverse_iterator reverse_iterator;
typedef pvector<Element>::const_reverse_iterator reverse_iterator;
#endif
typedef vector<Element>::const_reverse_iterator const_reverse_iterator;
typedef vector<Element>::difference_type difference_type;
typedef vector<Element>::size_type size_type;
typedef pvector<Element>::const_reverse_iterator const_reverse_iterator;
typedef pvector<Element>::difference_type difference_type;
typedef pvector<Element>::size_type size_type;
INLINE ConstPointerToArray();
INLINE ConstPointerToArray(const PointerToArray<Element> &copy);
@ -233,13 +232,13 @@ public:
INLINE operator const Element *() const;
INLINE const Element *p() const;
INLINE const vector<Element> &v() const;
INLINE const pvector<Element> &v() const;
INLINE int get_ref_count() const;
// Reassignment is by pointer, not memberwise as with a vector.
INLINE ConstPointerToArray<Element> &
operator = (RefCountObj<vector<Element> > *ptr);
operator = (RefCountObj<pvector<Element> > *ptr);
INLINE ConstPointerToArray<Element> &
operator = (const PointerToArray<Element> &copy);
INLINE ConstPointerToArray<Element> &
@ -252,7 +251,7 @@ private:
// NULL pointer. It might not be shared properly between different
// .so's, since it's a static member of a template class, but we
// don't really care.
static vector<Element> _empty_array;
static pvector<Element> _empty_array;
};

View File

@ -1446,12 +1446,14 @@ hide_collision_solids() {
////////////////////////////////////////////////////////////////////
// Function: NodePath::is_hidden
// Access: Public
// Description: Returns true if some arc above this bottom node has
// been set to 'hide', false if it should be visible.
// Description: Returns true if the bottom arc has been hidden,
// false otherwise. The bottom node may still be
// invisible due to a higher ancestor having been
// hidden; use get_hidden_ancestor() to check this.
////////////////////////////////////////////////////////////////////
INLINE bool NodePath::
is_hidden() const {
return !get_hidden_ancestor().is_empty();
return (arc()->has_transition(PruneTransition::get_class_type()));
}
////////////////////////////////////////////////////////////////////
@ -1489,10 +1491,26 @@ unstash() {
////////////////////////////////////////////////////////////////////
// Function: NodePath::is_stashed
// Access: Public
// Description: Returns true if some arc above this bottom node has
// been set to 'stash', false if it should be visible.
// Description: Returns true if the bottom arc has been 'stashed',
// false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool NodePath::
is_stashed() const {
return !get_stashed_ancestor().is_empty();
return (arc()->get_graph_type() == NodeRelation::get_stashed_type());
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::clear_wrt_cache
// Access: Public
// Description: Recursively calls clear_wrt_cache() on every arc
// beginning at the bottom arc and below. This wipes
// out the cached wrt information, which will make the
// next call to wrt() more expensive, but may reclaim
// some memory and free up some otherwise unused
// pointers.
////////////////////////////////////////////////////////////////////
INLINE void NodePath::
clear_wrt_cache() {
nassertv_always(!is_empty());
r_clear_wrt_cache(arc());
}

View File

@ -3147,3 +3147,23 @@ r_adjust_all_priorities(NodeRelation *arc, int adjustment) {
r_adjust_all_priorities(child_arc, adjustment);
}
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::r_clear_wrt_cache
// Access: Private
// Description: The recursive implementation of
// clear_wrt_cache(). This walks through the
// subgraph defined by the indicated arc and below.
////////////////////////////////////////////////////////////////////
void NodePath::
r_clear_wrt_cache(NodeRelation *arc) {
arc->clear_wrt_cache();
Node *dnode = arc->get_child();
int num_children = dnode->get_num_children(_graph_type);
for (int i = 0; i < num_children; i++) {
NodeRelation *child_arc = dnode->get_child(_graph_type, i);
r_clear_wrt_cache(child_arc);
}
}

View File

@ -510,6 +510,7 @@ PUBLISHED:
NodePath get_stashed_ancestor() const;
void prepare_scene(GraphicsStateGuardianBase *gsg);
INLINE void clear_wrt_cache();
void show_bounds();
void hide_bounds();
@ -542,6 +543,7 @@ private:
void r_list_transitions(ostream &out, int indent_level) const;
void r_adjust_all_priorities(NodeRelation *arc, int adjustment);
void r_clear_wrt_cache(NodeRelation *arc);
// It's important that there are no data members in this class. Put
// them in NodePathBase instead.