diff options
Diffstat (limited to 'core/script_debugger_remote.cpp')
-rw-r--r-- | core/script_debugger_remote.cpp | 313 |
1 files changed, 312 insertions, 1 deletions
diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index b56ff4c0e1..99d1e22c07 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -125,6 +125,10 @@ static ObjectID safe_get_instance_id(const Variant& p_v) { void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) { + //this function is called when there is a debugger break (bug on script) + //or when execution is paused from editor + + if (!tcp_client->is_connected()) { ERR_EXPLAIN("Script Debugger failed to connect, but being used anyway."); ERR_FAIL(); @@ -135,6 +139,8 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) { packet_peer_stream->put_var(p_can_continue); packet_peer_stream->put_var(p_script->debug_get_error()); + skip_profile_frame=true; // to avoid super long frame time for the frame + Input::MouseMode mouse_mode=Input::get_singleton()->get_mouse_mode(); if (mouse_mode!=Input::MOUSE_MODE_VISIBLE) Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); @@ -277,6 +283,16 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) { } else if (command=="request_video_mem") { _send_video_memory(); + } else if (command=="inspect_object") { + + ObjectID id = cmd[1]; + _send_object_id(id); + } else if (command=="set_object_property") { + + _set_object_property(cmd[1],cmd[2],cmd[3]); + + } else if (command=="reload_scripts") { + reload_all_scripts=true; } else if (command=="breakpoint") { bool set = cmd[3]; @@ -372,7 +388,7 @@ void ScriptDebuggerRemote::line_poll() { //the purpose of this is just processing events every now and then when the script might get too busy //otherwise bugs like infinite loops cant be catched - if (poll_every%512==0) + if (poll_every%2048==0) _poll_events(); poll_every++; @@ -533,8 +549,94 @@ bool ScriptDebuggerRemote::_parse_live_edit(const Array& cmd) { return true; } + +void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) { + + Object* obj = ObjectDB::get_instance(p_id); + if (!obj) + return; + + List<PropertyInfo> pinfo; + obj->get_property_list(&pinfo,true); + + int props_to_send=0; + for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + + if (E->get().usage&(PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_CATEGORY)) { + props_to_send++; + } + } + + packet_peer_stream->put_var("message:inspect_object"); + packet_peer_stream->put_var(props_to_send*5+4); + packet_peer_stream->put_var(p_id); + packet_peer_stream->put_var(obj->get_type()); + if (obj->is_type("Resource") || obj->is_type("Node")) + packet_peer_stream->put_var(obj->call("get_path")); + else + packet_peer_stream->put_var(""); + + packet_peer_stream->put_var(props_to_send); + + for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) { + + if (E->get().usage&(PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_CATEGORY)) { + + if (E->get().usage&PROPERTY_USAGE_CATEGORY) { + packet_peer_stream->put_var("*"+E->get().name); + } else { + packet_peer_stream->put_var(E->get().name); + } + + Variant var = obj->get(E->get().name); + + if (E->get().type==Variant::OBJECT || var.get_type()==Variant::OBJECT) { + + ObjectID id2; + Object *obj=var; + if (obj) { + id2=obj->get_instance_ID(); + } else { + id2=0; + } + + packet_peer_stream->put_var(Variant::INT); //hint string + packet_peer_stream->put_var(PROPERTY_HINT_OBJECT_ID); //hint + packet_peer_stream->put_var(E->get().hint_string); //hint string + packet_peer_stream->put_var(id2); //value + } else { + packet_peer_stream->put_var(E->get().type); + packet_peer_stream->put_var(E->get().hint); + packet_peer_stream->put_var(E->get().hint_string); + //only send information that can be sent.. + if (var.get_type()==Variant::IMAGE) { + var=Image(); + } + if (var.get_type()>=Variant::DICTIONARY) { + var=Array(); //send none for now, may be to big + } + packet_peer_stream->put_var(var); + } + + } + } + +} + +void ScriptDebuggerRemote::_set_object_property(ObjectID p_id, const String& p_property, const Variant& p_value) { + + Object* obj = ObjectDB::get_instance(p_id); + if (!obj) + return; + + obj->set(p_property,p_value); +} + void ScriptDebuggerRemote::_poll_events() { + //this si called from ::idle_poll, happens only when running the game, + //does not get called while on debug break + while(packet_peer_stream->get_available_packet_count()>0) { _get_output(); @@ -566,6 +668,40 @@ void ScriptDebuggerRemote::_poll_events() { } else if (command=="request_video_mem") { _send_video_memory(); + } else if (command=="inspect_object") { + + ObjectID id = cmd[1]; + _send_object_id(id); + } else if (command=="set_object_property") { + + _set_object_property(cmd[1],cmd[2],cmd[3]); + + } else if (command=="start_profiling") { + + for(int i=0;i<ScriptServer::get_language_count();i++) { + ScriptServer::get_language(i)->profiling_start(); + } + + max_frame_functions=cmd[1]; + profiler_function_signature_map.clear(); + profiling=true; + frame_time=0; + idle_time=0; + fixed_time=0; + fixed_frame_time=0; + + print_line("PROFILING ALRIGHT!"); + + } else if (command=="stop_profiling") { + + for(int i=0;i<ScriptServer::get_language_count();i++) { + ScriptServer::get_language(i)->profiling_stop(); + } + profiling=false; + _send_profiling_data(false); + print_line("PROFILING END!"); + } else if (command=="reload_scripts") { + reload_all_scripts=true; } else if (command=="breakpoint") { bool set = cmd[3]; @@ -582,8 +718,113 @@ void ScriptDebuggerRemote::_poll_events() { } +void ScriptDebuggerRemote::_send_profiling_data(bool p_for_frame) { + + + + + int ofs=0; + + for(int i=0;i<ScriptServer::get_language_count();i++) { + if (p_for_frame) + ofs+=ScriptServer::get_language(i)->profiling_get_frame_data(&profile_info[ofs],profile_info.size()-ofs); + else + ofs+=ScriptServer::get_language(i)->profiling_get_accumulated_data(&profile_info[ofs],profile_info.size()-ofs); + } + + for(int i=0;i<ofs;i++) { + profile_info_ptrs[i]=&profile_info[i]; + } + + SortArray<ScriptLanguage::ProfilingInfo*,ProfileInfoSort> sa; + sa.sort(profile_info_ptrs.ptr(),ofs); + + int to_send=MIN(ofs,max_frame_functions); + + //check signatures first + uint64_t total_script_time=0; + + for(int i=0;i<to_send;i++) { + + if (!profiler_function_signature_map.has(profile_info_ptrs[i]->signature)) { + + int idx = profiler_function_signature_map.size(); + packet_peer_stream->put_var("profile_sig"); + packet_peer_stream->put_var(2); + packet_peer_stream->put_var(profile_info_ptrs[i]->signature); + packet_peer_stream->put_var(idx); + + profiler_function_signature_map[profile_info_ptrs[i]->signature]=idx; + + + } + + total_script_time+=profile_info_ptrs[i]->self_time; + } + + //send frames then + + if (p_for_frame) { + packet_peer_stream->put_var("profile_frame"); + packet_peer_stream->put_var(8+profile_frame_data.size()*2+to_send*4); + } else { + packet_peer_stream->put_var("profile_total"); + packet_peer_stream->put_var(8+to_send*4); + } + + + packet_peer_stream->put_var(OS::get_singleton()->get_frames_drawn()); //total frame time + packet_peer_stream->put_var(frame_time); //total frame time + packet_peer_stream->put_var(idle_time); //idle frame time + packet_peer_stream->put_var(fixed_time); //fixed frame time + packet_peer_stream->put_var(fixed_frame_time); //fixed frame time + + packet_peer_stream->put_var(USEC_TO_SEC(total_script_time)); //total script execution time + + if (p_for_frame) { + + packet_peer_stream->put_var(profile_frame_data.size()); //how many profile framedatas to send + packet_peer_stream->put_var(to_send); //how many script functions to send + for (int i=0;i<profile_frame_data.size();i++) { + + + packet_peer_stream->put_var(profile_frame_data[i].name); + packet_peer_stream->put_var(profile_frame_data[i].data); + } + } else { + packet_peer_stream->put_var(0); //how many script functions to send + packet_peer_stream->put_var(to_send); //how many script functions to send + } + + + + for(int i=0;i<to_send;i++) { + + int sig_id=-1; + + if (profiler_function_signature_map.has(profile_info_ptrs[i]->signature)) { + sig_id=profiler_function_signature_map[profile_info_ptrs[i]->signature]; + } + + + + packet_peer_stream->put_var(sig_id); + packet_peer_stream->put_var(profile_info_ptrs[i]->call_count); + packet_peer_stream->put_var(profile_info_ptrs[i]->total_time/1000000.0); + packet_peer_stream->put_var(profile_info_ptrs[i]->self_time/1000000.0); + } + + if (p_for_frame) { + profile_frame_data.clear(); + } + +} + void ScriptDebuggerRemote::idle_poll() { + // this function is called every frame, except when there is a debugger break (::debug() in this class) + // execution stops and remains in the ::debug function + _get_output(); @@ -615,6 +856,24 @@ void ScriptDebuggerRemote::idle_poll() { } } + if (profiling) { + + if (skip_profile_frame) { + skip_profile_frame=false; + } else { + //send profiling info normally + _send_profiling_data(true); + } + } + + if (reload_all_scripts) { + + for(int i=0;i<ScriptServer::get_language_count();i++) { + ScriptServer::get_language(i)->reload_all_scripts(); + } + reload_all_scripts=false; + } + _poll_events(); } @@ -687,6 +946,50 @@ void ScriptDebuggerRemote::set_live_edit_funcs(LiveEditFuncs *p_funcs) { live_edit_funcs=p_funcs; } +bool ScriptDebuggerRemote::is_profiling() const { + + return profiling; +} +void ScriptDebuggerRemote::add_profiling_frame_data(const StringName& p_name,const Array& p_data){ + + int idx=-1; + for(int i=0;i<profile_frame_data.size();i++) { + if (profile_frame_data[i].name==p_name) { + idx=i; + break; + } + } + + FrameData fd; + fd.name=p_name; + fd.data=p_data; + + if (idx==-1) { + profile_frame_data.push_back(fd); + } else { + profile_frame_data[idx]=fd; + } +} + +void ScriptDebuggerRemote::profiling_start() { + //ignores this, uses it via connnection +} + +void ScriptDebuggerRemote::profiling_end() { + //ignores this, uses it via connnection +} + +void ScriptDebuggerRemote::profiling_set_frame_times(float p_frame_time, float p_idle_time, float p_fixed_time, float p_fixed_frame_time) { + + frame_time=p_frame_time; + idle_time=p_idle_time; + fixed_time=p_fixed_time; + fixed_frame_time=p_fixed_frame_time; + + +} + + ScriptDebuggerRemote::ResourceUsageFunc ScriptDebuggerRemote::resource_usage_func=NULL; ScriptDebuggerRemote::ScriptDebuggerRemote() { @@ -710,11 +1013,18 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() { char_count=0; msec_count=0; last_msec=0; + skip_profile_frame=false; eh.errfunc=_err_handler; eh.userdata=this; add_error_handler(&eh); + profile_info.resize(CLAMP(int(Globals::get_singleton()->get("debug/profiler_max_functions")),128,65535)); + profile_info_ptrs.resize(profile_info.size()); + profiling=false; + max_frame_functions=16; + reload_all_scripts=false; + } ScriptDebuggerRemote::~ScriptDebuggerRemote() { @@ -723,4 +1033,5 @@ ScriptDebuggerRemote::~ScriptDebuggerRemote() { remove_error_handler(&eh); memdelete(mutex); + } |