#include "services/device/compute_pressure/cpu_probe.h"
#include <memory>
#include "base/functional/bind.h"
#include "base/location.h"
#include "build/build_config.h"
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "services/device/compute_pressure/cpu_probe_linux.h"
#elif BUILDFLAG(IS_WIN)
#include "services/device/compute_pressure/cpu_probe_win.h"
#elif BUILDFLAG(IS_MAC)
#include "services/device/compute_pressure/cpu_probe_mac.h"
#endif
namespace device {
namespace {
constexpr double kThresholdDelta = 0.03;
constexpr std::array<double,
static_cast<size_t>(mojom::PressureState::kMaxValue) + 1>
kStateThresholds = {0.3,
0.6,
0.9,
1.0};
}
std::unique_ptr<CpuProbe> CpuProbe::Create(
base::TimeDelta sampling_interval,
base::RepeatingCallback<void(mojom::PressureState)> sampling_callback) {
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
return CpuProbeLinux::Create(sampling_interval, std::move(sampling_callback));
#elif BUILDFLAG(IS_WIN)
return CpuProbeWin::Create(sampling_interval, std::move(sampling_callback));
#elif BUILDFLAG(IS_MAC)
return CpuProbeMac::Create(sampling_interval, std::move(sampling_callback));
#else
return nullptr;
#endif
}
CpuProbe::CpuProbe(
base::TimeDelta sampling_interval,
base::RepeatingCallback<void(mojom::PressureState)> sampling_callback)
: sampling_interval_(sampling_interval),
sampling_callback_(std::move(sampling_callback)) {
CHECK(sampling_callback_);
}
CpuProbe::~CpuProbe() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void CpuProbe::EnsureStarted() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (timer_.IsRunning()) {
return;
}
CHECK(!got_probe_baseline_) << "got_probe_baseline_ incorrectly reset";
Update();
timer_.Start(FROM_HERE, sampling_interval_,
base::BindRepeating(&CpuProbe::Update, base::Unretained(this)));
}
void CpuProbe::Stop() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
timer_.AbandonAndStop();
got_probe_baseline_ = false;
}
void CpuProbe::OnPressureSampleAvailable(PressureSample sample) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!timer_.IsRunning()) {
return;
}
if (!got_probe_baseline_) {
got_probe_baseline_ = true;
return;
}
sampling_callback_.Run(CalculateState(sample));
}
mojom::PressureState CpuProbe::CalculateState(const PressureSample& sample) {
auto* it =
base::ranges::lower_bound(kStateThresholds, sample.cpu_utilization);
if (it == kStateThresholds.end()) {
NOTREACHED_NORETURN() << "unexpected value: " << sample.cpu_utilization;
}
size_t state_index = std::distance(kStateThresholds.begin(), it);
if (last_state_index_ - state_index != 1 ||
kStateThresholds[state_index] - sample.cpu_utilization >=
kThresholdDelta) {
last_state_index_ = state_index;
}
return static_cast<mojom::PressureState>(last_state_index_);
}
}