blob: a1dfdb5079835667f7dfcd5a89fee365bc50b5f1 [file] [log] [blame]
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_POWER_SCHEDULER_POWER_SCHEDULER_H_
#define COMPONENTS_POWER_SCHEDULER_POWER_SCHEDULER_H_
#include "base/component_export.h"
#include "base/cpu_affinity_posix.h"
#include "base/memory/raw_ptr.h"
#include "base/no_destructor.h"
#include "base/process/process_metrics.h"
#include "base/task/task_observer.h"
#include "components/power_scheduler/power_mode_arbiter.h"
namespace power_scheduler {
enum class SchedulingPolicy {
kNone,
kLittleCoresOnly,
kThrottleIdle,
kThrottleIdleAndNopAnimation,
};
struct COMPONENT_EXPORT(POWER_SCHEDULER) SchedulingPolicyParams {
SchedulingPolicy policy = SchedulingPolicy::kNone;
// If specified, the policy's throttling only takes effect after at least
// |min_time_in_mode| has elapsed since entering a throttleable PowerMode.
base::TimeDelta min_time_in_mode;
// If specified, the policy's throttling only takes effect if the process has
// spent at least (min_cputime_ratio * elapsed time) CPU time since entering
// the throttleable mode.
double min_cputime_ratio = 0;
};
class COMPONENT_EXPORT(POWER_SCHEDULER) PowerScheduler
: public base::TaskObserver,
public power_scheduler::PowerModeArbiter::Observer {
public:
static PowerScheduler* GetInstance();
PowerScheduler(const PowerScheduler&) = delete;
PowerScheduler& operator=(const PowerScheduler&) = delete;
// base::TaskObserver implementation.
void WillProcessTask(const base::PendingTask&,
bool was_blocked_or_low_priority) override;
void DidProcessTask(const base::PendingTask&) override;
// power_scheduler::PowerModeArbiter::Observer implementation.
void OnPowerModeChanged(power_scheduler::PowerMode old_mode,
power_scheduler::PowerMode new_mode) override;
// Set up the power observer if required by current policy.
// This function should be called from the main thread during the
// initialization of the process. Subsequent calls from other threads will
// have no effect.
void Setup();
// Set the scheduling policy based on the feature list and field trial
// parameters. Does not have any effect if the PowerScheduler features are
// disabled. Should be called on the process's main thread during process
// startup after feature list initialization.
void InitializePolicyFromFeatureList();
// Set the scheduling policy for the current process. Should be called on the
// process's main thread during process startup after feature list
// initialization. The affinity might change at runtime (e.g. after Chrome
// goes back from background), so the power scheduler will set up a polling
// mechanism to enforce the given mode.
void SetPolicy(SchedulingPolicy);
void SetPolicy(SchedulingPolicyParams);
// Protected methods for testing.
protected:
PowerScheduler(PowerModeArbiter*);
~PowerScheduler() override;
void SetupTaskRunners(
scoped_refptr<base::TaskRunner> thread_pool_task_runner);
base::CpuAffinityMode GetEnforcedCpuAffinityForTesting() {
return enforced_affinity_;
}
// Virtual for testing.
virtual base::TimeDelta GetProcessCpuTime();
base::CpuAffinityMode GetTargetCpuAffinity();
// Set the CPU affinity of the current process and set up the polling
// mechanism to enforce the affinity mode. The check is implemented as a
// TaskObserver that runs every 100th main thread task.
//
// Virtual for testing.
virtual void EnforceCpuAffinityOnSequence();
SchedulingPolicyParams GetPolicyForTesting() { return current_policy_; }
private:
friend class base::NoDestructor<PowerScheduler>;
// Register the power mode observer and apply the current policy if necessary.
void SetupPolicyOnSequence(SchedulingPolicyParams);
void OnPowerModeChangedOnSequence(power_scheduler::PowerMode old_mode,
power_scheduler::PowerMode new_mode);
// Apply CPU affinity settings according to current policy and power mode.
void ApplyPolicyOnSequence();
SEQUENCE_CHECKER(main_thread_checker_);
SEQUENCE_CHECKER(thread_pool_checker_);
scoped_refptr<base::TaskRunner> main_thread_task_runner_;
scoped_refptr<base::TaskRunner> thread_pool_task_runner_;
// Accessed only on the main thread.
static constexpr int kUpdateAfterEveryNTasks = 100;
int task_counter_ = 0;
bool did_call_setup_ = false;
SchedulingPolicyParams pending_policy_;
// Accessed only on the |thread_pool_task_runner_| sequence.
raw_ptr<PowerModeArbiter> arbiter_;
bool power_observer_registered_ = false;
bool task_observer_registered_ = false;
base::CpuAffinityMode enforced_affinity_ = base::CpuAffinityMode::kDefault;
base::TimeTicks enforced_affinity_setup_time_;
power_scheduler::PowerMode current_power_mode_ =
power_scheduler::PowerMode::kMaxValue;
SchedulingPolicyParams current_policy_;
base::TimeTicks time_entered_throttleable_mode_;
base::TimeDelta cputime_entered_throttleable_mode_;
std::unique_ptr<base::ProcessMetrics> process_metrics_;
};
} // namespace power_scheduler
#endif // COMPONENTS_POWER_SCHEDULER_POWER_SCHEDULER_H_