[base] Precise CPU usage by default on Windows.
Now that we're confident that QueryProcessCycleTime provides more accurate CPU measurements than GetProcessTimes, use it by default in ProcessMetrics::GetCumulativeCPUUsage and remove ProcessMetrics::GetPreciseCumulativeCPUUsage. Bug: 1313216 Change-Id: I5e22f1c18069bacd1199a14b4ab1ba6b811166b9 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4943814 Commit-Queue: Francois Pierre Doray <fdoray@chromium.org> Reviewed-by: Patrick Monette <pmonette@chromium.org> Reviewed-by: Avi Drissman <avi@chromium.org> Reviewed-by: Joe Mason <joenotcharles@google.com> Auto-Submit: Francois Pierre Doray <fdoray@chromium.org> Cr-Commit-Position: refs/heads/main@{#1218355}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
eb473c5951
commit
0017e24cb3
base/process
chrome/browser
components/performance_manager/resource_attribution
content/browser
@ -128,34 +128,6 @@ double ProcessMetrics::GetPlatformIndependentCPUUsage() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
double ProcessMetrics::GetPreciseCPUUsage(TimeDelta cumulative_cpu) {
|
||||
TimeTicks time = TimeTicks::Now();
|
||||
|
||||
if (last_precise_cumulative_cpu_.is_zero()) {
|
||||
// First call, just set the last values.
|
||||
last_precise_cumulative_cpu_ = cumulative_cpu;
|
||||
last_cpu_time_for_precise_cpu_usage_ = time;
|
||||
return 0;
|
||||
}
|
||||
|
||||
TimeDelta cpu_time_delta = cumulative_cpu - last_precise_cumulative_cpu_;
|
||||
TimeDelta time_delta = time - last_cpu_time_for_precise_cpu_usage_;
|
||||
DCHECK(!time_delta.is_zero());
|
||||
if (time_delta.is_zero())
|
||||
return 0;
|
||||
|
||||
last_precise_cumulative_cpu_ = cumulative_cpu;
|
||||
last_cpu_time_for_precise_cpu_usage_ = time;
|
||||
|
||||
return 100.0 * cpu_time_delta / time_delta;
|
||||
}
|
||||
|
||||
double ProcessMetrics::GetPreciseCPUUsage() {
|
||||
return GetPreciseCPUUsage(GetPreciseCumulativeCPUUsage());
|
||||
}
|
||||
#endif // BUILDFLAG(IS_WIN)
|
||||
|
||||
#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
|
||||
BUILDFLAG(IS_AIX)
|
||||
int ProcessMetrics::CalculateIdleWakeupsPerSecond(
|
||||
|
@ -136,32 +136,6 @@ class BASE_EXPORT ProcessMetrics {
|
||||
// will result in a time delta of 2 seconds/per 1 wall-clock second.
|
||||
[[nodiscard]] TimeDelta GetCumulativeCPUUsage();
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
// TODO(pmonette): Remove the precise version of the CPU usage functions once
|
||||
// we're validated that they are indeed better than the regular version above
|
||||
// and that they can replace the old implementation.
|
||||
|
||||
// Returns the percentage of time spent executing, across all threads of the
|
||||
// process, in the interval since the last time the method was called, using
|
||||
// the current |cumulative_cpu|.
|
||||
//
|
||||
// Same as GetPlatformIndependentCPUUSage() but implemented using
|
||||
// `QueryProcessCycleTime` for higher precision.
|
||||
[[nodiscard]] double GetPreciseCPUUsage(TimeDelta cumulative_cpu);
|
||||
|
||||
// Same as the above, but automatically calls GetPreciseCumulativeCPUUsage()
|
||||
// to determine the current cumulative CPU.
|
||||
[[nodiscard]] double GetPreciseCPUUsage();
|
||||
|
||||
// Returns the cumulative CPU usage across all threads of the process since
|
||||
// process start. In case of multi-core processors, a process can consume CPU
|
||||
// at a rate higher than wall-clock time, e.g. two cores at full utilization
|
||||
// will result in a time delta of 2 seconds/per 1 wall-clock second.
|
||||
//
|
||||
// This is implemented using `QueryProcessCycleTime` for higher precision.
|
||||
[[nodiscard]] TimeDelta GetPreciseCumulativeCPUUsage();
|
||||
#endif // BUILDFLAG(IS_WIN)
|
||||
|
||||
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || \
|
||||
BUILDFLAG(IS_AIX)
|
||||
// Emits the cumulative CPU usage for all currently active threads since they
|
||||
@ -266,11 +240,6 @@ class BASE_EXPORT ProcessMetrics {
|
||||
TimeDelta last_cumulative_cpu_;
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
TimeTicks last_cpu_time_for_precise_cpu_usage_;
|
||||
TimeDelta last_precise_cumulative_cpu_;
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
|
||||
BUILDFLAG(IS_AIX)
|
||||
// Same thing for idle wakeups.
|
||||
|
@ -68,19 +68,6 @@ TimeDelta TestCumulativeCPU(ProcessMetrics* metrics, TimeDelta prev_cpu_usage) {
|
||||
return current_cpu_usage;
|
||||
}
|
||||
|
||||
TimeDelta TestPreciseCumulativeCPU(ProcessMetrics* metrics,
|
||||
TimeDelta prev_cpu_usage) {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
const TimeDelta current_cpu_usage = metrics->GetPreciseCumulativeCPUUsage();
|
||||
EXPECT_GE(current_cpu_usage, prev_cpu_usage);
|
||||
EXPECT_GE(metrics->GetPreciseCPUUsage(), 0.0);
|
||||
return current_cpu_usage;
|
||||
#else
|
||||
// Do nothing. Not supported on this platform.
|
||||
return base::TimeDelta();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // ENABLE_CPU_TESTS
|
||||
|
||||
std::unique_ptr<ProcessMetrics> CreateProcessMetricsForTest(
|
||||
@ -386,9 +373,6 @@ TEST_F(SystemMetricsTest, TestNoNegativeCpuUsage) {
|
||||
std::unique_ptr<ProcessMetrics> metrics(CreateProcessMetricsForTest(handle));
|
||||
|
||||
EXPECT_GE(metrics->GetPlatformIndependentCPUUsage(), 0.0);
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
EXPECT_GE(metrics->GetPreciseCPUUsage(), 0.0);
|
||||
#endif
|
||||
|
||||
Thread thread1("thread1");
|
||||
Thread thread2("thread2");
|
||||
@ -411,23 +395,15 @@ TEST_F(SystemMetricsTest, TestNoNegativeCpuUsage) {
|
||||
thread3.task_runner()->PostTask(FROM_HERE, BindOnce(&BusyWork, &vec3));
|
||||
|
||||
TimeDelta prev_cpu_usage = TestCumulativeCPU(metrics.get(), TimeDelta());
|
||||
TimeDelta prev_precise_cpu_usage =
|
||||
TestPreciseCumulativeCPU(metrics.get(), TimeDelta());
|
||||
|
||||
thread1.Stop();
|
||||
prev_cpu_usage = TestCumulativeCPU(metrics.get(), prev_cpu_usage);
|
||||
prev_precise_cpu_usage =
|
||||
TestPreciseCumulativeCPU(metrics.get(), prev_precise_cpu_usage);
|
||||
|
||||
thread2.Stop();
|
||||
prev_cpu_usage = TestCumulativeCPU(metrics.get(), prev_cpu_usage);
|
||||
prev_precise_cpu_usage =
|
||||
TestPreciseCumulativeCPU(metrics.get(), prev_precise_cpu_usage);
|
||||
|
||||
thread3.Stop();
|
||||
prev_cpu_usage = TestCumulativeCPU(metrics.get(), prev_cpu_usage);
|
||||
prev_precise_cpu_usage =
|
||||
TestPreciseCumulativeCPU(metrics.get(), prev_precise_cpu_usage);
|
||||
}
|
||||
#endif // ENABLE_CPU_TESTS
|
||||
|
||||
|
@ -120,6 +120,28 @@ struct SYSTEM_PERFORMANCE_INFORMATION {
|
||||
ULONG SystemCalls;
|
||||
};
|
||||
|
||||
TimeDelta GetImpreciseCumulativeCPUUsage(const win::ScopedHandle& process) {
|
||||
FILETIME creation_time;
|
||||
FILETIME exit_time;
|
||||
FILETIME kernel_time;
|
||||
FILETIME user_time;
|
||||
|
||||
if (!process.is_valid()) {
|
||||
return TimeDelta();
|
||||
}
|
||||
|
||||
if (!GetProcessTimes(process.get(), &creation_time, &exit_time, &kernel_time,
|
||||
&user_time)) {
|
||||
// This should never fail because we duplicate the handle to guarantee it
|
||||
// will remain valid.
|
||||
DCHECK(false);
|
||||
return TimeDelta();
|
||||
}
|
||||
|
||||
return TimeDelta::FromFileTime(kernel_time) +
|
||||
TimeDelta::FromFileTime(user_time);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
size_t GetMaxFds() {
|
||||
@ -140,31 +162,10 @@ std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics(
|
||||
}
|
||||
|
||||
TimeDelta ProcessMetrics::GetCumulativeCPUUsage() {
|
||||
FILETIME creation_time;
|
||||
FILETIME exit_time;
|
||||
FILETIME kernel_time;
|
||||
FILETIME user_time;
|
||||
|
||||
if (!process_.is_valid())
|
||||
return TimeDelta();
|
||||
|
||||
if (!GetProcessTimes(process_.get(), &creation_time, &exit_time, &kernel_time,
|
||||
&user_time)) {
|
||||
// This should never fail because we duplicate the handle to guarantee it
|
||||
// will remain valid.
|
||||
DCHECK(false);
|
||||
return TimeDelta();
|
||||
}
|
||||
|
||||
return TimeDelta::FromFileTime(kernel_time) +
|
||||
TimeDelta::FromFileTime(user_time);
|
||||
}
|
||||
|
||||
TimeDelta ProcessMetrics::GetPreciseCumulativeCPUUsage() {
|
||||
#if defined(ARCH_CPU_ARM64)
|
||||
// Precise CPU usage is not available on Arm CPUs because they don't support
|
||||
// constant rate TSC.
|
||||
return GetCumulativeCPUUsage();
|
||||
return GetImpreciseCumulativeCPUUsage(process_);
|
||||
#else // !defined(ARCH_CPU_ARM64)
|
||||
if (!time_internal::HasConstantRateTSC())
|
||||
return GetCumulativeCPUUsage();
|
||||
@ -172,10 +173,10 @@ TimeDelta ProcessMetrics::GetPreciseCumulativeCPUUsage() {
|
||||
const double tsc_ticks_per_second = time_internal::TSCTicksPerSecond();
|
||||
if (tsc_ticks_per_second == 0) {
|
||||
// TSC is only initialized once TSCTicksPerSecond() is called twice 50 ms
|
||||
// apart on the same thread to get a baseline. This often doesn't happen in
|
||||
// unit tests, and theoretically may happen in production if
|
||||
// GetPreciseCumulativeCPUUsage() is called before any uses of ThreadTicks.
|
||||
return GetCumulativeCPUUsage();
|
||||
// apart on the same thread to get a baseline. In unit tests, it is frequent
|
||||
// for the initialization not to be complete. In production, it can also
|
||||
// theoretically happen.
|
||||
return GetImpreciseCumulativeCPUUsage(process_);
|
||||
}
|
||||
|
||||
ULONG64 process_cycle_time = 0;
|
||||
|
@ -58,11 +58,7 @@ std::unique_ptr<base::ProcessMetrics> CreateProcessMetrics(
|
||||
ProcessMonitor::Metrics SampleMetrics(base::ProcessMetrics& process_metrics) {
|
||||
ProcessMonitor::Metrics metrics;
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
metrics.cpu_usage = process_metrics.GetPreciseCPUUsage();
|
||||
#else
|
||||
metrics.cpu_usage = process_metrics.GetPlatformIndependentCPUUsage();
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
|
||||
BUILDFLAG(IS_AIX)
|
||||
@ -94,16 +90,9 @@ ProcessMonitor::Metrics GetLastIntervalMetrics(
|
||||
base::ProcessMetrics& process_metrics,
|
||||
base::TimeDelta cumulative_cpu_usage) {
|
||||
ProcessMonitor::Metrics metrics;
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
metrics.cpu_usage = process_metrics.GetPreciseCPUUsage(cumulative_cpu_usage);
|
||||
#else
|
||||
metrics.cpu_usage =
|
||||
process_metrics.GetPlatformIndependentCPUUsage(cumulative_cpu_usage);
|
||||
#endif
|
||||
|
||||
// TODO: Add other values in ProcessMonitor::Metrics.
|
||||
|
||||
return metrics;
|
||||
}
|
||||
|
||||
|
@ -67,11 +67,7 @@ CPUMeasurementDelegateImpl::CPUMeasurementDelegateImpl(
|
||||
}
|
||||
|
||||
base::TimeDelta CPUMeasurementDelegateImpl::GetCumulativeCPUUsage() {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
return process_metrics_->GetPreciseCumulativeCPUUsage();
|
||||
#else
|
||||
return process_metrics_->GetCumulativeCPUUsage();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -68,11 +68,7 @@ CPUMeasurementDelegateImpl::CPUMeasurementDelegateImpl(
|
||||
}
|
||||
|
||||
base::TimeDelta CPUMeasurementDelegateImpl::GetCumulativeCPUUsage() {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
return process_metrics_->GetPreciseCumulativeCPUUsage();
|
||||
#else
|
||||
return process_metrics_->GetCumulativeCPUUsage();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns true if `result` is in the default-initialized state.
|
||||
|
@ -45,15 +45,7 @@ base::TimeDelta GetCPUUsage(base::ProcessHandle process_handle) {
|
||||
std::unique_ptr<base::ProcessMetrics> process_metrics =
|
||||
base::ProcessMetrics::CreateProcessMetrics(process_handle);
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
// Use the precise version which is Windows specific.
|
||||
// TODO(pmonette): Clean up this code when the precise version becomes the
|
||||
// default.
|
||||
return process_metrics->GetPreciseCumulativeCPUUsage();
|
||||
#else
|
||||
return process_metrics->GetCumulativeCPUUsage();
|
||||
#endif
|
||||
}
|
||||
#endif // !BUILDFLAG(IS_ANDROID)
|
||||
|
||||
|
Reference in New Issue
Block a user