commit 0f91735b3bd960f7bb9b720cc75a4bd99bf661ca
parent 4ffa205cca52b7c040a251578b963f260bca1a50
Author: Florian Quèze <florian@queze.net>
Date: Mon, 20 Oct 2025 19:28:12 +0000
Bug 1992094 - Record thermal state as profiler markers on Mac, r=mstange,profiler-reviewers.
Differential Revision: https://phabricator.services.mozilla.com/D267216
Diffstat:
3 files changed, 89 insertions(+), 0 deletions(-)
diff --git a/tools/profiler/core/ProfilerThermalState-mac.mm b/tools/profiler/core/ProfilerThermalState-mac.mm
@@ -0,0 +1,74 @@
+/* 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/. */
+
+#include "mozilla/ProfilerMarkers.h"
+#include "mozilla/ProfilerState.h"
+#include <Foundation/Foundation.h>
+
+static nsLiteralCString ThermalStateToString(NSProcessInfoThermalState state) {
+ switch (state) {
+ case NSProcessInfoThermalStateNominal:
+ return "Nominal"_ns;
+ case NSProcessInfoThermalStateFair:
+ return "Fair"_ns;
+ case NSProcessInfoThermalStateSerious:
+ return "Serious"_ns;
+ case NSProcessInfoThermalStateCritical:
+ return "Critical"_ns;
+ default:
+ return "Unknown"_ns;
+ }
+}
+
+static void AddThermalStateMarker() {
+ NSProcessInfoThermalState state = [[NSProcessInfo processInfo] thermalState];
+ PROFILER_MARKER_TEXT(
+ "Thermal State", OTHER,
+ mozilla::MarkerOptions(mozilla::MarkerThreadId::MainThread()),
+ ThermalStateToString(state));
+}
+
+static id<NSObject> gThermalObserver = nil;
+
+static void ThermalStateCallback(ProfilingState aProfilingState) {
+ if (aProfilingState == ProfilingState::Started) {
+ if (gThermalObserver) {
+ return; // Already registered
+ }
+
+ // Add marker for current thermal state
+ AddThermalStateMarker();
+
+ // Register for thermal state change notifications
+ gThermalObserver = [[NSNotificationCenter defaultCenter]
+ addObserverForName:NSProcessInfoThermalStateDidChangeNotification
+ object:nil
+ queue:nil
+ usingBlock:^(NSNotification* note) {
+ AddThermalStateMarker();
+ }];
+ } else if (aProfilingState == ProfilingState::Pausing) {
+ // Add marker but keep observer active
+ AddThermalStateMarker();
+ } else if (aProfilingState == ProfilingState::Stopping) {
+ if (!gThermalObserver) {
+ return;
+ }
+
+ // Add final marker for thermal state
+ AddThermalStateMarker();
+
+ [[NSNotificationCenter defaultCenter] removeObserver:gThermalObserver];
+ gThermalObserver = nil;
+ }
+}
+
+void profiler_register_thermal_state_observer() {
+ profiler_add_state_change_callback(
+ AllProfilingStates(),
+ [](ProfilingState aProfilingState) {
+ ThermalStateCallback(aProfilingState);
+ },
+ 0);
+}
diff --git a/tools/profiler/core/platform.cpp b/tools/profiler/core/platform.cpp
@@ -297,6 +297,11 @@ void profiler_dump_and_stop();
// Forward declare the function to call when we need to start the profiler.
void profiler_start_from_signal();
+#if defined(GP_OS_darwin)
+// Forward declare thermal state observer function (macOS only)
+void profiler_register_thermal_state_observer();
+#endif
+
mozilla::Atomic<int, mozilla::MemoryOrdering::Relaxed> gSkipSampling;
#if defined(GP_OS_android)
@@ -6160,6 +6165,13 @@ void profiler_init(void* aStackTop) {
// so let's record it again now.
profiler_mark_thread_awake();
+#if defined(GP_OS_darwin)
+ // Register thermal state observer callback on macOS (parent process only)
+ if (XRE_IsParentProcess()) {
+ profiler_register_thermal_state_observer();
+ }
+#endif
+
invoke_profiler_state_change_callbacks(ProfilingState::Started);
// We do this with gPSMutex unlocked. The comment in profiler_stop() explains
diff --git a/tools/profiler/moz.build b/tools/profiler/moz.build
@@ -99,6 +99,9 @@ if CONFIG["MOZ_GECKO_PROFILER"]:
"core/EHABIStackWalk.cpp",
]
elif CONFIG["OS_TARGET"] == "Darwin":
+ UNIFIED_SOURCES += [
+ "core/ProfilerThermalState-mac.mm",
+ ]
if CONFIG["TARGET_CPU"] == "aarch64":
UNIFIED_SOURCES += [
"core/PowerCounters-mac-arm64.cpp",