0

Add SystemPowerMonitor in //components/power_metrics

It monitors system-wide power consumption.
Specifically, it first obtains absolute energy data from
power_metrics::EnergyMetricsProvider, then calculates the power
consumption and calls TRACE_COUNTER to write power value into trace log.

Bug: 1385251
Change-Id: I756755df3f6ec91688aef7dc4156b845246056ea
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4472031
Reviewed-by: Mark Pearson <mpearson@chromium.org>
Commit-Queue: Francois Pierre Doray <fdoray@chromium.org>
Reviewed-by: Francois Pierre Doray <fdoray@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1145923}
This commit is contained in:
Shiyi Zou
2023-05-18 14:22:37 +00:00
committed by Chromium LUCI CQ
parent 4e10c9c110
commit d2956aa221
7 changed files with 613 additions and 2 deletions

@ -259,6 +259,7 @@
X(TRACE_DISABLED_BY_DEFAULT("skia.gpu.cache")) \
X(TRACE_DISABLED_BY_DEFAULT("skia.shaders")) \
X(TRACE_DISABLED_BY_DEFAULT("SyncFileSystem")) \
X(TRACE_DISABLED_BY_DEFAULT("system_power")) \
X(TRACE_DISABLED_BY_DEFAULT("system_stats")) \
X(TRACE_DISABLED_BY_DEFAULT("thread_pool_diagnostics")) \
X(TRACE_DISABLED_BY_DEFAULT("toplevel.ipc")) \

@ -6035,7 +6035,6 @@ static_library("browser") {
"//components/crash/core/app",
"//components/metal_util",
"//components/policy/core/common:common_constants",
"//components/power_metrics",
"//components/remote_cocoa/browser:browser",
"//sandbox/mac:seatbelt",
"//sandbox/policy",
@ -6213,6 +6212,7 @@ static_library("browser") {
"//chrome/browser/enterprise/connectors/device_trust/key_management/core",
"//chrome/browser/enterprise/connectors/device_trust/key_management/core/persistence",
"//chrome/services/system_signals/public/cpp/browser",
"//components/power_metrics",
]
public_deps +=
[ "//chrome/browser/enterprise/connectors/analysis:sdk_manager" ]

@ -23,6 +23,7 @@
#include "base/task/thread_pool.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/time/time.h"
#include "base/trace_event/trace_log.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "build/config/compiler/compiler_buildflags.h"
@ -110,6 +111,10 @@
#include "components/user_manager/user_manager.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
#include "components/power_metrics/system_power_monitor.h"
#endif
namespace {
// The number of restarts to wait until removing the enable-benchmarking flag.
@ -741,6 +746,11 @@ void ChromeBrowserMainExtraPartsMetrics::PostBrowserStart() {
pressure_metrics_reporter_ = std::make_unique<PressureMetricsReporter>();
#endif // BUILDFLAG(IS_LINUX)
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
base::trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(
power_metrics::SystemPowerMonitor::GetInstance());
#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
HandleEnableBenchmarkingCountdownAsync();
}

@ -48,6 +48,13 @@ static_library("power_metrics") {
"energy_metrics_provider_linux.h",
]
}
if (is_win || is_linux) {
sources += [
"system_power_monitor.cc",
"system_power_monitor.h",
]
}
}
source_set("unit_tests") {
@ -57,6 +64,7 @@ source_set("unit_tests") {
deps = [
":power_metrics",
"//base",
"//testing/gtest",
]
@ -68,7 +76,11 @@ source_set("unit_tests") {
configs += [ "//build/config/compiler:enable_arc" ]
data = [ "test/data/" ]
}
deps += [ "//base" ]
if (is_win || is_linux) {
sources += [ "system_power_monitor_unittest.cc" ]
deps += [ "//base/test:test_support" ]
}
}

@ -0,0 +1,228 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/power_metrics/system_power_monitor.h"
#include <array>
#include <cstring>
#include "base/functional/bind.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/trace_event/trace_event.h"
namespace power_metrics {
namespace {
constexpr const char kTraceCategory[] =
TRACE_DISABLED_BY_DEFAULT("system_power");
constexpr const char kPackagePowerTraceCounterName[] = "Package Power (mW)";
constexpr const char kCpuPowerTraceCounterName[] = "CPU Power (mW)";
constexpr const char kIntegratedGpuPowerTraceCounterName[] = "iGPU Power (mW)";
constexpr const char kDramPowerTraceCounterName[] = "DRAM Power (mW)";
constexpr const char kPsysPowerTraceCounterName[] = "Psys Power (mW)";
constexpr const char kVddcrVddTraceCounterName[] = "VDDCR VDD (mW)";
constexpr const char kVddcrSocTraceCounterName[] = "VDDCR SOC (mW)";
constexpr const char kCurrentSocketTraceCounterName[] = "Current Socket (mW)";
constexpr const char kApuPowerTraceCounterName[] = "APU Power (mW)";
// Here we determine if the specified metric is valid according to whether its
// corresponding value in the provided sample is greater than 0, since the
// absolute energy must be greater than 0.
bool GenerateValidMetrics(const EnergyMetricsProvider::EnergyMetrics& sample,
std::vector<const char*>& valid_metrics) {
if (sample.package_nanojoules > 0) {
valid_metrics.push_back(kPackagePowerTraceCounterName);
}
if (sample.cpu_nanojoules > 0) {
valid_metrics.push_back(kCpuPowerTraceCounterName);
}
if (sample.gpu_nanojoules > 0) {
valid_metrics.push_back(kIntegratedGpuPowerTraceCounterName);
}
if (sample.dram_nanojoules > 0) {
valid_metrics.push_back(kDramPowerTraceCounterName);
}
if (sample.psys_nanojoules > 0) {
valid_metrics.push_back(kPsysPowerTraceCounterName);
}
if (sample.vdd_nanojoules > 0) {
valid_metrics.push_back(kVddcrVddTraceCounterName);
}
if (sample.soc_nanojoules > 0) {
valid_metrics.push_back(kVddcrSocTraceCounterName);
}
if (sample.socket_nanojoules > 0) {
valid_metrics.push_back(kCurrentSocketTraceCounterName);
}
if (sample.apu_nanojoules > 0) {
valid_metrics.push_back(kApuPowerTraceCounterName);
}
return !valid_metrics.empty();
}
int64_t CalculateNanojoulesDeltaFromSamples(
const EnergyMetricsProvider::EnergyMetrics& new_sample,
const EnergyMetricsProvider::EnergyMetrics& old_sample,
const char* metric) {
if (std::strcmp(metric, kPackagePowerTraceCounterName) == 0) {
return static_cast<int64_t>(new_sample.package_nanojoules -
old_sample.package_nanojoules);
} else if (std::strcmp(metric, kCpuPowerTraceCounterName) == 0) {
return static_cast<int64_t>(new_sample.cpu_nanojoules -
old_sample.cpu_nanojoules);
} else if (std::strcmp(metric, kIntegratedGpuPowerTraceCounterName) == 0) {
return static_cast<int64_t>(new_sample.gpu_nanojoules -
old_sample.gpu_nanojoules);
} else if (std::strcmp(metric, kDramPowerTraceCounterName) == 0) {
return static_cast<int64_t>(new_sample.dram_nanojoules -
old_sample.dram_nanojoules);
} else if (std::strcmp(metric, kPsysPowerTraceCounterName) == 0) {
return static_cast<int64_t>(new_sample.psys_nanojoules -
old_sample.psys_nanojoules);
} else if (std::strcmp(metric, kVddcrVddTraceCounterName) == 0) {
return static_cast<int64_t>(new_sample.vdd_nanojoules -
old_sample.vdd_nanojoules);
} else if (std::strcmp(metric, kVddcrSocTraceCounterName) == 0) {
return static_cast<int64_t>(new_sample.soc_nanojoules -
old_sample.soc_nanojoules);
} else if (std::strcmp(metric, kCurrentSocketTraceCounterName) == 0) {
return static_cast<int64_t>(new_sample.socket_nanojoules -
old_sample.socket_nanojoules);
} else if (std::strcmp(metric, kApuPowerTraceCounterName) == 0) {
return static_cast<int64_t>(new_sample.apu_nanojoules -
old_sample.apu_nanojoules);
}
NOTREACHED_NORETURN() << "Unexpected metric: " << metric;
}
} // namespace
SystemPowerMonitorDelegate::SystemPowerMonitorDelegate() = default;
SystemPowerMonitorDelegate::~SystemPowerMonitorDelegate() = default;
void SystemPowerMonitorDelegate::RecordSystemPower(const char* metric,
base::TimeTicks timestamp,
int64_t power) {
TRACE_COUNTER_WITH_TIMESTAMP1(TRACE_DISABLED_BY_DEFAULT("system_power"),
metric, timestamp, power);
}
bool SystemPowerMonitorDelegate::IsTraceCategoryEnabled() const {
bool enabled;
TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled);
return enabled;
}
SystemPowerMonitorHelper::SystemPowerMonitorHelper(
std::unique_ptr<EnergyMetricsProvider> provider,
std::unique_ptr<SystemPowerMonitorDelegate> delegate)
: provider_(std::move(provider)), delegate_(std::move(delegate)) {}
SystemPowerMonitorHelper::~SystemPowerMonitorHelper() = default;
void SystemPowerMonitorHelper::Start() {
CHECK(provider_);
CHECK(!timer_.IsRunning());
if (!delegate_->IsTraceCategoryEnabled()) {
return;
}
// If the provider fails to capture valid sample at the first time, we
// determine that it is unable to provide valid data and give up starting the
// timer.
auto sample = provider_->CaptureMetrics();
if (!sample.has_value()) {
return;
}
// To avoid redundant loops on invalid metrics, we select the valid metrics
// before start.
CHECK(valid_metrics_.empty());
if (!GenerateValidMetrics(sample.value(), valid_metrics_)) {
return;
}
last_sample_ = sample.value();
last_timestamp_ = base::TimeTicks::Now();
timer_.Start(FROM_HERE, kDefaultSampleInterval,
base::BindRepeating(&SystemPowerMonitorHelper::Sample,
base::Unretained(this)));
}
void SystemPowerMonitorHelper::Stop() {
timer_.Stop();
valid_metrics_.clear();
}
void SystemPowerMonitorHelper::Sample() {
// If the provider fails to capture valid metrics after the timer started,
// we leave the timer running.
auto sample = provider_->CaptureMetrics();
if (!sample.has_value()) {
return;
}
base::TimeTicks timestamp = base::TimeTicks::Now();
base::TimeDelta interval = timestamp - last_timestamp_;
CHECK(interval.is_positive());
for (auto const* metric : valid_metrics_) {
int64_t nanojoules = CalculateNanojoulesDeltaFromSamples(
sample.value(), last_sample_, metric);
CHECK_GE(nanojoules, 0ll);
int64_t milliwatts = nanojoules / interval.InMicroseconds();
delegate_->RecordSystemPower(metric, last_timestamp_, milliwatts);
}
last_sample_ = sample.value();
last_timestamp_ = timestamp;
}
bool SystemPowerMonitorHelper::IsTimerRunningForTesting() {
return timer_.IsRunning();
}
SystemPowerMonitor::SystemPowerMonitor()
: SystemPowerMonitor(EnergyMetricsProvider::Create(),
std::make_unique<SystemPowerMonitorDelegate>()) {}
SystemPowerMonitor::SystemPowerMonitor(
std::unique_ptr<EnergyMetricsProvider> provider,
std::unique_ptr<SystemPowerMonitorDelegate> delegate) {
helper_ = base::SequenceBound<SystemPowerMonitorHelper>(
base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
base::TaskPriority::BEST_EFFORT}),
std::move(provider), std::move(delegate));
}
SystemPowerMonitor::~SystemPowerMonitor() = default;
// static
SystemPowerMonitor* SystemPowerMonitor::GetInstance() {
static base::NoDestructor<SystemPowerMonitor> instance;
return instance.get();
}
void SystemPowerMonitor::OnTraceLogEnabled() {
helper_.AsyncCall(&SystemPowerMonitorHelper::Start);
}
void SystemPowerMonitor::OnTraceLogDisabled() {
helper_.AsyncCall(&SystemPowerMonitorHelper::Stop);
}
base::SequenceBound<SystemPowerMonitorHelper>*
SystemPowerMonitor::GetHelperForTesting() {
return helper_ ? &helper_ : nullptr;
}
} // namespace power_metrics

@ -0,0 +1,107 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_POWER_METRICS_SYSTEM_POWER_MONITOR_H_
#define COMPONENTS_POWER_METRICS_SYSTEM_POWER_MONITOR_H_
#include <memory>
#include <vector>
#include "base/threading/sequence_bound.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/trace_event/trace_log.h"
#include "components/power_metrics/energy_metrics_provider.h"
namespace power_metrics {
// A delegate to isolate System Power Monitor functionality mainly for
// testing.
class SystemPowerMonitorDelegate {
public:
SystemPowerMonitorDelegate();
SystemPowerMonitorDelegate(const SystemPowerMonitorDelegate&) = delete;
SystemPowerMonitorDelegate& operator=(const SystemPowerMonitorDelegate&) =
delete;
virtual ~SystemPowerMonitorDelegate();
// Emits trace counter. The metric string stands for trace counter name,
// timestamp is the counter timestamp, power is the corresponding counter
// value of system power consumption in units of milliwatts.
virtual void RecordSystemPower(const char* metric,
base::TimeTicks timestamp,
int64_t power);
// Returns whether the tracing category is enabled to determine if we should
// record.
virtual bool IsTraceCategoryEnabled() const;
};
// Manages a timer to regularly sample and emit trace events, whose start and
// stop are controlled by System Power Monitor.
class SystemPowerMonitorHelper {
public:
// Default sampling interval, which should be set to larger or equal to 50 ms.
static constexpr base::TimeDelta kDefaultSampleInterval =
base::Milliseconds(50);
SystemPowerMonitorHelper(
std::unique_ptr<EnergyMetricsProvider> provider,
std::unique_ptr<SystemPowerMonitorDelegate> delegate);
SystemPowerMonitorHelper(const SystemPowerMonitorHelper&) = delete;
SystemPowerMonitorHelper& operator=(const SystemPowerMonitorHelper&) = delete;
~SystemPowerMonitorHelper();
void Start();
void Stop();
void Sample();
bool IsTimerRunningForTesting();
private:
std::vector<const char*> valid_metrics_;
EnergyMetricsProvider::EnergyMetrics last_sample_;
base::TimeTicks last_timestamp_;
base::RepeatingTimer timer_;
// Used to derive instant system energy metrics.
std::unique_ptr<EnergyMetricsProvider> provider_;
std::unique_ptr<SystemPowerMonitorDelegate> delegate_;
};
// Monitors system-wide power consumption. Gets data from EnergyMetricsProvider.
class SystemPowerMonitor
: public base::trace_event::TraceLog::EnabledStateObserver {
public:
SystemPowerMonitor();
SystemPowerMonitor(const SystemPowerMonitor&) = delete;
SystemPowerMonitor& operator=(const SystemPowerMonitor&) = delete;
~SystemPowerMonitor() override;
static SystemPowerMonitor* GetInstance();
// TraceLog::EnabledStateObserver.
void OnTraceLogEnabled() override;
void OnTraceLogDisabled() override;
private:
friend class SystemPowerMonitorTest;
SystemPowerMonitor(std::unique_ptr<EnergyMetricsProvider> provider,
std::unique_ptr<SystemPowerMonitorDelegate> delegate);
base::SequenceBound<SystemPowerMonitorHelper>* GetHelperForTesting();
base::SequenceBound<SystemPowerMonitorHelper> helper_;
};
} // namespace power_metrics
#endif // COMPONENTS_POWER_METRICS_SYSTEM_POWER_MONITOR_H_

@ -0,0 +1,253 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/power_metrics/system_power_monitor.h"
#include "base/memory/raw_ptr.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace power_metrics {
class FakeProvider : public EnergyMetricsProvider {
public:
void set_metrics(EnergyMetrics metrics) { metrics_ = metrics; }
absl::optional<EnergyMetrics> CaptureMetrics() override { return metrics_; }
private:
absl::optional<EnergyMetrics> metrics_;
};
class FakeDelegate : public SystemPowerMonitorDelegate {
public:
void set_trace_category_enabled(bool enabled) {
trace_category_enabled_ = enabled;
}
void RecordSystemPower(const char* category,
base::TimeTicks timestamp,
int64_t power) override {
timestamp_ = timestamp;
if (strcmp(category, "Package Power (mW)") == 0) {
system_power_.package_nanojoules = static_cast<uint64_t>(power);
} else if (strcmp(category, "CPU Power (mW)") == 0) {
system_power_.cpu_nanojoules = static_cast<uint64_t>(power);
} else if (strcmp(category, "iGPU Power (mW)") == 0) {
system_power_.gpu_nanojoules = static_cast<uint64_t>(power);
} else if (strcmp(category, "DRAM Power (mW)") == 0) {
system_power_.dram_nanojoules = static_cast<uint64_t>(power);
} else if (strcmp(category, "Psys Power (mW)") == 0) {
system_power_.psys_nanojoules = static_cast<uint64_t>(power);
} else if (strcmp(category, "VDDCR VDD (mW)") == 0) {
system_power_.vdd_nanojoules = static_cast<uint64_t>(power);
} else if (strcmp(category, "VDDCR SOC (mW)") == 0) {
system_power_.soc_nanojoules = static_cast<uint64_t>(power);
} else if (strcmp(category, "Current Socket (mW)") == 0) {
system_power_.socket_nanojoules = static_cast<uint64_t>(power);
} else if (strcmp(category, "APU Power (mW)") == 0) {
system_power_.apu_nanojoules = static_cast<uint64_t>(power);
}
}
bool IsTraceCategoryEnabled() const override {
return trace_category_enabled_;
}
EnergyMetricsProvider::EnergyMetrics& SystemPower() { return system_power_; }
base::TimeTicks timestamp() { return timestamp_; }
private:
// We use EnergyMetrics to save recorded power data in milliwatts for
// simplicity.
EnergyMetricsProvider::EnergyMetrics system_power_;
base::TimeTicks timestamp_;
bool trace_category_enabled_{true};
};
class SystemPowerMonitorHelperTest : public testing::Test {
public:
SystemPowerMonitorHelperTest()
: task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
void SetUp() override {
auto provider = std::make_unique<FakeProvider>();
provider_ = provider.get();
auto delegate = std::make_unique<FakeDelegate>();
delegate_ = delegate.get();
helper_ = std::make_unique<SystemPowerMonitorHelper>(std::move(provider),
std::move(delegate));
}
void TearDown() override { helper_.reset(); }
base::test::TaskEnvironment& task_environment() { return task_environment_; }
SystemPowerMonitorHelper* helper() { return helper_.get(); }
FakeDelegate* delegate() { return delegate_.get(); }
FakeProvider* provider() { return provider_.get(); }
protected:
base::test::TaskEnvironment task_environment_;
private:
std::unique_ptr<SystemPowerMonitorHelper> helper_;
raw_ptr<FakeDelegate> delegate_;
raw_ptr<FakeProvider> provider_;
};
class SystemPowerMonitorTest : public testing::Test {
public:
SystemPowerMonitorTest() : task_environment_() {}
void SetUp() override {
auto provider = std::make_unique<FakeProvider>();
// Assign a valid metric to provider, so the timer can start successfully.
provider->set_metrics({1llu});
monitor_.reset(new SystemPowerMonitor(std::move(provider),
std::make_unique<FakeDelegate>()));
}
void TearDown() override { monitor_.reset(); }
SystemPowerMonitor* monitor() { return monitor_.get(); }
base::SequenceBound<SystemPowerMonitorHelper>* helper() {
return monitor_->GetHelperForTesting();
}
protected:
base::test::TaskEnvironment task_environment_;
private:
std::unique_ptr<SystemPowerMonitor> monitor_;
};
TEST_F(SystemPowerMonitorHelperTest, MonitorHelperStartStop) {
provider()->set_metrics({1llu});
helper()->Start();
ASSERT_TRUE(helper()->IsTimerRunningForTesting());
helper()->Stop();
ASSERT_FALSE(helper()->IsTimerRunningForTesting());
helper()->Start();
ASSERT_TRUE(helper()->IsTimerRunningForTesting());
helper()->Stop();
ASSERT_FALSE(helper()->IsTimerRunningForTesting());
}
TEST_F(SystemPowerMonitorHelperTest, TimerStartFailed_InvalidSample) {
// We haven't set metrics for provider, so monitor gets an
// absl::nullopt sample at the beginning and it will not start.
helper()->Start();
ASSERT_FALSE(helper()->IsTimerRunningForTesting());
}
TEST_F(SystemPowerMonitorHelperTest, TimerStartFailed_MetricsAllZero) {
// If the metrics are all 0, we determine that there is no valid metric
// provided, so monitor will not start.
provider()->set_metrics({});
helper()->Start();
ASSERT_FALSE(helper()->IsTimerRunningForTesting());
}
TEST_F(SystemPowerMonitorHelperTest, TraceCategoryEnableDisable) {
provider()->set_metrics({1llu});
delegate()->set_trace_category_enabled(false);
ASSERT_FALSE(delegate()->IsTraceCategoryEnabled());
helper()->Start();
ASSERT_FALSE(helper()->IsTimerRunningForTesting());
delegate()->set_trace_category_enabled(true);
ASSERT_TRUE(delegate()->IsTraceCategoryEnabled());
helper()->Start();
ASSERT_TRUE(helper()->IsTimerRunningForTesting());
}
TEST_F(SystemPowerMonitorHelperTest, TestSample) {
EnergyMetricsProvider::EnergyMetrics sample1 = {
100000llu, 100000llu, 100000llu, 100000llu, 100000llu,
100000llu, 100000llu, 100000llu, 100000llu};
EnergyMetricsProvider::EnergyMetrics sample2 = {
200000llu, 300000llu, 400000llu, 500000llu, 600000llu,
700000llu, 800000llu, 900000llu, 1000000llu};
provider()->set_metrics(sample1);
helper()->Start();
ASSERT_TRUE(helper()->IsTimerRunningForTesting());
provider()->set_metrics(sample2);
task_environment().FastForwardBy(
SystemPowerMonitorHelper::kDefaultSampleInterval);
auto power = delegate()->SystemPower();
EXPECT_EQ(delegate()->timestamp() +
SystemPowerMonitorHelper::kDefaultSampleInterval,
task_environment().NowTicks());
EXPECT_EQ(
power.package_nanojoules,
(sample2.package_nanojoules - sample1.package_nanojoules) /
SystemPowerMonitorHelper::kDefaultSampleInterval.InMicroseconds());
EXPECT_EQ(
power.cpu_nanojoules,
(sample2.cpu_nanojoules - sample1.cpu_nanojoules) /
SystemPowerMonitorHelper::kDefaultSampleInterval.InMicroseconds());
EXPECT_EQ(
power.gpu_nanojoules,
(sample2.gpu_nanojoules - sample1.gpu_nanojoules) /
SystemPowerMonitorHelper::kDefaultSampleInterval.InMicroseconds());
EXPECT_EQ(
power.dram_nanojoules,
(sample2.dram_nanojoules - sample1.dram_nanojoules) /
SystemPowerMonitorHelper::kDefaultSampleInterval.InMicroseconds());
EXPECT_EQ(
power.psys_nanojoules,
(sample2.psys_nanojoules - sample1.psys_nanojoules) /
SystemPowerMonitorHelper::kDefaultSampleInterval.InMicroseconds());
EXPECT_EQ(
power.vdd_nanojoules,
(sample2.vdd_nanojoules - sample1.vdd_nanojoules) /
SystemPowerMonitorHelper::kDefaultSampleInterval.InMicroseconds());
EXPECT_EQ(
power.soc_nanojoules,
(sample2.soc_nanojoules - sample1.soc_nanojoules) /
SystemPowerMonitorHelper::kDefaultSampleInterval.InMicroseconds());
EXPECT_EQ(
power.socket_nanojoules,
(sample2.socket_nanojoules - sample1.socket_nanojoules) /
SystemPowerMonitorHelper::kDefaultSampleInterval.InMicroseconds());
EXPECT_EQ(
power.apu_nanojoules,
(sample2.apu_nanojoules - sample1.apu_nanojoules) /
SystemPowerMonitorHelper::kDefaultSampleInterval.InMicroseconds());
}
TEST_F(SystemPowerMonitorTest, TraceLogEnableDisable) {
ASSERT_NE(helper(), nullptr);
base::test::TestFuture<bool> future_enable;
monitor()->OnTraceLogEnabled();
helper()
->AsyncCall(&SystemPowerMonitorHelper::IsTimerRunningForTesting)
.Then(base::BindOnce(
[](base::OnceCallback<void(bool)> callback, bool is_running) {
std::move(callback).Run(is_running);
},
future_enable.GetCallback()));
EXPECT_TRUE(future_enable.Get());
base::test::TestFuture<bool> future_disable;
monitor()->OnTraceLogDisabled();
helper()
->AsyncCall(&SystemPowerMonitorHelper::IsTimerRunningForTesting)
.Then(base::BindOnce(
[](base::OnceCallback<void(bool)> callback, bool is_running) {
std::move(callback).Run(is_running);
},
future_disable.GetCallback()));
EXPECT_FALSE(future_disable.Get());
}
} // namespace power_metrics