1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* FFI functions for Profiler Rust API to call into profiler */
9 #include "ProfilerBindings.h"
11 #include "GeckoProfiler.h"
14 #include <type_traits>
16 void gecko_profiler_register_thread(const char* aName
) {
17 PROFILER_REGISTER_THREAD(aName
);
20 void gecko_profiler_unregister_thread() { PROFILER_UNREGISTER_THREAD(); }
22 void gecko_profiler_construct_label(mozilla::AutoProfilerLabel
* aAutoLabel
,
23 JS::ProfilingCategoryPair aCategoryPair
) {
24 #ifdef MOZ_GECKO_PROFILER
25 new (aAutoLabel
) mozilla::AutoProfilerLabel(
26 "", nullptr, aCategoryPair
,
28 js::ProfilingStackFrame::Flags::LABEL_DETERMINED_BY_CATEGORY_PAIR
));
32 void gecko_profiler_destruct_label(mozilla::AutoProfilerLabel
* aAutoLabel
) {
33 #ifdef MOZ_GECKO_PROFILER
34 aAutoLabel
->~AutoProfilerLabel();
38 void gecko_profiler_construct_timestamp_now(mozilla::TimeStamp
* aTimeStamp
) {
39 new (aTimeStamp
) mozilla::TimeStamp(mozilla::TimeStamp::Now());
42 void gecko_profiler_clone_timestamp(const mozilla::TimeStamp
* aSrcTimeStamp
,
43 mozilla::TimeStamp
* aDestTimeStamp
) {
44 new (aDestTimeStamp
) mozilla::TimeStamp(*aSrcTimeStamp
);
47 void gecko_profiler_destruct_timestamp(mozilla::TimeStamp
* aTimeStamp
) {
48 aTimeStamp
->~TimeStamp();
51 void gecko_profiler_add_timestamp(const mozilla::TimeStamp
* aTimeStamp
,
52 mozilla::TimeStamp
* aDestTimeStamp
,
53 double aMicroseconds
) {
54 new (aDestTimeStamp
) mozilla::TimeStamp(
55 *aTimeStamp
+ mozilla::TimeDuration::FromMicroseconds(aMicroseconds
));
58 void gecko_profiler_subtract_timestamp(const mozilla::TimeStamp
* aTimeStamp
,
59 mozilla::TimeStamp
* aDestTimeStamp
,
60 double aMicroseconds
) {
61 new (aDestTimeStamp
) mozilla::TimeStamp(
62 *aTimeStamp
- mozilla::TimeDuration::FromMicroseconds(aMicroseconds
));
65 void gecko_profiler_construct_marker_timing_instant_at(
66 mozilla::MarkerTiming
* aMarkerTiming
, const mozilla::TimeStamp
* aTime
) {
67 #ifdef MOZ_GECKO_PROFILER
68 static_assert(std::is_trivially_copyable_v
<mozilla::MarkerTiming
>);
69 mozilla::MarkerTiming::UnsafeConstruct(aMarkerTiming
, *aTime
,
71 mozilla::MarkerTiming::Phase::Instant
);
75 void gecko_profiler_construct_marker_timing_instant_now(
76 mozilla::MarkerTiming
* aMarkerTiming
) {
77 #ifdef MOZ_GECKO_PROFILER
78 static_assert(std::is_trivially_copyable_v
<mozilla::MarkerTiming
>);
79 mozilla::MarkerTiming::UnsafeConstruct(
80 aMarkerTiming
, mozilla::TimeStamp::Now(), mozilla::TimeStamp
{},
81 mozilla::MarkerTiming::Phase::Instant
);
85 void gecko_profiler_construct_marker_timing_interval(
86 mozilla::MarkerTiming
* aMarkerTiming
, const mozilla::TimeStamp
* aStartTime
,
87 const mozilla::TimeStamp
* aEndTime
) {
88 #ifdef MOZ_GECKO_PROFILER
89 static_assert(std::is_trivially_copyable_v
<mozilla::MarkerTiming
>);
90 mozilla::MarkerTiming::UnsafeConstruct(
91 aMarkerTiming
, *aStartTime
, *aEndTime
,
92 mozilla::MarkerTiming::Phase::Interval
);
96 void gecko_profiler_construct_marker_timing_interval_until_now_from(
97 mozilla::MarkerTiming
* aMarkerTiming
,
98 const mozilla::TimeStamp
* aStartTime
) {
99 #ifdef MOZ_GECKO_PROFILER
100 static_assert(std::is_trivially_copyable_v
<mozilla::MarkerTiming
>);
101 mozilla::MarkerTiming::UnsafeConstruct(
102 aMarkerTiming
, *aStartTime
, mozilla::TimeStamp::Now(),
103 mozilla::MarkerTiming::Phase::Interval
);
107 void gecko_profiler_construct_marker_timing_interval_start(
108 mozilla::MarkerTiming
* aMarkerTiming
, const mozilla::TimeStamp
* aTime
) {
109 #ifdef MOZ_GECKO_PROFILER
110 static_assert(std::is_trivially_copyable_v
<mozilla::MarkerTiming
>);
111 mozilla::MarkerTiming::UnsafeConstruct(
112 aMarkerTiming
, *aTime
, mozilla::TimeStamp
{},
113 mozilla::MarkerTiming::Phase::IntervalStart
);
117 void gecko_profiler_construct_marker_timing_interval_end(
118 mozilla::MarkerTiming
* aMarkerTiming
, const mozilla::TimeStamp
* aTime
) {
119 #ifdef MOZ_GECKO_PROFILER
120 static_assert(std::is_trivially_copyable_v
<mozilla::MarkerTiming
>);
121 mozilla::MarkerTiming::UnsafeConstruct(
122 aMarkerTiming
, mozilla::TimeStamp
{}, *aTime
,
123 mozilla::MarkerTiming::Phase::IntervalEnd
);
127 void gecko_profiler_destruct_marker_timing(
128 mozilla::MarkerTiming
* aMarkerTiming
) {
129 #ifdef MOZ_GECKO_PROFILER
130 aMarkerTiming
->~MarkerTiming();
134 mozilla::MarkerSchema
* gecko_profiler_construct_marker_schema(
135 const mozilla::MarkerSchema::Location
* aLocations
, size_t aLength
) {
136 #ifdef MOZ_GECKO_PROFILER
137 return new mozilla::MarkerSchema(aLocations
, aLength
);
143 mozilla::MarkerSchema
*
144 gecko_profiler_construct_marker_schema_with_special_front_end_location() {
145 #ifdef MOZ_GECKO_PROFILER
146 return new mozilla::MarkerSchema(
147 mozilla::MarkerSchema::SpecialFrontendLocation
{});
153 void gecko_profiler_destruct_marker_schema(
154 mozilla::MarkerSchema
* aMarkerSchema
) {
155 #ifdef MOZ_GECKO_PROFILER
156 delete aMarkerSchema
;
160 void gecko_profiler_marker_schema_set_chart_label(
161 mozilla::MarkerSchema
* aSchema
, const char* aLabel
, size_t aLabelLength
) {
162 #ifdef MOZ_GECKO_PROFILER
163 aSchema
->SetChartLabel(std::string(aLabel
, aLabelLength
));
167 void gecko_profiler_marker_schema_set_tooltip_label(
168 mozilla::MarkerSchema
* aSchema
, const char* aLabel
, size_t aLabelLength
) {
169 #ifdef MOZ_GECKO_PROFILER
170 aSchema
->SetTooltipLabel(std::string(aLabel
, aLabelLength
));
174 void gecko_profiler_marker_schema_set_table_label(
175 mozilla::MarkerSchema
* aSchema
, const char* aLabel
, size_t aLabelLength
) {
176 #ifdef MOZ_GECKO_PROFILER
177 aSchema
->SetTableLabel(std::string(aLabel
, aLabelLength
));
181 void gecko_profiler_marker_schema_set_all_labels(mozilla::MarkerSchema
* aSchema
,
183 size_t aLabelLength
) {
184 #ifdef MOZ_GECKO_PROFILER
185 aSchema
->SetAllLabels(std::string(aLabel
, aLabelLength
));
189 void gecko_profiler_marker_schema_add_key_format(
190 mozilla::MarkerSchema
* aSchema
, const char* aKey
, size_t aKeyLength
,
191 mozilla::MarkerSchema::Format aFormat
) {
192 #ifdef MOZ_GECKO_PROFILER
193 aSchema
->AddKeyFormat(std::string(aKey
, aKeyLength
), aFormat
);
197 void gecko_profiler_marker_schema_add_key_label_format(
198 mozilla::MarkerSchema
* aSchema
, const char* aKey
, size_t aKeyLength
,
199 const char* aLabel
, size_t aLabelLength
,
200 mozilla::MarkerSchema::Format aFormat
) {
201 #ifdef MOZ_GECKO_PROFILER
202 aSchema
->AddKeyLabelFormat(std::string(aKey
, aKeyLength
),
203 std::string(aLabel
, aLabelLength
), aFormat
);
207 void gecko_profiler_marker_schema_add_key_format_searchable(
208 mozilla::MarkerSchema
* aSchema
, const char* aKey
, size_t aKeyLength
,
209 mozilla::MarkerSchema::Format aFormat
,
210 mozilla::MarkerSchema::Searchable aSearchable
) {
211 #ifdef MOZ_GECKO_PROFILER
212 aSchema
->AddKeyFormatSearchable(std::string(aKey
, aKeyLength
), aFormat
,
217 void gecko_profiler_marker_schema_add_key_label_format_searchable(
218 mozilla::MarkerSchema
* aSchema
, const char* aKey
, size_t aKeyLength
,
219 const char* aLabel
, size_t aLabelLength
,
220 mozilla::MarkerSchema::Format aFormat
,
221 mozilla::MarkerSchema::Searchable aSearchable
) {
222 #ifdef MOZ_GECKO_PROFILER
223 aSchema
->AddKeyLabelFormatSearchable(std::string(aKey
, aKeyLength
),
224 std::string(aLabel
, aLabelLength
),
225 aFormat
, aSearchable
);
229 void gecko_profiler_marker_schema_add_static_label_value(
230 mozilla::MarkerSchema
* aSchema
, const char* aLabel
, size_t aLabelLength
,
231 const char* aValue
, size_t aValueLength
) {
232 #ifdef MOZ_GECKO_PROFILER
233 aSchema
->AddStaticLabelValue(std::string(aLabel
, aLabelLength
),
234 std::string(aValue
, aValueLength
));
238 void gecko_profiler_marker_schema_stream(
239 mozilla::baseprofiler::SpliceableJSONWriter
* aWriter
, const char* aName
,
240 size_t aNameLength
, mozilla::MarkerSchema
* aMarkerSchema
,
241 void* aStreamedNamesSet
) {
242 #ifdef MOZ_GECKO_PROFILER
243 auto* streamedNames
= static_cast<std::set
<std::string
>*>(aStreamedNamesSet
);
244 // std::set.insert(T&&) returns a pair, its `second` is true if the element
245 // was actually inserted (i.e., it was not there yet.).
246 const bool didInsert
=
247 streamedNames
->insert(std::string(aName
, aNameLength
)).second
;
249 std::move(*aMarkerSchema
)
250 .Stream(*aWriter
, mozilla::Span(aName
, aNameLength
));
255 void gecko_profiler_json_writer_int_property(
256 mozilla::baseprofiler::SpliceableJSONWriter
* aWriter
, const char* aName
,
257 size_t aNameLength
, int64_t aValue
) {
258 #ifdef MOZ_GECKO_PROFILER
259 aWriter
->IntProperty(mozilla::Span(aName
, aNameLength
), aValue
);
263 void gecko_profiler_json_writer_float_property(
264 mozilla::baseprofiler::SpliceableJSONWriter
* aWriter
, const char* aName
,
265 size_t aNameLength
, double aValue
) {
266 #ifdef MOZ_GECKO_PROFILER
267 aWriter
->DoubleProperty(mozilla::Span(aName
, aNameLength
), aValue
);
271 void gecko_profiler_json_writer_bool_property(
272 mozilla::baseprofiler::SpliceableJSONWriter
* aWriter
, const char* aName
,
273 size_t aNameLength
, bool aValue
) {
274 #ifdef MOZ_GECKO_PROFILER
275 aWriter
->BoolProperty(mozilla::Span(aName
, aNameLength
), aValue
);
278 void gecko_profiler_json_writer_string_property(
279 mozilla::baseprofiler::SpliceableJSONWriter
* aWriter
, const char* aName
,
280 size_t aNameLength
, const char* aValue
, size_t aValueLength
) {
281 #ifdef MOZ_GECKO_PROFILER
282 aWriter
->StringProperty(mozilla::Span(aName
, aNameLength
),
283 mozilla::Span(aValue
, aValueLength
));
287 void gecko_profiler_json_writer_unique_string_property(
288 mozilla::baseprofiler::SpliceableJSONWriter
* aWriter
, const char* aName
,
289 size_t aNameLength
, const char* aValue
, size_t aValueLength
) {
290 #ifdef MOZ_GECKO_PROFILER
291 aWriter
->UniqueStringProperty(mozilla::Span(aName
, aNameLength
),
292 mozilla::Span(aValue
, aValueLength
));
296 void gecko_profiler_json_writer_null_property(
297 mozilla::baseprofiler::SpliceableJSONWriter
* aWriter
, const char* aName
,
298 size_t aNameLength
) {
299 #ifdef MOZ_GECKO_PROFILER
300 aWriter
->NullProperty(mozilla::Span(aName
, aNameLength
));
304 void gecko_profiler_add_marker_untyped(
305 const char* aName
, size_t aNameLength
,
306 mozilla::baseprofiler::ProfilingCategoryPair aCategoryPair
,
307 mozilla::MarkerTiming
* aMarkerTiming
,
308 mozilla::StackCaptureOptions aStackCaptureOptions
) {
309 #ifdef MOZ_GECKO_PROFILER
311 mozilla::ProfilerString8View(aName
, aNameLength
),
312 mozilla::MarkerCategory
{aCategoryPair
},
313 mozilla::MarkerOptions(
314 std::move(*aMarkerTiming
),
315 mozilla::MarkerStack::WithCaptureOptions(aStackCaptureOptions
)));
319 void gecko_profiler_add_marker_text(
320 const char* aName
, size_t aNameLength
,
321 mozilla::baseprofiler::ProfilingCategoryPair aCategoryPair
,
322 mozilla::MarkerTiming
* aMarkerTiming
,
323 mozilla::StackCaptureOptions aStackCaptureOptions
, const char* aText
,
324 size_t aTextLength
) {
325 #ifdef MOZ_GECKO_PROFILER
327 mozilla::ProfilerString8View(aName
, aNameLength
),
328 mozilla::MarkerCategory
{aCategoryPair
},
329 mozilla::MarkerOptions(
330 std::move(*aMarkerTiming
),
331 mozilla::MarkerStack::WithCaptureOptions(aStackCaptureOptions
)),
332 geckoprofiler::markers::TextMarker
{},
333 mozilla::ProfilerString8View(aText
, aTextLength
));
337 void gecko_profiler_add_marker(
338 const char* aName
, size_t aNameLength
,
339 mozilla::baseprofiler::ProfilingCategoryPair aCategoryPair
,
340 mozilla::MarkerTiming
* aMarkerTiming
,
341 mozilla::StackCaptureOptions aStackCaptureOptions
, uint8_t aMarkerTag
,
342 const uint8_t* aPayload
, size_t aPayloadSize
) {
343 #ifdef MOZ_GECKO_PROFILER
344 // Copy the marker timing and create the marker option.
345 mozilla::MarkerOptions
markerOptions(
346 std::move(*aMarkerTiming
),
347 mozilla::MarkerStack::WithCaptureOptions(aStackCaptureOptions
));
349 // Currently it's not possible to add a threadId option, but we will
351 if (markerOptions
.ThreadId().IsUnspecified()) {
352 // If yet unspecified, set thread to this thread where the marker is added.
353 markerOptions
.Set(mozilla::MarkerThreadId::CurrentThread());
356 auto& buffer
= profiler_get_core_buffer();
357 mozilla::Span
payload(aPayload
, aPayloadSize
);
359 mozilla::StackCaptureOptions captureOptions
=
360 markerOptions
.Stack().CaptureOptions();
361 if (captureOptions
!= mozilla::StackCaptureOptions::NoStack
&&
362 // Do not capture a stack if the NoMarkerStacks feature is set.
363 profiler_active_without_feature(ProfilerFeature::NoMarkerStacks
)) {
364 // A capture was requested, let's attempt to do it here&now. This avoids a
365 // lot of allocations that would be necessary if capturing a backtrace
367 // TODO use a local on-stack byte buffer to remove last allocation.
368 // TODO reduce internal profiler stack levels, see bug 1659872.
369 mozilla::ProfileBufferChunkManagerSingle
chunkManager(
370 mozilla::ProfileBufferChunkManager::scExpectedMaximumStackSize
);
371 mozilla::ProfileChunkedBuffer
chunkedBuffer(
372 mozilla::ProfileChunkedBuffer::ThreadSafety::WithoutMutex
,
374 markerOptions
.StackRef().UseRequestedBacktrace(
375 profiler_capture_backtrace_into(chunkedBuffer
, captureOptions
)
379 // This call must be made from here, while chunkedBuffer is in scope.
381 mozilla::ProfileBufferEntryKind::Marker
, markerOptions
,
382 mozilla::ProfilerString8View(aName
, aNameLength
),
383 mozilla::MarkerCategory
{aCategoryPair
},
384 mozilla::base_profiler_markers_detail::Streaming::DeserializerTag(
386 mozilla::MarkerPayloadType::Rust
, payload
);
391 mozilla::ProfileBufferEntryKind::Marker
, markerOptions
,
392 mozilla::ProfilerString8View(aName
, aNameLength
),
393 mozilla::MarkerCategory
{aCategoryPair
},
394 mozilla::base_profiler_markers_detail::Streaming::DeserializerTag(
396 mozilla::MarkerPayloadType::Rust
, payload
);