2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* script_debugger_local.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2014-02-10 02:10:30 +01:00
/*************************************************************************/
2018-01-01 14:40:08 +01:00
/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
2014-02-10 02:10:30 +01:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "script_debugger_local.h"
2017-01-16 08:04:19 +01:00
2014-02-10 02:10:30 +01:00
# include "os/os.h"
2017-03-05 16:44:50 +01:00
void ScriptDebuggerLocal : : debug ( ScriptLanguage * p_script , bool p_can_continue ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
print_line ( " Debugger Break, Reason: ' " + p_script - > debug_get_error ( ) + " ' " ) ;
print_line ( " *Frame " + itos ( 0 ) + " - " + p_script - > debug_get_stack_level_source ( 0 ) + " : " + itos ( p_script - > debug_get_stack_level_line ( 0 ) ) + " in function ' " + p_script - > debug_get_stack_level_function ( 0 ) + " ' " ) ;
2014-02-10 02:10:30 +01:00
print_line ( " Enter \" help \" for assistance. " ) ;
2017-03-05 16:44:50 +01:00
int current_frame = 0 ;
int total_frames = p_script - > debug_get_stack_level_count ( ) ;
while ( true ) {
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > print ( " debug> " ) ;
String line = OS : : get_singleton ( ) - > get_stdin_string ( ) . strip_edges ( ) ;
2017-03-05 16:44:50 +01:00
if ( line = = " " ) {
print_line ( " Debugger Break, Reason: ' " + p_script - > debug_get_error ( ) + " ' " ) ;
print_line ( " *Frame " + itos ( current_frame ) + " - " + p_script - > debug_get_stack_level_source ( current_frame ) + " : " + itos ( p_script - > debug_get_stack_level_line ( current_frame ) ) + " in function ' " + p_script - > debug_get_stack_level_function ( current_frame ) + " ' " ) ;
2014-02-10 02:10:30 +01:00
print_line ( " Enter \" help \" for assistance. " ) ;
2017-03-05 16:44:50 +01:00
} else if ( line = = " c " | | line = = " continue " )
2014-02-10 02:10:30 +01:00
break ;
2017-03-05 16:44:50 +01:00
else if ( line = = " bt " | | line = = " breakpoint " ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < total_frames ; i + + ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
String cfi = ( current_frame = = i ) ? " * " : " " ; //current frame indicator
print_line ( cfi + " Frame " + itos ( i ) + " - " + p_script - > debug_get_stack_level_source ( i ) + " : " + itos ( p_script - > debug_get_stack_level_line ( i ) ) + " in function ' " + p_script - > debug_get_stack_level_function ( i ) + " ' " ) ;
2014-02-10 02:10:30 +01:00
}
} else if ( line . begins_with ( " fr " ) | | line . begins_with ( " frame " ) ) {
2017-03-05 16:44:50 +01:00
if ( line . get_slice_count ( " " ) = = 1 ) {
print_line ( " *Frame " + itos ( current_frame ) + " - " + p_script - > debug_get_stack_level_source ( current_frame ) + " : " + itos ( p_script - > debug_get_stack_level_line ( current_frame ) ) + " in function ' " + p_script - > debug_get_stack_level_function ( current_frame ) + " ' " ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-03-05 16:44:50 +01:00
int frame = line . get_slicec ( ' ' , 1 ) . to_int ( ) ;
if ( frame < 0 | | frame > = total_frames ) {
2014-02-10 02:10:30 +01:00
print_line ( " Error: Invalid frame. " ) ;
} else {
2017-03-05 16:44:50 +01:00
current_frame = frame ;
print_line ( " *Frame " + itos ( frame ) + " - " + p_script - > debug_get_stack_level_source ( frame ) + " : " + itos ( p_script - > debug_get_stack_level_line ( frame ) ) + " in function ' " + p_script - > debug_get_stack_level_function ( frame ) + " ' " ) ;
2014-02-10 02:10:30 +01:00
}
}
2017-03-05 16:44:50 +01:00
} else if ( line = = " lv " | | line = = " locals " ) {
2014-02-10 02:10:30 +01:00
List < String > locals ;
List < Variant > values ;
2017-03-05 16:44:50 +01:00
p_script - > debug_get_stack_level_locals ( current_frame , & locals , & values ) ;
List < Variant > : : Element * V = values . front ( ) ;
for ( List < String > : : Element * E = locals . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
print_line ( E - > get ( ) + " : " + String ( V - > get ( ) ) ) ;
V = V - > next ( ) ;
}
2017-03-05 16:44:50 +01:00
} else if ( line = = " gv " | | line = = " globals " ) {
2014-02-10 02:10:30 +01:00
List < String > locals ;
List < Variant > values ;
p_script - > debug_get_globals ( & locals , & values ) ;
2017-03-05 16:44:50 +01:00
List < Variant > : : Element * V = values . front ( ) ;
for ( List < String > : : Element * E = locals . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
print_line ( E - > get ( ) + " : " + String ( V - > get ( ) ) ) ;
V = V - > next ( ) ;
}
2017-03-05 16:44:50 +01:00
} else if ( line = = " mv " | | line = = " members " ) {
2014-02-10 02:10:30 +01:00
List < String > locals ;
List < Variant > values ;
2017-03-05 16:44:50 +01:00
p_script - > debug_get_stack_level_members ( current_frame , & locals , & values ) ;
List < Variant > : : Element * V = values . front ( ) ;
for ( List < String > : : Element * E = locals . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 02:10:30 +01:00
print_line ( E - > get ( ) + " : " + String ( V - > get ( ) ) ) ;
V = V - > next ( ) ;
}
} else if ( line . begins_with ( " p " ) | | line . begins_with ( " print " ) ) {
2017-03-05 16:44:50 +01:00
if ( line . get_slice_count ( " " ) < = 1 ) {
2014-02-10 02:10:30 +01:00
print_line ( " Usage: print <expre> " ) ;
} else {
2017-03-05 16:44:50 +01:00
String expr = line . get_slicec ( ' ' , 2 ) ;
String res = p_script - > debug_parse_stack_level_expression ( current_frame , expr ) ;
2014-02-10 02:10:30 +01:00
print_line ( res ) ;
}
2017-03-05 16:44:50 +01:00
} else if ( line = = " s " | | line = = " step " ) {
2014-02-10 02:10:30 +01:00
set_depth ( - 1 ) ;
set_lines_left ( 1 ) ;
break ;
} else if ( line . begins_with ( " n " ) | | line . begins_with ( " next " ) ) {
set_depth ( 0 ) ;
set_lines_left ( 1 ) ;
break ;
} else if ( line . begins_with ( " br " ) | | line . begins_with ( " break " ) ) {
2017-03-05 16:44:50 +01:00
if ( line . get_slice_count ( " " ) < = 1 ) {
2014-02-10 02:10:30 +01:00
//show breakpoints
} else {
2017-03-05 16:44:50 +01:00
String bppos = line . get_slicec ( ' ' , 1 ) ;
String source = bppos . get_slicec ( ' : ' , 0 ) . strip_edges ( ) ;
int line = bppos . get_slicec ( ' : ' , 1 ) . strip_edges ( ) . to_int ( ) ;
2014-02-10 02:10:30 +01:00
source = breakpoint_find_source ( source ) ;
2017-03-05 16:44:50 +01:00
insert_breakpoint ( line , source ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
print_line ( " BreakPoint at " + source + " : " + itos ( line ) ) ;
2014-02-10 02:10:30 +01:00
}
} else if ( line . begins_with ( " delete " ) ) {
2017-03-05 16:44:50 +01:00
if ( line . get_slice_count ( " " ) < = 1 ) {
2014-02-10 02:10:30 +01:00
clear_breakpoints ( ) ;
} else {
2017-03-05 16:44:50 +01:00
String bppos = line . get_slicec ( ' ' , 1 ) ;
String source = bppos . get_slicec ( ' : ' , 0 ) . strip_edges ( ) ;
int line = bppos . get_slicec ( ' : ' , 1 ) . strip_edges ( ) . to_int ( ) ;
2014-02-10 02:10:30 +01:00
source = breakpoint_find_source ( source ) ;
2017-03-05 16:44:50 +01:00
remove_breakpoint ( line , source ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
print_line ( " Removed BreakPoint at " + source + " : " + itos ( line ) ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
} else if ( line = = " h " | | line = = " help " ) {
2014-02-10 02:10:30 +01:00
print_line ( " Built-In Debugger command list: \n " ) ;
print_line ( " \t c,continue : \t \t Continue execution. " ) ;
print_line ( " \t bt,backtrace : \t \t Show stack trace (frames). " ) ;
print_line ( " \t fr,frame <frame>: \t Change current frame. " ) ;
print_line ( " \t lv,locals : \t \t Show local variables for current frame. " ) ;
print_line ( " \t mv,members : \t \t Show member variables for \" this \" in frame. " ) ;
print_line ( " \t gv,globals : \t \t Show global variables. " ) ;
print_line ( " \t p,print <expr> : \t Execute and print variable in expression. " ) ;
print_line ( " \t s,step : \t \t Step to next line. " ) ;
print_line ( " \t n,next : \t \t Next line. " ) ;
print_line ( " \t br,break source:line : \t Place a breakpoint. " ) ;
print_line ( " \t delete [source:line]: \t \t Delete one/all breakpoints. " ) ;
} else {
print_line ( " Error: Invalid command, enter \" help \" for assistance. " ) ;
}
}
}
2016-05-22 02:18:16 +02:00
struct _ScriptDebuggerLocalProfileInfoSort {
2017-03-05 16:44:50 +01:00
bool operator ( ) ( const ScriptLanguage : : ProfilingInfo & A , const ScriptLanguage : : ProfilingInfo & B ) const {
2016-05-22 02:18:16 +02:00
return A . total_time > B . total_time ;
}
} ;
2017-09-30 16:19:07 +02:00
void ScriptDebuggerLocal : : profiling_set_frame_times ( float p_frame_time , float p_idle_time , float p_physics_time , float p_physics_frame_time ) {
2016-05-22 02:18:16 +02:00
2017-03-05 16:44:50 +01:00
frame_time = p_frame_time ;
idle_time = p_idle_time ;
2017-09-30 16:19:07 +02:00
physics_time = p_physics_time ;
physics_frame_time = p_physics_frame_time ;
2016-05-22 02:18:16 +02:00
}
void ScriptDebuggerLocal : : idle_poll ( ) {
if ( ! profiling )
return ;
uint64_t diff = OS : : get_singleton ( ) - > get_ticks_usec ( ) - idle_accum ;
2017-03-05 16:44:50 +01:00
if ( diff < 1000000 ) //show every one second
2016-05-22 02:18:16 +02:00
return ;
idle_accum = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
2017-03-05 16:44:50 +01:00
int ofs = 0 ;
for ( int i = 0 ; i < ScriptServer : : get_language_count ( ) ; i + + ) {
ofs + = ScriptServer : : get_language ( i ) - > profiling_get_frame_data ( & pinfo [ ofs ] , pinfo . size ( ) - ofs ) ;
2016-05-22 02:18:16 +02:00
}
2017-03-05 16:44:50 +01:00
SortArray < ScriptLanguage : : ProfilingInfo , _ScriptDebuggerLocalProfileInfoSort > sort ;
2017-11-25 04:07:54 +01:00
sort . sort ( pinfo . ptrw ( ) , ofs ) ;
2016-05-22 02:18:16 +02:00
//falta el frame time
2017-03-05 16:44:50 +01:00
uint64_t script_time_us = 0 ;
2016-05-22 02:18:16 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < ofs ; i + + ) {
2016-05-22 02:18:16 +02:00
2017-03-05 16:44:50 +01:00
script_time_us + = pinfo [ i ] . self_time ;
2016-05-22 02:18:16 +02:00
}
2017-03-05 16:44:50 +01:00
float script_time = USEC_TO_SEC ( script_time_us ) ;
2016-05-22 02:18:16 +02:00
2017-03-05 16:44:50 +01:00
float total_time = frame_time ;
2016-05-22 02:18:16 +02:00
//print script total
2017-03-05 16:44:50 +01:00
print_line ( " FRAME: total: " + rtos ( frame_time ) + " script: " + rtos ( script_time ) + " / " + itos ( script_time * 100 / total_time ) + " % " ) ;
2016-05-22 02:18:16 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < ofs ; i + + ) {
2016-05-22 02:18:16 +02:00
2017-03-05 16:44:50 +01:00
print_line ( itos ( i ) + " : " + pinfo [ i ] . signature ) ;
float tt = USEC_TO_SEC ( pinfo [ i ] . total_time ) ;
float st = USEC_TO_SEC ( pinfo [ i ] . self_time ) ;
print_line ( " \t total: " + rtos ( tt ) + " / " + itos ( tt * 100 / total_time ) + " % \t self: " + rtos ( st ) + " / " + itos ( st * 100 / total_time ) + " % tcalls: " + itos ( pinfo [ i ] . call_count ) ) ;
2016-05-22 02:18:16 +02:00
}
}
void ScriptDebuggerLocal : : profiling_start ( ) {
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < ScriptServer : : get_language_count ( ) ; i + + ) {
2016-05-22 02:18:16 +02:00
ScriptServer : : get_language ( i ) - > profiling_start ( ) ;
}
print_line ( " BEGIN PROFILING " ) ;
2017-03-05 16:44:50 +01:00
profiling = true ;
2016-05-22 02:18:16 +02:00
pinfo . resize ( 32768 ) ;
2017-03-05 16:44:50 +01:00
frame_time = 0 ;
2017-09-30 16:19:07 +02:00
physics_time = 0 ;
2017-03-05 16:44:50 +01:00
idle_time = 0 ;
2017-09-30 16:19:07 +02:00
physics_frame_time = 0 ;
2016-05-22 02:18:16 +02:00
}
void ScriptDebuggerLocal : : profiling_end ( ) {
2017-03-05 16:44:50 +01:00
int ofs = 0 ;
2016-05-22 02:18:16 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < ScriptServer : : get_language_count ( ) ; i + + ) {
ofs + = ScriptServer : : get_language ( i ) - > profiling_get_accumulated_data ( & pinfo [ ofs ] , pinfo . size ( ) - ofs ) ;
2016-05-22 02:18:16 +02:00
}
2017-03-05 16:44:50 +01:00
SortArray < ScriptLanguage : : ProfilingInfo , _ScriptDebuggerLocalProfileInfoSort > sort ;
2017-11-25 04:07:54 +01:00
sort . sort ( pinfo . ptrw ( ) , ofs ) ;
2016-05-22 02:18:16 +02:00
2017-03-05 16:44:50 +01:00
uint64_t total_us = 0 ;
for ( int i = 0 ; i < ofs ; i + + ) {
total_us + = pinfo [ i ] . self_time ;
2016-05-22 02:18:16 +02:00
}
2017-03-05 16:44:50 +01:00
float total_time = total_us / 1000000.0 ;
2016-05-22 02:18:16 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < ofs ; i + + ) {
2016-05-22 02:18:16 +02:00
2017-03-05 16:44:50 +01:00
print_line ( itos ( i ) + " : " + pinfo [ i ] . signature ) ;
float tt = USEC_TO_SEC ( pinfo [ i ] . total_time ) ;
float st = USEC_TO_SEC ( pinfo [ i ] . self_time ) ;
print_line ( " \t total_ms: " + rtos ( tt ) + " \t self_ms: " + rtos ( st ) + " total%: " + itos ( tt * 100 / total_time ) + " \t self%: " + itos ( st * 100 / total_time ) + " \t calls: " + itos ( pinfo [ i ] . call_count ) ) ;
2016-05-22 02:18:16 +02:00
}
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < ScriptServer : : get_language_count ( ) ; i + + ) {
2016-05-22 02:18:16 +02:00
ScriptServer : : get_language ( i ) - > profiling_stop ( ) ;
}
2017-03-05 16:44:50 +01:00
profiling = false ;
2016-05-22 02:18:16 +02:00
}
2017-03-05 16:44:50 +01:00
void ScriptDebuggerLocal : : send_message ( const String & p_message , const Array & p_args ) {
2014-02-10 02:10:30 +01:00
2018-02-05 11:18:49 +01:00
// This needs to be cleaned up entirely.
// print_line("MESSAGE: '" + p_message + "' - " + String(Variant(p_args)));
2014-02-10 02:10:30 +01:00
}
2018-01-09 17:19:03 +01:00
void ScriptDebuggerLocal : : send_error ( const String & p_func , const String & p_file , int p_line , const String & p_err , const String & p_descr , ErrorHandlerType p_type , const Vector < ScriptLanguage : : StackInfo > & p_stack_info ) {
print_line ( " ERROR: ' " + ( p_descr . empty ( ) ? p_err : p_descr ) + " ' " ) ;
}
2014-02-10 02:10:30 +01:00
ScriptDebuggerLocal : : ScriptDebuggerLocal ( ) {
2017-03-05 16:44:50 +01:00
profiling = false ;
idle_accum = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
2014-02-10 02:10:30 +01:00
}