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:
parent
1f5d4a62e9
commit
f1cc14d525
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 #:"))));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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", "");
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ public:
|
|||
int call_count = 0;
|
||||
double self_time = 0;
|
||||
double total_time = 0;
|
||||
double internal_time = 0;
|
||||
};
|
||||
|
||||
// Servers profiler
|
||||
|
|
Loading…
Reference in New Issue