Add some stats

master
Marc Gilleron 2020-08-26 21:17:57 +01:00
parent d8a8936f34
commit bcfc8ce04e
5 changed files with 61 additions and 4 deletions

View File

@ -33,6 +33,11 @@ void register_voxel_types() {
VoxelGraphNodeDB::create_singleton();
VoxelServer::create_singleton();
Engine::get_singleton()->add_singleton(Engine::Singleton("VoxelServer", VoxelServer::get_singleton()));
// TODO Can I prevent users from instancing it? is "register_virtual_class" correct for a class that's not abstract?
ClassDB::register_class<VoxelServer>();
// Storage
ClassDB::register_class<VoxelBuffer>();
ClassDB::register_class<VoxelMap>();
@ -98,11 +103,12 @@ void unregister_voxel_types() {
.format(varray(used_blocks)));
}
VoxelMemoryPool::destroy_singleton();
// TODO No remove?
#ifdef TOOLS_ENABLED
VoxelDebug::free_debug_box_mesh();
// TODO No remove?
// TODO Seriously, no remove?
//EditorPlugins::remove_by_type<VoxelGraphEditorPlugin>();
#endif
}

View File

@ -385,6 +385,36 @@ void VoxelServer::get_min_max_block_padding(
}
}
static unsigned int debug_get_active_thread_count(const VoxelThreadPool &pool) {
unsigned int active_count = 0;
for (unsigned int i = 0; i < pool.get_thread_count(); ++i) {
VoxelThreadPool::State s = pool.get_thread_debug_state(i);
if (s == VoxelThreadPool::STATE_RUNNING) {
++active_count;
}
}
return active_count;
}
static Dictionary debug_get_pool_stats(const VoxelThreadPool &pool) {
Dictionary d;
d["tasks"] = pool.get_debug_remaining_tasks();
d["active_threads"] = debug_get_active_thread_count(pool);
d["thread_count"] = pool.get_thread_count();
return d;
}
Dictionary VoxelServer::_b_get_stats() {
Dictionary d;
d["streaming"] = debug_get_pool_stats(_streaming_thread_pool);
d["meshing"] = debug_get_pool_stats(_meshing_thread_pool);
return d;
}
void VoxelServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_stats"), &VoxelServer::_b_get_stats);
}
//----------------------------------------------------------------------------------------------------------------------
void VoxelServer::BlockDataRequest::run(VoxelTaskContext ctx) {

View File

@ -11,7 +11,8 @@
// Access point for asynchronous voxel processing APIs.
// Functions must be used from the main thread.
class VoxelServer {
class VoxelServer : public Object {
GDCLASS(VoxelServer, Object)
public:
struct BlockMeshOutput {
enum Type {
@ -74,6 +75,10 @@ public:
void process();
private:
Dictionary _b_get_stats();
static void _bind_methods();
// Since we are going to send data to tasks running in multiple threads, a few strategies are in place:
//
// - Copy the data for each thread. This is suitable for simple information that doesn't change after scheduling.

View File

@ -72,6 +72,7 @@ void VoxelThreadPool::enqueue(IVoxelTask *task) {
TaskItem t;
t.task = task;
_tasks.push_back(t);
++_debug_received_tasks;
}
// TODO Do I need to post a certain amount of times?
_tasks_semaphore->post();
@ -84,6 +85,7 @@ void VoxelThreadPool::enqueue(ArraySlice<IVoxelTask *> tasks) {
TaskItem t;
t.task = tasks[i];
_tasks.push_back(t);
++_debug_received_tasks;
}
}
// TODO Do I need to post a certain amount of times?
@ -148,6 +150,7 @@ void VoxelThreadPool::thread_func(ThreadData &data) {
MutexLock lock(_completed_tasks_mutex);
for (size_t i = 0; i < cancelled_tasks.size(); ++i) {
_completed_tasks.push_back(cancelled_tasks[i]);
++_debug_completed_tasks;
}
cancelled_tasks.clear();
}
@ -155,7 +158,7 @@ void VoxelThreadPool::thread_func(ThreadData &data) {
//print_line(String("Processing {0} tasks").format(varray(tasks.size())));
if (tasks.empty()) {
data.debug_state = STATE_WAITNG;
data.debug_state = STATE_WAITING;
// Wait for more tasks
data.waiting = true;
@ -178,6 +181,7 @@ void VoxelThreadPool::thread_func(ThreadData &data) {
for (size_t i = 0; i < tasks.size(); ++i) {
TaskItem &item = tasks[i];
_completed_tasks.push_back(item.task);
++_debug_completed_tasks;
}
}
@ -235,6 +239,14 @@ void VoxelThreadPool::wait_for_all_tasks() {
}
}
// Debug information can be wrong, on some rare occasions.
// The variables should be safely updated, but computing or reading from them is not thread safe.
// Thought it wasnt worth locking for debugging.
VoxelThreadPool::State VoxelThreadPool::get_thread_debug_state(uint32_t i) const {
return _threads[i].debug_state;
}
unsigned int VoxelThreadPool::get_debug_remaining_tasks() const {
return _debug_received_tasks - _debug_completed_tasks;
}

View File

@ -36,7 +36,7 @@ public:
enum State {
STATE_RUNNING = 0,
STATE_PICKING,
STATE_WAITNG,
STATE_WAITING,
STATE_STOPPED
};
@ -75,6 +75,7 @@ public:
void wait_for_all_tasks();
State get_thread_debug_state(uint32_t i) const;
unsigned int get_debug_remaining_tasks() const;
private:
struct TaskItem {
@ -110,6 +111,9 @@ private:
uint32_t _batch_count = 1;
uint32_t _priority_update_period = 32;
unsigned int _debug_received_tasks = 0;
unsigned int _debug_completed_tasks = 0;
};
#endif // VOXEL_THREAD_TASK_MANAGER_H