/* 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/. */ #ifndef ProfilerRunnable_h #define ProfilerRunnable_h #include "GeckoProfiler.h" #include "nsIThreadPool.h" // Treat runnable profiling separately, as this can add considerable overhead // and ETW allows disabling it explicitly. static inline bool profiler_thread_is_profiling_runnables() { return profiler_thread_is_being_profiled(ThreadProfilingFeatures::Markers) || (profiler_is_etw_collecting_markers() && ETW::IsProfilingGroup( mozilla::MarkerSchema::ETWMarkerGroup::Scheduling)) || profiler_is_perfetto_tracing(); } #if !defined(MOZ_COLLECTING_RUNNABLE_TELEMETRY) # define AUTO_PROFILE_FOLLOWING_RUNNABLE(runnable) #else # define AUTO_PROFILE_FOLLOWING_RUNNABLE(runnable) \ mozilla::Maybe raiiRunnableMarker; \ if (profiler_thread_is_profiling_runnables()) { \ raiiRunnableMarker.emplace(runnable); \ } namespace mozilla { struct RunnableMarker : BaseMarkerType { static constexpr const char* Name = "Runnable"; static constexpr const char* Description = "Marker representing a runnable being executed."; using MS = MarkerSchema; static constexpr MS::PayloadField PayloadFields[] = { { "name", MS::InputType::CString, "Runnable Name", MS::Format::String, }, { "runnable", MS::InputType::Uint64, "Runnable", MS::Format::TerminatingFlow, }, }; static constexpr MS::Location Locations[] = {MS::Location::MarkerChart, MS::Location::MarkerTable}; static constexpr const char* ChartLabel = "{marker.data.name}"; static constexpr const char* TableLabel = "{marker.data.name}" " runnable: {marker.data.runnable}"; static constexpr bool IsStackBased = true; static constexpr MS::ETWMarkerGroup Group = MS::ETWMarkerGroup::Scheduling; static void TranslateMarkerInputToSchema(void* aContext, const nsCString& aName, Flow aFlow) { ETW::OutputMarkerSchema(aContext, RunnableMarker{}, aName, aFlow); } static void StreamJSONMarkerData(baseprofiler::SpliceableJSONWriter& aWriter, const nsCString& aName, Flow aFlow) { aWriter.StringProperty("name", aName); aWriter.FlowProperty("runnable", aFlow); } }; class MOZ_RAII AutoProfileRunnable { public: explicit AutoProfileRunnable(Runnable* aRunnable) : mStartTime(TimeStamp::Now()), mRunnable(Flow::FromPointer(aRunnable)) { aRunnable->GetName(mName); } explicit AutoProfileRunnable(nsIRunnable* aRunnable) : mStartTime(TimeStamp::Now()), mRunnable(Flow::FromPointer(aRunnable)) { nsCOMPtr threadPool = do_QueryInterface(aRunnable); if (threadPool) { // nsThreadPool::Run has its own call to AUTO_PROFILE_FOLLOWING_RUNNABLE, // avoid nesting runnable markers. return; } nsCOMPtr named = do_QueryInterface(aRunnable); if (named) { named->GetName(mName); } else { mName = "Unnamed runnable"; } } ~AutoProfileRunnable() { if (mName.IsEmpty()) { return; } AUTO_PROFILER_LABEL("AutoProfileRunnable", PROFILER); AUTO_PROFILER_STATS(AUTO_PROFILE_RUNNABLE); profiler_add_marker("Runnable", ::mozilla::baseprofiler::category::OTHER, MarkerTiming::IntervalUntilNowFrom(mStartTime), RunnableMarker{}, mName, mRunnable); } protected: TimeStamp mStartTime; nsAutoCString mName; Flow mRunnable; }; } // namespace mozilla #endif #endif // ProfilerRunnable_h