Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/objectdb_profiler/editor/data_viewers/summary_view.cpp
11325 views
1
/**************************************************************************/
2
/* summary_view.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "summary_view.h"
32
33
#include "core/os/time.h"
34
#include "editor/editor_node.h"
35
#include "scene/gui/center_container.h"
36
#include "scene/gui/label.h"
37
#include "scene/gui/panel_container.h"
38
#include "scene/gui/rich_text_label.h"
39
#include "scene/resources/style_box_flat.h"
40
41
SnapshotSummaryView::SnapshotSummaryView() {
42
set_name(TTRC("Summary"));
43
44
set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
45
set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
46
47
MarginContainer *mc = memnew(MarginContainer);
48
mc->add_theme_constant_override("margin_left", 5);
49
mc->add_theme_constant_override("margin_right", 5);
50
mc->add_theme_constant_override("margin_top", 5);
51
mc->add_theme_constant_override("margin_bottom", 5);
52
mc->set_anchors_preset(LayoutPreset::PRESET_FULL_RECT);
53
PanelContainer *content_wrapper = memnew(PanelContainer);
54
content_wrapper->set_anchors_preset(LayoutPreset::PRESET_FULL_RECT);
55
Ref<StyleBoxFlat> content_wrapper_sbf;
56
content_wrapper_sbf.instantiate();
57
content_wrapper_sbf->set_bg_color(EditorNode::get_singleton()->get_editor_theme()->get_color("dark_color_2", "Editor"));
58
content_wrapper->add_theme_style_override(SceneStringName(panel), content_wrapper_sbf);
59
content_wrapper->add_child(mc);
60
add_child(content_wrapper);
61
62
VBoxContainer *content = memnew(VBoxContainer);
63
mc->add_child(content);
64
content->set_anchors_preset(LayoutPreset::PRESET_FULL_RECT);
65
66
PanelContainer *pc = memnew(PanelContainer);
67
Ref<StyleBoxFlat> sbf;
68
sbf.instantiate();
69
sbf->set_bg_color(EditorNode::get_singleton()->get_editor_theme()->get_color("dark_color_3", "Editor"));
70
pc->add_theme_style_override("panel", sbf);
71
content->add_child(pc);
72
pc->set_anchors_preset(LayoutPreset::PRESET_TOP_WIDE);
73
Label *title = memnew(Label(TTRC("ObjectDB Snapshot Summary")));
74
pc->add_child(title);
75
title->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_CENTER);
76
title->set_vertical_alignment(VerticalAlignment::VERTICAL_ALIGNMENT_CENTER);
77
78
explainer_text = memnew(CenterContainer);
79
explainer_text->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
80
explainer_text->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
81
content->add_child(explainer_text);
82
VBoxContainer *explainer_lines = memnew(VBoxContainer);
83
explainer_text->add_child(explainer_lines);
84
Label *l1 = memnew(Label(TTRC("Press 'Take ObjectDB Snapshot' to snapshot the ObjectDB.")));
85
Label *l2 = memnew(Label(TTRC("Memory in Godot is either owned natively by the engine or owned by the ObjectDB.")));
86
Label *l3 = memnew(Label(TTRC("ObjectDB Snapshots capture only memory owned by the ObjectDB.")));
87
l1->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_CENTER);
88
l2->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_CENTER);
89
l3->set_horizontal_alignment(HorizontalAlignment::HORIZONTAL_ALIGNMENT_CENTER);
90
explainer_lines->add_child(l1);
91
explainer_lines->add_child(l2);
92
explainer_lines->add_child(l3);
93
94
ScrollContainer *sc = memnew(ScrollContainer);
95
sc->set_anchors_preset(LayoutPreset::PRESET_FULL_RECT);
96
sc->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
97
sc->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
98
content->add_child(sc);
99
100
blurb_list = memnew(VBoxContainer);
101
sc->add_child(blurb_list);
102
blurb_list->set_v_size_flags(SizeFlags::SIZE_EXPAND_FILL);
103
blurb_list->set_h_size_flags(SizeFlags::SIZE_EXPAND_FILL);
104
}
105
106
void SnapshotSummaryView::show_snapshot(GameStateSnapshot *p_data, GameStateSnapshot *p_diff_data) {
107
SnapshotView::show_snapshot(p_data, p_diff_data);
108
explainer_text->set_visible(false);
109
110
String snapshot_a_name = diff_data == nullptr ? TTRC("Snapshot") : TTRC("Snapshot A");
111
String snapshot_b_name = TTRC("Snapshot B");
112
113
_push_overview_blurb(snapshot_a_name + " " + TTRC("Overview"), snapshot_data);
114
if (diff_data) {
115
_push_overview_blurb(snapshot_b_name + " " + TTRC("Overview"), diff_data);
116
}
117
118
_push_node_blurb(snapshot_a_name + " " + TTRC("Nodes"), snapshot_data);
119
if (diff_data) {
120
_push_node_blurb(snapshot_b_name + " " + TTRC("Nodes"), diff_data);
121
}
122
123
_push_refcounted_blurb(snapshot_a_name + " " + TTRC("RefCounteds"), snapshot_data);
124
if (diff_data) {
125
_push_refcounted_blurb(snapshot_b_name + " " + TTRC("RefCounteds"), diff_data);
126
}
127
128
_push_object_blurb(snapshot_a_name + " " + TTRC("Objects"), snapshot_data);
129
if (diff_data) {
130
_push_object_blurb(snapshot_b_name + " " + TTRC("Objects"), diff_data);
131
}
132
}
133
134
void SnapshotSummaryView::clear_snapshot() {
135
// Just clear out the blurbs and leave the explainer.
136
for (int i = 0; i < blurb_list->get_child_count(); i++) {
137
blurb_list->get_child(i)->queue_free();
138
}
139
snapshot_data = nullptr;
140
diff_data = nullptr;
141
explainer_text->set_visible(true);
142
}
143
144
SummaryBlurb::SummaryBlurb(const String &p_title, const String &p_rtl_content) {
145
add_theme_constant_override("margin_left", 2);
146
add_theme_constant_override("margin_right", 2);
147
add_theme_constant_override("margin_top", 2);
148
add_theme_constant_override("margin_bottom", 2);
149
150
label = memnew(RichTextLabel);
151
label->add_theme_constant_override(SceneStringName(line_separation), 6);
152
label->set_text_direction(Control::TEXT_DIRECTION_INHERITED);
153
label->set_fit_content(true);
154
label->set_use_bbcode(true);
155
label->add_newline();
156
label->push_bold();
157
label->add_text(p_title);
158
label->pop();
159
label->add_newline();
160
label->add_newline();
161
label->append_text(p_rtl_content);
162
add_child(label);
163
}
164
165
void SnapshotSummaryView::_push_overview_blurb(const String &p_title, GameStateSnapshot *p_snapshot) {
166
String c = "";
167
168
c += "[ul]\n";
169
c += vformat(" [i]%s[/i] %s\n", TTR("Name:"), p_snapshot->name);
170
if (p_snapshot->snapshot_context.has("timestamp")) {
171
c += vformat(" [i]%s[/i] %s\n", TTR("Timestamp:"), Time::get_singleton()->get_datetime_string_from_unix_time((double)p_snapshot->snapshot_context["timestamp"]));
172
}
173
if (p_snapshot->snapshot_context.has("game_version")) {
174
c += vformat(" [i]%s[/i] %s\n", TTR("Game Version:"), (String)p_snapshot->snapshot_context["game_version"]);
175
}
176
if (p_snapshot->snapshot_context.has("editor_version")) {
177
c += vformat(" [i]%s[/i] %s\n", TTR("Editor Version:"), (String)p_snapshot->snapshot_context["editor_version"]);
178
}
179
180
double bytes_to_mb = 0.000001;
181
if (p_snapshot->snapshot_context.has("mem_usage")) {
182
c += vformat(" [i]%s[/i] %s\n", TTR("Memory Used:"), String::num((double)((uint64_t)p_snapshot->snapshot_context["mem_usage"]) * bytes_to_mb, 3) + " MB");
183
}
184
if (p_snapshot->snapshot_context.has("mem_max_usage")) {
185
c += vformat(" [i]%s[/i] %s\n", TTR("Max Memory Used:"), String::num((double)((uint64_t)p_snapshot->snapshot_context["mem_max_usage"]) * bytes_to_mb, 3) + " MB");
186
}
187
c += vformat(" [i]%s[/i] %s\n", TTR("Total Objects:"), itos(p_snapshot->objects.size()));
188
189
int node_count = 0;
190
for (const KeyValue<ObjectID, SnapshotDataObject *> &pair : p_snapshot->objects) {
191
if (pair.value->is_node()) {
192
node_count++;
193
}
194
}
195
c += vformat(" [i]%s[/i] %s\n", TTR("Total Nodes:"), itos(node_count));
196
c += "[/ul]\n";
197
198
blurb_list->add_child(memnew(SummaryBlurb(p_title, c)));
199
}
200
201
void SnapshotSummaryView::_push_node_blurb(const String &p_title, GameStateSnapshot *p_snapshot) {
202
LocalVector<String> nodes;
203
nodes.reserve(p_snapshot->objects.size());
204
205
for (const KeyValue<ObjectID, SnapshotDataObject *> &pair : p_snapshot->objects) {
206
// if it's a node AND it doesn't have a parent node
207
if (pair.value->is_node() && !pair.value->extra_debug_data.has("node_parent") && pair.value->extra_debug_data.has("node_is_scene_root") && !pair.value->extra_debug_data["node_is_scene_root"]) {
208
String node_name = pair.value->extra_debug_data["node_name"];
209
nodes.push_back(node_name != "" ? node_name : pair.value->get_name());
210
}
211
}
212
213
if (nodes.size() <= 1) {
214
return;
215
}
216
217
String c = TTRC("Multiple root nodes [i](possible call to 'remove_child' without 'queue_free')[/i]\n");
218
c += "[ul]\n";
219
for (const String &node : nodes) {
220
c += " " + node + "\n";
221
}
222
c += "[/ul]\n";
223
224
blurb_list->add_child(memnew(SummaryBlurb(p_title, c)));
225
}
226
227
void SnapshotSummaryView::_push_refcounted_blurb(const String &p_title, GameStateSnapshot *p_snapshot) {
228
LocalVector<String> rcs;
229
rcs.reserve(p_snapshot->objects.size());
230
231
for (const KeyValue<ObjectID, SnapshotDataObject *> &pair : p_snapshot->objects) {
232
if (pair.value->is_refcounted()) {
233
int ref_count = (uint64_t)pair.value->extra_debug_data["ref_count"];
234
Array ref_cycles = (Array)pair.value->extra_debug_data["ref_cycles"];
235
236
if (ref_count == ref_cycles.size()) {
237
rcs.push_back(pair.value->get_name());
238
}
239
}
240
}
241
242
if (rcs.is_empty()) {
243
return;
244
}
245
246
String c = TTRC("RefCounted objects only referenced in cycles [i](cycles often indicate a memory leaks)[/i]\n");
247
c += "[ul]\n";
248
for (const String &rc : rcs) {
249
c += " " + rc + "\n";
250
}
251
c += "[/ul]\n";
252
253
blurb_list->add_child(memnew(SummaryBlurb(p_title, c)));
254
}
255
256
void SnapshotSummaryView::_push_object_blurb(const String &p_title, GameStateSnapshot *p_snapshot) {
257
LocalVector<String> objects;
258
objects.reserve(p_snapshot->objects.size());
259
260
for (const KeyValue<ObjectID, SnapshotDataObject *> &pair : p_snapshot->objects) {
261
if (pair.value->inbound_references.is_empty() && pair.value->outbound_references.is_empty()) {
262
if (!pair.value->get_script().is_null()) {
263
// This blurb will have a lot of false positives, but we can at least suppress false positives
264
// from unreferenced nodes that are part of the scene tree.
265
if (pair.value->is_node() && (bool)pair.value->extra_debug_data["node_is_scene_root"]) {
266
objects.push_back(pair.value->get_name());
267
}
268
}
269
}
270
}
271
272
if (objects.is_empty()) {
273
return;
274
}
275
276
String c = TTRC("Scripted objects not referenced by any other objects [i](unreferenced objects may indicate a memory leak)[/i]\n");
277
c += "[ul]\n";
278
for (const String &object : objects) {
279
c += " " + object + "\n";
280
}
281
c += "[/ul]\n";
282
283
blurb_list->add_child(memnew(SummaryBlurb(p_title, c)));
284
}
285
286