mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
task output
This commit is contained in:
parent
a09a538878
commit
306873b3ac
@ -235,3 +235,6 @@ class TaskManager:
|
||||
def stop(self):
|
||||
# Set a flag so we will stop before beginning next frame
|
||||
self.running = False
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.mgr)
|
||||
|
@ -13,29 +13,6 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTask::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE AsyncTask::
|
||||
AsyncTask(const string &name) :
|
||||
Namable(name),
|
||||
_delay(0.0),
|
||||
_has_delay(false),
|
||||
_wake_time(0.0),
|
||||
_sort(0),
|
||||
_priority(0),
|
||||
_state(S_inactive),
|
||||
_servicing_thread(NULL),
|
||||
_manager(NULL),
|
||||
_chain(NULL)
|
||||
{
|
||||
#ifdef HAVE_PYTHON
|
||||
_python_object = NULL;
|
||||
#endif // HAVE_PYTHON
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTask::get_state
|
||||
// Access: Published
|
||||
@ -256,3 +233,39 @@ get_python_object() const {
|
||||
}
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTask::get_dt
|
||||
// Access: Published
|
||||
// Description: Returns the amount of time elapsed during the task's
|
||||
// previous run cycle, in seconds.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE double AsyncTask::
|
||||
get_dt() const {
|
||||
return _dt;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTask::get_max_dt
|
||||
// Access: Published
|
||||
// Description: Returns the maximum amount of time elapsed during any
|
||||
// one of the task's previous run cycles, in seconds.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE double AsyncTask::
|
||||
get_max_dt() const {
|
||||
return _max_dt;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTask::get_average_dt
|
||||
// Access: Published
|
||||
// Description: Returns the average amount of time elapsed during
|
||||
// each of the task's previous run cycles, in seconds.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE double AsyncTask::
|
||||
get_average_dt() const {
|
||||
if (_num_frames == 0) {
|
||||
return 0.0;
|
||||
} else {
|
||||
return _total_dt / _num_frames;
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,33 @@
|
||||
|
||||
TypeHandle AsyncTask::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTask::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
AsyncTask::
|
||||
AsyncTask(const string &name) :
|
||||
Namable(name),
|
||||
_delay(0.0),
|
||||
_has_delay(false),
|
||||
_wake_time(0.0),
|
||||
_sort(0),
|
||||
_priority(0),
|
||||
_state(S_inactive),
|
||||
_servicing_thread(NULL),
|
||||
_manager(NULL),
|
||||
_chain(NULL),
|
||||
_dt(0.0),
|
||||
_max_dt(0.0),
|
||||
_total_dt(0.0),
|
||||
_num_frames(0)
|
||||
{
|
||||
#ifdef HAVE_PYTHON
|
||||
_python_object = NULL;
|
||||
#endif // HAVE_PYTHON
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTask::Destructor
|
||||
// Access: Public, Virtual
|
||||
@ -47,7 +74,7 @@ remove() {
|
||||
// Function: AsyncTask::get_elapsed_time
|
||||
// Access: Published
|
||||
// Description: Returns the amount of time that has elapsed since
|
||||
// task was started, according to the task manager's
|
||||
// the task was started, according to the task manager's
|
||||
// clock.
|
||||
//
|
||||
// It is only valid to call this if the task's status is
|
||||
@ -224,6 +251,36 @@ output(ostream &out) const {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTask::unlock_and_do_task
|
||||
// Access: Protected
|
||||
// Description: Called by the AsyncTaskManager to actually run the
|
||||
// task. Assumes the lock is held. See do_task().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
AsyncTask::DoneStatus AsyncTask::
|
||||
unlock_and_do_task() {
|
||||
nassertr(_manager != (AsyncTaskManager *)NULL, DS_done);
|
||||
PT(ClockObject) clock = _manager->get_clock();
|
||||
|
||||
// It's important to release the lock while the task is being
|
||||
// serviced.
|
||||
_manager->_lock.release();
|
||||
|
||||
double start = clock->get_real_time();
|
||||
DoneStatus status = do_task();
|
||||
double end = clock->get_real_time();
|
||||
|
||||
// Now reacquire the lock (so we can return with the lock held).
|
||||
_manager->_lock.lock();
|
||||
|
||||
_dt = end - start;
|
||||
_max_dt = max(_dt, _max_dt);
|
||||
_total_dt += _dt;
|
||||
++_num_frames;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTask::do_task
|
||||
// Access: Protected, Virtual
|
||||
@ -241,6 +298,8 @@ output(ostream &out) const {
|
||||
//
|
||||
// DS_abort: abort the task, and interrupt the whole
|
||||
// AsyncTaskManager.
|
||||
//
|
||||
// This function is called with the lock *not* held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
AsyncTask::DoneStatus AsyncTask::
|
||||
do_task() {
|
||||
|
@ -42,7 +42,7 @@ class AsyncTaskChain;
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA_EVENT AsyncTask : public TypedReferenceCount, public Namable {
|
||||
public:
|
||||
INLINE AsyncTask(const string &name = string());
|
||||
AsyncTask(const string &name = string());
|
||||
virtual ~AsyncTask();
|
||||
ALLOC_DELETED_CHAIN(AsyncTask);
|
||||
|
||||
@ -96,9 +96,14 @@ PUBLISHED:
|
||||
INLINE PyObject *get_python_object() const;
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
INLINE double get_dt() const;
|
||||
INLINE double get_max_dt() const;
|
||||
INLINE double get_average_dt() const;
|
||||
|
||||
virtual void output(ostream &out) const;
|
||||
|
||||
protected:
|
||||
DoneStatus unlock_and_do_task();
|
||||
virtual DoneStatus do_task();
|
||||
|
||||
protected:
|
||||
@ -115,6 +120,11 @@ protected:
|
||||
AsyncTaskManager *_manager;
|
||||
AsyncTaskChain *_chain;
|
||||
|
||||
double _dt;
|
||||
double _max_dt;
|
||||
double _total_dt;
|
||||
int _num_frames;
|
||||
|
||||
private:
|
||||
#ifdef HAVE_PYTHON
|
||||
PyObject *_python_object;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "pStatTimer.h"
|
||||
#include "clockObject.h"
|
||||
#include <algorithm>
|
||||
#include <stdio.h> // For sprintf/snprintf
|
||||
|
||||
TypeHandle AsyncTaskChain::_type_handle;
|
||||
|
||||
@ -507,15 +508,7 @@ service_one_task(AsyncTaskChain::AsyncTaskChainThread *thread) {
|
||||
task->_state = AsyncTask::S_servicing;
|
||||
task->_servicing_thread = thread;
|
||||
|
||||
// Now release the chain lock while we actually service the
|
||||
// task.
|
||||
_manager->_lock.release();
|
||||
AsyncTask::DoneStatus ds = task->do_task();
|
||||
|
||||
// Now we have to re-acquire the chain lock, so we can put the
|
||||
// task back on the queue (and so we can return with the lock
|
||||
// still held).
|
||||
_manager->_lock.lock();
|
||||
AsyncTask::DoneStatus ds = task->unlock_and_do_task();
|
||||
|
||||
if (thread != (AsyncTaskChain::AsyncTaskChainThread *)NULL) {
|
||||
thread->_servicing = NULL;
|
||||
@ -801,8 +794,28 @@ do_poll() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void AsyncTaskChain::
|
||||
do_write(ostream &out, int indent_level) const {
|
||||
indent(out, indent_level)
|
||||
<< get_type() << " " << get_name() << "\n";
|
||||
if (has_name()) {
|
||||
indent(out, indent_level)
|
||||
<< get_name() << "\n";
|
||||
}
|
||||
|
||||
static const size_t buffer_size = 1024;
|
||||
char buffer[buffer_size];
|
||||
sprintf(buffer, " %-32s %8s %8s %8s %8s %6s",
|
||||
"Task",
|
||||
"sleep(s)",
|
||||
"dt(ms)", "avg", "max",
|
||||
"sort");
|
||||
nassertv(strlen(buffer) < buffer_size);
|
||||
|
||||
indent(out, indent_level)
|
||||
<< buffer << "\n";
|
||||
|
||||
indent(out, indent_level);
|
||||
for (int i = 0; i < 32+8+8+8+8+6+7; ++i) {
|
||||
out << '-';
|
||||
}
|
||||
out << "\n";
|
||||
|
||||
// Collect a list of all active tasks, then sort them into order for
|
||||
// output.
|
||||
@ -818,55 +831,78 @@ do_write(ostream &out, int indent_level) const {
|
||||
}
|
||||
}
|
||||
|
||||
if (!tasks.empty()) {
|
||||
indent(out, indent_level + 2)
|
||||
<< "Active tasks:\n";
|
||||
sort(tasks.begin(), tasks.end(), AsyncTaskSortPriority());
|
||||
|
||||
sort(tasks.begin(), tasks.end(), AsyncTaskSortPriority());
|
||||
double now = _manager->_clock->get_frame_time();
|
||||
|
||||
// Since AsyncTaskSortPriority() sorts backwards (because of STL's
|
||||
// push_heap semantics), we go through the task list in reverse
|
||||
// order to print them forwards.
|
||||
TaskHeap::reverse_iterator ti;
|
||||
int current_sort = tasks.back()->get_sort() - 1;
|
||||
for (ti = tasks.rbegin(); ti != tasks.rend(); ++ti) {
|
||||
AsyncTask *task = (*ti);
|
||||
if (task->get_sort() != current_sort) {
|
||||
current_sort = task->get_sort();
|
||||
indent(out, indent_level + 2)
|
||||
<< "sort = " << current_sort << "\n";
|
||||
}
|
||||
if (task->_state == AsyncTask::S_servicing) {
|
||||
indent(out, indent_level + 3)
|
||||
<< "*" << *task << "\n";
|
||||
} else {
|
||||
indent(out, indent_level + 4)
|
||||
<< *task << "\n";
|
||||
}
|
||||
}
|
||||
// Since AsyncTaskSortPriority() sorts backwards (because of STL's
|
||||
// push_heap semantics), we go through the task list in reverse
|
||||
// order to print them forwards.
|
||||
TaskHeap::reverse_iterator ti;
|
||||
int current_sort = tasks.back()->get_sort() - 1;
|
||||
for (ti = tasks.rbegin(); ti != tasks.rend(); ++ti) {
|
||||
AsyncTask *task = (*ti);
|
||||
write_task_line(out, indent_level, task, now);
|
||||
}
|
||||
|
||||
if (!_sleeping.empty()) {
|
||||
indent(out, indent_level + 2)
|
||||
<< "Sleeping tasks:\n";
|
||||
double now = _manager->_clock->get_frame_time();
|
||||
|
||||
// Instead of iterating through the _sleeping list in heap order,
|
||||
// copy it and then use repeated pops to get it out in sorted
|
||||
// order, for the user's satisfaction.
|
||||
TaskHeap sleeping = _sleeping;
|
||||
while (!sleeping.empty()) {
|
||||
PT(AsyncTask) task = sleeping.front();
|
||||
pop_heap(sleeping.begin(), sleeping.end(), AsyncTaskSortWakeTime());
|
||||
sleeping.pop_back();
|
||||
|
||||
indent(out, indent_level + 4)
|
||||
<< task->get_wake_time() - now << "s: "
|
||||
<< *task << "\n";
|
||||
}
|
||||
// Instead of iterating through the _sleeping list in heap order,
|
||||
// copy it and then use repeated pops to get it out in sorted
|
||||
// order, for the user's satisfaction.
|
||||
TaskHeap sleeping = _sleeping;
|
||||
while (!sleeping.empty()) {
|
||||
PT(AsyncTask) task = sleeping.front();
|
||||
pop_heap(sleeping.begin(), sleeping.end(), AsyncTaskSortWakeTime());
|
||||
sleeping.pop_back();
|
||||
|
||||
write_task_line(out, indent_level, task, now);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTaskChain::write_task_line
|
||||
// Access: Protected
|
||||
// Description: Writes a single line for a task in the report
|
||||
// generated by do_write(). Assumes the lock is already
|
||||
// held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void AsyncTaskChain::
|
||||
write_task_line(ostream &out, int indent_level, AsyncTask *task, double now) const {
|
||||
char servicing_flag = ' ';
|
||||
if (task->_state == AsyncTask::S_servicing) {
|
||||
servicing_flag = '*';
|
||||
} else if (task->_state == AsyncTask::S_servicing_removed) {
|
||||
servicing_flag = '-';
|
||||
}
|
||||
|
||||
static const size_t buffer_size = 1024;
|
||||
char buffer[buffer_size];
|
||||
|
||||
if (task->_state == AsyncTask::S_sleeping) {
|
||||
// For sleeping tasks, include the wake time, as an elapsed time
|
||||
// in seconds.
|
||||
string name = task->get_name().substr(0, 32);
|
||||
sprintf(buffer, "%c%-32s %8.1f %8.1f %8.1f %8.1f %6d",
|
||||
servicing_flag, name.c_str(),
|
||||
task->_wake_time - now,
|
||||
task->_dt * 1000.0, task->get_average_dt() * 1000.0,
|
||||
task->_max_dt * 1000.0,
|
||||
task->_sort);
|
||||
} else {
|
||||
// For active tasks, don't include a wake time. This means we
|
||||
// have more space for the name.
|
||||
string name = task->get_name().substr(0, 41);
|
||||
sprintf(buffer, "%c%-41s %8.1f %8.1f %8.1f %6d",
|
||||
servicing_flag, name.c_str(),
|
||||
task->_dt * 1000.0, task->get_average_dt() * 1000.0,
|
||||
task->_max_dt * 1000.0,
|
||||
task->_sort);
|
||||
}
|
||||
nassertv(strlen(buffer) < buffer_size);
|
||||
|
||||
indent(out, indent_level)
|
||||
<< buffer << "\n";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AsyncTaskChain::AsyncTaskChainThread::Constructor
|
||||
// Access: Public
|
||||
|
@ -108,6 +108,8 @@ protected:
|
||||
void do_poll();
|
||||
void do_write(ostream &out, int indent_level) const;
|
||||
|
||||
void write_task_line(ostream &out, int indent_level, AsyncTask *task, double now) const;
|
||||
|
||||
protected:
|
||||
class AsyncTaskChainThread : public Thread {
|
||||
public:
|
||||
|
@ -37,6 +37,8 @@ AsyncTaskManager(const string &name) :
|
||||
Namable(name),
|
||||
_clock(ClockObject::get_global_clock())
|
||||
{
|
||||
// Make a default task chain.
|
||||
do_make_task_chain("");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
Loading…
x
Reference in New Issue
Block a user