فهرست منبع

reduce overhead on DCPacker construction and push/pop operations

David Rose 21 سال پیش
والد
کامیت
3ac771804b
3فایلهای تغییر یافته به همراه99 افزوده شده و 19 حذف شده
  1. 47 0
      direct/src/dcparser/dcPacker.I
  2. 39 17
      direct/src/dcparser/dcPacker.cxx
  3. 13 2
      direct/src/dcparser/dcPacker.h

+ 47 - 0
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;
+}

+ 39 - 17
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

+ 13 - 2
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;
+    StackElement *_next;
+
+    static StackElement *_deleted_chain;
+    static int _num_ever_allocated;
   };
-  typedef pvector<StackElement> Stack;
+  StackElement *_stack;
 
-  Stack _stack;
   const DCPackerInterface *_current_field;
   const DCPackerInterface *_current_parent;
   int _current_field_index;