Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / tools / profiler / core / MicroGeckoProfiler.cpp
blob9a0062171bcf83a7dac5b9aac99eb6111dcb82a3
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "GeckoProfiler.h"
6 #include "ProfilerStackWalk.h"
8 #include "mozilla/Maybe.h"
9 #include "nsPrintfCString.h"
10 #include "public/GeckoTraceEvent.h"
11 #include "mozilla/ProfilerState.h"
13 using namespace mozilla;
14 using webrtc::trace_event_internal::TraceValueUnion;
16 void uprofiler_register_thread(const char* name, void* stacktop) {
17 #ifdef MOZ_GECKO_PROFILER
18 profiler_register_thread(name, stacktop);
19 #endif // MOZ_GECKO_PROFILER
22 void uprofiler_unregister_thread() {
23 #ifdef MOZ_GECKO_PROFILER
24 profiler_unregister_thread();
25 #endif // MOZ_GECKO_PROFILER
28 #ifdef MOZ_GECKO_PROFILER
29 namespace {
30 Maybe<MarkerTiming> ToTiming(char phase) {
31 switch (phase) {
32 case 'B':
33 return Some(MarkerTiming::IntervalStart());
34 case 'E':
35 return Some(MarkerTiming::IntervalEnd());
36 case 'I':
37 return Some(MarkerTiming::InstantNow());
38 default:
39 return Nothing();
43 MarkerCategory ToCategory(const char category) {
44 switch (category) {
45 case 'S':
46 return geckoprofiler::category::SANDBOX;
47 case 'M':
48 return geckoprofiler::category::MEDIA_RT;
49 default:
50 return geckoprofiler::category::OTHER;
54 struct TraceOption {
55 bool mPassed = false;
56 ProfilerString8View mName;
57 Variant<int64_t, bool, double, ProfilerString8View> mValue = AsVariant(false);
60 struct TraceMarker {
61 static constexpr int MAX_NUM_ARGS = 6;
62 using OptionsType = std::tuple<TraceOption, TraceOption, TraceOption,
63 TraceOption, TraceOption, TraceOption>;
64 static constexpr mozilla::Span<const char> MarkerTypeName() {
65 return MakeStringSpan("TraceEvent");
67 static void StreamJSONMarkerData(
68 mozilla::baseprofiler::SpliceableJSONWriter& aWriter,
69 const OptionsType& aArgs) {
70 auto writeValue = [&](const auto& aName, const auto& aVariant) {
71 aVariant.match(
72 [&](const int64_t& aValue) { aWriter.IntProperty(aName, aValue); },
73 [&](const bool& aValue) { aWriter.BoolProperty(aName, aValue); },
74 [&](const double& aValue) { aWriter.DoubleProperty(aName, aValue); },
75 [&](const ProfilerString8View& aValue) {
76 aWriter.StringProperty(aName, aValue);
77 });
79 if (const auto& arg = std::get<0>(aArgs); arg.mPassed) {
80 aWriter.StringProperty("name1", arg.mName);
81 writeValue("val1", arg.mValue);
83 if (const auto& arg = std::get<1>(aArgs); arg.mPassed) {
84 aWriter.StringProperty("name2", arg.mName);
85 writeValue("val2", arg.mValue);
87 if (const auto& arg = std::get<2>(aArgs); arg.mPassed) {
88 aWriter.StringProperty("name3", arg.mName);
89 writeValue("val3", arg.mValue);
91 if (const auto& arg = std::get<3>(aArgs); arg.mPassed) {
92 aWriter.StringProperty("name4", arg.mName);
93 writeValue("val4", arg.mValue);
95 if (const auto& arg = std::get<4>(aArgs); arg.mPassed) {
96 aWriter.StringProperty("name5", arg.mName);
97 writeValue("val5", arg.mValue);
99 if (const auto& arg = std::get<5>(aArgs); arg.mPassed) {
100 aWriter.StringProperty("name6", arg.mName);
101 writeValue("val6", arg.mValue);
104 static mozilla::MarkerSchema MarkerTypeDisplay() {
105 using MS = MarkerSchema;
106 MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
107 schema.SetChartLabel("{marker.name}");
108 schema.SetTableLabel(
109 "{marker.name} {marker.data.name1} {marker.data.val1} "
110 "{marker.data.name2} {marker.data.val2}"
111 "{marker.data.name3} {marker.data.val3}"
112 "{marker.data.name4} {marker.data.val4}"
113 "{marker.data.name5} {marker.data.val5}"
114 "{marker.data.name6} {marker.data.val6}");
115 schema.AddKeyLabelFormatSearchable("name1", "Key 1", MS::Format::String,
116 MS::Searchable::Searchable);
117 schema.AddKeyLabelFormatSearchable("val1", "Value 1", MS::Format::String,
118 MS::Searchable::Searchable);
119 schema.AddKeyLabelFormatSearchable("name2", "Key 2", MS::Format::String,
120 MS::Searchable::Searchable);
121 schema.AddKeyLabelFormatSearchable("val2", "Value 2", MS::Format::String,
122 MS::Searchable::Searchable);
123 schema.AddKeyLabelFormatSearchable("name3", "Key 3", MS::Format::String,
124 MS::Searchable::Searchable);
125 schema.AddKeyLabelFormatSearchable("val3", "Value 3", MS::Format::String,
126 MS::Searchable::Searchable);
127 schema.AddKeyLabelFormatSearchable("name4", "Key 4", MS::Format::String,
128 MS::Searchable::Searchable);
129 schema.AddKeyLabelFormatSearchable("val4", "Value 4", MS::Format::String,
130 MS::Searchable::Searchable);
131 schema.AddKeyLabelFormatSearchable("name5", "Key 5", MS::Format::String,
132 MS::Searchable::Searchable);
133 schema.AddKeyLabelFormatSearchable("val5", "Value 5", MS::Format::String,
134 MS::Searchable::Searchable);
135 schema.AddKeyLabelFormatSearchable("name6", "Key 6", MS::Format::String,
136 MS::Searchable::Searchable);
137 schema.AddKeyLabelFormatSearchable("val6", "Value 6", MS::Format::String,
138 MS::Searchable::Searchable);
139 return schema;
142 } // namespace
144 namespace mozilla {
145 template <>
146 struct ProfileBufferEntryWriter::Serializer<TraceOption> {
147 static Length Bytes(const TraceOption& aOption) {
148 // 1 byte to store passed flag, then object size if passed.
149 return aOption.mPassed ? (1 + SumBytes(aOption.mName, aOption.mValue)) : 1;
152 static void Write(ProfileBufferEntryWriter& aEW, const TraceOption& aOption) {
153 // 'T'/'t' is just an arbitrary 1-byte value to distinguish states.
154 if (aOption.mPassed) {
155 aEW.WriteObject<char>('T');
156 // Use the Serializer for the name/value pair.
157 aEW.WriteObject(aOption.mName);
158 aEW.WriteObject(aOption.mValue);
159 } else {
160 aEW.WriteObject<char>('t');
165 template <>
166 struct ProfileBufferEntryReader::Deserializer<TraceOption> {
167 static void ReadInto(ProfileBufferEntryReader& aER, TraceOption& aOption) {
168 char c = aER.ReadObject<char>();
169 if ((aOption.mPassed = (c == 'T'))) {
170 aER.ReadIntoObject(aOption.mName);
171 aER.ReadIntoObject(aOption.mValue);
172 } else {
173 MOZ_ASSERT(c == 't');
177 static TraceOption Read(ProfileBufferEntryReader& aER) {
178 TraceOption option;
179 ReadInto(aER, option);
180 return option;
183 } // namespace mozilla
184 #endif // MOZ_GECKO_PROFILER
186 void uprofiler_simple_event_marker_internal(
187 const char* name, const char category, char phase, int num_args,
188 const char** arg_names, const unsigned char* arg_types,
189 const unsigned long long* arg_values, bool capture_stack = false,
190 void* provided_stack = nullptr) {
191 #ifdef MOZ_GECKO_PROFILER
192 if (!profiler_thread_is_being_profiled_for_markers()) {
193 return;
195 Maybe<MarkerTiming> timing = ToTiming(phase);
196 if (!timing) {
197 if (getenv("MOZ_LOG_UNKNOWN_TRACE_EVENT_PHASES")) {
198 fprintf(stderr, "XXX UProfiler: phase not handled: '%c'\n", phase);
200 return;
202 MOZ_ASSERT(num_args <= TraceMarker::MAX_NUM_ARGS);
203 TraceMarker::OptionsType tuple;
204 TraceOption* args[6] = {&std::get<0>(tuple), &std::get<1>(tuple),
205 &std::get<2>(tuple), &std::get<3>(tuple),
206 &std::get<4>(tuple), &std::get<5>(tuple)};
207 for (int i = 0; i < std::min(num_args, TraceMarker::MAX_NUM_ARGS); ++i) {
208 auto& arg = *args[i];
209 arg.mPassed = true;
210 arg.mName = ProfilerString8View::WrapNullTerminatedString(arg_names[i]);
211 switch (arg_types[i]) {
212 case TRACE_VALUE_TYPE_UINT:
213 MOZ_ASSERT(arg_values[i] <= std::numeric_limits<int64_t>::max());
214 arg.mValue = AsVariant(static_cast<int64_t>(
215 reinterpret_cast<const TraceValueUnion*>(&arg_values[i])->as_uint));
216 break;
217 case TRACE_VALUE_TYPE_INT:
218 arg.mValue = AsVariant(static_cast<int64_t>(
219 reinterpret_cast<const TraceValueUnion*>(&arg_values[i])->as_int));
220 break;
221 case TRACE_VALUE_TYPE_BOOL:
222 arg.mValue = AsVariant(
223 reinterpret_cast<const TraceValueUnion*>(&arg_values[i])->as_bool);
224 break;
225 case TRACE_VALUE_TYPE_DOUBLE:
226 arg.mValue =
227 AsVariant(reinterpret_cast<const TraceValueUnion*>(&arg_values[i])
228 ->as_double);
229 break;
230 case TRACE_VALUE_TYPE_POINTER:
231 arg.mValue = AsVariant(ProfilerString8View(nsPrintfCString(
232 "%p", reinterpret_cast<const TraceValueUnion*>(&arg_values[i])
233 ->as_pointer)));
234 break;
235 case TRACE_VALUE_TYPE_STRING:
236 arg.mValue = AsVariant(ProfilerString8View::WrapNullTerminatedString(
237 reinterpret_cast<const TraceValueUnion*>(&arg_values[i])
238 ->as_string));
239 break;
240 case TRACE_VALUE_TYPE_COPY_STRING:
241 arg.mValue = AsVariant(ProfilerString8View(
242 nsCString(reinterpret_cast<const TraceValueUnion*>(&arg_values[i])
243 ->as_string)));
244 break;
245 default:
246 MOZ_ASSERT_UNREACHABLE("Unexpected trace value type");
247 arg.mValue = AsVariant(ProfilerString8View(
248 nsPrintfCString("Unexpected type: %u", arg_types[i])));
249 break;
253 profiler_add_marker(
254 ProfilerString8View::WrapNullTerminatedString(name), ToCategory(category),
255 {timing.extract(),
256 capture_stack
257 ? MarkerStack::Capture(StackCaptureOptions::Full)
258 : (provided_stack
259 ? MarkerStack::UseBacktrace(
260 *(static_cast<mozilla::ProfileChunkedBuffer*>(
261 provided_stack)))
262 : MarkerStack::Capture(StackCaptureOptions::NoStack))},
263 TraceMarker{}, tuple);
264 #endif // MOZ_GECKO_PROFILER
267 void uprofiler_simple_event_marker_capture_stack(
268 const char* name, const char category, char phase, int num_args,
269 const char** arg_names, const unsigned char* arg_types,
270 const unsigned long long* arg_values) {
271 uprofiler_simple_event_marker_internal(
272 name, category, phase, num_args, arg_names, arg_types, arg_values, true);
275 void uprofiler_simple_event_marker_with_stack(
276 const char* name, const char category, char phase, int num_args,
277 const char** arg_names, const unsigned char* arg_types,
278 const unsigned long long* arg_values, void* provided_stack) {
279 MOZ_ASSERT(provided_stack != nullptr);
280 uprofiler_simple_event_marker_internal(name, category, phase, num_args,
281 arg_names, arg_types, arg_values,
282 false, provided_stack);
285 void uprofiler_simple_event_marker(const char* name, const char category,
286 char phase, int num_args,
287 const char** arg_names,
288 const unsigned char* arg_types,
289 const unsigned long long* arg_values) {
290 uprofiler_simple_event_marker_internal(name, category, phase, num_args,
291 arg_names, arg_types, arg_values);
294 bool uprofiler_backtrace_into_buffer(NativeStack* aNativeStack, void* aBuffer) {
295 #if defined(MOZ_GECKO_PROFILER)
296 return profiler_backtrace_into_buffer(
297 *(static_cast<mozilla::ProfileChunkedBuffer*>(aBuffer)), *aNativeStack);
298 #else
299 return false;
300 #endif
303 void uprofiler_native_backtrace(const void* top, NativeStack* nativeStack) {
304 #if defined(MOZ_GECKO_PROFILER)
305 DoNativeBacktraceDirect(top, *nativeStack, nullptr);
306 #endif
309 bool uprofiler_is_active() { return profiler_is_active(); }
311 bool uprofiler_feature_active(int32_t aFeature) {
312 return profiler_feature_active(aFeature);
315 bool uprofiler_get(struct UprofilerFuncPtrs* aFuncPtrs) {
316 if (!aFuncPtrs) {
317 return false;
320 aFuncPtrs->register_thread = uprofiler_register_thread;
321 aFuncPtrs->unregister_thread = uprofiler_unregister_thread;
322 aFuncPtrs->simple_event_marker = uprofiler_simple_event_marker;
323 aFuncPtrs->simple_event_marker_capture_stack =
324 uprofiler_simple_event_marker_capture_stack;
325 aFuncPtrs->simple_event_marker_with_stack =
326 uprofiler_simple_event_marker_with_stack;
327 aFuncPtrs->backtrace_into_buffer = uprofiler_backtrace_into_buffer;
328 aFuncPtrs->native_backtrace = uprofiler_native_backtrace;
329 aFuncPtrs->is_active = uprofiler_is_active;
330 aFuncPtrs->feature_active = uprofiler_feature_active;
332 return true;