diff --git a/core/profiling/profiling.cpp b/core/profiling/profiling.cpp index 77ac1c5b71c..43ca84ad4dc 100644 --- a/core/profiling/profiling.cpp +++ b/core/profiling/profiling.cpp @@ -36,7 +36,7 @@ #include "core/os/mutex.h" #include "core/templates/paged_allocator.h" -namespace TracyInternal { +namespace tracy { static bool configured = false; static const char dummy_string[] = "dummy"; @@ -57,6 +57,7 @@ struct StringInternData { struct SourceLocationInternData { const StringInternData *file; const StringInternData *function; + const StringInternData *name; tracy::SourceLocationData source_location_data; @@ -111,14 +112,7 @@ const StringInternData *_intern_name(const StringName &p_name) { return _data; } -const char *intern_name(const StringName &p_name) { - ERR_FAIL_COND_V(!configured, dummy_string); - - MutexLock lock(TracyInternTable::mutex); - return _intern_name(p_name)->name_utf8.get_data(); -} - -const tracy::SourceLocationData *intern_source_location(const void *p_function_ptr, const StringName &p_file, const StringName &p_function, uint32_t p_line) { +const tracy::SourceLocationData *intern_source_location(const void *p_function_ptr, const StringName &p_file, const StringName &p_function, const StringName &p_name, uint32_t p_line, bool p_is_script) { ERR_FAIL_COND_V(!configured, &dummy_source_location); const uint32_t hash = HashMapHasherDefault::hash(p_function_ptr); @@ -128,7 +122,7 @@ const tracy::SourceLocationData *intern_source_location(const void *p_function_p SourceLocationInternData *_data = TracyInternTable::source_location_table[idx]; while (_data) { - if (_data->function_ptr_hash == hash && _data->source_location_data.line == p_line && _data->file->name == p_file && _data->function->name == p_function) { + if (_data->function_ptr_hash == hash && _data->source_location_data.line == p_line && _data->file->name == p_file && _data->function->name == p_function && _data->name->name == p_name) { return &_data->source_location_data; } _data = _data->next; @@ -139,13 +133,14 @@ const tracy::SourceLocationData *intern_source_location(const void *p_function_p _data->function_ptr_hash = hash; _data->file = _intern_name(p_file); _data->function = _intern_name(p_function); + _data->name = _intern_name(p_name); _data->source_location_data.file = _data->file->name_utf8.get_data(); _data->source_location_data.function = _data->function->name_utf8.get_data(); - _data->source_location_data.name = _data->source_location_data.function; + _data->source_location_data.name = _data->name->name_utf8.get_data(); _data->source_location_data.line = p_line; - _data->source_location_data.color = 0x478cbf; // godot_logo_blue + _data->source_location_data.color = p_is_script ? 0x478cbf : 0; // godot_logo_blue _data->next = TracyInternTable::source_location_table[idx]; _data->prev = nullptr; @@ -157,20 +152,20 @@ const tracy::SourceLocationData *intern_source_location(const void *p_function_p return &_data->source_location_data; } -} // namespace TracyInternal +} // namespace tracy void godot_init_profiler() { - MutexLock lock(TracyInternal::TracyInternTable::mutex); - ERR_FAIL_COND(TracyInternal::configured); + MutexLock lock(tracy::TracyInternTable::mutex); + ERR_FAIL_COND(tracy::configured); - for (uint32_t i = 0; i < TracyInternal::TracyInternTable::TABLE_LEN; i++) { - TracyInternal::TracyInternTable::source_location_table[i] = nullptr; + for (uint32_t i = 0; i < tracy::TracyInternTable::TABLE_LEN; i++) { + tracy::TracyInternTable::source_location_table[i] = nullptr; } - for (uint32_t i = 0; i < TracyInternal::TracyInternTable::TABLE_LEN; i++) { - TracyInternal::TracyInternTable::string_table[i] = nullptr; + for (uint32_t i = 0; i < tracy::TracyInternTable::TABLE_LEN; i++) { + tracy::TracyInternTable::string_table[i] = nullptr; } - TracyInternal::configured = true; + tracy::configured = true; // Send our first event to tracy; otherwise it doesn't start collecting data. // FrameMark is kind of fitting because it communicates "this is where we started tracing". @@ -178,25 +173,25 @@ void godot_init_profiler() { } void godot_cleanup_profiler() { - MutexLock lock(TracyInternal::TracyInternTable::mutex); - ERR_FAIL_COND(!TracyInternal::configured); + MutexLock lock(tracy::TracyInternTable::mutex); + ERR_FAIL_COND(!tracy::configured); - for (uint32_t i = 0; i < TracyInternal::TracyInternTable::TABLE_LEN; i++) { - while (TracyInternal::TracyInternTable::source_location_table[i]) { - TracyInternal::SourceLocationInternData *d = TracyInternal::TracyInternTable::source_location_table[i]; - TracyInternal::TracyInternTable::source_location_table[i] = TracyInternal::TracyInternTable::source_location_table[i]->next; - TracyInternal::TracyInternTable::source_location_allocator.free(d); + for (uint32_t i = 0; i < tracy::TracyInternTable::TABLE_LEN; i++) { + while (tracy::TracyInternTable::source_location_table[i]) { + tracy::SourceLocationInternData *d = tracy::TracyInternTable::source_location_table[i]; + tracy::TracyInternTable::source_location_table[i] = tracy::TracyInternTable::source_location_table[i]->next; + tracy::TracyInternTable::source_location_allocator.free(d); } } - for (uint32_t i = 0; i < TracyInternal::TracyInternTable::TABLE_LEN; i++) { - while (TracyInternal::TracyInternTable::string_table[i]) { - TracyInternal::StringInternData *d = TracyInternal::TracyInternTable::string_table[i]; - TracyInternal::TracyInternTable::string_table[i] = TracyInternal::TracyInternTable::string_table[i]->next; - TracyInternal::TracyInternTable::string_allocator.free(d); + for (uint32_t i = 0; i < tracy::TracyInternTable::TABLE_LEN; i++) { + while (tracy::TracyInternTable::string_table[i]) { + tracy::StringInternData *d = tracy::TracyInternTable::string_table[i]; + tracy::TracyInternTable::string_table[i] = tracy::TracyInternTable::string_table[i]->next; + tracy::TracyInternTable::string_allocator.free(d); } } - TracyInternal::configured = false; + tracy::configured = false; } #elif defined(GODOT_USE_PERFETTO) diff --git a/core/profiling/profiling.h b/core/profiling/profiling.h index 43d50c2bb09..caaf442821b 100644 --- a/core/profiling/profiling.h +++ b/core/profiling/profiling.h @@ -51,10 +51,10 @@ #include -namespace TracyInternal { -const char *intern_name(const StringName &p_name); -const tracy::SourceLocationData *intern_source_location(const void *p_function_ptr, const StringName &p_file, const StringName &p_function, uint32_t p_line); -} //namespace TracyInternal +// Hijacking the tracy namespace so we can use their macros. +namespace tracy { +const SourceLocationData *intern_source_location(const void *p_function_ptr, const StringName &p_file, const StringName &p_function, const StringName &p_name, uint32_t p_line, bool p_is_script); +} //namespace tracy // Define tracing macros. #define GodotProfileFrameMark FrameMark @@ -72,8 +72,11 @@ const tracy::SourceLocationData *intern_source_location(const void *p_function_p static constexpr tracy::SourceLocationData TracyConcat(__tracy_source_location, TracyLine){ m_zone_name, TracyFunction, TracyFile, (uint32_t)TracyLine, 0 }; \ new (&__godot_tracy_zone_##m_group_name) tracy::ScopedZone(&TracyConcat(__tracy_source_location, TracyLine), TRACY_CALLSTACK, true) #endif -#define GodotProfileZoneGroupedFirstScript(m_varname, m_ptr, m_file, m_function, m_line) \ - tracy::ScopedZone __godot_tracy_zone_##m_group_name(TracyInternal::intern_source_location(m_ptr, m_file, m_function, m_line)) + +#define GodotProfileZoneScript(m_ptr, m_file, m_function, m_name, m_line) \ + tracy::ScopedZone __godot_tracy_script(tracy::intern_source_location(m_ptr, m_file, m_function, m_name, m_line, true)) +#define GodotProfileZoneScriptSystemCall(m_ptr, m_file, m_function, m_name, m_line) \ + tracy::ScopedZone __godot_tracy_zone_system_call(tracy::intern_source_location(m_ptr, m_file, m_function, m_name, m_line, false)) // Memory allocation #define GodotProfileAlloc(m_ptr, m_size) TracyAlloc(m_ptr, m_size) @@ -111,7 +114,9 @@ struct PerfettoGroupedEventEnder { #define GodotProfileZoneGrouped(m_group_name, m_zone_name) \ __godot_perfetto_zone_##m_group_name._end_now(); \ TRACE_EVENT_BEGIN("godot", m_zone_name); -#define GodotProfileZoneGroupedFirstScript(m_varname, m_ptr, m_file, m_function, m_line) \\ TODO + +#define GodotProfileZoneScript(m_ptr, m_file, m_function, m_name, m_line) +#define GodotProfileZoneScriptSystemCall(m_ptr, m_file, m_function, m_name, m_line) #define GodotProfileAlloc(m_ptr, m_size) #define GodotProfileFree(m_ptr) @@ -169,7 +174,8 @@ private: #define GodotProfileZone(m_zone_name) \ GodotProfileZoneGroupedFirst(__COUNTER__, m_zone_name) -#define GodotProfileZoneGroupedFirstScript(m_varname, m_ptr, m_file, m_function, m_line) +#define GodotProfileZoneScript(m_ptr, m_file, m_function, m_name, m_line) +#define GodotProfileZoneScriptSystemCall(m_ptr, m_file, m_function, m_name, m_line) // Instruments has its own memory profiling, so these are no-ops. #define GodotProfileAlloc(m_ptr, m_size) @@ -202,10 +208,11 @@ void godot_cleanup_profiler(); // There must be a one to one correspondence of GodotProfileAlloc and GodotProfileFree calls. #define GodotProfileFree(m_ptr) -// Define a zone with custom source information (for scripting) -// m_varname is equivalent to GodotProfileZoneGrouped varnames. +// Define a zone for a script call (dynamic source location). // m_ptr is a pointer to the function instance, which will be used for the lookup. -// m_file, m_function are StringNames, m_line is a uint32_t, all used for the source location. -#define GodotProfileZoneGroupedFirstScript(m_varname, m_ptr, m_file, m_function, m_line) +// m_file, m_function, m_name are StringNames, and m_line is uint32_t +#define GodotProfileZoneScript(m_ptr, m_file, m_function, m_name, m_line) +// Define a zone for a system call from a script (dynamic source location). +#define GodotProfileZoneScriptSystemCall(m_ptr, m_file, m_function, m_name, m_line) #endif diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 6a6e2a04873..7ad2ae09ad4 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -496,7 +496,7 @@ void (*type_init_function_table[])(Variant *) = { #define METHOD_CALL_ON_FREED_INSTANCE_ERROR(method_pointer) "Cannot call method '" + (method_pointer)->get_name() + "' on a previously freed instance." Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Callable::CallError &r_err, CallState *p_state) { - GodotProfileZoneGroupedFirstScript(zone, this, source, name, _initial_line); + GodotProfileZoneScript(this, source, name, name, _initial_line); OPCODES_TABLE; @@ -1907,6 +1907,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GD_ERR_BREAK(methodname_idx < 0 || methodname_idx >= _global_names_count); const StringName *methodname = &_global_names_ptr[methodname_idx]; + GodotProfileZoneScriptSystemCall(methodname, source, name, *methodname, line); + GET_INSTRUCTION_ARG(base, argc); Variant **argptrs = instruction_args; @@ -2027,6 +2029,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _methods_count); MethodBind *method = _methods_ptr[_code_ptr[ip + 2]]; + GodotProfileZoneScriptSystemCall(method, source, name, method->get_name(), line); + GET_INSTRUCTION_ARG(base, argc); #ifdef DEBUG_ENABLED @@ -2112,6 +2116,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GD_ERR_BREAK(methodname_idx < 0 || methodname_idx >= _global_names_count); const StringName *methodname = &_global_names_ptr[methodname_idx]; + GodotProfileZoneScriptSystemCall(methodname, source, name, *methodname, line); + int argc = _code_ptr[ip + 3]; GD_ERR_BREAK(argc < 0); @@ -2142,6 +2148,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GD_ERR_BREAK(_code_ptr[ip + 1] < 0 || _code_ptr[ip + 1] >= _methods_count); MethodBind *method = _methods_ptr[_code_ptr[ip + 1]]; + GodotProfileZoneScriptSystemCall(method, source, name, method->get_name(), line); + int argc = _code_ptr[ip + 2]; GD_ERR_BREAK(argc < 0); @@ -2188,6 +2196,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _methods_count); MethodBind *method = _methods_ptr[_code_ptr[ip + 2]]; + GodotProfileZoneScriptSystemCall(method, source, name, method->get_name(), line); + Variant **argptrs = instruction_args; #ifdef DEBUG_ENABLED @@ -2224,6 +2234,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _methods_count); MethodBind *method = _methods_ptr[_code_ptr[ip + 2]]; + GodotProfileZoneScriptSystemCall(method, source, name, method->get_name(), line); + Variant **argptrs = instruction_args; #ifdef DEBUG_ENABLED uint64_t call_time = 0; @@ -2260,6 +2272,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _methods_count); MethodBind *method = _methods_ptr[_code_ptr[ip + 2]]; + GodotProfileZoneScriptSystemCall(method, source, name, method->get_name(), line); + GET_INSTRUCTION_ARG(base, argc); #ifdef DEBUG_ENABLED @@ -2312,6 +2326,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a GD_ERR_BREAK(_code_ptr[ip + 2] < 0 || _code_ptr[ip + 2] >= _methods_count); MethodBind *method = _methods_ptr[_code_ptr[ip + 2]]; + GodotProfileZoneScriptSystemCall(method, source, name, method->get_name(), line); + GET_INSTRUCTION_ARG(base, argc); #ifdef DEBUG_ENABLED bool freed = false; @@ -2483,6 +2499,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #endif const StringName *methodname = &_global_names_ptr[self_fun]; + GodotProfileZoneScriptSystemCall(methodname, source, name, *methodname, line); + Variant **argptrs = instruction_args; GET_INSTRUCTION_ARG(dst, argc);