Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* FFI functions for Profiler Rust API to call into profiler */
#include "ProfilerBindings.h"
#include "GeckoProfiler.h"
#include <set>
#include <type_traits>
void gecko_profiler_register_thread(const char* aName) {
PROFILER_REGISTER_THREAD(aName);
}
void gecko_profiler_unregister_thread() { PROFILER_UNREGISTER_THREAD(); }
void gecko_profiler_construct_label(mozilla::AutoProfilerLabel* aAutoLabel,
JS::ProfilingCategoryPair aCategoryPair) {
#ifdef MOZ_GECKO_PROFILER
new (aAutoLabel) mozilla::AutoProfilerLabel(
"", nullptr, aCategoryPair,
uint32_t(
js::ProfilingStackFrame::Flags::LABEL_DETERMINED_BY_CATEGORY_PAIR));
#endif
}
void gecko_profiler_destruct_label(mozilla::AutoProfilerLabel* aAutoLabel) {
#ifdef MOZ_GECKO_PROFILER
aAutoLabel->~AutoProfilerLabel();
#endif
}
void gecko_profiler_construct_timestamp_now(mozilla::TimeStamp* aTimeStamp) {
new (aTimeStamp) mozilla::TimeStamp(mozilla::TimeStamp::Now());
}
void gecko_profiler_clone_timestamp(const mozilla::TimeStamp* aSrcTimeStamp,
mozilla::TimeStamp* aDestTimeStamp) {
new (aDestTimeStamp) mozilla::TimeStamp(*aSrcTimeStamp);
}
void gecko_profiler_destruct_timestamp(mozilla::TimeStamp* aTimeStamp) {
aTimeStamp->~TimeStamp();
}
void gecko_profiler_add_timestamp(const mozilla::TimeStamp* aTimeStamp,
mozilla::TimeStamp* aDestTimeStamp,
double aMicroseconds) {
new (aDestTimeStamp) mozilla::TimeStamp(
*aTimeStamp + mozilla::TimeDuration::FromMicroseconds(aMicroseconds));
}
void gecko_profiler_subtract_timestamp(const mozilla::TimeStamp* aTimeStamp,
mozilla::TimeStamp* aDestTimeStamp,
double aMicroseconds) {
new (aDestTimeStamp) mozilla::TimeStamp(
*aTimeStamp - mozilla::TimeDuration::FromMicroseconds(aMicroseconds));
}
void gecko_profiler_construct_marker_timing_instant_at(
mozilla::MarkerTiming* aMarkerTiming, const mozilla::TimeStamp* aTime) {
#ifdef MOZ_GECKO_PROFILER
static_assert(std::is_trivially_copyable_v<mozilla::MarkerTiming>);
mozilla::MarkerTiming::UnsafeConstruct(aMarkerTiming, *aTime,
mozilla::TimeStamp{},
mozilla::MarkerTiming::Phase::Instant);
#endif
}
void gecko_profiler_construct_marker_timing_instant_now(
mozilla::MarkerTiming* aMarkerTiming) {
#ifdef MOZ_GECKO_PROFILER
static_assert(std::is_trivially_copyable_v<mozilla::MarkerTiming>);
mozilla::MarkerTiming::UnsafeConstruct(
aMarkerTiming, mozilla::TimeStamp::Now(), mozilla::TimeStamp{},
mozilla::MarkerTiming::Phase::Instant);
#endif
}
void gecko_profiler_construct_marker_timing_interval(
mozilla::MarkerTiming* aMarkerTiming, const mozilla::TimeStamp* aStartTime,
const mozilla::TimeStamp* aEndTime) {
#ifdef MOZ_GECKO_PROFILER
static_assert(std::is_trivially_copyable_v<mozilla::MarkerTiming>);
mozilla::MarkerTiming::UnsafeConstruct(
aMarkerTiming, *aStartTime, *aEndTime,
mozilla::MarkerTiming::Phase::Interval);
#endif
}
void gecko_profiler_construct_marker_timing_interval_until_now_from(
mozilla::MarkerTiming* aMarkerTiming,
const mozilla::TimeStamp* aStartTime) {
#ifdef MOZ_GECKO_PROFILER
static_assert(std::is_trivially_copyable_v<mozilla::MarkerTiming>);
mozilla::MarkerTiming::UnsafeConstruct(
aMarkerTiming, *aStartTime, mozilla::TimeStamp::Now(),
mozilla::MarkerTiming::Phase::Interval);
#endif
}
void gecko_profiler_construct_marker_timing_interval_start(
mozilla::MarkerTiming* aMarkerTiming, const mozilla::TimeStamp* aTime) {
#ifdef MOZ_GECKO_PROFILER
static_assert(std::is_trivially_copyable_v<mozilla::MarkerTiming>);
mozilla::MarkerTiming::UnsafeConstruct(
aMarkerTiming, *aTime, mozilla::TimeStamp{},
mozilla::MarkerTiming::Phase::IntervalStart);
#endif
}
void gecko_profiler_construct_marker_timing_interval_end(
mozilla::MarkerTiming* aMarkerTiming, const mozilla::TimeStamp* aTime) {
#ifdef MOZ_GECKO_PROFILER
static_assert(std::is_trivially_copyable_v<mozilla::MarkerTiming>);
mozilla::MarkerTiming::UnsafeConstruct(
aMarkerTiming, mozilla::TimeStamp{}, *aTime,
mozilla::MarkerTiming::Phase::IntervalEnd);
#endif
}
void gecko_profiler_destruct_marker_timing(
mozilla::MarkerTiming* aMarkerTiming) {
#ifdef MOZ_GECKO_PROFILER
aMarkerTiming->~MarkerTiming();
#endif
}
mozilla::MarkerSchema* gecko_profiler_construct_marker_schema(
const mozilla::MarkerSchema::Location* aLocations, size_t aLength) {
#ifdef MOZ_GECKO_PROFILER
return new mozilla::MarkerSchema(aLocations, aLength);
#else
return nullptr;
#endif
}
mozilla::MarkerSchema*
gecko_profiler_construct_marker_schema_with_special_front_end_location() {
#ifdef MOZ_GECKO_PROFILER
return new mozilla::MarkerSchema(
mozilla::MarkerSchema::SpecialFrontendLocation{});
#else
return nullptr;
#endif
}
void gecko_profiler_destruct_marker_schema(
mozilla::MarkerSchema* aMarkerSchema) {
#ifdef MOZ_GECKO_PROFILER
delete aMarkerSchema;
#endif
}
void gecko_profiler_marker_schema_set_chart_label(
mozilla::MarkerSchema* aSchema, const char* aLabel, size_t aLabelLength) {
#ifdef MOZ_GECKO_PROFILER
aSchema->SetChartLabel(std::string(aLabel, aLabelLength));
#endif
}
void gecko_profiler_marker_schema_set_tooltip_label(
mozilla::MarkerSchema* aSchema, const char* aLabel, size_t aLabelLength) {
#ifdef MOZ_GECKO_PROFILER
aSchema->SetTooltipLabel(std::string(aLabel, aLabelLength));
#endif
}
void gecko_profiler_marker_schema_set_table_label(
mozilla::MarkerSchema* aSchema, const char* aLabel, size_t aLabelLength) {
#ifdef MOZ_GECKO_PROFILER
aSchema->SetTableLabel(std::string(aLabel, aLabelLength));
#endif
}
void gecko_profiler_marker_schema_set_all_labels(mozilla::MarkerSchema* aSchema,
const char* aLabel,
size_t aLabelLength) {
#ifdef MOZ_GECKO_PROFILER
aSchema->SetAllLabels(std::string(aLabel, aLabelLength));
#endif
}
void gecko_profiler_marker_schema_add_key_format(
mozilla::MarkerSchema* aSchema, const char* aKey, size_t aKeyLength,
mozilla::MarkerSchema::Format aFormat) {
#ifdef MOZ_GECKO_PROFILER
aSchema->AddKeyFormat(std::string(aKey, aKeyLength), aFormat);
#endif
}
void gecko_profiler_marker_schema_add_key_label_format(
mozilla::MarkerSchema* aSchema, const char* aKey, size_t aKeyLength,
const char* aLabel, size_t aLabelLength,
mozilla::MarkerSchema::Format aFormat) {
#ifdef MOZ_GECKO_PROFILER
aSchema->AddKeyLabelFormat(std::string(aKey, aKeyLength),
std::string(aLabel, aLabelLength), aFormat);
#endif
}
void gecko_profiler_marker_schema_add_key_format_searchable(
mozilla::MarkerSchema* aSchema, const char* aKey, size_t aKeyLength,
mozilla::MarkerSchema::Format aFormat,
mozilla::MarkerSchema::Searchable aSearchable) {
#ifdef MOZ_GECKO_PROFILER
aSchema->AddKeyFormatSearchable(std::string(aKey, aKeyLength), aFormat,
aSearchable);
#endif
}
void gecko_profiler_marker_schema_add_key_label_format_searchable(
mozilla::MarkerSchema* aSchema, const char* aKey, size_t aKeyLength,
const char* aLabel, size_t aLabelLength,
mozilla::MarkerSchema::Format aFormat,
mozilla::MarkerSchema::Searchable aSearchable) {
#ifdef MOZ_GECKO_PROFILER
aSchema->AddKeyLabelFormatSearchable(std::string(aKey, aKeyLength),
std::string(aLabel, aLabelLength),
aFormat, aSearchable);
#endif
}
void gecko_profiler_marker_schema_add_static_label_value(
mozilla::MarkerSchema* aSchema, const char* aLabel, size_t aLabelLength,
const char* aValue, size_t aValueLength) {
#ifdef MOZ_GECKO_PROFILER
aSchema->AddStaticLabelValue(std::string(aLabel, aLabelLength),
std::string(aValue, aValueLength));
#endif
}
void gecko_profiler_marker_schema_stream(
mozilla::baseprofiler::SpliceableJSONWriter* aWriter, const char* aName,
size_t aNameLength, mozilla::MarkerSchema* aMarkerSchema,
void* aStreamedNamesSet) {
#ifdef MOZ_GECKO_PROFILER
auto* streamedNames = static_cast<std::set<std::string>*>(aStreamedNamesSet);
// std::set.insert(T&&) returns a pair, its `second` is true if the element
// was actually inserted (i.e., it was not there yet.).
const bool didInsert =
streamedNames->insert(std::string(aName, aNameLength)).second;
if (didInsert) {
std::move(*aMarkerSchema)
.Stream(*aWriter, mozilla::Span(aName, aNameLength));
}
#endif
}
void gecko_profiler_json_writer_int_property(
mozilla::baseprofiler::SpliceableJSONWriter* aWriter, const char* aName,
size_t aNameLength, int64_t aValue) {
#ifdef MOZ_GECKO_PROFILER
aWriter->IntProperty(mozilla::Span(aName, aNameLength), aValue);
#endif
}
void gecko_profiler_json_writer_float_property(
mozilla::baseprofiler::SpliceableJSONWriter* aWriter, const char* aName,
size_t aNameLength, double aValue) {
#ifdef MOZ_GECKO_PROFILER
aWriter->DoubleProperty(mozilla::Span(aName, aNameLength), aValue);
#endif
}
void gecko_profiler_json_writer_bool_property(
mozilla::baseprofiler::SpliceableJSONWriter* aWriter, const char* aName,
size_t aNameLength, bool aValue) {
#ifdef MOZ_GECKO_PROFILER
aWriter->BoolProperty(mozilla::Span(aName, aNameLength), aValue);
#endif
}
void gecko_profiler_json_writer_string_property(
mozilla::baseprofiler::SpliceableJSONWriter* aWriter, const char* aName,
size_t aNameLength, const char* aValue, size_t aValueLength) {
#ifdef MOZ_GECKO_PROFILER
aWriter->StringProperty(mozilla::Span(aName, aNameLength),
mozilla::Span(aValue, aValueLength));
#endif
}
void gecko_profiler_json_writer_unique_string_property(
mozilla::baseprofiler::SpliceableJSONWriter* aWriter, const char* aName,
size_t aNameLength, const char* aValue, size_t aValueLength) {
#ifdef MOZ_GECKO_PROFILER
aWriter->UniqueStringProperty(mozilla::Span(aName, aNameLength),
mozilla::Span(aValue, aValueLength));
#endif
}
void gecko_profiler_json_writer_null_property(
mozilla::baseprofiler::SpliceableJSONWriter* aWriter, const char* aName,
size_t aNameLength) {
#ifdef MOZ_GECKO_PROFILER
aWriter->NullProperty(mozilla::Span(aName, aNameLength));
#endif
}
void gecko_profiler_add_marker_untyped(
const char* aName, size_t aNameLength,
mozilla::baseprofiler::ProfilingCategoryPair aCategoryPair,
mozilla::MarkerTiming* aMarkerTiming,
mozilla::StackCaptureOptions aStackCaptureOptions) {
#ifdef MOZ_GECKO_PROFILER
profiler_add_marker(
mozilla::ProfilerString8View(aName, aNameLength),
mozilla::MarkerCategory{aCategoryPair},
mozilla::MarkerOptions(
std::move(*aMarkerTiming),
mozilla::MarkerStack::WithCaptureOptions(aStackCaptureOptions)));
#endif
}
void gecko_profiler_add_marker_text(
const char* aName, size_t aNameLength,
mozilla::baseprofiler::ProfilingCategoryPair aCategoryPair,
mozilla::MarkerTiming* aMarkerTiming,
mozilla::StackCaptureOptions aStackCaptureOptions, const char* aText,
size_t aTextLength) {
#ifdef MOZ_GECKO_PROFILER
profiler_add_marker(
mozilla::ProfilerString8View(aName, aNameLength),
mozilla::MarkerCategory{aCategoryPair},
mozilla::MarkerOptions(
std::move(*aMarkerTiming),
mozilla::MarkerStack::WithCaptureOptions(aStackCaptureOptions)),
geckoprofiler::markers::TextMarker{},
mozilla::ProfilerString8View(aText, aTextLength));
#endif
}
void gecko_profiler_add_marker(
const char* aName, size_t aNameLength,
mozilla::baseprofiler::ProfilingCategoryPair aCategoryPair,
mozilla::MarkerTiming* aMarkerTiming,
mozilla::StackCaptureOptions aStackCaptureOptions, uint8_t aMarkerTag,
const uint8_t* aPayload, size_t aPayloadSize) {
#ifdef MOZ_GECKO_PROFILER
// Copy the marker timing and create the marker option.
mozilla::MarkerOptions markerOptions(
std::move(*aMarkerTiming),
mozilla::MarkerStack::WithCaptureOptions(aStackCaptureOptions));
// Currently it's not possible to add a threadId option, but we will
// have it soon.
if (markerOptions.ThreadId().IsUnspecified()) {
// If yet unspecified, set thread to this thread where the marker is added.
markerOptions.Set(mozilla::MarkerThreadId::CurrentThread());
}
auto& buffer = profiler_get_core_buffer();
mozilla::Span payload(aPayload, aPayloadSize);
mozilla::StackCaptureOptions captureOptions =
markerOptions.Stack().CaptureOptions();
if (captureOptions != mozilla::StackCaptureOptions::NoStack &&
// Do not capture a stack if the NoMarkerStacks feature is set.
profiler_active_without_feature(ProfilerFeature::NoMarkerStacks)) {
// A capture was requested, let's attempt to do it here&now. This avoids a
// lot of allocations that would be necessary if capturing a backtrace
// separately.
// TODO use a local on-stack byte buffer to remove last allocation.
// TODO reduce internal profiler stack levels, see bug 1659872.
mozilla::ProfileBufferChunkManagerSingle chunkManager(
mozilla::ProfileBufferChunkManager::scExpectedMaximumStackSize);
mozilla::ProfileChunkedBuffer chunkedBuffer(
mozilla::ProfileChunkedBuffer::ThreadSafety::WithoutMutex,
chunkManager);
markerOptions.StackRef().UseRequestedBacktrace(
profiler_capture_backtrace_into(chunkedBuffer, captureOptions)
? &chunkedBuffer
: nullptr);
// This call must be made from here, while chunkedBuffer is in scope.
buffer.PutObjects(
mozilla::ProfileBufferEntryKind::Marker, markerOptions,
mozilla::ProfilerString8View(aName, aNameLength),
mozilla::MarkerCategory{aCategoryPair},
mozilla::base_profiler_markers_detail::Streaming::DeserializerTag(
aMarkerTag),
mozilla::MarkerPayloadType::Rust, payload);
return;
}
buffer.PutObjects(
mozilla::ProfileBufferEntryKind::Marker, markerOptions,
mozilla::ProfilerString8View(aName, aNameLength),
mozilla::MarkerCategory{aCategoryPair},
mozilla::base_profiler_markers_detail::Streaming::DeserializerTag(
aMarkerTag),
mozilla::MarkerPayloadType::Rust, payload);
#endif
}