Fix missing time for some script functions in profiler

Fixes the issue by adding a mechanism by which the functions that were
previously disappearing can be profiled too. This is optional with
an editor setting, since collecting more information naturally slows the engine
further while profiling.

Fixes #23715, #40251, #29049
This commit is contained in:
msreis 2023-03-05 14:37:11 +02:00 committed by Yuri Sizov
parent 1f5d4a62e9
commit f1cc14d525
16 changed files with 191 additions and 57 deletions

View File

@ -384,10 +384,12 @@ public:
uint64_t call_count;
uint64_t total_time;
uint64_t self_time;
uint64_t internal_time;
};
virtual void profiling_start() = 0;
virtual void profiling_stop() = 0;
virtual void profiling_set_save_native_calls(bool p_enable) = 0;
virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) = 0;
virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) = 0;

View File

@ -145,6 +145,7 @@ void ScriptLanguageExtension::_bind_methods() {
GDVIRTUAL_BIND(_profiling_start);
GDVIRTUAL_BIND(_profiling_stop);
GDVIRTUAL_BIND(_profiling_set_save_native_calls, "enable");
GDVIRTUAL_BIND(_profiling_get_accumulated_data, "info_array", "info_max");
GDVIRTUAL_BIND(_profiling_get_frame_data, "info_array", "info_max");

View File

@ -607,6 +607,7 @@ public:
EXBIND0(profiling_start)
EXBIND0(profiling_stop)
EXBIND1(profiling_set_save_native_calls, bool)
GDVIRTUAL2R(int, _profiling_get_accumulated_data, GDExtensionPtr<ScriptLanguageExtensionProfilingInfo>, int)

View File

@ -185,6 +185,9 @@
<member name="debugger/auto_switch_to_remote_scene_tree" type="bool" setter="" getter="">
If [code]true[/code], automatically switches to the [b]Remote[/b] scene tree when running the project from the editor. If [code]false[/code], stays on the [b]Local[/b] scene tree when running the project from the editor.
</member>
<member name="debugger/profile_native_calls" type="bool" setter="" getter="">
If [code]true[/code], enables collection of profiling data from non-GDScript Godot functions, such as engine class methods. Enabling this slows execution while profiling further.
</member>
<member name="debugger/profiler_frame_history_size" type="int" setter="" getter="">
The size of the profiler's frame history. The default value (3600) allows seeing up to 60 seconds of profiling if the project renders at a constant 60 FPS. Higher values allow viewing longer periods of profiling in the graphs, especially when the project is running at high framerates.
</member>

View File

@ -276,6 +276,12 @@
<description>
</description>
</method>
<method name="_profiling_set_save_native_calls" qualifiers="virtual">
<return type="void" />
<param index="0" name="enable" type="bool" />
<description>
</description>
</method>
<method name="_profiling_start" qualifiers="virtual">
<return type="void" />
<description>

View File

@ -97,6 +97,7 @@ void EditorProfiler::clear() {
plot_sigs.clear();
plot_sigs.insert("physics_frame_time");
plot_sigs.insert("category_frame_time");
display_internal_profiles->set_visible(EDITOR_GET("debugger/profile_native_calls"));
updating_frame = true;
cursor_metric_edit->set_min(0);
@ -352,6 +353,9 @@ void EditorProfiler::_update_frame() {
for (int j = m.categories[i].items.size() - 1; j >= 0; j--) {
const Metric::Category::Item &it = m.categories[i].items[j];
if (it.internal == it.total && !display_internal_profiles->is_pressed() && m.categories[i].name == "Script Functions") {
continue;
}
TreeItem *item = variables->create_item(category);
item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
item->set_editable(0, true);
@ -363,6 +367,9 @@ void EditorProfiler::_update_frame() {
item->set_tooltip_text(0, it.name + "\n" + it.script + ":" + itos(it.line));
float time = dtime == DISPLAY_SELF_TIME ? it.self : it.total;
if (dtime == DISPLAY_SELF_TIME && !display_internal_profiles->is_pressed()) {
time += it.internal;
}
item->set_text(1, _get_time_as_text(m, time, it.calls));
@ -404,6 +411,10 @@ void EditorProfiler::_clear_pressed() {
_update_plot();
}
void EditorProfiler::_internal_profiles_pressed() {
_combo_changed(0);
}
void EditorProfiler::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
@ -635,6 +646,11 @@ EditorProfiler::EditorProfiler() {
hb->add_child(display_time);
display_internal_profiles = memnew(CheckButton(TTR("Display internal functions")));
display_internal_profiles->set_pressed(false);
display_internal_profiles->connect("pressed", callable_mp(this, &EditorProfiler::_internal_profiles_pressed));
hb->add_child(display_internal_profiles);
hb->add_spacer();
hb->add_child(memnew(Label(TTR("Frame #:"))));

View File

@ -33,6 +33,7 @@
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/check_button.h"
#include "scene/gui/label.h"
#include "scene/gui/option_button.h"
#include "scene/gui/spin_box.h"
@ -67,6 +68,7 @@ public:
int line = 0;
float self = 0;
float total = 0;
float internal = 0;
int calls = 0;
};
@ -105,6 +107,8 @@ private:
OptionButton *display_mode = nullptr;
OptionButton *display_time = nullptr;
CheckButton *display_internal_profiles = nullptr;
SpinBox *cursor_metric_edit = nullptr;
Vector<Metric> frame_metrics;
@ -130,6 +134,8 @@ private:
void _activate_pressed();
void _clear_pressed();
void _internal_profiles_pressed();
String _get_time_as_text(const Metric &m, float p_time, int p_calls);
void _make_metric_ptrs(Metric &m);

View File

@ -758,6 +758,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, uint64_t p_thread
int calls = frame.script_functions[i].call_count;
float total = frame.script_functions[i].total_time;
float self = frame.script_functions[i].self_time;
float internal = frame.script_functions[i].internal_time;
EditorProfiler::Metric::Category::Item item;
if (profiler_signature.has(signature)) {
@ -782,6 +783,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, uint64_t p_thread
item.calls = calls;
item.self = self;
item.total = total;
item.internal = internal;
funcs.items.write[i] = item;
}
@ -1097,7 +1099,9 @@ void ScriptEditorDebugger::_profiler_activate(bool p_enable, int p_type) {
// Add max funcs options to request.
Array opts;
int max_funcs = EDITOR_GET("debugger/profiler_frame_max_functions");
bool include_native = EDITOR_GET("debugger/profile_native_calls");
opts.push_back(CLAMP(max_funcs, 16, 512));
opts.push_back(include_native);
msg_data.push_back(opts);
}
_put_msg("profiler:servers", msg_data);

View File

@ -776,6 +776,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_frame_max_functions", 64, "16,512,1")
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "debugger/remote_scene_tree_refresh_interval", 1.0, "0.1,10,0.01,or_greater")
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "debugger/remote_inspect_refresh_interval", 0.2, "0.02,10,0.01,or_greater")
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "debugger/profile_native_calls", false, "")
// HTTP Proxy
_initial_set("network/http_proxy/host", "");

View File

@ -2220,6 +2220,8 @@ void GDScriptLanguage::profiling_start() {
elem->self()->profile.last_frame_call_count = 0;
elem->self()->profile.last_frame_self_time = 0;
elem->self()->profile.last_frame_total_time = 0;
elem->self()->profile.native_calls.clear();
elem->self()->profile.last_native_calls.clear();
elem = elem->next();
}
@ -2227,6 +2229,13 @@ void GDScriptLanguage::profiling_start() {
#endif
}
void GDScriptLanguage::profiling_set_save_native_calls(bool p_enable) {
#ifdef DEBUG_ENABLED
MutexLock lock(mutex);
profile_native_calls = p_enable;
#endif
}
void GDScriptLanguage::profiling_stop() {
#ifdef DEBUG_ENABLED
MutexLock lock(this->mutex);
@ -2241,17 +2250,32 @@ int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr,
MutexLock lock(this->mutex);
profiling_collate_native_call_data(true);
SelfList<GDScriptFunction> *elem = function_list.first();
while (elem) {
if (current >= p_info_max) {
break;
}
int last_non_internal = current;
p_info_arr[current].call_count = elem->self()->profile.call_count.get();
p_info_arr[current].self_time = elem->self()->profile.self_time.get();
p_info_arr[current].total_time = elem->self()->profile.total_time.get();
p_info_arr[current].signature = elem->self()->profile.signature;
elem = elem->next();
current++;
int nat_time = 0;
HashMap<String, GDScriptFunction::Profile::NativeProfile>::ConstIterator nat_calls = elem->self()->profile.native_calls.begin();
while (nat_calls) {
p_info_arr[current].call_count = nat_calls->value.call_count;
p_info_arr[current].total_time = nat_calls->value.total_time;
p_info_arr[current].self_time = nat_calls->value.total_time;
p_info_arr[current].signature = nat_calls->value.signature;
nat_time += nat_calls->value.total_time;
current++;
++nat_calls;
}
p_info_arr[last_non_internal].internal_time = nat_time;
elem = elem->next();
}
#endif
@ -2264,17 +2288,33 @@ int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_
#ifdef DEBUG_ENABLED
MutexLock lock(this->mutex);
profiling_collate_native_call_data(false);
SelfList<GDScriptFunction> *elem = function_list.first();
while (elem) {
if (current >= p_info_max) {
break;
}
if (elem->self()->profile.last_frame_call_count > 0) {
int last_non_internal = current;
p_info_arr[current].call_count = elem->self()->profile.last_frame_call_count;
p_info_arr[current].self_time = elem->self()->profile.last_frame_self_time;
p_info_arr[current].total_time = elem->self()->profile.last_frame_total_time;
p_info_arr[current].signature = elem->self()->profile.signature;
current++;
int nat_time = 0;
HashMap<String, GDScriptFunction::Profile::NativeProfile>::ConstIterator nat_calls = elem->self()->profile.last_native_calls.begin();
while (nat_calls) {
p_info_arr[current].call_count = nat_calls->value.call_count;
p_info_arr[current].total_time = nat_calls->value.total_time;
p_info_arr[current].self_time = nat_calls->value.total_time;
p_info_arr[current].internal_time = nat_calls->value.total_time;
p_info_arr[current].signature = nat_calls->value.signature;
nat_time += nat_calls->value.total_time;
current++;
++nat_calls;
}
p_info_arr[last_non_internal].internal_time = nat_time;
}
elem = elem->next();
}
@ -2283,6 +2323,33 @@ int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_
return current;
}
void GDScriptLanguage::profiling_collate_native_call_data(bool p_accumulated) {
#ifdef DEBUG_ENABLED
// The same native call can be called from multiple functions, so join them together here.
// Only use the name of the function (ie signature.split[2]).
HashMap<String, GDScriptFunction::Profile::NativeProfile *> seen_nat_calls;
SelfList<GDScriptFunction> *elem = function_list.first();
while (elem) {
HashMap<String, GDScriptFunction::Profile::NativeProfile> *nat_calls = p_accumulated ? &elem->self()->profile.native_calls : &elem->self()->profile.last_native_calls;
HashMap<String, GDScriptFunction::Profile::NativeProfile>::Iterator it = nat_calls->begin();
while (it != nat_calls->end()) {
Vector<String> sig = it->value.signature.split("::");
HashMap<String, GDScriptFunction::Profile::NativeProfile *>::ConstIterator already_found = seen_nat_calls.find(sig[2]);
if (already_found) {
already_found->value->total_time += it->value.total_time;
already_found->value->call_count += it->value.call_count;
elem->self()->profile.last_native_calls.remove(it);
} else {
seen_nat_calls.insert(sig[2], &it->value);
}
++it;
}
elem = elem->next();
}
#endif
}
struct GDScriptDepSort {
//must support sorting so inheritance works properly (parent must be reloaded first)
bool operator()(const Ref<GDScript> &A, const Ref<GDScript> &B) const {
@ -2482,9 +2549,11 @@ void GDScriptLanguage::frame() {
elem->self()->profile.last_frame_call_count = elem->self()->profile.frame_call_count.get();
elem->self()->profile.last_frame_self_time = elem->self()->profile.frame_self_time.get();
elem->self()->profile.last_frame_total_time = elem->self()->profile.frame_total_time.get();
elem->self()->profile.last_native_calls = elem->self()->profile.native_calls;
elem->self()->profile.frame_call_count.set(0);
elem->self()->profile.frame_self_time.set(0);
elem->self()->profile.frame_total_time.set(0);
elem->self()->profile.native_calls.clear();
elem = elem->next();
}
}

View File

@ -439,6 +439,7 @@ class GDScriptLanguage : public ScriptLanguage {
SelfList<GDScriptFunction>::List function_list;
bool profiling;
bool profile_native_calls;
uint64_t script_frame_time;
HashMap<String, ObjectID> orphan_subclasses;
@ -590,6 +591,8 @@ public:
virtual void profiling_start() override;
virtual void profiling_stop() override;
virtual void profiling_set_save_native_calls(bool p_enable) override;
void profiling_collate_native_call_data(bool p_accumulated);
virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) override;
virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) override;

View File

@ -474,6 +474,13 @@ private:
uint64_t last_frame_call_count = 0;
uint64_t last_frame_self_time = 0;
uint64_t last_frame_total_time = 0;
typedef struct NativeProfile {
uint64_t call_count;
uint64_t total_time;
String signature;
} NativeProfile;
HashMap<String, NativeProfile> native_calls;
HashMap<String, NativeProfile> last_native_calls;
} profile;
#endif
@ -514,6 +521,7 @@ public:
void debug_get_stack_member_state(int p_line, List<Pair<StringName, int>> *r_stackvars) const;
#ifdef DEBUG_ENABLED
void _profile_native_call(uint64_t p_t_taken, const String &p_function_name, const String &p_instance_class_name = String());
void disassemble(const Vector<String> &p_code_lines) const;
#endif

View File

@ -36,6 +36,18 @@
#include "core/os/os.h"
#ifdef DEBUG_ENABLED
static bool _profile_count_as_native(const Object *p_base_obj, const StringName &p_methodname) {
if (!p_base_obj) {
return false;
}
StringName cname = p_base_obj->get_class_name();
if ((p_methodname == "new" && cname == "GDScript") || p_methodname == "call") {
return false;
}
return ClassDB::class_exists(cname) && ClassDB::has_method(cname, p_methodname, false);
}
static String _get_element_type(Variant::Type builtin_type, const StringName &native_type, const Ref<Script> &script_type) {
if (script_type.is_valid() && script_type->is_valid()) {
return GDScript::debug_get_script_name(script_type);
@ -84,6 +96,18 @@ static String _get_var_type(const Variant *p_var) {
return basestr;
}
void GDScriptFunction::_profile_native_call(uint64_t p_t_taken, const String &p_func_name, const String &p_instance_class_name) {
HashMap<String, Profile::NativeProfile>::Iterator inner_prof = profile.native_calls.find(p_func_name);
if (inner_prof) {
inner_prof->value.call_count += 1;
} else {
String sig = vformat("%s::0::%s%s%s", get_script()->get_script_path(), p_instance_class_name, p_instance_class_name.is_empty() ? "" : ".", p_func_name);
inner_prof = profile.native_calls.insert(p_func_name, Profile::NativeProfile{ 1, 0, sig });
}
inner_prof->value.total_time += p_t_taken;
}
#endif // DEBUG_ENABLED
Variant GDScriptFunction::_get_default_variant_for_data_type(const GDScriptDataType &p_data_type) {
@ -631,9 +655,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
bool exit_ok = false;
bool awaited = false;
#endif
#ifdef DEBUG_ENABLED
int variant_address_limits[ADDR_TYPE_MAX] = { _stack_size, _constant_count, p_instance ? p_instance->members.size() : 0 };
#endif
@ -1661,16 +1682,14 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
if (GDScriptLanguage::get_singleton()->profiling) {
call_time = OS::get_singleton()->get_ticks_usec();
}
Variant::Type base_type = base->get_type();
Object *base_obj = base->get_validated_object();
StringName base_class = base_obj ? base_obj->get_class_name() : StringName();
#endif
Callable::CallError err;
if (call_ret) {
GET_INSTRUCTION_ARG(ret, argc + 1);
#ifdef DEBUG_ENABLED
Variant::Type base_type = base->get_type();
Object *base_obj = base->get_validated_object();
StringName base_class = base_obj ? base_obj->get_class_name() : StringName();
#endif
base->callp(*methodname, (const Variant **)argptrs, argc, *ret, err);
#ifdef DEBUG_ENABLED
if (ret->get_type() == Variant::NIL) {
@ -1704,8 +1723,13 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
base->callp(*methodname, (const Variant **)argptrs, argc, ret, err);
}
#ifdef DEBUG_ENABLED
if (GDScriptLanguage::get_singleton()->profiling) {
function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
uint64_t t_taken = OS::get_singleton()->get_ticks_usec() - call_time;
if (GDScriptLanguage::get_singleton()->profile_native_calls && _profile_count_as_native(base_obj, *methodname)) {
_profile_native_call(t_taken, *methodname, base_class);
}
function_call_time += t_taken;
}
if (err.error != Callable::CallError::CALL_OK) {
@ -1782,8 +1806,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
uint64_t call_time = 0;
if (GDScriptLanguage::get_singleton()->profiling) {
if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) {
call_time = OS::get_singleton()->get_ticks_usec();
}
#endif
@ -1797,8 +1820,11 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
#ifdef DEBUG_ENABLED
if (GDScriptLanguage::get_singleton()->profiling) {
function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) {
uint64_t t_taken = OS::get_singleton()->get_ticks_usec() - call_time;
_profile_native_call(t_taken, method->get_name(), method->get_instance_class());
function_call_time += t_taken;
}
if (err.error != Callable::CallError::CALL_OK) {
@ -1851,22 +1877,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
const Variant **argptrs = const_cast<const Variant **>(instruction_args);
#ifdef DEBUG_ENABLED
uint64_t call_time = 0;
if (GDScriptLanguage::get_singleton()->profiling) {
call_time = OS::get_singleton()->get_ticks_usec();
}
#endif
Callable::CallError err;
Variant::call_static(builtin_type, *methodname, argptrs, argc, *ret, err);
#ifdef DEBUG_ENABLED
if (GDScriptLanguage::get_singleton()->profiling) {
function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
}
if (err.error != Callable::CallError::CALL_OK) {
err_text = _get_call_error(err, "static function '" + methodname->operator String() + "' in type '" + Variant::get_type_name(builtin_type) + "'", argptrs);
OPCODE_BREAK;
@ -1895,8 +1909,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
uint64_t call_time = 0;
if (GDScriptLanguage::get_singleton()->profiling) {
if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) {
call_time = OS::get_singleton()->get_ticks_usec();
}
#endif
@ -1905,15 +1918,17 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
*ret = method->call(nullptr, argptrs, argc, err);
#ifdef DEBUG_ENABLED
if (GDScriptLanguage::get_singleton()->profiling) {
function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) {
uint64_t t_taken = OS::get_singleton()->get_ticks_usec() - call_time;
_profile_native_call(t_taken, method->get_name(), method->get_instance_class());
function_call_time += t_taken;
}
#endif
if (err.error != Callable::CallError::CALL_OK) {
err_text = _get_call_error(err, "static function '" + method->get_name().operator String() + "' in type '" + method->get_instance_class().operator String() + "'", argptrs);
OPCODE_BREAK;
}
#endif
ip += 3;
}
@ -1951,8 +1966,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
uint64_t call_time = 0;
if (GDScriptLanguage::get_singleton()->profiling) {
if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) {
call_time = OS::get_singleton()->get_ticks_usec();
}
#endif
@ -1961,10 +1975,13 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
method->validated_call(base_obj, (const Variant **)argptrs, ret);
#ifdef DEBUG_ENABLED
if (GDScriptLanguage::get_singleton()->profiling) {
function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) {
uint64_t t_taken = OS::get_singleton()->get_ticks_usec() - call_time;
_profile_native_call(t_taken, method->get_name(), method->get_instance_class());
function_call_time += t_taken;
}
#endif
ip += 3;
}
DISPATCH_OPCODE;
@ -1998,8 +2015,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
Variant **argptrs = instruction_args;
#ifdef DEBUG_ENABLED
uint64_t call_time = 0;
if (GDScriptLanguage::get_singleton()->profiling) {
if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) {
call_time = OS::get_singleton()->get_ticks_usec();
}
#endif
@ -2009,10 +2025,13 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
method->validated_call(base_obj, (const Variant **)argptrs, nullptr);
#ifdef DEBUG_ENABLED
if (GDScriptLanguage::get_singleton()->profiling) {
function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
if (GDScriptLanguage::get_singleton()->profiling && GDScriptLanguage::get_singleton()->profile_native_calls) {
uint64_t t_taken = OS::get_singleton()->get_ticks_usec() - call_time;
_profile_native_call(t_taken, method->get_name(), method->get_instance_class());
function_call_time += t_taken;
}
#endif
ip += 3;
}
DISPATCH_OPCODE;
@ -2033,22 +2052,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
Variant::ValidatedBuiltInMethod method = _builtin_methods_ptr[_code_ptr[ip + 2]];
Variant **argptrs = instruction_args;
#ifdef DEBUG_ENABLED
uint64_t call_time = 0;
if (GDScriptLanguage::get_singleton()->profiling) {
call_time = OS::get_singleton()->get_ticks_usec();
}
#endif
GET_INSTRUCTION_ARG(ret, argc + 1);
method(base, (const Variant **)argptrs, argc, ret);
#ifdef DEBUG_ENABLED
if (GDScriptLanguage::get_singleton()->profiling) {
function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
}
#endif
ip += 3;
}
DISPATCH_OPCODE;

View File

@ -463,6 +463,7 @@ public:
/* PROFILING FUNCTIONS */
/* TODO */ void profiling_start() override {}
/* TODO */ void profiling_stop() override {}
/* TODO */ void profiling_set_save_native_calls(bool p_enable) override {}
/* TODO */ int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) override {
return 0;
}

View File

@ -108,12 +108,13 @@ Array ServersDebugger::ServersProfilerFrame::serialize() {
}
}
arr.push_back(script_functions.size() * 4);
arr.push_back(script_functions.size() * 5);
for (int i = 0; i < script_functions.size(); i++) {
arr.push_back(script_functions[i].sig_id);
arr.push_back(script_functions[i].call_count);
arr.push_back(script_functions[i].self_time);
arr.push_back(script_functions[i].total_time);
arr.push_back(script_functions[i].internal_time);
}
return arr;
}
@ -149,14 +150,15 @@ bool ServersDebugger::ServersProfilerFrame::deserialize(const Array &p_arr) {
int func_size = p_arr[idx];
idx += 1;
CHECK_SIZE(p_arr, idx + func_size, "ServersProfilerFrame");
for (int i = 0; i < func_size / 4; i++) {
for (int i = 0; i < func_size / 5; i++) {
ScriptFunctionInfo fi;
fi.sig_id = p_arr[idx];
fi.call_count = p_arr[idx + 1];
fi.self_time = p_arr[idx + 2];
fi.total_time = p_arr[idx + 3];
fi.internal_time = p_arr[idx + 4];
script_functions.push_back(fi);
idx += 4;
idx += 5;
}
CHECK_END(p_arr, idx, "ServersProfilerFrame");
return true;
@ -210,8 +212,11 @@ public:
sig_map.clear();
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
ScriptServer::get_language(i)->profiling_start();
if (p_opts.size() == 2 && p_opts[1].get_type() == Variant::BOOL) {
ScriptServer::get_language(i)->profiling_set_save_native_calls(p_opts[1]);
}
}
if (p_opts.size() == 1 && p_opts[0].get_type() == Variant::INT) {
if (p_opts.size() > 0 && p_opts[0].get_type() == Variant::INT) {
max_frame_functions = MAX(0, int(p_opts[0]));
}
} else {
@ -265,6 +270,7 @@ public:
w[i].call_count = ptrs[i]->call_count;
w[i].total_time = ptrs[i]->total_time / 1000000.0;
w[i].self_time = ptrs[i]->self_time / 1000000.0;
w[i].internal_time = ptrs[i]->internal_time / 1000000.0;
}
}

View File

@ -69,6 +69,7 @@ public:
int call_count = 0;
double self_time = 0;
double total_time = 0;
double internal_time = 0;
};
// Servers profiler