Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/profiling/profiling.cpp
14735 views
1
/**************************************************************************/
2
/* profiling.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 "profiling.h"
32
33
#if defined(GODOT_USE_TRACY)
34
// Use the tracy profiler.
35
36
#include "core/os/mutex.h"
37
#include "core/templates/paged_allocator.h"
38
39
namespace tracy {
40
static bool configured = false;
41
42
static const char dummy_string[] = "dummy";
43
static tracy::SourceLocationData dummy_source_location = tracy::SourceLocationData{ dummy_string, dummy_string, dummy_string, 0, 0 };
44
45
// Implementation similar to StringName.
46
struct StringInternData {
47
StringName name;
48
CharString name_utf8;
49
50
uint32_t hash = 0;
51
StringInternData *prev = nullptr;
52
StringInternData *next = nullptr;
53
54
StringInternData() {}
55
};
56
57
struct SourceLocationInternData {
58
const StringInternData *file;
59
const StringInternData *function;
60
const StringInternData *name;
61
62
tracy::SourceLocationData source_location_data;
63
64
uint32_t function_ptr_hash = 0;
65
SourceLocationInternData *prev = nullptr;
66
SourceLocationInternData *next = nullptr;
67
68
SourceLocationInternData() {}
69
};
70
71
struct TracyInternTable {
72
constexpr static uint32_t TABLE_BITS = 16;
73
constexpr static uint32_t TABLE_LEN = 1 << TABLE_BITS;
74
constexpr static uint32_t TABLE_MASK = TABLE_LEN - 1;
75
76
static inline BinaryMutex mutex;
77
78
static inline SourceLocationInternData *source_location_table[TABLE_LEN];
79
static inline PagedAllocator<SourceLocationInternData> source_location_allocator;
80
81
static inline StringInternData *string_table[TABLE_LEN];
82
static inline PagedAllocator<StringInternData> string_allocator;
83
};
84
85
const StringInternData *_intern_name(const StringName &p_name) {
86
CRASH_COND(!configured);
87
88
const uint32_t hash = p_name.hash();
89
const uint32_t idx = hash & TracyInternTable::TABLE_MASK;
90
91
StringInternData *_data = TracyInternTable::string_table[idx];
92
93
while (_data) {
94
if (_data->hash == hash) {
95
return _data;
96
}
97
_data = _data->next;
98
}
99
100
_data = TracyInternTable::string_allocator.alloc();
101
_data->name = p_name;
102
_data->name_utf8 = p_name.operator String().utf8();
103
104
_data->next = TracyInternTable::string_table[idx];
105
_data->prev = nullptr;
106
107
if (TracyInternTable::string_table[idx]) {
108
TracyInternTable::string_table[idx]->prev = _data;
109
}
110
TracyInternTable::string_table[idx] = _data;
111
112
return _data;
113
}
114
115
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) {
116
ERR_FAIL_COND_V(!configured, &dummy_source_location);
117
118
const uint32_t hash = HashMapHasherDefault::hash(p_function_ptr);
119
const uint32_t idx = hash & TracyInternTable::TABLE_MASK;
120
121
MutexLock lock(TracyInternTable::mutex);
122
SourceLocationInternData *_data = TracyInternTable::source_location_table[idx];
123
124
while (_data) {
125
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) {
126
return &_data->source_location_data;
127
}
128
_data = _data->next;
129
}
130
131
_data = TracyInternTable::source_location_allocator.alloc();
132
133
_data->function_ptr_hash = hash;
134
_data->file = _intern_name(p_file);
135
_data->function = _intern_name(p_function);
136
_data->name = _intern_name(p_name);
137
138
_data->source_location_data.file = _data->file->name_utf8.get_data();
139
_data->source_location_data.function = _data->function->name_utf8.get_data();
140
_data->source_location_data.name = _data->name->name_utf8.get_data();
141
142
_data->source_location_data.line = p_line;
143
_data->source_location_data.color = p_is_script ? 0x478cbf : 0; // godot_logo_blue
144
145
_data->next = TracyInternTable::source_location_table[idx];
146
_data->prev = nullptr;
147
148
if (TracyInternTable::source_location_table[idx]) {
149
TracyInternTable::source_location_table[idx]->prev = _data;
150
}
151
TracyInternTable::source_location_table[idx] = _data;
152
153
return &_data->source_location_data;
154
}
155
} // namespace tracy
156
157
void godot_init_profiler() {
158
MutexLock lock(tracy::TracyInternTable::mutex);
159
ERR_FAIL_COND(tracy::configured);
160
161
for (uint32_t i = 0; i < tracy::TracyInternTable::TABLE_LEN; i++) {
162
tracy::TracyInternTable::source_location_table[i] = nullptr;
163
}
164
for (uint32_t i = 0; i < tracy::TracyInternTable::TABLE_LEN; i++) {
165
tracy::TracyInternTable::string_table[i] = nullptr;
166
}
167
168
tracy::configured = true;
169
170
// Send our first event to tracy; otherwise it doesn't start collecting data.
171
// FrameMark is kind of fitting because it communicates "this is where we started tracing".
172
FrameMark;
173
}
174
175
void godot_cleanup_profiler() {
176
MutexLock lock(tracy::TracyInternTable::mutex);
177
ERR_FAIL_COND(!tracy::configured);
178
179
for (uint32_t i = 0; i < tracy::TracyInternTable::TABLE_LEN; i++) {
180
while (tracy::TracyInternTable::source_location_table[i]) {
181
tracy::SourceLocationInternData *d = tracy::TracyInternTable::source_location_table[i];
182
tracy::TracyInternTable::source_location_table[i] = tracy::TracyInternTable::source_location_table[i]->next;
183
tracy::TracyInternTable::source_location_allocator.free(d);
184
}
185
}
186
for (uint32_t i = 0; i < tracy::TracyInternTable::TABLE_LEN; i++) {
187
while (tracy::TracyInternTable::string_table[i]) {
188
tracy::StringInternData *d = tracy::TracyInternTable::string_table[i];
189
tracy::TracyInternTable::string_table[i] = tracy::TracyInternTable::string_table[i]->next;
190
tracy::TracyInternTable::string_allocator.free(d);
191
}
192
}
193
194
tracy::configured = false;
195
}
196
197
#elif defined(GODOT_USE_PERFETTO)
198
PERFETTO_TRACK_EVENT_STATIC_STORAGE();
199
200
void godot_init_profiler() {
201
perfetto::TracingInitArgs args;
202
203
args.backends |= perfetto::kSystemBackend;
204
205
perfetto::Tracing::Initialize(args);
206
perfetto::TrackEvent::Register();
207
}
208
209
void godot_cleanup_profiler() {
210
// Stub
211
}
212
213
#elif defined(GODOT_USE_INSTRUMENTS)
214
215
namespace apple::instruments {
216
217
os_log_t LOG;
218
os_log_t LOG_TRACING;
219
220
} // namespace apple::instruments
221
222
void godot_init_profiler() {
223
static bool initialized = false;
224
if (initialized) {
225
return;
226
}
227
initialized = true;
228
apple::instruments::LOG = os_log_create("org.godotengine.godot", OS_LOG_CATEGORY_POINTS_OF_INTEREST);
229
#ifdef INSTRUMENTS_SAMPLE_CALLSTACKS
230
apple::instruments::LOG_TRACING = os_log_create("org.godotengine.godot", OS_LOG_CATEGORY_DYNAMIC_STACK_TRACING);
231
#else
232
apple::instruments::LOG_TRACING = os_log_create("org.godotengine.godot", "tracing");
233
#endif
234
}
235
236
void godot_cleanup_profiler() {
237
}
238
239
#else
240
void godot_init_profiler() {
241
// Stub
242
}
243
244
void godot_cleanup_profiler() {
245
// Stub
246
}
247
#endif
248
249