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
30 Maybe
<MarkerTiming
> ToTiming(char phase
) {
33 return Some(MarkerTiming::IntervalStart());
35 return Some(MarkerTiming::IntervalEnd());
37 return Some(MarkerTiming::InstantNow());
43 MarkerCategory
ToCategory(const char category
) {
46 return geckoprofiler::category::SANDBOX
;
48 return geckoprofiler::category::MEDIA_RT
;
50 return geckoprofiler::category::OTHER
;
56 ProfilerString8View mName
;
57 Variant
<int64_t, bool, double, ProfilerString8View
> mValue
= AsVariant(false);
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
) {
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
);
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
);
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
);
160 aEW
.WriteObject
<char>('t');
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
);
173 MOZ_ASSERT(c
== 't');
177 static TraceOption
Read(ProfileBufferEntryReader
& aER
) {
179 ReadInto(aER
, 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()) {
195 Maybe
<MarkerTiming
> timing
= ToTiming(phase
);
197 if (getenv("MOZ_LOG_UNKNOWN_TRACE_EVENT_PHASES")) {
198 fprintf(stderr
, "XXX UProfiler: phase not handled: '%c'\n", phase
);
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
];
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
));
217 case TRACE_VALUE_TYPE_INT
:
218 arg
.mValue
= AsVariant(static_cast<int64_t>(
219 reinterpret_cast<const TraceValueUnion
*>(&arg_values
[i
])->as_int
));
221 case TRACE_VALUE_TYPE_BOOL
:
222 arg
.mValue
= AsVariant(
223 reinterpret_cast<const TraceValueUnion
*>(&arg_values
[i
])->as_bool
);
225 case TRACE_VALUE_TYPE_DOUBLE
:
227 AsVariant(reinterpret_cast<const TraceValueUnion
*>(&arg_values
[i
])
230 case TRACE_VALUE_TYPE_POINTER
:
231 arg
.mValue
= AsVariant(ProfilerString8View(nsPrintfCString(
232 "%p", reinterpret_cast<const TraceValueUnion
*>(&arg_values
[i
])
235 case TRACE_VALUE_TYPE_STRING
:
236 arg
.mValue
= AsVariant(ProfilerString8View::WrapNullTerminatedString(
237 reinterpret_cast<const TraceValueUnion
*>(&arg_values
[i
])
240 case TRACE_VALUE_TYPE_COPY_STRING
:
241 arg
.mValue
= AsVariant(ProfilerString8View(
242 nsCString(reinterpret_cast<const TraceValueUnion
*>(&arg_values
[i
])
246 MOZ_ASSERT_UNREACHABLE("Unexpected trace value type");
247 arg
.mValue
= AsVariant(ProfilerString8View(
248 nsPrintfCString("Unexpected type: %u", arg_types
[i
])));
254 ProfilerString8View::WrapNullTerminatedString(name
), ToCategory(category
),
257 ? MarkerStack::Capture(StackCaptureOptions::Full
)
259 ? MarkerStack::UseBacktrace(
260 *(static_cast<mozilla::ProfileChunkedBuffer
*>(
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
);
303 void uprofiler_native_backtrace(const void* top
, NativeStack
* nativeStack
) {
304 #if defined(MOZ_GECKO_PROFILER)
305 DoNativeBacktraceDirect(top
, *nativeStack
, nullptr);
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
) {
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
;