Return expected from ProcessMetrics CPU methods
Also adds base::OptionalFromExpected and base::OptionalToExpected to base/types/optional_util.h, because converting to an optional in one line would require annoying casting. Bug: 40285287 Change-Id: I84c4d789d4b7b31b25fb87d7032bcf26a5e8bf4e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5362194 Reviewed-by: Dmitry Gozman <dgozman@chromium.org> Reviewed-by: David Roger <droger@chromium.org> Reviewed-by: danakj <danakj@chromium.org> Auto-Submit: Joe Mason <joenotcharles@google.com> Commit-Queue: John Abd-El-Malek <jam@chromium.org> Reviewed-by: John Abd-El-Malek <jam@chromium.org> Cr-Commit-Position: refs/heads/main@{#1277773}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
7c312cdcad
commit
550eed6bb7
base
process
process_metrics.ccprocess_metrics.hprocess_metrics_apple.ccprocess_metrics_freebsd.ccprocess_metrics_fuchsia.ccprocess_metrics_linux.ccprocess_metrics_openbsd.ccprocess_metrics_unittest.ccprocess_metrics_win.cc
types
chrome/browser
components/performance_manager/resource_attribution
content
browser
common
android
ipc
third_party/blink/renderer/core/inspector
@ -123,12 +123,11 @@ double ProcessMetrics::GetPlatformIndependentCPUUsage(
|
||||
return 100.0 * cpu_time_delta / time_delta;
|
||||
}
|
||||
|
||||
std::optional<double> ProcessMetrics::GetPlatformIndependentCPUUsage() {
|
||||
const std::optional<TimeDelta> cpu_usage = GetCumulativeCPUUsage();
|
||||
if (!cpu_usage.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return GetPlatformIndependentCPUUsage(cpu_usage.value());
|
||||
base::expected<double, ProcessCPUUsageError>
|
||||
ProcessMetrics::GetPlatformIndependentCPUUsage() {
|
||||
return GetCumulativeCPUUsage().transform([this](base::TimeDelta cpu_usage) {
|
||||
return GetPlatformIndependentCPUUsage(cpu_usage);
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/gtest_prod_util.h"
|
||||
@ -20,6 +19,7 @@
|
||||
#include "base/process/process_handle.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "base/values.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
@ -64,6 +64,19 @@ struct PageFaultCounts {
|
||||
// Convert a POSIX timeval to microseconds.
|
||||
BASE_EXPORT int64_t TimeValToMicroseconds(const struct timeval& tv);
|
||||
|
||||
enum class ProcessCPUUsageError {
|
||||
// The OS returned an error while measuring the CPU usage. The possible causes
|
||||
// vary by platform.
|
||||
kSystemError,
|
||||
|
||||
// Process CPU usage couldn't be measured because the process wasn't running.
|
||||
// Some platforms may return kSystemError instead in this situation.
|
||||
kProcessNotFound,
|
||||
|
||||
// CPU usage measurement isn't implemented on this platform.
|
||||
kNotImplemented,
|
||||
};
|
||||
|
||||
// Provides performance metrics for a specified process (CPU usage and IO
|
||||
// counters). Use CreateCurrentProcessMetrics() to get an instance for the
|
||||
// current process, or CreateProcessMetrics() to get an instance for an
|
||||
@ -127,14 +140,16 @@ class BASE_EXPORT ProcessMetrics {
|
||||
// Same as the above, but automatically calls GetCumulativeCPUUsage() to
|
||||
// determine the current cumulative CPU. Returns nullopt if
|
||||
// GetCumulativeCPUUsage() fails.
|
||||
[[nodiscard]] std::optional<double> GetPlatformIndependentCPUUsage();
|
||||
[[nodiscard]] base::expected<double, ProcessCPUUsageError>
|
||||
GetPlatformIndependentCPUUsage();
|
||||
|
||||
// Returns the cumulative CPU usage across all threads of the process since
|
||||
// process start, or nullopt on error. 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.
|
||||
[[nodiscard]] std::optional<TimeDelta> GetCumulativeCPUUsage();
|
||||
[[nodiscard]] base::expected<TimeDelta, ProcessCPUUsageError>
|
||||
GetCumulativeCPUUsage();
|
||||
|
||||
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || \
|
||||
BUILDFLAG(IS_AIX)
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "base/notimplemented.h"
|
||||
#include "base/numerics/safe_math.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
@ -44,16 +45,21 @@ namespace base {
|
||||
|
||||
namespace {
|
||||
|
||||
bool GetTaskInfo(mach_port_t task, task_basic_info_64* task_info_data) {
|
||||
base::expected<task_basic_info_64, ProcessCPUUsageError> GetTaskInfo(
|
||||
mach_port_t task) {
|
||||
if (task == MACH_PORT_NULL) {
|
||||
return false;
|
||||
return base::unexpected(ProcessCPUUsageError::kProcessNotFound);
|
||||
}
|
||||
task_basic_info_64 task_info_data{};
|
||||
mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
|
||||
kern_return_t kr =
|
||||
task_info(task, TASK_BASIC_INFO_64,
|
||||
reinterpret_cast<task_info_t>(task_info_data), &count);
|
||||
reinterpret_cast<task_info_t>(&task_info_data), &count);
|
||||
// Most likely cause for failure: |task| is a zombie.
|
||||
return kr == KERN_SUCCESS;
|
||||
if (kr != KERN_SUCCESS) {
|
||||
return base::unexpected(ProcessCPUUsageError::kSystemError);
|
||||
}
|
||||
return base::ok(task_info_data);
|
||||
}
|
||||
|
||||
MachVMRegionResult ParseOutputFromMachVMRegion(kern_return_t kr) {
|
||||
@ -95,10 +101,11 @@ mach_port_t ProcessMetrics::TaskForHandle(ProcessHandle process_handle) const {
|
||||
return task;
|
||||
}
|
||||
|
||||
std::optional<TimeDelta> ProcessMetrics::GetCumulativeCPUUsage() {
|
||||
base::expected<TimeDelta, ProcessCPUUsageError>
|
||||
ProcessMetrics::GetCumulativeCPUUsage() {
|
||||
mach_port_t task = TaskForHandle(process_);
|
||||
if (task == MACH_PORT_NULL) {
|
||||
return std::nullopt;
|
||||
return base::unexpected(ProcessCPUUsageError::kProcessNotFound);
|
||||
}
|
||||
|
||||
// Libtop explicitly loops over the threads (libtop_pinfo_update_cpu_usage()
|
||||
@ -110,12 +117,13 @@ std::optional<TimeDelta> ProcessMetrics::GetCumulativeCPUUsage() {
|
||||
&thread_info_count);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
// Most likely cause: |task| is a zombie.
|
||||
return std::nullopt;
|
||||
return base::unexpected(ProcessCPUUsageError::kSystemError);
|
||||
}
|
||||
|
||||
task_basic_info_64 task_info_data;
|
||||
if (!GetTaskInfo(task, &task_info_data)) {
|
||||
return std::nullopt;
|
||||
const base::expected<task_basic_info_64, ProcessCPUUsageError>
|
||||
task_info_data = GetTaskInfo(task);
|
||||
if (!task_info_data.has_value()) {
|
||||
return base::unexpected(task_info_data.error());
|
||||
}
|
||||
|
||||
/* Set total_time. */
|
||||
@ -126,8 +134,8 @@ std::optional<TimeDelta> ProcessMetrics::GetCumulativeCPUUsage() {
|
||||
timeradd(&user_timeval, &system_timeval, &task_timeval);
|
||||
|
||||
// ... task info contains terminated time.
|
||||
TIME_VALUE_TO_TIMEVAL(&task_info_data.user_time, &user_timeval);
|
||||
TIME_VALUE_TO_TIMEVAL(&task_info_data.system_time, &system_timeval);
|
||||
TIME_VALUE_TO_TIMEVAL(&task_info_data->user_time, &user_timeval);
|
||||
TIME_VALUE_TO_TIMEVAL(&task_info_data->system_time, &system_timeval);
|
||||
timeradd(&user_timeval, &task_timeval, &task_timeval);
|
||||
timeradd(&system_timeval, &task_timeval, &task_timeval);
|
||||
|
||||
@ -139,10 +147,10 @@ std::optional<TimeDelta> ProcessMetrics::GetCumulativeCPUUsage() {
|
||||
// a lag before it shows up in the terminated thread times returned by
|
||||
// GetTaskInfo(). Make sure CPU usage doesn't appear to go backwards if
|
||||
// GetCumulativeCPUUsage() is called in the interval.
|
||||
return std::optional(last_measured_cpu_);
|
||||
return base::ok(last_measured_cpu_);
|
||||
}
|
||||
last_measured_cpu_ = measured_cpu;
|
||||
return std::optional(measured_cpu);
|
||||
return base::ok(measured_cpu);
|
||||
}
|
||||
|
||||
int ProcessMetrics::GetPackageIdleWakeupsPerSecond() {
|
||||
|
@ -23,20 +23,22 @@ std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics(
|
||||
return WrapUnique(new ProcessMetrics(process));
|
||||
}
|
||||
|
||||
std::optional<double> ProcessMetrics::GetPlatformIndependentCPUUsage() {
|
||||
base::expected<double, ProcessCPUUsageError>
|
||||
ProcessMetrics::GetPlatformIndependentCPUUsage() {
|
||||
struct kinfo_proc info;
|
||||
int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, process_};
|
||||
size_t length = sizeof(info);
|
||||
|
||||
if (sysctl(mib, std::size(mib), &info, &length, NULL, 0) < 0)
|
||||
return std::nullopt;
|
||||
return base::unexpected(ProcessCPUUsageError::kSystemError);
|
||||
|
||||
return std::optional(double{info.ki_pctcpu} / FSCALE * 100.0);
|
||||
return base::ok(double{info.ki_pctcpu} / FSCALE * 100.0);
|
||||
}
|
||||
|
||||
std::optional<TimeDelta> ProcessMetrics::GetCumulativeCPUUsage() {
|
||||
base::expected<TimeDelta, ProcessCPUUsageError>
|
||||
ProcessMetrics::GetCumulativeCPUUsage() {
|
||||
NOTREACHED();
|
||||
return std::nullopt;
|
||||
return base::unexpected(ProcessCPUUsageError::kNotImplemented);
|
||||
}
|
||||
|
||||
size_t GetSystemCommitCharge() {
|
||||
|
@ -35,16 +35,17 @@ std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics(
|
||||
return base::WrapUnique(new ProcessMetrics(process));
|
||||
}
|
||||
|
||||
std::optional<TimeDelta> ProcessMetrics::GetCumulativeCPUUsage() {
|
||||
base::expected<TimeDelta, ProcessCPUUsageError>
|
||||
ProcessMetrics::GetCumulativeCPUUsage() {
|
||||
zx_info_task_runtime_t stats;
|
||||
|
||||
zx_status_t status = zx::unowned_process(process_)->get_info(
|
||||
ZX_INFO_TASK_RUNTIME, &stats, sizeof(stats), nullptr, nullptr);
|
||||
if (status != ZX_OK) {
|
||||
return std::nullopt;
|
||||
return base::unexpected(ProcessCPUUsageError::kSystemError);
|
||||
}
|
||||
|
||||
return std::optional(TimeDelta::FromZxDuration(stats.cpu_time));
|
||||
return base::ok(TimeDelta::FromZxDuration(stats.cpu_time));
|
||||
}
|
||||
|
||||
bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) {
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/system/sys_info.h"
|
||||
#include "base/threading/thread_restrictions.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "base/values.h"
|
||||
#include "build/build_config.h"
|
||||
#include "third_party/abseil-cpp/absl/strings/ascii.h"
|
||||
@ -59,26 +60,27 @@ uint64_t ReadFileToUint64(const FilePath& file) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get the total CPU from a proc stat buffer. Return value is a TimeDelta
|
||||
// converted from a number of jiffies on success or nullopt if parsing failed.
|
||||
std::optional<TimeDelta> ParseTotalCPUTimeFromStats(
|
||||
// Get the total CPU from a proc stat buffer. Return value is a TimeDelta
|
||||
// converted from a number of jiffies on success or an error code if parsing
|
||||
// failed.
|
||||
base::expected<TimeDelta, ProcessCPUUsageError> ParseTotalCPUTimeFromStats(
|
||||
base::span<const std::string> proc_stats) {
|
||||
const std::optional<int64_t> utime =
|
||||
internal::GetProcStatsFieldAsOptionalInt64(proc_stats,
|
||||
internal::VM_UTIME);
|
||||
if (utime.value_or(-1) < 0) {
|
||||
return std::nullopt;
|
||||
return base::unexpected(ProcessCPUUsageError::kSystemError);
|
||||
}
|
||||
const std::optional<int64_t> stime =
|
||||
internal::GetProcStatsFieldAsOptionalInt64(proc_stats,
|
||||
internal::VM_UTIME);
|
||||
if (stime.value_or(-1) < 0) {
|
||||
return std::nullopt;
|
||||
return base::unexpected(ProcessCPUUsageError::kSystemError);
|
||||
}
|
||||
const TimeDelta cpu_time = internal::ClockTicksToTimeDelta(
|
||||
base::ClampAdd(utime.value(), stime.value()));
|
||||
CHECK(!cpu_time.is_negative());
|
||||
return std::optional(cpu_time);
|
||||
return base::ok(cpu_time);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -94,12 +96,13 @@ size_t ProcessMetrics::GetResidentSetSize() const {
|
||||
checked_cast<size_t>(getpagesize());
|
||||
}
|
||||
|
||||
std::optional<TimeDelta> ProcessMetrics::GetCumulativeCPUUsage() {
|
||||
base::expected<TimeDelta, ProcessCPUUsageError>
|
||||
ProcessMetrics::GetCumulativeCPUUsage() {
|
||||
std::string buffer;
|
||||
std::vector<std::string> proc_stats;
|
||||
if (!internal::ReadProcStats(process_, &buffer) ||
|
||||
!internal::ParseProcStats(buffer, &proc_stats)) {
|
||||
return std::nullopt;
|
||||
return base::unexpected(ProcessCPUUsageError::kSystemError);
|
||||
}
|
||||
|
||||
return ParseTotalCPUTimeFromStats(proc_stats);
|
||||
@ -121,7 +124,7 @@ bool ProcessMetrics::GetCumulativeCPUUsagePerThread(
|
||||
return;
|
||||
}
|
||||
|
||||
const std::optional<TimeDelta> thread_time =
|
||||
const base::expected<TimeDelta, ProcessCPUUsageError> thread_time =
|
||||
ParseTotalCPUTimeFromStats(proc_stats);
|
||||
if (thread_time.has_value()) {
|
||||
cpu_per_thread.emplace_back(tid, thread_time.value());
|
||||
|
@ -8,31 +8,31 @@
|
||||
#include <stdint.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <optional>
|
||||
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/types/expected.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace {
|
||||
|
||||
static std::optional<int> GetProcessCPU(pid_t pid) {
|
||||
base::expected<int, ProcessCPUUsageError> GetProcessCPU(pid_t pid) {
|
||||
struct kinfo_proc info;
|
||||
size_t length;
|
||||
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid,
|
||||
sizeof(struct kinfo_proc), 0 };
|
||||
|
||||
if (sysctl(mib, std::size(mib), NULL, &length, NULL, 0) < 0) {
|
||||
return std::nullopt;
|
||||
return base::unexpected(ProcessCPUUsageError::kSystemError);
|
||||
}
|
||||
|
||||
mib[5] = (length / sizeof(struct kinfo_proc));
|
||||
|
||||
if (sysctl(mib, std::size(mib), &info, &length, NULL, 0) < 0) {
|
||||
return std::nullopt;
|
||||
return base::unexpected(ProcessCPUUsageError::kSystemError);
|
||||
}
|
||||
|
||||
return std::optional(info.p_pctcpu);
|
||||
return base::ok(info.p_pctcpu);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -43,27 +43,29 @@ std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics(
|
||||
return WrapUnique(new ProcessMetrics(process));
|
||||
}
|
||||
|
||||
std::optional<double> ProcessMetrics::GetPlatformIndependentCPUUsage() {
|
||||
base::expected<double, ProcessCPUUsageError>
|
||||
ProcessMetrics::GetPlatformIndependentCPUUsage() {
|
||||
TimeTicks time = TimeTicks::Now();
|
||||
|
||||
if (last_cpu_time_.is_zero()) {
|
||||
// First call, just set the last values.
|
||||
last_cpu_time_ = time;
|
||||
return std::optional(0.0);
|
||||
return base::ok(0.0);
|
||||
}
|
||||
|
||||
const std::optional<int> cpu = GetProcessCPU(process_);
|
||||
const base::expected<int, ProcessCPUUsageError> cpu = GetProcessCPU(process_);
|
||||
if (!cpu.has_value()) {
|
||||
return std::nullopt;
|
||||
return base::unexpected(cpu.error());
|
||||
}
|
||||
|
||||
last_cpu_time_ = time;
|
||||
return std::optional(double{cpu.value()} / FSCALE * 100.0);
|
||||
return base::ok(double{cpu.value()} / FSCALE * 100.0);
|
||||
}
|
||||
|
||||
std::optional<TimeDelta> ProcessMetrics::GetCumulativeCPUUsage() {
|
||||
base::expected<TimeDelta, ProcessCPUUsageError>
|
||||
ProcessMetrics::GetCumulativeCPUUsage() {
|
||||
NOTREACHED();
|
||||
return std::nullopt;
|
||||
return base::unexpected(ProcessCPUUsageError::kNotImplemented);
|
||||
}
|
||||
|
||||
ProcessMetrics::ProcessMetrics(ProcessHandle process)
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@ -30,10 +29,12 @@
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/system/sys_info.h"
|
||||
#include "base/test/gmock_expected_support.h"
|
||||
#include "base/test/gtest_util.h"
|
||||
#include "base/test/multiprocess_test.h"
|
||||
#include "base/test/test_timeouts.h"
|
||||
#include "base/threading/thread.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "build/blink_buildflags.h"
|
||||
#include "build/build_config.h"
|
||||
#include "build/chromeos_buildflags.h"
|
||||
@ -66,11 +67,13 @@ namespace base::debug {
|
||||
|
||||
namespace {
|
||||
|
||||
using base::test::ErrorIs;
|
||||
using base::test::ValueIs;
|
||||
using ::testing::_;
|
||||
using ::testing::AssertionFailure;
|
||||
using ::testing::AssertionResult;
|
||||
using ::testing::AssertionSuccess;
|
||||
using ::testing::Ge;
|
||||
using ::testing::Optional;
|
||||
|
||||
#if ENABLE_CPU_TESTS
|
||||
|
||||
@ -88,10 +91,10 @@ void BusyWork(std::vector<std::string>* vec) {
|
||||
// returns an empty TimeDelta so that each test doesn't need to check for
|
||||
// nullopt repeatedly.
|
||||
TimeDelta TestCumulativeCPU(ProcessMetrics* metrics, TimeDelta prev_cpu_usage) {
|
||||
const std::optional<TimeDelta> current_cpu_usage =
|
||||
const base::expected<TimeDelta, ProcessCPUUsageError> current_cpu_usage =
|
||||
metrics->GetCumulativeCPUUsage();
|
||||
EXPECT_THAT(current_cpu_usage, Optional(Ge(prev_cpu_usage)));
|
||||
EXPECT_THAT(metrics->GetPlatformIndependentCPUUsage(), Optional(Ge(0.0)));
|
||||
EXPECT_THAT(current_cpu_usage, ValueIs(Ge(prev_cpu_usage)));
|
||||
EXPECT_THAT(metrics->GetPlatformIndependentCPUUsage(), ValueIs(Ge(0.0)));
|
||||
return current_cpu_usage.value_or(TimeDelta());
|
||||
}
|
||||
|
||||
@ -634,7 +637,7 @@ TEST_F(SystemMetricsTest, TestNoNegativeCpuUsage) {
|
||||
std::unique_ptr<ProcessMetrics> metrics =
|
||||
ProcessMetrics::CreateCurrentProcessMetrics();
|
||||
|
||||
EXPECT_THAT(metrics->GetPlatformIndependentCPUUsage(), Optional(Ge(0.0)));
|
||||
EXPECT_THAT(metrics->GetPlatformIndependentCPUUsage(), ValueIs(Ge(0.0)));
|
||||
|
||||
Thread thread1("thread1");
|
||||
Thread thread2("thread2");
|
||||
@ -699,8 +702,8 @@ TEST_F(SystemMetricsTest, MeasureChildCpuUsage) {
|
||||
TestCumulativeCPU(metrics.get(), cpu_usage2);
|
||||
#else
|
||||
// All other platforms return an error.
|
||||
EXPECT_EQ(metrics->GetCumulativeCPUUsage(), std::nullopt);
|
||||
EXPECT_EQ(metrics->GetPlatformIndependentCPUUsage(), std::nullopt);
|
||||
EXPECT_THAT(metrics->GetCumulativeCPUUsage(), ErrorIs(_));
|
||||
EXPECT_THAT(metrics->GetPlatformIndependentCPUUsage(), ErrorIs(_));
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -714,8 +717,8 @@ TEST_F(SystemMetricsTest, InvalidProcessCpuUsage) {
|
||||
std::unique_ptr<ProcessMetrics> metrics =
|
||||
ProcessMetrics::CreateProcessMetrics(kNullProcessHandle);
|
||||
#endif
|
||||
EXPECT_EQ(metrics->GetCumulativeCPUUsage(), std::nullopt);
|
||||
EXPECT_EQ(metrics->GetPlatformIndependentCPUUsage(), std::nullopt);
|
||||
EXPECT_THAT(metrics->GetCumulativeCPUUsage(), ErrorIs(_));
|
||||
EXPECT_THAT(metrics->GetPlatformIndependentCPUUsage(), ErrorIs(_));
|
||||
}
|
||||
|
||||
#endif // ENABLE_CPU_TESTS
|
||||
|
@ -120,7 +120,7 @@ struct SYSTEM_PERFORMANCE_INFORMATION {
|
||||
ULONG SystemCalls;
|
||||
};
|
||||
|
||||
std::optional<TimeDelta> GetImpreciseCumulativeCPUUsage(
|
||||
base::expected<TimeDelta, ProcessCPUUsageError> GetImpreciseCumulativeCPUUsage(
|
||||
const win::ScopedHandle& process) {
|
||||
FILETIME creation_time;
|
||||
FILETIME exit_time;
|
||||
@ -128,18 +128,18 @@ std::optional<TimeDelta> GetImpreciseCumulativeCPUUsage(
|
||||
FILETIME user_time;
|
||||
|
||||
if (!process.is_valid()) {
|
||||
return std::nullopt;
|
||||
return base::unexpected(ProcessCPUUsageError::kSystemError);
|
||||
}
|
||||
|
||||
if (!GetProcessTimes(process.get(), &creation_time, &exit_time, &kernel_time,
|
||||
&user_time)) {
|
||||
// This should never fail when the handle is valid.
|
||||
NOTREACHED(NotFatalUntil::M125);
|
||||
return std::nullopt;
|
||||
return base::unexpected(ProcessCPUUsageError::kSystemError);
|
||||
}
|
||||
|
||||
return std::optional(TimeDelta::FromFileTime(kernel_time) +
|
||||
TimeDelta::FromFileTime(user_time));
|
||||
return base::ok(TimeDelta::FromFileTime(kernel_time) +
|
||||
TimeDelta::FromFileTime(user_time));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -161,7 +161,8 @@ std::unique_ptr<ProcessMetrics> ProcessMetrics::CreateProcessMetrics(
|
||||
return WrapUnique(new ProcessMetrics(process));
|
||||
}
|
||||
|
||||
std::optional<TimeDelta> ProcessMetrics::GetCumulativeCPUUsage() {
|
||||
base::expected<TimeDelta, ProcessCPUUsageError>
|
||||
ProcessMetrics::GetCumulativeCPUUsage() {
|
||||
#if defined(ARCH_CPU_ARM64)
|
||||
// Precise CPU usage is not available on Arm CPUs because they don't support
|
||||
// constant rate TSC.
|
||||
@ -181,18 +182,18 @@ std::optional<TimeDelta> ProcessMetrics::GetCumulativeCPUUsage() {
|
||||
}
|
||||
|
||||
if (!process_.is_valid()) {
|
||||
return std::nullopt;
|
||||
return base::unexpected(ProcessCPUUsageError::kProcessNotFound);
|
||||
}
|
||||
|
||||
ULONG64 process_cycle_time = 0;
|
||||
if (!QueryProcessCycleTime(process_.get(), &process_cycle_time)) {
|
||||
// This should never fail when the handle is valid.
|
||||
NOTREACHED(NotFatalUntil::M125);
|
||||
return std::nullopt;
|
||||
return base::unexpected(ProcessCPUUsageError::kSystemError);
|
||||
}
|
||||
|
||||
const double process_time_seconds = process_cycle_time / tsc_ticks_per_second;
|
||||
return std::optional(Seconds(process_time_seconds));
|
||||
return base::ok(Seconds(process_time_seconds));
|
||||
#endif // !defined(ARCH_CPU_ARM64)
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,11 @@
|
||||
#ifndef BASE_TYPES_OPTIONAL_UTIL_H_
|
||||
#define BASE_TYPES_OPTIONAL_UTIL_H_
|
||||
|
||||
#include <concepts>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include "base/types/expected.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
@ -60,6 +64,48 @@ std::optional<T> OptionalFromPtr(const T* value) {
|
||||
return value ? std::optional<T>(*value) : std::nullopt;
|
||||
}
|
||||
|
||||
// Helper for creating a `base::expected<U, F>` from an `std::optional<T>` and
|
||||
// an error of type E, where T is convertible to U and E is convertible to F. If
|
||||
// `opt` contains a value, this copies it into the `base::expected`, otherwise
|
||||
// it moves `err` in.
|
||||
template <class T, class E, class U = T, class F = E>
|
||||
base::expected<U, F> OptionalToExpected(const std::optional<T>& opt, E&& err)
|
||||
requires(std::convertible_to<T, U> && std::copyable<T> &&
|
||||
std::convertible_to<E, F> && std::movable<E>)
|
||||
{
|
||||
if (opt.has_value()) {
|
||||
return base::ok(opt.value());
|
||||
}
|
||||
return base::unexpected(std::move(err));
|
||||
}
|
||||
|
||||
// As above, but copies `err` into the `base:expected` if `opt` doesn't contain
|
||||
// a value.
|
||||
template <class T, class E, class U = T, class F = E>
|
||||
base::expected<U, F> OptionalToExpected(const std::optional<T>& opt,
|
||||
const E& err)
|
||||
requires(std::convertible_to<T, U> && std::copyable<T> &&
|
||||
std::convertible_to<E, F> && std::copyable<E>)
|
||||
{
|
||||
if (opt.has_value()) {
|
||||
return base::ok(opt.value());
|
||||
}
|
||||
return base::unexpected(err);
|
||||
}
|
||||
|
||||
// Helper for creating an `std::optional<U>` from a `base::expected<T, E>`,
|
||||
// where T is convertible to U. If `exp` contains a value, this copies it into
|
||||
// the `std::optional`, otherwise it returns std::nullopt.
|
||||
template <class T, class E, class U = T>
|
||||
std::optional<U> OptionalFromExpected(const base::expected<T, E>& exp)
|
||||
requires(std::convertible_to<T, U>)
|
||||
{
|
||||
if (exp.has_value()) {
|
||||
return std::optional(exp.value());
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_TYPES_OPTIONAL_UTIL_H_
|
||||
|
@ -4,6 +4,11 @@
|
||||
|
||||
#include "base/types/optional_util.h"
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "base/types/expected.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace base {
|
||||
@ -27,5 +32,65 @@ TEST(OptionalUtilTest, OptionalFromPtr) {
|
||||
EXPECT_EQ(optional_f, OptionalFromPtr(&f));
|
||||
}
|
||||
|
||||
TEST(OptionalUtilTest, OptionalToExpected) {
|
||||
std::optional<int> i_opt;
|
||||
|
||||
// No conversions.
|
||||
base::expected<int, int> i_exp = OptionalToExpected(i_opt, -1);
|
||||
EXPECT_EQ(i_exp, base::unexpected(-1));
|
||||
|
||||
// Error type converted.
|
||||
i_exp = OptionalToExpected(i_opt, -1.0);
|
||||
EXPECT_EQ(i_exp, base::unexpected(-1));
|
||||
|
||||
i_opt = 2;
|
||||
|
||||
// No conversions.
|
||||
i_exp = OptionalToExpected(i_opt, -1);
|
||||
EXPECT_EQ(i_exp, base::ok(2));
|
||||
|
||||
// Value type converted.
|
||||
base::expected<float, int> f_exp = OptionalToExpected(i_opt, -1);
|
||||
EXPECT_EQ(f_exp, base::ok(2.0));
|
||||
|
||||
// Non-movable error type. "is null" is a const char array, which must be
|
||||
// copied before converting to a string. Forces the compiler to choose the
|
||||
// OptionalToExpected override that copies its error argument, to validate
|
||||
// that it's copied correctly.
|
||||
auto exp_with_str_error =
|
||||
OptionalToExpected<int, std::string>(std::nullopt, "is null");
|
||||
EXPECT_EQ(exp_with_str_error, base::unexpected("is null"));
|
||||
|
||||
// Non-copyable error type. Forces the compiler to choose the
|
||||
// OptionalToExpected override that moves its error argument, to validate that
|
||||
// it's moved correctly.
|
||||
auto exp_with_ptr_error = OptionalToExpected<int, std::unique_ptr<int>>(
|
||||
std::nullopt, std::make_unique<int>(-1));
|
||||
ASSERT_FALSE(exp_with_ptr_error.has_value());
|
||||
EXPECT_EQ(*(exp_with_ptr_error.error()), -1);
|
||||
}
|
||||
|
||||
TEST(OptionalUtilTest, OptionalFromExpected) {
|
||||
base::expected<int, std::string> i_exp = base::unexpected("uninitialized");
|
||||
|
||||
// No conversion.
|
||||
std::optional<int> i_opt = OptionalFromExpected(i_exp);
|
||||
EXPECT_EQ(i_opt, std::nullopt);
|
||||
|
||||
// Value type converted.
|
||||
std::optional<float> f_opt = OptionalFromExpected(i_exp);
|
||||
EXPECT_EQ(f_opt, std::nullopt);
|
||||
|
||||
i_exp = base::ok(1);
|
||||
|
||||
// No conversion.
|
||||
i_opt = OptionalFromExpected(i_exp);
|
||||
EXPECT_EQ(i_opt, 1);
|
||||
|
||||
// Value type converted.
|
||||
f_opt = OptionalFromExpected(i_exp);
|
||||
EXPECT_EQ(f_opt, 1.0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace base
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include "base/process/process_metrics.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "base/types/optional_util.h"
|
||||
#include "build/build_config.h"
|
||||
#include "chrome/browser/extensions/chrome_content_browser_client_extensions_part.h"
|
||||
#include "chrome/browser/metrics/power/power_metrics_constants.h"
|
||||
@ -58,7 +60,8 @@ std::unique_ptr<base::ProcessMetrics> CreateProcessMetrics(
|
||||
ProcessMonitor::Metrics SampleMetrics(base::ProcessMetrics& process_metrics) {
|
||||
ProcessMonitor::Metrics metrics;
|
||||
|
||||
metrics.cpu_usage = process_metrics.GetPlatformIndependentCPUUsage();
|
||||
metrics.cpu_usage = base::OptionalFromExpected(
|
||||
process_metrics.GetPlatformIndependentCPUUsage());
|
||||
|
||||
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
|
||||
BUILDFLAG(IS_AIX)
|
||||
|
@ -5,13 +5,13 @@
|
||||
#include "chrome/browser/task_manager/sampling/task_group_sampler.h"
|
||||
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/functional/callback.h"
|
||||
#include "base/process/process_metrics.h"
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "build/build_config.h"
|
||||
#include "build/chromeos_buildflags.h"
|
||||
#include "chrome/browser/task_manager/task_manager_observer.h"
|
||||
@ -119,7 +119,7 @@ TaskGroupSampler::~TaskGroupSampler() {
|
||||
|
||||
double TaskGroupSampler::RefreshCpuUsage() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(worker_pool_sequenced_checker_);
|
||||
const std::optional<double> cpu_usage =
|
||||
const base::expected<double, base::ProcessCPUUsageError> cpu_usage =
|
||||
process_metrics_->GetPlatformIndependentCPUUsage();
|
||||
if (!cpu_usage.has_value()) {
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "base/process/process.h"
|
||||
#include "base/process/process_handle.h"
|
||||
#include "base/process/process_metrics.h"
|
||||
#include "base/types/optional_util.h"
|
||||
#include "build/build_config.h"
|
||||
#include "components/performance_manager/public/graph/process_node.h"
|
||||
#include "components/performance_manager/resource_attribution/cpu_measurement_monitor.h"
|
||||
@ -47,7 +48,8 @@ CPUMeasurementDelegateImpl::CPUMeasurementDelegateImpl(
|
||||
|
||||
std::optional<base::TimeDelta>
|
||||
CPUMeasurementDelegateImpl::GetCumulativeCPUUsage() {
|
||||
return process_metrics_->GetCumulativeCPUUsage();
|
||||
// TODO(crbug.com/40285287): Return the error code to callers.
|
||||
return base::OptionalFromExpected(process_metrics_->GetCumulativeCPUUsage());
|
||||
}
|
||||
|
||||
// The default production factory for CPUMeasurementDelegateImpl objects.
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include "base/process/launch.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/tracing/protos/chrome_track_event.pbzero.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "base/types/optional_util.h"
|
||||
#include "build/build_config.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/child_process_launcher_utils.h"
|
||||
@ -47,7 +49,7 @@ std::optional<base::TimeDelta> GetCPUUsage(base::ProcessHandle process_handle) {
|
||||
std::unique_ptr<base::ProcessMetrics> process_metrics =
|
||||
base::ProcessMetrics::CreateProcessMetrics(process_handle);
|
||||
#endif
|
||||
return process_metrics->GetCumulativeCPUUsage();
|
||||
return base::OptionalFromExpected(process_metrics->GetCumulativeCPUUsage());
|
||||
}
|
||||
#endif // !BUILDFLAG(IS_ANDROID)
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "base/functional/bind.h"
|
||||
#include "base/process/process_metrics.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "build/build_config.h"
|
||||
#include "content/browser/gpu/compositor_util.h"
|
||||
#include "content/browser/gpu/gpu_data_manager_impl.h"
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include "base/command_line.h"
|
||||
@ -32,6 +31,7 @@
|
||||
#include "base/task/thread_pool.h"
|
||||
#include "base/threading/platform_thread.h"
|
||||
#include "base/threading/thread_id_name_manager.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "content/common/process_visibility_tracker.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "content/public/common/process_type.h"
|
||||
@ -224,8 +224,8 @@ class ProcessCpuTimeMetrics::DetailedCpuTimeMetrics {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::optional<base::TimeDelta> cumulative_cpu_time =
|
||||
process_metrics_->GetCumulativeCPUUsage();
|
||||
const base::expected<base::TimeDelta, base::ProcessCPUUsageError>
|
||||
cumulative_cpu_time = process_metrics_->GetCumulativeCPUUsage();
|
||||
base::TimeDelta process_cpu_time_delta;
|
||||
if (cumulative_cpu_time.has_value()) {
|
||||
process_cpu_time_delta = cumulative_cpu_time.value() - reported_cpu_time_;
|
||||
@ -428,8 +428,8 @@ void ProcessCpuTimeMetrics::CollectHighLevelMetricsOnThreadPool() {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::optional<base::TimeDelta> cumulative_cpu_usage =
|
||||
process_metrics_->GetCumulativeCPUUsage();
|
||||
const base::expected<base::TimeDelta, base::ProcessCPUUsageError>
|
||||
cumulative_cpu_usage = process_metrics_->GetCumulativeCPUUsage();
|
||||
base::TimeDelta process_cpu_time_delta;
|
||||
if (cumulative_cpu_usage.has_value()) {
|
||||
process_cpu_time_delta = cumulative_cpu_usage.value() - reported_cpu_time_;
|
||||
|
@ -3,7 +3,6 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
|
||||
@ -18,6 +17,7 @@
|
||||
#include "base/test/perf_log.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/timer/timer.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "ipc/ipc_channel_proxy.h"
|
||||
#include "ipc/ipc_perftest_messages.h"
|
||||
#include "ipc/ipc_perftest_util.h"
|
||||
|
@ -4,12 +4,12 @@
|
||||
|
||||
#include "third_party/blink/renderer/core/inspector/inspector_performance_agent.h"
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include "base/process/process.h"
|
||||
#include "base/process/process_metrics.h"
|
||||
#include "base/time/time_override.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "build/build_config.h"
|
||||
#include "third_party/blink/public/platform/platform.h"
|
||||
#include "third_party/blink/renderer/core/execution_context/agent.h"
|
||||
|
Reference in New Issue
Block a user