First version of Profiler

It is now possible to profile GDScript as well as some parts of Godot
internals.
This commit is contained in:
Juan Linietsky 2016-05-21 21:18:16 -03:00
parent c195c0df6b
commit a75f896338
35 changed files with 2245 additions and 180 deletions

View file

@ -41,6 +41,8 @@
#include "globals.h"
#include "editor_node.h"
#include "main/performance.h"
#include "editor_profiler.h"
#include "editor_settings.h"
class ScriptEditorDebuggerVariables : public Object {
@ -208,7 +210,13 @@ void ScriptEditorDebugger::_parse_message(const String& p_msg,const Array& p_dat
docontinue->set_disabled(false);
emit_signal("breaked",true,can_continue);
OS::get_singleton()->move_window_to_foreground();
tabs->set_current_tab(0);
if (!profiler->is_seeking())
tabs->set_current_tab(0);
profiler->set_enabled(false);
EditorNode::get_singleton()->get_pause_button()->set_pressed(true);
EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
@ -225,6 +233,11 @@ void ScriptEditorDebugger::_parse_message(const String& p_msg,const Array& p_dat
docontinue->set_disabled(true);
emit_signal("breaked",false,false);
//tabs->set_current_tab(0);
profiler->set_enabled(true);
profiler->disable_seeking();
EditorNode::get_singleton()->get_pause_button()->set_pressed(false);
} else if (p_msg=="message:click_ctrl") {
@ -441,6 +454,137 @@ void ScriptEditorDebugger::_parse_message(const String& p_msg,const Array& p_dat
packet_peer_stream->put_var(oe.warning);
packet_peer_stream->put_var(oe.callstack);
*/
} else if (p_msg=="profile_sig") {
//cache a signature
print_line("SIG: "+String(Variant(p_data)));
profiler_signature[p_data[1]]=p_data[0];
} else if (p_msg=="profile_frame" || p_msg=="profile_total") {
EditorProfiler::Metric metric;
metric.valid=true;
metric.frame_number=p_data[0];
metric.frame_time=p_data[1];
metric.idle_time=p_data[2];
metric.fixed_time=p_data[3];
metric.fixed_frame_time=p_data[4];
int frame_data_amount = p_data[6];
int frame_function_amount = p_data[7];
if (frame_data_amount) {
EditorProfiler::Metric::Category frame_time;
frame_time.signature="category_frame_time";
frame_time.name="Frame Time";
frame_time.total_time=metric.frame_time;
EditorProfiler::Metric::Category::Item item;
item.calls=1;
item.line=0;
item.name="Fixed Time";
item.total=metric.fixed_time;
item.self=item.total;
item.signature="fixed_time";
frame_time.items.push_back(item);
item.name="Idle Time";
item.total=metric.idle_time;
item.self=item.total;
item.signature="idle_time";
frame_time.items.push_back(item);
item.name="Fixed Frame Time";
item.total=metric.fixed_frame_time;
item.self=item.total;
item.signature="fixed_frame_time";
frame_time.items.push_back(item);
metric.categories.push_back(frame_time);
}
int idx=8;
for(int i=0;i<frame_data_amount;i++) {
EditorProfiler::Metric::Category c;
String name=p_data[idx++];
Array values=p_data[idx++];
c.name=name.capitalize();
c.items.resize(values.size()/2);
c.total_time=0;
c.signature="categ::"+name;
for(int i=0;i<values.size();i+=2) {
EditorProfiler::Metric::Category::Item item;
item.name=values[i];
item.calls=1;
item.self=values[i+1];
item.total=item.self;
item.signature="categ::"+name+"::"+item.name;
item.name=item.name.capitalize();
c.total_time+=item.total;
c.items[i/2]=item;
}
metric.categories.push_back(c);
}
EditorProfiler::Metric::Category funcs;
funcs.total_time=p_data[5]; //script time
funcs.items.resize(frame_function_amount);
funcs.name="Script Functions";
funcs.signature="script_functions";
for(int i=0;i<frame_function_amount;i++) {
int signature = p_data[idx++];
int calls = p_data[idx++];
float total = p_data[idx++];
float self = p_data[idx++];
EditorProfiler::Metric::Category::Item item;
if (profiler_signature.has(signature)) {
item.signature=profiler_signature[signature];
String name = profiler_signature[signature];
Vector<String> strings = name.split("::");
if (strings.size()==3) {
item.name=strings[2];
item.script=strings[0];
item.line=strings[1].to_int();
}
} else {
item.name="SigErr "+itos(signature);
}
item.calls=calls;
item.self=self;
item.total=total;
funcs.items[i]=item;
}
metric.categories.push_back(funcs);
if (p_msg=="profile_frame")
profiler->add_frame_metric(metric,false);
else
profiler->add_frame_metric(metric,true);
} else if (p_msg=="kill_me") {
editor->call_deferred("stop_child_process");
@ -586,15 +730,25 @@ void ScriptEditorDebugger::_notification(int p_what) {
reason->set_text(TTR("Child Process Connected"));
reason->set_tooltip(TTR("Child Process Connected"));
profiler->clear();
scene_tree->clear();
le_set->set_disabled(true);
le_clear->set_disabled(false);
error_list->clear();
error_stack->clear();
error_count=0;
profiler_signature.clear();
//live_edit_root->set_text("/root");
EditorNode::get_singleton()->get_pause_button()->set_pressed(false);
EditorNode::get_singleton()->get_pause_button()->set_disabled(false);
update_live_edit_root();
if (profiler->is_profiling()) {
_profiler_activate(true);
}
} else {
@ -656,6 +810,7 @@ void ScriptEditorDebugger::_notification(int p_what) {
}
message_type=cmd;
//print_line("GOT: "+message_type);
ret = ppeer->get_var(cmd);
if (ret!=OK) {
@ -744,8 +899,14 @@ void ScriptEditorDebugger::stop(){
node_path_cache.clear();
res_path_cache.clear();
profiler_signature.clear();
le_clear->set_disabled(false);
le_set->set_disabled(true);
profiler->set_enabled(true);
EditorNode::get_singleton()->get_pause_button()->set_pressed(false);
EditorNode::get_singleton()->get_pause_button()->set_disabled(true);
if (hide_on_stop) {
@ -756,6 +917,44 @@ void ScriptEditorDebugger::stop(){
}
void ScriptEditorDebugger::_profiler_activate(bool p_enable) {
if (!connection.is_valid())
return;
if (p_enable) {
profiler_signature.clear();
Array msg;
msg.push_back("start_profiling");
int max_funcs = EditorSettings::get_singleton()->get("debugger/profiler_frame_max_functions");
max_funcs = CLAMP(max_funcs,16,512);
msg.push_back(max_funcs);
ppeer->put_var(msg);
print_line("BEGIN PROFILING!");
} else {
Array msg;
msg.push_back("stop_profiling");
ppeer->put_var(msg);
print_line("END PROFILING!");
}
}
void ScriptEditorDebugger::_profiler_seeked() {
if (!connection.is_valid() || !connection->is_connected())
return;
if (breaked)
return;
debug_break();;
}
void ScriptEditorDebugger::_stack_dump_frame_selected() {
@ -1172,6 +1371,21 @@ void ScriptEditorDebugger::set_hide_on_stop(bool p_hide) {
hide_on_stop=p_hide;
}
void ScriptEditorDebugger::_paused() {
ERR_FAIL_COND(connection.is_null());
ERR_FAIL_COND(!connection->is_connected());
if (!breaked && EditorNode::get_singleton()->get_pause_button()->is_pressed()) {
debug_break();
}
if (breaked && !EditorNode::get_singleton()->get_pause_button()->is_pressed()) {
debug_continue();
}
}
void ScriptEditorDebugger::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_stack_dump_frame_selected"),&ScriptEditorDebugger::_stack_dump_frame_selected);
@ -1189,6 +1403,11 @@ void ScriptEditorDebugger::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_error_selected"),&ScriptEditorDebugger::_error_selected);
ObjectTypeDB::bind_method(_MD("_error_stack_selected"),&ScriptEditorDebugger::_error_stack_selected);
ObjectTypeDB::bind_method(_MD("_profiler_activate"),&ScriptEditorDebugger::_profiler_activate);
ObjectTypeDB::bind_method(_MD("_profiler_seeked"),&ScriptEditorDebugger::_profiler_seeked);
ObjectTypeDB::bind_method(_MD("_paused"),&ScriptEditorDebugger::_paused);
ObjectTypeDB::bind_method(_MD("live_debug_create_node"),&ScriptEditorDebugger::live_debug_create_node);
ObjectTypeDB::bind_method(_MD("live_debug_instance_node"),&ScriptEditorDebugger::live_debug_instance_node);
@ -1320,6 +1539,12 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor){
error_split->set_name(TTR("Errors"));
tabs->add_child(error_split);
profiler = memnew( EditorProfiler );
profiler->set_name("Profiler");
tabs->add_child(profiler);
profiler->connect("enable_profiling",this,"_profiler_activate");
profiler->connect("break_request",this,"_profiler_seeked");
HSplitContainer *hsp = memnew( HSplitContainer );
@ -1334,7 +1559,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor){
perf_draw = memnew( Control );
perf_draw->connect("draw",this,"_performance_draw");
hsp->add_child(perf_draw);
hsp->set_name("Performance");
hsp->set_name("Metrics");
hsp->set_split_offset(300);
tabs->add_child(hsp);
perf_max.resize(Performance::MONITOR_MAX);
@ -1468,6 +1693,8 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor){
hide_on_stop=true;
last_error_count=0;
EditorNode::get_singleton()->get_pause_button()->connect("pressed",this,"_paused");
}