Ver código fonte

report different types of cyclers in pstats

David Rose 20 anos atrás
pai
commit
7b1b8bb4af

+ 49 - 4
panda/src/display/graphicsEngine.cxx

@@ -60,7 +60,7 @@ PStatCollector GraphicsEngine::_transform_states_unused_pcollector("TransformSta
 PStatCollector GraphicsEngine::_render_states_pcollector("RenderStates");
 PStatCollector GraphicsEngine::_render_states_unused_pcollector("RenderStates:Unused");
 PStatCollector GraphicsEngine::_cyclers_pcollector("PipelineCyclers");
-PStatCollector GraphicsEngine::_dirty_cyclers_pcollector("PipelineCyclers:Dirty");
+PStatCollector GraphicsEngine::_dirty_cyclers_pcollector("Dirty PipelineCyclers");
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::Constructor
@@ -540,10 +540,18 @@ render_frame() {
     }
   }
 
-#if defined(DO_PIPELINING) && defined(HAVE_THREADS)
+#if defined(THREADED_PIPELINE) && defined(DO_PSTATS)
   _cyclers_pcollector.set_level(_pipeline->get_num_cyclers());
   _dirty_cyclers_pcollector.set_level(_pipeline->get_num_dirty_cyclers());
-#endif  // DO_PIPELINING && HAVE_THREADS
+
+#ifdef DEBUG_THREADS
+  if (PStatClient::is_connected()) {
+    _pipeline->iterate_all_cycler_types(pstats_count_cycler_type, this);
+    _pipeline->iterate_dirty_cycler_types(pstats_count_dirty_cycler_type, this);
+  }
+#endif  // DEBUG_THREADS
+
+#endif  // THREADED_PIPELINE && DO_PSTATS
 
   // Now cycle the pipeline and officially begin the next frame.
   {
@@ -1458,6 +1466,42 @@ terminate_threads() {
   _threads.clear();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::pstats_count_cycler_type
+//       Access: Private, Static
+//  Description: A callback function for
+//               Pipeline::iterate_all_cycler_types() to report the
+//               cycler types to PStats.
+////////////////////////////////////////////////////////////////////
+void GraphicsEngine::
+pstats_count_cycler_type(TypeHandle type, int count, void *data) {
+  GraphicsEngine *self = (GraphicsEngine *)data;
+  CyclerTypeCounters::iterator ci = self->_all_cycler_types.find(type);
+  if (ci == self->_all_cycler_types.end()) {
+    PStatCollector collector(_cyclers_pcollector, type.get_name());
+    ci = self->_all_cycler_types.insert(CyclerTypeCounters::value_type(type, collector)).first;
+  }
+  (*ci).second.set_level(count);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsEngine::pstats_count_dirty_cycler_type
+//       Access: Private, Static
+//  Description: A callback function for
+//               Pipeline::iterate_dirty_cycler_types() to report the
+//               cycler types to PStats.
+////////////////////////////////////////////////////////////////////
+void GraphicsEngine::
+pstats_count_dirty_cycler_type(TypeHandle type, int count, void *data) {
+  GraphicsEngine *self = (GraphicsEngine *)data;
+  CyclerTypeCounters::iterator ci = self->_dirty_cycler_types.find(type);
+  if (ci == self->_dirty_cycler_types.end()) {
+    PStatCollector collector(_dirty_cyclers_pcollector, type.get_name());
+    ci = self->_dirty_cycler_types.insert(CyclerTypeCounters::value_type(type, collector)).first;
+  }
+  (*ci).second.set_level(count);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsEngine::get_invert_polygon_state
 //       Access: Protected, Static
@@ -1505,11 +1549,12 @@ get_window_renderer(const string &name, int pipeline_stage) {
 
   PT(RenderThread) thread = new RenderThread(name, this);
   thread->set_min_pipeline_stage(pipeline_stage);
-  _pipeline->set_min_stages(pipeline_stage + 1);
 
   thread->start(TP_normal, true, true);
   _threads[name] = thread;
 
+  nassertr(pipeline_stage < _pipeline->get_num_stages(), thread.p());
+
   return thread.p();
 }
 

+ 8 - 0
panda/src/display/graphicsEngine.h

@@ -171,6 +171,14 @@ private:
   void do_resort_windows();
   void terminate_threads();
 
+#ifdef DO_PSTATS
+  typedef map<TypeHandle, PStatCollector> CyclerTypeCounters;
+  CyclerTypeCounters _all_cycler_types;
+  CyclerTypeCounters _dirty_cycler_types;
+  static void pstats_count_cycler_type(TypeHandle type, int count, void *data);
+  static void pstats_count_dirty_cycler_type(TypeHandle type, int count, void *data);
+#endif  // DO_PSTATS
+
   static const RenderState *get_invert_polygon_state();
 
   // The WindowRenderer class records the stages of the pipeline that

+ 2 - 2
panda/src/pstatclient/pStatProperties.cxx

@@ -211,8 +211,8 @@ static LevelCollectorProperties level_properties[] = {
   { 1, "RenderStates:On nodes",            { 0.2, 0.8, 1.0 } },
   { 1, "RenderStates:Cached",              { 1.0, 0.0, 0.2 } },
   { 1, "RenderStates:Unused",              { 0.2, 0.2, 0.2 } },
-  { 1, "PipelineCyclers",                  { 0.5, 0.5, 1.0 },  "", 5000 },
-  { 1, "PipelineCyclers:Dirty",            { 0.2, 0.2, 0.2 } },
+  { 1, "PipelineCyclers",                  { 0.5, 0.5, 1.0 },  "", 50000 },
+  { 1, "Dirty PipelineCyclers",            { 0.2, 0.2, 0.2 },  "", 5000 },
   { 0, NULL }
 };
 

+ 1 - 12
panda/src/putil/pipeline.I

@@ -30,17 +30,6 @@ get_render_pipeline() {
   return _render_pipeline;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: Pipeline::set_min_stages
-//       Access: Public
-//  Description: Ensures that at least the indicated number of stages
-//               are in the pipeline.
-////////////////////////////////////////////////////////////////////
-INLINE void Pipeline::
-set_min_stages(int min_stages) {
-  set_num_stages(max(min_stages, get_num_stages()));
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: Pipeline::get_num_stages
 //       Access: Public
@@ -62,7 +51,7 @@ get_num_stages() const {
 INLINE int Pipeline::
 get_num_cyclers() const {
   ReMutexHolder holder(_lock);
-  return _cyclers.size();
+  return _num_cyclers;
 }
 #endif  // THREADED_PIPELINE
 

+ 110 - 50
panda/src/putil/pipeline.cxx

@@ -19,6 +19,7 @@
 #include "pipeline.h"
 #include "pipelineCyclerTrueImpl.h"
 #include "reMutexHolder.h"
+#include "configVariableInt.h"
 
 Pipeline *Pipeline::_render_pipeline = (Pipeline *)NULL;
 
@@ -28,12 +29,12 @@ Pipeline *Pipeline::_render_pipeline = (Pipeline *)NULL;
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 Pipeline::
-Pipeline(const string &name) :
-  Namable(name)
+Pipeline(const string &name, int num_stages) :
+  Namable(name),
+  _num_stages(num_stages)
 {
-  _num_stages = 1;
-
 #ifdef THREADED_PIPELINE
+  _num_cyclers = 0;
   _cycling = false;
 #endif  // THREADED_PIPELINE
 }
@@ -46,7 +47,7 @@ Pipeline(const string &name) :
 Pipeline::
 ~Pipeline() {
 #ifdef THREADED_PIPELINE
-  nassertv(_cyclers.empty());
+  nassertv(_num_cyclers == 0);
   nassertv(!_cycling);
 #endif  // THREADED_PIPELINE
 }
@@ -91,6 +92,10 @@ cycle() {
           // set for next time.
           bool inserted = next_dirty_cyclers.insert(cycler).second;
           nassertv(inserted);
+        } else {
+#ifdef DEBUG_THREADS
+          inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1);
+#endif
         }
       }
       break;
@@ -104,6 +109,10 @@ cycle() {
         if (cycler->_dirty) {
           bool inserted = next_dirty_cyclers.insert(cycler).second;
           nassertv(inserted);
+        } else {
+#ifdef DEBUG_THREADS
+          inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1);
+#endif
         }
       }
       break;
@@ -117,6 +126,10 @@ cycle() {
         if (cycler->_dirty) {
           bool inserted = next_dirty_cyclers.insert(cycler).second;
           nassertv(inserted);
+        } else {
+#ifdef DEBUG_THREADS
+          inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1);
+#endif
         }
       }
       break;
@@ -135,44 +148,6 @@ cycle() {
 #endif  // THREADED_PIPELINE
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: Pipeline::set_num_stages
-//       Access: Public
-//  Description: Specifies the number of stages required for the
-//               pipeline.
-////////////////////////////////////////////////////////////////////
-void Pipeline::
-set_num_stages(int num_stages) {
-  nassertv(num_stages >= 1);
-#ifdef THREADED_PIPELINE
-  ReMutexHolder holder(_lock);
-  if (num_stages != _num_stages) {
-    
-    // We need to lock every PipelineCycler object in the world before
-    // we can adjust the number of stages.
-    Cyclers::iterator ci;
-    for (ci = _cyclers.begin(); ci != _cyclers.end(); ++ci) {
-      (*ci)->_lock.lock();
-    }
-      
-    _num_stages = num_stages;
-      
-    for (ci = _cyclers.begin(); ci != _cyclers.end(); ++ci) {
-      (*ci)->set_num_stages(num_stages);
-    }
-    
-    // Now release them all.
-    for (ci = _cyclers.begin(); ci != _cyclers.end(); ++ci) {
-      (*ci)->_lock.release();
-    }
-  }
-
-#else  // THREADED_PIPELINE
-  _num_stages = num_stages;
-#endif  // THREADED_PIPELINE
-}
-
-
 #ifdef THREADED_PIPELINE
 ////////////////////////////////////////////////////////////////////
 //     Function: Pipeline::add_cycler
@@ -186,8 +161,11 @@ add_cycler(PipelineCyclerTrueImpl *cycler) {
   ReMutexHolder holder(_lock);
   nassertv(!cycler->_dirty);
   nassertv(!_cycling);
-  bool inserted = _cyclers.insert(cycler).second;
-  nassertv(inserted);
+  ++_num_cyclers;
+
+#ifdef DEBUG_THREADS
+  inc_cycler_type(_all_cycler_types, cycler->get_parent_type(), 1);
+#endif
 }
 #endif  // THREADED_PIPELINE
 
@@ -212,6 +190,10 @@ add_dirty_cycler(PipelineCyclerTrueImpl *cycler) {
 
   bool inserted = _dirty_cyclers.insert(cycler).second;
   nassertv(inserted);
+
+#ifdef DEBUG_THREADS
+  inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), 1);
+#endif
 }
 #endif  // THREADED_PIPELINE
 
@@ -229,20 +211,66 @@ remove_cycler(PipelineCyclerTrueImpl *cycler) {
 
   ReMutexHolder holder(_lock);
   nassertv(!_cycling);
-  
-  Cyclers::iterator ci = _cyclers.find(cycler);
-  nassertv(ci != _cyclers.end());
-  _cyclers.erase(ci);
+
+  --_num_cyclers;
+
+#ifdef DEBUG_THREADS
+  inc_cycler_type(_all_cycler_types, cycler->get_parent_type(), -1);
+#endif
 
   if (cycler->_dirty) {
     cycler->_dirty = false;
     Cyclers::iterator ci = _dirty_cyclers.find(cycler);
     nassertv(ci != _dirty_cyclers.end());
     _dirty_cyclers.erase(ci);
+#ifdef DEBUG_THREADS
+    inc_cycler_type(_dirty_cycler_types, cycler->get_parent_type(), -1);
+#endif
   }
 }
 #endif  // THREADED_PIPELINE
 
+#ifdef DEBUG_THREADS
+////////////////////////////////////////////////////////////////////
+//     Function: Pipeline::iterate_all_cycler_types
+//       Access: Public
+//  Description: Walks through the list of all the different
+//               PipelineCycler types in the universe.  For each one,
+//               calls the indicated callback function with the
+//               TypeHandle of the respective type (actually, the
+//               result of cycler::get_parent_type()) and the count of
+//               pipeline cyclers of that type.  Mainly used for
+//               PStats reporting.
+////////////////////////////////////////////////////////////////////
+void Pipeline::
+iterate_all_cycler_types(CallbackFunc *func, void *data) const {
+  ReMutexHolder holder(_lock);
+  TypeCount::const_iterator ci;
+  for (ci = _all_cycler_types.begin(); ci != _all_cycler_types.end(); ++ci) {
+    func((*ci).first, (*ci).second, data);
+  }
+}
+#endif  // DEBUG_THREADS
+
+#ifdef DEBUG_THREADS
+////////////////////////////////////////////////////////////////////
+//     Function: Pipeline::iterate_dirty_cycler_types
+//       Access: Public
+//  Description: Walks through the list of all the different
+//               PipelineCycler types, for only the dirty
+//               PipelineCyclers.  See also
+//               iterate_all_cycler_types().
+////////////////////////////////////////////////////////////////////
+void Pipeline::
+iterate_dirty_cycler_types(CallbackFunc *func, void *data) const {
+  ReMutexHolder holder(_lock);
+  TypeCount::const_iterator ci;
+  for (ci = _dirty_cycler_types.begin(); ci != _dirty_cycler_types.end(); ++ci) {
+    func((*ci).first, (*ci).second, data);
+  }
+}
+#endif  // DEBUG_THREADS
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Pipeline::make_render_pipeline
 //       Access: Private, Static
@@ -250,6 +278,38 @@ remove_cycler(PipelineCyclerTrueImpl *cycler) {
 ////////////////////////////////////////////////////////////////////
 void Pipeline::
 make_render_pipeline() {
+  ConfigVariableInt pipeline_stages
+    ("pipeline-stages", 1,
+     PRC_DESC("The number of stages in the render pipeline.  This is only "
+              "meaningful if threaded pipelining is compiled into Panda, in "
+              "which case you should set this to 1, 2, or 3, according to "
+              "your application's threading model.  You may set it larger "
+              "than your application requires, but this will incur additional "
+              "overhead."));
+
   nassertv(_render_pipeline == (Pipeline *)NULL);
-  _render_pipeline = new Pipeline("render");
+  _render_pipeline = new Pipeline("render", pipeline_stages);
+}
+
+#ifdef DEBUG_THREADS
+////////////////////////////////////////////////////////////////////
+//     Function: Pipeline::inc_cycler_type
+//       Access: Private, Static
+//  Description: Increments (or decrements, according to added) the
+//               value for TypeHandle in the indicated TypeCount map.
+//               This is used in DEBUG_THREADS mode to track the types
+//               of PipelineCyclers that are coming and going, mainly
+//               for PStats reporting.
+//
+//               It is assumed the lock is held during this call.
+////////////////////////////////////////////////////////////////////
+void Pipeline::
+inc_cycler_type(TypeCount &count, TypeHandle type, int addend) {
+  TypeCount::iterator ci = count.find(type);
+  if (ci == count.end()) {
+    ci = count.insert(TypeCount::value_type(type, 0)).first;
+  }
+  (*ci).second += addend;
+  nassertv((*ci).second >= 0);
 }
+#endif  // DEBUG_THREADS

+ 16 - 4
panda/src/putil/pipeline.h

@@ -42,15 +42,13 @@ struct PipelineCyclerTrueImpl;
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA Pipeline : public Namable {
 public:
-  Pipeline(const string &name);
+  Pipeline(const string &name, int num_stages);
   ~Pipeline();
 
   INLINE static Pipeline *get_render_pipeline();
 
   void cycle();
 
-  void set_num_stages(int num_stages);
-  INLINE void set_min_stages(int min_stages);
   INLINE int get_num_stages() const;
 
 #ifdef THREADED_PIPELINE
@@ -60,6 +58,13 @@ public:
 
   INLINE int get_num_cyclers() const;
   INLINE int get_num_dirty_cyclers() const;
+  
+#ifdef DEBUG_THREADS
+  typedef void CallbackFunc(TypeHandle type, int count, void *data);
+  void iterate_all_cycler_types(CallbackFunc *func, void *data) const;
+  void iterate_dirty_cycler_types(CallbackFunc *func, void *data) const;
+#endif  // DEBUG_THREADS
+
 #endif  // THREADED_PIPELINE
 
 private:
@@ -69,10 +74,17 @@ private:
   static Pipeline *_render_pipeline;
 
 #ifdef THREADED_PIPELINE
+  int _num_cyclers;
   typedef pset<PipelineCyclerTrueImpl *> Cyclers;
-  Cyclers _cyclers;
   Cyclers _dirty_cyclers;
 
+#ifdef DEBUG_THREADS
+  typedef pmap<TypeHandle, int> TypeCount;
+  TypeCount _all_cycler_types, _dirty_cycler_types;
+  
+  static void inc_cycler_type(TypeCount &count, TypeHandle type, int addend);
+#endif  // DEBUG_THREADS
+
   // This is true only during cycle().
   bool _cycling;
 

+ 11 - 0
panda/src/putil/pipelineCyclerDummyImpl.I

@@ -368,6 +368,17 @@ release_write_stage(int n, CycleData *pointer) {
   _write_count--;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PipelineCyclerDummyImpl::get_parent_type
+//       Access: Public
+//  Description: Returns the type of object that owns this cycler, as
+//               reported by CycleData::get_parent_type().
+////////////////////////////////////////////////////////////////////
+INLINE TypeHandle PipelineCyclerDummyImpl::
+get_parent_type() const {
+  return _data->get_parent_type();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PipelineCyclerDummyImpl::cheat
 //       Access: Public

+ 2 - 0
panda/src/putil/pipelineCyclerDummyImpl.h

@@ -73,6 +73,8 @@ public:
   INLINE CycleData *elevate_read_stage(int n, const CycleData *pointer);
   INLINE void release_write_stage(int n, CycleData *pointer);
 
+  INLINE TypeHandle get_parent_type() const;
+
   INLINE CycleData *cheat() const;
   INLINE int get_read_count() const;
   INLINE int get_write_count() const;

+ 11 - 0
panda/src/putil/pipelineCyclerTrivialImpl.I

@@ -339,6 +339,17 @@ INLINE void PipelineCyclerTrivialImpl::
 release_write_stage(int, CycleData *) {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PipelineCyclerTrivialImpl::get_parent_type
+//       Access: Public
+//  Description: Returns the type of object that owns this cycler, as
+//               reported by CycleData::get_parent_type().
+////////////////////////////////////////////////////////////////////
+INLINE TypeHandle PipelineCyclerTrivialImpl::
+get_parent_type() const {
+  return cheat()->get_parent_type();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PipelineCyclerTrivialImpl::cheat
 //       Access: Public

+ 2 - 0
panda/src/putil/pipelineCyclerTrivialImpl.h

@@ -76,6 +76,8 @@ public:
   INLINE CycleData *elevate_read_stage(int n, const CycleData *pointer);
   INLINE void release_write_stage(int n, CycleData *pointer);
 
+  INLINE TypeHandle get_parent_type() const;
+
   INLINE CycleData *cheat() const;
   INLINE int get_read_count() const;
   INLINE int get_write_count() const;

+ 11 - 0
panda/src/putil/pipelineCyclerTrueImpl.I

@@ -266,6 +266,17 @@ release_write_stage(int n, CycleData *pointer) {
   _lock.release();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PipelineCyclerTrueImpl::get_parent_type
+//       Access: Public
+//  Description: Returns the type of object that owns this cycler, as
+//               reported by CycleData::get_parent_type().
+////////////////////////////////////////////////////////////////////
+INLINE TypeHandle PipelineCyclerTrueImpl::
+get_parent_type() const {
+  return _data[0]->get_parent_type();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PipelineCyclerTrueImpl::cheat
 //       Access: Public

+ 14 - 12
panda/src/putil/pipelineCyclerTrueImpl.cxx

@@ -37,13 +37,14 @@ PipelineCyclerTrueImpl(CycleData *initial_data, Pipeline *pipeline) :
   if (_pipeline == (Pipeline *)NULL) {
     _pipeline = Pipeline::get_render_pipeline();
   }
-  _pipeline->add_cycler(this);
 
   _num_stages = _pipeline->get_num_stages();
   _data = new PT(CycleData)[_num_stages];
   for (int i = 0; i < _num_stages; ++i) {
     _data[i] = initial_data;
   }
+
+  _pipeline->add_cycler(this);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -58,23 +59,19 @@ PipelineCyclerTrueImpl(const PipelineCyclerTrueImpl &copy) :
   _lock(this)
 {
   ReMutexHolder holder(_lock);
-  _pipeline->add_cycler(this);
-  if (copy._dirty) {
-    _pipeline->add_dirty_cycler(this);
-  }
-
   ReMutexHolder holder2(copy._lock);
+  
   _num_stages = _pipeline->get_num_stages();
   nassertv(_num_stages == copy._num_stages);
   _data = new PT(CycleData)[_num_stages];
-
+  
   // It's no longer critically important that we preserve pointerwise
   // equivalence between different stages in the copy, but it doesn't
   // cost much and might be a little more efficient, so we do it
   // anyway.
   typedef pmap<CycleData *, PT(CycleData) > Pointers;
   Pointers pointers;
-
+  
   for (int i = 0; i < _num_stages; ++i) {
     PT(CycleData) &new_pt = pointers[copy._data[i]];
     if (new_pt == NULL) {
@@ -82,6 +79,11 @@ PipelineCyclerTrueImpl(const PipelineCyclerTrueImpl &copy) :
     }
     _data[i] = new_pt;
   }
+
+  _pipeline->add_cycler(this);
+  if (copy._dirty) {
+    _pipeline->add_dirty_cycler(this);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -93,8 +95,7 @@ void PipelineCyclerTrueImpl::
 operator = (const PipelineCyclerTrueImpl &copy) {
   ReMutexHolder holder1(_lock);
   ReMutexHolder holder2(copy._lock);
-
-  nassertv(_num_stages == copy._num_stages);
+  nassertv(get_parent_type() == copy.get_parent_type());
 
   typedef pmap<CycleData *, PT(CycleData) > Pointers;
   Pointers pointers;
@@ -120,11 +121,12 @@ operator = (const PipelineCyclerTrueImpl &copy) {
 PipelineCyclerTrueImpl::
 ~PipelineCyclerTrueImpl() {
   ReMutexHolder holder(_lock);
+
+  _pipeline->remove_cycler(this);
+
   delete[] _data;
   _data = NULL;
   _num_stages = 0;
-
-  _pipeline->remove_cycler(this);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 0
panda/src/putil/pipelineCyclerTrueImpl.h

@@ -74,6 +74,8 @@ public:
   INLINE CycleData *elevate_read_stage(int n, const CycleData *pointer);
   INLINE void release_write_stage(int n, CycleData *pointer);
 
+  INLINE TypeHandle get_parent_type() const;
+
   INLINE CycleData *cheat() const;
   INLINE int get_read_count() const;
   INLINE int get_write_count() const;