report different types of cyclers in pstats

This commit is contained in:
David Rose 2006-02-15 21:44:52 +00:00
parent 11337e4c20
commit 7b1b8bb4af
13 changed files with 239 additions and 84 deletions

View File

@ -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();
}

View File

@ -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

View File

@ -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 }
};

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);
}
////////////////////////////////////////////////////////////////////

View File

@ -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;