/* 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/. */ //! Gecko profiler state. use crate::gecko_bindings::structs::ThreadProfilingFeatures; /// Whether the Gecko profiler is currently active. /// A typical use of this API: /// ```rust /// if gecko_profiler::is_active() { /// // do something. /// } /// ``` /// /// This implementation must be kept in sync with /// `mozilla::profiler::detail::RacyFeatures::IsActive`. #[inline] pub fn is_active() -> bool { use crate::gecko_bindings::structs::mozilla::profiler::detail; let active_and_features = get_active_and_features(); (active_and_features & detail::RacyFeatures_Active) != 0 } /// Whether the Gecko profiler is currently active and unpaused. /// A typical use of this API: /// ```rust /// if gecko_profiler::is_active_and_unpaused() { /// // do something. /// } /// ``` /// /// This implementation must be kept in sync with /// `mozilla::profiler::detail::RacyFeatures::IsActiveAndUnpaused`. #[inline] pub fn is_active_and_unpaused() -> bool { use crate::gecko_bindings::structs::mozilla::profiler::detail; let active_and_features = get_active_and_features(); (active_and_features & detail::RacyFeatures_Active) != 0 && (active_and_features & detail::RacyFeatures_Paused) == 0 } /// Whether the Gecko Profiler can accept markers. /// This should be used before doing some potentially-expensive work that's used in a marker. E.g.: /// ```rust /// if gecko_profiler::current_thread_is_being_profiled_for_markers() { /// // Do something expensive and add the marker with that data. /// } /// ``` /// /// This implementation must be kept in sync with /// ProfilerMarkers.h:profiler_thread_is_being_profiled_for_markers #[inline] pub fn current_thread_is_being_profiled_for_markers() -> bool { current_thread_is_being_profiled(ThreadProfilingFeatures::Markers) || is_etw_collecting_markers() || is_perfetto_tracing() } /// Returns the value of atomic `RacyFeatures::sActiveAndFeatures` from the C++ side. #[inline] fn get_active_and_features() -> u32 { use crate::gecko_bindings::structs::mozilla::profiler::detail; use std::sync::atomic::{AtomicU32, Ordering}; // This is reaching for the C++ atomic value instead of calling an FFI // function to return this value. Because, calling an FFI function is much // more expensive compared to this method. That's why it's worth to go with // this solution for performance. But it's crucial to keep the implementation // of this and the callers in sync with the C++ counterparts. let active_and_features: &AtomicU32 = unsafe { let ptr: *const u32 = std::ptr::addr_of!(detail::RacyFeatures_sActiveAndFeatures); // TODO: Switch this to use `AtomicU32::from_ptr` once our Rust MSRV is at least 1.75.0 &*ptr.cast() }; active_and_features.load(Ordering::Relaxed) } /// This implementation must be kept in sync with /// `mozilla::profiler::detail::RacyFeatures::IsETWCollecting`. #[inline] fn is_etw_collecting_markers() -> bool { use crate::gecko_bindings::structs::mozilla::profiler::detail; let active_and_features = get_active_and_features(); (active_and_features & detail::RacyFeatures_ETWCollectionEnabled) != 0 } /// This implementation must be kept in sync with /// `mozilla::profiler::detail::RacyFeatures::IsPerfettoTracing`. #[inline] fn is_perfetto_tracing() -> bool { use crate::gecko_bindings::structs::mozilla::profiler::detail; let active_and_features = get_active_and_features(); (active_and_features & detail::RacyFeatures_PerfettoTracingEnabled) != 0 } /// This implementation must be kept in sync with /// `ProfilerThreadState.h:profiler_thread_is_being_profiled` #[inline] fn current_thread_is_being_profiled(thread_profiling_features: ThreadProfilingFeatures) -> bool { if !is_active_and_unpaused() { return false; } use crate::gecko_bindings::bindings; unsafe { bindings::gecko_profiler_current_thread_is_registered(thread_profiling_features) } }