From 3ac771804ba94dc477a235e0bee0d0af537d6f05 Mon Sep 17 00:00:00 2001 From: David Rose Date: Fri, 2 Jul 2004 17:11:59 +0000 Subject: [PATCH] reduce overhead on DCPacker construction and push/pop operations --- direct/src/dcparser/dcPacker.I | 47 +++++++++++++++++++++++++++ direct/src/dcparser/dcPacker.cxx | 56 ++++++++++++++++++++++---------- direct/src/dcparser/dcPacker.h | 17 ++++++++-- 3 files changed, 100 insertions(+), 20 deletions(-) diff --git a/direct/src/dcparser/dcPacker.I b/direct/src/dcparser/dcPacker.I index 2c79001532..28396b029c 100755 --- a/direct/src/dcparser/dcPacker.I +++ b/direct/src/dcparser/dcPacker.I @@ -680,6 +680,19 @@ get_write_pointer(size_t size) { return _pack_data.get_write_pointer(size); } +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::StackElement::get_num_stack_elements_ever_allocated +// Access: Published, Static +// Description: Returns the number of DCPacker::StackElement pointers +// ever simultaneously allocated; these are now either +// in active use or have been recycled into the deleted +// DCPacker::StackElement pool to be used again. +//////////////////////////////////////////////////////////////////// +INLINE int DCPacker:: +get_num_stack_elements_ever_allocated() { + return StackElement::_num_ever_allocated; +} + //////////////////////////////////////////////////////////////////// // Function: DCPacker::raw_pack_int8 // Access: Published @@ -1138,3 +1151,37 @@ advance() { _current_field = _current_parent->get_nested_field(_current_field_index); } } + +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::StackElement::operator new +// Access: Public +// Description: Allocates the memory for a new DCPacker::StackElement. +// This is specialized here to provide for fast +// allocation of these things. +//////////////////////////////////////////////////////////////////// +INLINE void *DCPacker::StackElement:: +operator new(size_t size) { + if (_deleted_chain != (DCPacker::StackElement *)NULL) { + StackElement *obj = _deleted_chain; + _deleted_chain = _deleted_chain->_next; + return obj; + } +#ifndef NDEBUG + _num_ever_allocated++; +#endif // NDEBUG + return ::operator new(size); +} + +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::StackElement::operator delete +// Access: Public +// Description: Frees the memory for a deleted DCPacker::StackElement. +// This is specialized here to provide for fast +// allocation of these things. +//////////////////////////////////////////////////////////////////// +INLINE void DCPacker::StackElement:: +operator delete(void *ptr) { + StackElement *obj = (StackElement *)ptr; + obj->_next = _deleted_chain; + _deleted_chain = obj; +} diff --git a/direct/src/dcparser/dcPacker.cxx b/direct/src/dcparser/dcPacker.cxx index a5c9c41162..6546e5bacd 100755 --- a/direct/src/dcparser/dcPacker.cxx +++ b/direct/src/dcparser/dcPacker.cxx @@ -24,6 +24,9 @@ #include "dcSwitchParameter.h" #include "dcClass.h" +DCPacker::StackElement *DCPacker::StackElement::_deleted_chain = NULL; +int DCPacker::StackElement::_num_ever_allocated = 0; + //////////////////////////////////////////////////////////////////// // Function: DCPacker::Constructor // Access: Published @@ -39,6 +42,7 @@ DCPacker() { _live_catalog = NULL; _pack_error = false; _range_error = false; + _stack = NULL; clear(); } @@ -99,7 +103,7 @@ end_pack() { _mode = M_idle; - if (!_stack.empty() || _current_field != NULL || _current_parent != NULL) { + if (_stack != NULL || _current_field != NULL || _current_parent != NULL) { _pack_error = true; } @@ -192,7 +196,7 @@ end_unpack() { _mode = M_idle; - if (!_stack.empty() || _current_field != NULL || _current_parent != NULL) { + if (_stack != NULL || _current_field != NULL || _current_parent != NULL) { // This happens if we have not unpacked all of the fields. // However, this is not an error if we have called seek() during // the unpack session (in which case the _catalog will be @@ -313,7 +317,7 @@ seek(const string &field_name) { // If we are seeking, we don't need to remember our current stack // position. - _stack.clear(); + clear_stack(); _current_field = entry._field; _current_parent = entry._parent; _current_field_index = entry._field_index; @@ -332,7 +336,7 @@ seek(const string &field_name) { } else if (_mode == M_repack) { nassertr(_catalog != (DCPackerCatalog *)NULL, false); - if (!_stack.empty() || _current_field != (DCPackerInterface *)NULL) { + if (_stack != NULL || _current_field != NULL) { // It is an error to reseek while the stack is nonempty--that // means we haven't finished packing the current field. _pack_error = true; @@ -427,12 +431,13 @@ push() { _pack_error = true; } else { - StackElement element; - element._current_parent = _current_parent; - element._current_field_index = _current_field_index; - element._push_marker = _push_marker; - element._pop_marker = _pop_marker; - _stack.push_back(element); + StackElement *element = new StackElement; + element->_current_parent = _current_parent; + element->_current_field_index = _current_field_index; + element->_push_marker = _push_marker; + element->_pop_marker = _pop_marker; + element->_next = _stack; + _stack = element; _current_parent = _current_field; @@ -521,7 +526,7 @@ pop() { _pack_error = true; } - if (_stack.empty()) { + if (_stack == NULL) { // Unbalanced pop(). _pack_error = true; @@ -548,12 +553,15 @@ pop() { } _current_field = _current_parent; - _current_parent = _stack.back()._current_parent; - _current_field_index = _stack.back()._current_field_index; - _push_marker = _stack.back()._push_marker; - _pop_marker = _stack.back()._pop_marker; + _current_parent = _stack->_current_parent; + _current_field_index = _stack->_current_field_index; + _push_marker = _stack->_push_marker; + _pop_marker = _stack->_pop_marker; _num_nested_fields = (_current_parent == NULL) ? 0 : _current_parent->get_num_nested_fields(); - _stack.pop_back(); + + StackElement *next = _stack->_next; + delete _stack; + _stack = next; } advance(); @@ -1093,7 +1101,7 @@ handle_switch(const DCSwitchParameter *switch_parameter) { //////////////////////////////////////////////////////////////////// void DCPacker:: clear() { - _stack.clear(); + clear_stack(); _current_field = NULL; _current_parent = NULL; _current_field_index = 0; @@ -1110,6 +1118,20 @@ clear() { _root = NULL; } +//////////////////////////////////////////////////////////////////// +// Function: DCPacker::clear_stack +// Access: Private +// Description: Empties the stack. +//////////////////////////////////////////////////////////////////// +void DCPacker:: +clear_stack() { + while (_stack != (StackElement *)NULL) { + StackElement *next = _stack->_next; + delete _stack; + _stack = next; + } +} + #ifdef HAVE_PYTHON //////////////////////////////////////////////////////////////////// // Function: DCPacker::pack_class_object diff --git a/direct/src/dcparser/dcPacker.h b/direct/src/dcparser/dcPacker.h index 2b780d3a02..c85acf8270 100755 --- a/direct/src/dcparser/dcPacker.h +++ b/direct/src/dcparser/dcPacker.h @@ -131,6 +131,8 @@ public: INLINE char *get_write_pointer(size_t size); PUBLISHED: + INLINE static int get_num_stack_elements_ever_allocated(); + // The following methods are used only for packing (or unpacking) // raw data into the buffer between packing sessions (e.g. between // calls to end_pack() and the next begin_pack()). @@ -177,6 +179,7 @@ private: INLINE void advance(); void handle_switch(const DCSwitchParameter *switch_parameter); void clear(); + void clear_stack(); #ifdef HAVE_PYTHON void pack_class_object(const DCClass *dclass, PyObject *object); @@ -208,14 +211,22 @@ private: class StackElement { public: + // As an optimization, we implement operator new and delete here + // to minimize allocation overhead during push() and pop(). + INLINE void *operator new(size_t size); + INLINE void operator delete(void *ptr); + const DCPackerInterface *_current_parent; int _current_field_index; size_t _push_marker; size_t _pop_marker; - }; - typedef pvector Stack; + StackElement *_next; + + static StackElement *_deleted_chain; + static int _num_ever_allocated; + }; + StackElement *_stack; - Stack _stack; const DCPackerInterface *_current_field; const DCPackerInterface *_current_parent; int _current_field_index;