00001 // Filename: memoryUsagePointers.cxx 00002 // Created by: drose (25May00) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "memoryUsagePointers.h" 00016 00017 #ifdef DO_MEMORY_USAGE 00018 00019 #include "config_express.h" 00020 #include "referenceCount.h" 00021 #include "typedReferenceCount.h" 00022 00023 #ifdef HAVE_PYTHON 00024 // Pick up a few declarations so we can create Python wrappers in 00025 // get_python_pointer(), below. 00026 00027 #include "py_panda.h" 00028 00029 #ifndef CPPPARSER 00030 extern EXPCL_PANDAEXPRESS Dtool_PyTypedObject Dtool_TypedObject; 00031 extern EXPCL_PANDAEXPRESS Dtool_PyTypedObject Dtool_TypedReferenceCount; 00032 extern EXPCL_PANDAEXPRESS Dtool_PyTypedObject Dtool_ReferenceCount; 00033 #endif // CPPPARSER 00034 00035 #endif // HAVE_PYTHON 00036 00037 //////////////////////////////////////////////////////////////////// 00038 // Function: MemoryUsagePointers::Constructor 00039 // Access: Published 00040 // Description: 00041 //////////////////////////////////////////////////////////////////// 00042 MemoryUsagePointers:: 00043 MemoryUsagePointers() { 00044 } 00045 00046 //////////////////////////////////////////////////////////////////// 00047 // Function: MemoryUsagePointers::Destructor 00048 // Access: Published 00049 // Description: 00050 //////////////////////////////////////////////////////////////////// 00051 MemoryUsagePointers:: 00052 ~MemoryUsagePointers() { 00053 } 00054 00055 //////////////////////////////////////////////////////////////////// 00056 // Function: MemoryUsagePointers::get_num_pointers 00057 // Access: Published 00058 // Description: Returns the number of pointers in the set. 00059 //////////////////////////////////////////////////////////////////// 00060 int MemoryUsagePointers:: 00061 get_num_pointers() const { 00062 return _entries.size(); 00063 } 00064 00065 //////////////////////////////////////////////////////////////////// 00066 // Function: MemoryUsagePointers::get_pointer 00067 // Access: Published 00068 // Description: Returns the nth pointer of the set. 00069 //////////////////////////////////////////////////////////////////// 00070 ReferenceCount *MemoryUsagePointers:: 00071 get_pointer(int n) const { 00072 nassertr(n >= 0 && n < get_num_pointers(), NULL); 00073 return _entries[n]._ref_ptr; 00074 } 00075 00076 //////////////////////////////////////////////////////////////////// 00077 // Function: MemoryUsagePointers::get_typed_pointer 00078 // Access: Published 00079 // Description: Returns the nth pointer of the set, typecast to a 00080 // TypedObject if possible. If the pointer is not a 00081 // TypedObject or if the cast cannot be made, returns 00082 // NULL. 00083 //////////////////////////////////////////////////////////////////// 00084 TypedObject *MemoryUsagePointers:: 00085 get_typed_pointer(int n) const { 00086 nassertr(n >= 0 && n < get_num_pointers(), NULL); 00087 TypedObject *typed_ptr = _entries[n]._typed_ptr; 00088 00089 if (typed_ptr != (TypedObject *)NULL) { 00090 return typed_ptr; 00091 } 00092 00093 ReferenceCount *ref_ptr = _entries[n]._ref_ptr; 00094 00095 TypeHandle type = _entries[n]._type; 00096 00097 // We can only cast-across to a TypedObject when we explicitly know 00098 // the inheritance path. Most of the time, this will be via 00099 // TypedReferenceCount. There are classes defined in other packages 00100 // that inherit from TypedObject and ReferenceCount separately (like 00101 // Node), but we can't do anything about that here without knowing 00102 // about the particular class. (Actually, we couldn't do anything 00103 // about Node anyway, because it inherits virtually from 00104 // ReferenceCount.) 00105 00106 // RTTI can't help us here, because ReferenceCount has no virtual 00107 // functions, so we can't use C++'s new dynamic_cast feature. 00108 00109 if (type != TypeHandle::none() && 00110 type.is_derived_from(TypedReferenceCount::get_class_type())) { 00111 return (TypedReferenceCount *)ref_ptr; 00112 } 00113 return NULL; 00114 } 00115 00116 //////////////////////////////////////////////////////////////////// 00117 // Function: MemoryUsagePointers::get_type 00118 // Access: Published 00119 // Description: Returns the actual type of the nth pointer, if it is 00120 // known. 00121 //////////////////////////////////////////////////////////////////// 00122 TypeHandle MemoryUsagePointers:: 00123 get_type(int n) const { 00124 nassertr(n >= 0 && n < get_num_pointers(), TypeHandle::none()); 00125 return _entries[n]._type; 00126 } 00127 00128 //////////////////////////////////////////////////////////////////// 00129 // Function: MemoryUsagePointers::get_type_name 00130 // Access: Published 00131 // Description: Returns the type name of the nth pointer, if it is 00132 // known. 00133 //////////////////////////////////////////////////////////////////// 00134 string MemoryUsagePointers:: 00135 get_type_name(int n) const { 00136 nassertr(n >= 0 && n < get_num_pointers(), ""); 00137 return get_type(n).get_name(); 00138 } 00139 00140 //////////////////////////////////////////////////////////////////// 00141 // Function: MemoryUsagePointers::get_age 00142 // Access: Published 00143 // Description: Returns the age of the nth pointer: the number of 00144 // seconds elapsed between the time it was allocated and 00145 // the time it was added to this set via a call to 00146 // MemoryUsage::get_pointers(). 00147 //////////////////////////////////////////////////////////////////// 00148 double MemoryUsagePointers:: 00149 get_age(int n) const { 00150 nassertr(n >= 0 && n < get_num_pointers(), 0.0); 00151 return _entries[n]._age; 00152 } 00153 00154 #ifdef HAVE_PYTHON 00155 //////////////////////////////////////////////////////////////////// 00156 // Function: MemoryUsagePointers::get_python_pointer 00157 // Access: Published 00158 // Description: Returns the nth object, represented as a Python 00159 // object of the appropriate type. Reference counting 00160 // will be properly set on the Python object. 00161 // 00162 // get_typed_pointer() is almost as good as this, but 00163 // (a) it does not set the reference count, and (b) it 00164 // does not work for objects that do not inherit from 00165 // TypedObject. This will work for any object whose 00166 // type is known, which has a Python representation. 00167 //////////////////////////////////////////////////////////////////// 00168 PyObject *MemoryUsagePointers:: 00169 get_python_pointer(int n) const { 00170 nassertr(n >= 0 && n < get_num_pointers(), NULL); 00171 TypedObject *typed_ptr = _entries[n]._typed_ptr; 00172 ReferenceCount *ref_ptr = _entries[n]._ref_ptr; 00173 00174 bool memory_rules = false; 00175 if (ref_ptr != (ReferenceCount *)NULL) { 00176 memory_rules = true; 00177 ref_ptr->ref(); 00178 } 00179 00180 if (typed_ptr != (TypedObject *)NULL) { 00181 return DTool_CreatePyInstanceTyped(typed_ptr, Dtool_TypedObject, 00182 memory_rules, false, 00183 typed_ptr->get_type_index()); 00184 } 00185 00186 if (ref_ptr == (ReferenceCount *)NULL) { 00187 return Py_BuildValue(""); 00188 } 00189 00190 TypeHandle type = _entries[n]._type; 00191 if (type != TypeHandle::none()) { 00192 // Use TypedReferenceCount if we have it. 00193 if (type.is_derived_from(TypedReferenceCount::get_class_type())) { 00194 TypedReferenceCount *typed_ref_ptr = (TypedReferenceCount *)ref_ptr; 00195 00196 return DTool_CreatePyInstanceTyped(typed_ref_ptr, Dtool_TypedReferenceCount, 00197 memory_rules, false, 00198 type.get_index()); 00199 } 00200 00201 // Otherwise, trust that there is a downcast path to the actual type. 00202 return DTool_CreatePyInstanceTyped(ref_ptr, Dtool_ReferenceCount, 00203 memory_rules, false, 00204 type.get_index()); 00205 } 00206 00207 // If worse comes to worst, just return a ReferenceCount wrapper. 00208 return DTool_CreatePyInstance(ref_ptr, Dtool_ReferenceCount, 00209 memory_rules, false); 00210 } 00211 #endif 00212 00213 //////////////////////////////////////////////////////////////////// 00214 // Function: MemoryUsagePointers::clear 00215 // Access: Published 00216 // Description: Empties the set of pointers. 00217 //////////////////////////////////////////////////////////////////// 00218 void MemoryUsagePointers:: 00219 clear() { 00220 _entries.clear(); 00221 } 00222 00223 //////////////////////////////////////////////////////////////////// 00224 // Function: MemoryUsagePointers::output 00225 // Access: Published 00226 // Description: 00227 //////////////////////////////////////////////////////////////////// 00228 void MemoryUsagePointers:: 00229 output(ostream &out) const { 00230 out << _entries.size() << " pointers."; 00231 } 00232 00233 //////////////////////////////////////////////////////////////////// 00234 // Function: MemoryUsagePointers::clear 00235 // Access: Private 00236 // Description: Adds a new entry to the set. Intended to be called 00237 // only by MemoryUsage. 00238 //////////////////////////////////////////////////////////////////// 00239 void MemoryUsagePointers:: 00240 add_entry(ReferenceCount *ref_ptr, TypedObject *typed_ptr, 00241 TypeHandle type, double age) { 00242 // We can't safely add pointers with a zero reference count. They 00243 // might be statically-allocated or something, and if we try to add 00244 // them they'll try to destruct when the PointerTo later goes away. 00245 if (ref_ptr->get_ref_count() != 0) { 00246 _entries.push_back(Entry(ref_ptr, typed_ptr, type, age)); 00247 } 00248 } 00249 00250 00251 #endif // DO_MEMORY_USAGE