Skip to content

Commit

Permalink
Bug 1747138 - Breakdown CPU and GPU time by process type, r=chutten,g…
Browse files Browse the repository at this point in the history
…svelto

Differential Revision: https://phabricator.services.mozilla.com/D134441
  • Loading branch information
fqueze committed Feb 3, 2022
1 parent 75ecedf commit 301e687
Show file tree
Hide file tree
Showing 11 changed files with 511 additions and 31 deletions.
7 changes: 7 additions & 0 deletions dom/base/nsContentUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
#include "mozilla/EventQueue.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/FlushType.h"
#include "mozilla/FOGIPC.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/HangAnnotations.h"
#include "mozilla/IMEStateManager.h"
Expand Down Expand Up @@ -10117,8 +10118,14 @@ nsContentUtils::UserInteractionObserver::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData) {
if (!strcmp(aTopic, kUserInteractionInactive)) {
if (sUserActive && XRE_IsParentProcess()) {
glean::RecordPowerMetrics();
}
sUserActive = false;
} else if (!strcmp(aTopic, kUserInteractionActive)) {
if (!sUserActive && XRE_IsParentProcess()) {
glean::RecordPowerMetrics();
}
sUserActive = true;
} else {
NS_WARNING("Unexpected observer notification");
Expand Down
6 changes: 6 additions & 0 deletions dom/ipc/ContentChild.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2839,6 +2839,12 @@ mozilla::ipc::IPCResult ContentChild::RecvNotifyProcessPriorityChanged(
ProcessPriorityToString(mProcessPriority)),
ProfilerString8View::WrapNullTerminatedString(
ProcessPriorityToString(aPriority)));

// Record FOG data before the priority change.
// Ignore the change if it's the first time we set the process priority.
if (mProcessPriority != hal::PROCESS_PRIORITY_UNKNOWN) {
glean::RecordPowerMetrics();
}
mProcessPriority = aPriority;

os->NotifyObservers(static_cast<nsIPropertyBag2*>(props),
Expand Down
2 changes: 2 additions & 0 deletions dom/ipc/ContentChild.h
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,8 @@ class ContentChild final : public PContentChild,
BrowsingContext* aStartingAt,
const DispatchBeforeUnloadToSubtreeResolver& aResolver);

hal::ProcessPriority GetProcessPriority() const { return mProcessPriority; }

private:
mozilla::ipc::IPCResult RecvFlushFOGData(FlushFOGDataResolver&& aResolver);

Expand Down
40 changes: 22 additions & 18 deletions dom/ipc/ProcessPriorityManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ class ProcessPriorityManagerImpl final : public nsIObserver,

static void StaticInit();
static bool PrefsEnabled();
static void SetProcessPriorityIfEnabled(int aPid, ProcessPriority aPriority);
static bool TestMode();

NS_DECL_ISUPPORTS
Expand Down Expand Up @@ -365,6 +366,17 @@ bool ProcessPriorityManagerImpl::PrefsEnabled() {
!StaticPrefs::dom_ipc_tabs_disabled();
}

/* static */
void ProcessPriorityManagerImpl::SetProcessPriorityIfEnabled(
int aPid, ProcessPriority aPriority) {
// The preference doesn't disable the process priority manager, but only its
// effect. This way the IPCs still happen and can be used to collect telemetry
// about CPU use.
if (PrefsEnabled()) {
hal::SetProcessPriority(aPid, aPriority);
}
}

/* static */
bool ProcessPriorityManagerImpl::TestMode() {
return StaticPrefs::dom_ipc_processPriorityManager_testMode();
Expand All @@ -382,20 +394,13 @@ void ProcessPriorityManagerImpl::StaticInit() {
return;
}

// If IPC tabs aren't enabled at startup, don't bother with any of this.
if (!PrefsEnabled()) {
LOG("InitProcessPriorityManager bailing due to prefs.");

// Run StaticInit() again if the prefs change. We don't expect this to
// happen in normal operation, but it happens during testing.
if (!sPrefListenersRegistered) {
sPrefListenersRegistered = true;
Preferences::RegisterCallback(PrefChangedCallback,
"dom.ipc.processPriorityManager.enabled");
Preferences::RegisterCallback(PrefChangedCallback,
"dom.ipc.tabs.disabled");
}
return;
// Run StaticInit() again if the prefs change. We don't expect this to
// happen in normal operation, but it happens during testing.
if (!sPrefListenersRegistered) {
sPrefListenersRegistered = true;
Preferences::RegisterCallback(PrefChangedCallback,
"dom.ipc.processPriorityManager.enabled");
Preferences::RegisterCallback(PrefChangedCallback, "dom.ipc.tabs.disabled");
}

sInitialized = true;
Expand Down Expand Up @@ -426,7 +431,7 @@ void ProcessPriorityManagerImpl::Init() {
// The parent process's priority never changes; set it here and then forget
// about it. We'll manage only subprocesses' priorities using the process
// priority manager.
hal::SetProcessPriority(getpid(), PROCESS_PRIORITY_PARENT_PROCESS);
SetProcessPriorityIfEnabled(getpid(), PROCESS_PRIORITY_PARENT_PROCESS);

nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
Expand Down Expand Up @@ -762,8 +767,7 @@ void ParticularProcessPriorityManager::SetPriorityNow(
return;
}

if (!ProcessPriorityManagerImpl::PrefsEnabled() || !mContentParent ||
mPriority == aPriority) {
if (!mContentParent || mPriority == aPriority) {
return;
}

Expand Down Expand Up @@ -794,7 +798,7 @@ void ParticularProcessPriorityManager::SetPriorityNow(
Telemetry::ScalarID::DOM_CONTENTPROCESS_OS_PRIORITY_LOWERED, 1);
}

hal::SetProcessPriority(Pid(), mPriority);
ProcessPriorityManagerImpl::SetProcessPriorityIfEnabled(Pid(), mPriority);

if (oldPriority != mPriority) {
ProcessPriorityManagerImpl::GetSingleton()->NotifyProcessPriorityChanged(
Expand Down
16 changes: 16 additions & 0 deletions hal/HalWakeLock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "Hal.h"
#include "base/process_util.h"
#include "mozilla/FOGIPC.h"
#include "mozilla/HalWakeLock.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
Expand Down Expand Up @@ -199,6 +200,14 @@ void ModifyWakeLock(const nsAString& aTopic, hal::WakeLockControl aLockAdjust,

WakeLockState oldState =
ComputeWakeLockState(totalCount.numLocks, totalCount.numHidden);

if (ComputeWakeLockState(totalCount.numLocks + aLockAdjust,
totalCount.numHidden + aHiddenAdjust) != oldState &&
(aTopic.Equals(u"video-playing"_ns) ||
aTopic.Equals(u"audio-playing"_ns))) {
glean::RecordPowerMetrics();
}

bool processWasLocked = processCount.numLocks > 0;

processCount.numLocks += aLockAdjust;
Expand Down Expand Up @@ -235,6 +244,13 @@ void GetWakeLockInfo(const nsAString& aTopic,
return;
}

if (!sLockTable) {
// This can happen during some gtests.
NS_WARNING("Attempting to get wake lock information before initialization");
*aWakeLockInfo = WakeLockInformation();
return;
}

ProcessLockTable* table = sLockTable->Get(aTopic);
if (!table) {
*aWakeLockInfo = WakeLockInfoFromLockCount(aTopic, LockCount());
Expand Down
75 changes: 64 additions & 11 deletions toolkit/components/glean/ipc/FOGIPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "mozilla/gfx/GPUChild.h"
#include "mozilla/gfx/GPUParent.h"
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/Hal.h"
#include "mozilla/MozPromise.h"
#include "mozilla/net/SocketProcessChild.h"
#include "mozilla/net/SocketProcessParent.h"
Expand Down Expand Up @@ -43,15 +44,68 @@ using FlushFOGDataPromise = mozilla::dom::ContentParent::FlushFOGDataPromise;
namespace mozilla {
namespace glean {

static void RecordPowerMetrics() {
void RecordPowerMetrics() {
static uint64_t previousCpuTime = 0, previousGpuTime = 0;

uint64_t cpuTime;
uint64_t cpuTime, newCpuTime = 0;
if (NS_SUCCEEDED(GetCpuTimeSinceProcessStartInMs(&cpuTime)) &&
cpuTime > previousCpuTime) {
uint64_t newCpuTime = cpuTime - previousCpuTime;
previousCpuTime += newCpuTime;
newCpuTime = cpuTime - previousCpuTime;
}

uint64_t gpuTime, newGpuTime = 0;
if (NS_SUCCEEDED(GetGpuTimeSinceProcessStartInMs(&gpuTime)) &&
gpuTime > previousGpuTime) {
newGpuTime = gpuTime - previousGpuTime;
}

if (!newCpuTime && !newGpuTime) {
// Nothing to record.
return;
}

// Compute the process type string.
nsAutoCString type(XRE_GetProcessTypeString());
if (XRE_IsContentProcess()) {
auto* cc = dom::ContentChild::GetSingleton();
if (cc) {
type.Assign(dom::RemoteTypePrefix(cc->GetRemoteType()));
if (StringBeginsWith(type, WEB_REMOTE_TYPE)) {
type.AssignLiteral("web");
switch (cc->GetProcessPriority()) {
case hal::PROCESS_PRIORITY_BACKGROUND:
type.AppendLiteral(".background");
break;
case hal::PROCESS_PRIORITY_FOREGROUND:
type.AppendLiteral(".foreground");
break;
case hal::PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE:
type.AppendLiteral(".background-perceivable");
break;
default:
break;
}
}
}
} else if (XRE_IsParentProcess()) {
if (nsContentUtils::GetUserIsInteracting()) {
type.AssignLiteral("parent.active");
} else {
type.AssignLiteral("parent.inactive");
}
hal::WakeLockInformation info;
GetWakeLockInfo(u"video-playing"_ns, &info);
if (info.numLocks() != 0 && info.numHidden() < info.numLocks()) {
type.AppendLiteral(".playing-video");
} else {
GetWakeLockInfo(u"audio-playing"_ns, &info);
if (info.numLocks()) {
type.AppendLiteral(".playing-audio");
}
}
}

if (newCpuTime) {
// The counters are reset at least once a day. Assuming all cores are used
// continuously, an int32 can hold the data for 24.85 cores.
// This should be fine for now, but may overflow in the future.
Expand All @@ -61,19 +115,18 @@ static void RecordPowerMetrics() {
nNewCpuTime = std::numeric_limits<int32_t>::max();
}
power::total_cpu_time_ms.Add(nNewCpuTime);
power::cpu_time_per_process_type_ms.Get(type).Add(nNewCpuTime);
previousCpuTime += newCpuTime;
}

uint64_t gpuTime;
if (NS_SUCCEEDED(GetGpuTimeSinceProcessStartInMs(&gpuTime)) &&
gpuTime > previousGpuTime) {
uint64_t newGpuTime = gpuTime - previousGpuTime;
previousGpuTime += newGpuTime;

if (newGpuTime) {
int32_t nNewGpuTime = int32_t(newGpuTime);
if (newGpuTime > std::numeric_limits<int32_t>::max()) {
nNewGpuTime = std::numeric_limits<int32_t>::max();
}
power::total_gpu_time_ms.Add(int32_t(nNewGpuTime));
power::total_gpu_time_ms.Add(nNewGpuTime);
power::gpu_time_per_process_type_ms.Get(type).Add(nNewGpuTime);
previousGpuTime += newGpuTime;
}
}

Expand Down
2 changes: 2 additions & 0 deletions toolkit/components/glean/ipc/FOGIPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ RefPtr<GenericPromise> FlushAndUseFOGData();
void TestTriggerMetrics(uint32_t processType,
const RefPtr<dom::Promise>& promise);

void RecordPowerMetrics();

} // namespace glean
} // namespace mozilla

Expand Down
51 changes: 49 additions & 2 deletions toolkit/components/processtools/metrics.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,55 @@
$schema: moz://mozilla.org/schemas/glean/metrics/2-0-0

power:
cpu_time_per_process_type_ms:
type: labeled_counter
description: >
CPU time used by each process type in ms.
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1747138
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1747138
data_sensitivity:
- technical
notification_emails:
- [email protected]
expires: never
labels: &per_process_type_labels
- parent.active
- parent.active.playing-audio
- parent.active.playing-video
- parent.inactive
- parent.inactive.playing-audio
- parent.inactive.playing-video
- prealloc
- privilegedabout
- rdd
- socket
- web.background
- web.background-perceivable
- web.foreground
- extension
- gpu
- gmplugin
- utility
telemetry_mirror: POWER_CPU_TIME_PER_PROCESS_TYPE_MS

gpu_time_per_process_type_ms:
type: labeled_counter
description: >
GPU time used by each process type in ms.
bugs:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1747138
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=1747138
data_sensitivity:
- technical
notification_emails:
- [email protected]
expires: never
labels: *per_process_type_labels
telemetry_mirror: POWER_GPU_TIME_PER_PROCESS_TYPE_MS

total_cpu_time_ms:
type: counter
description: >
Expand Down Expand Up @@ -46,5 +95,3 @@ power:
- [email protected]
expires: never
telemetry_mirror: POWER_TOTAL_GPU_TIME_MS
no_lint:
- COMMON_PREFIX
1 change: 1 addition & 0 deletions toolkit/components/processtools/tests/browser/browser.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ prefs=
support-files =
dummy.html

[browser_test_powerMetrics.js]
[browser_test_procinfo.js]
skip-if = (ccov && os == "linux") # https://bugzilla.mozilla.org/show_bug.cgi?id=1608080
Loading

0 comments on commit 301e687

Please sign in to comment.