Commit bf73bd94 authored by Yury Khmel's avatar Yury Khmel Committed by Commit Bot

arc: extends throttle service.

This adds ability to enforce throttling mode and adds obsever to receive
throttling change updates.
DD: go/arc_power_control

TEST=Unit test + locally in context of prototype.
BUG=b:170982650

Change-Id: I1fe3633ff5792355917c890280155a8b5d73892f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2477454
Commit-Queue: Yury Khmel <khmel@google.com>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#818748}
parent f64b5a8c
......@@ -56,4 +56,9 @@ std::string ThrottleObserver::GetDebugDescription() const {
(active() ? "active" : "inactive") + ")");
}
std::ostream& operator<<(std::ostream& os,
const ThrottleObserver::PriorityLevel& level) {
return os << LevelToString(level);
}
} // namespace chromeos
......@@ -63,6 +63,9 @@ class ThrottleObserver {
DISALLOW_COPY_AND_ASSIGN(ThrottleObserver);
};
std::ostream& operator<<(std::ostream& os,
const ThrottleObserver::PriorityLevel& level);
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_THROTTLE_OBSERVER_H_
......@@ -16,6 +16,14 @@ ThrottleService::ThrottleService(content::BrowserContext* context)
ThrottleService::~ThrottleService() = default;
void ThrottleService::AddServiceObserver(ServiceObserver* observer) {
service_observers_.AddObserver(observer);
}
void ThrottleService::RemoveServiceObserver(ServiceObserver* observer) {
service_observers_.RemoveObserver(observer);
}
void ThrottleService::NotifyObserverStateChangedForTesting() {
OnObserverStateChanged();
}
......@@ -48,19 +56,34 @@ void ThrottleService::StopObservers() {
observer->StopObserving();
}
void ThrottleService::SetEnforced(ThrottleObserver::PriorityLevel level) {
if (enforced_level_ == level)
return;
enforced_level_ = level;
OnObserverStateChanged();
}
void ThrottleService::OnObserverStateChanged() {
ThrottleObserver::PriorityLevel max_level =
ThrottleObserver::PriorityLevel::LOW;
ThrottleObserver* effective_observer = nullptr;
for (auto& observer : observers_) {
if (!observer->active())
continue;
DVLOG(1) << "Active Throttle Observer: " << observer->GetDebugDescription();
if (observer->level() >= max_level) {
max_level = observer->level();
effective_observer = observer.get();
if (enforced_level_ == ThrottleObserver::PriorityLevel::UNKNOWN) {
// Auto mode
for (auto& observer : observers_) {
if (!observer->active())
continue;
DVLOG(1) << "Active Throttle Observer: "
<< observer->GetDebugDescription();
if (observer->level() >= max_level) {
max_level = observer->level();
effective_observer = observer.get();
}
}
} else {
// Enforced mode
max_level = enforced_level_;
DVLOG(1) << "Throttle is enforced to " << enforced_level_;
}
if (effective_observer != last_effective_observer_) {
......@@ -83,6 +106,9 @@ void ThrottleService::SetLevel(ThrottleObserver::PriorityLevel level) {
return;
level_ = level;
ThrottleInstance(level);
for (auto& observer : service_observers_)
observer.OnThrottle(level);
}
} // namespace chromeos
......@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "chrome/browser/chromeos/throttle_observer.h"
namespace content {
......@@ -26,13 +27,32 @@ namespace chromeos {
// PriorityLevel, and calls ThrottleInstance with that level.
class ThrottleService {
public:
class ServiceObserver : public base::CheckedObserver {
public:
// Notifies that throttling has been changed.
virtual void OnThrottle(ThrottleObserver::PriorityLevel level) = 0;
};
explicit ThrottleService(content::BrowserContext* context);
virtual ~ThrottleService();
void AddServiceObserver(ServiceObserver* observer);
void RemoveServiceObserver(ServiceObserver* observer);
// Functions for testing
void NotifyObserverStateChangedForTesting();
void SetObserversForTesting(
std::vector<std::unique_ptr<ThrottleObserver>> observers);
// Sets enforced mode when level is fixed regardless of other observers.
// Setting this to ThrottleObserver::PriorityLevel::UNKNOWN effectifly
// switches to auto mode.
void SetEnforced(ThrottleObserver::PriorityLevel level);
ThrottleObserver::PriorityLevel level() const { return level_; }
ThrottleObserver::PriorityLevel enforced_level() const {
return enforced_level_;
}
void set_level_for_testing(ThrottleObserver::PriorityLevel level);
protected:
......@@ -58,15 +78,17 @@ class ThrottleService {
return observers_;
}
content::BrowserContext* context() const { return context_; }
ThrottleObserver::PriorityLevel level() const { return level_; }
private:
content::BrowserContext* const context_;
std::vector<std::unique_ptr<ThrottleObserver>> observers_;
ThrottleObserver::PriorityLevel level_{
ThrottleObserver::PriorityLevel::UNKNOWN};
ThrottleObserver::PriorityLevel enforced_level_ = {
ThrottleObserver::PriorityLevel::UNKNOWN};
ThrottleObserver* last_effective_observer_{nullptr};
base::TimeTicks last_throttle_transition_;
base::ObserverList<ServiceObserver> service_observers_;
base::WeakPtrFactory<ThrottleService> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(ThrottleService);
......
......@@ -12,6 +12,38 @@
namespace chromeos {
namespace {
class TestObserver : public ThrottleService::ServiceObserver {
public:
TestObserver() = default;
~TestObserver() override = default;
// ThrottleService::Observer:
void OnThrottle(ThrottleObserver::PriorityLevel level) override {
last_level_ = level;
++update_count_;
}
int GetUpdateCountAndReset() {
const int update_count = update_count_;
update_count_ = 0;
return update_count;
}
ThrottleObserver::PriorityLevel last_level() const { return last_level_; }
private:
int update_count_ = 0;
ThrottleObserver::PriorityLevel last_level_ =
ThrottleObserver::PriorityLevel::UNKNOWN;
TestObserver(TestObserver const&) = delete;
TestObserver& operator=(TestObserver const&) = delete;
};
} // namespace
class TestThrottleService : public ThrottleService {
public:
using ThrottleService::ThrottleService;
......@@ -169,4 +201,47 @@ TEST_F(ThrottleServiceTest, RecordCpuRestrictionDisabledUMA) {
service()->last_recorded_observer_name());
}
// Tests that verifies enforcement mode.
TEST_F(ThrottleServiceTest, TestEnforced) {
low_observer()->SetActive(true);
EXPECT_EQ(ThrottleObserver::PriorityLevel::LOW, service()->level());
service()->SetEnforced(ThrottleObserver::PriorityLevel::NORMAL);
EXPECT_EQ(ThrottleObserver::PriorityLevel::NORMAL, service()->level());
service()->SetEnforced(ThrottleObserver::PriorityLevel::UNKNOWN);
EXPECT_EQ(ThrottleObserver::PriorityLevel::LOW, service()->level());
low_observer()->SetActive(false);
critical_observer()->SetActive(true);
EXPECT_EQ(ThrottleObserver::PriorityLevel::CRITICAL,
service()->last_throttle_level());
service()->SetEnforced(ThrottleObserver::PriorityLevel::LOW);
EXPECT_EQ(ThrottleObserver::PriorityLevel::LOW, service()->level());
service()->SetEnforced(ThrottleObserver::PriorityLevel::UNKNOWN);
EXPECT_EQ(ThrottleObserver::PriorityLevel::CRITICAL, service()->level());
}
// Tests that verifies observer notifications.
TEST_F(ThrottleServiceTest, TestObservers) {
TestObserver test_observer;
service()->AddServiceObserver(&test_observer);
EXPECT_EQ(0, test_observer.GetUpdateCountAndReset());
low_observer()->SetActive(true);
EXPECT_EQ(ThrottleObserver::PriorityLevel::LOW, test_observer.last_level());
EXPECT_EQ(ThrottleObserver::PriorityLevel::LOW, service()->level());
EXPECT_EQ(1, test_observer.GetUpdateCountAndReset());
low_observer()->SetActive(false);
critical_observer()->SetActive(true);
EXPECT_EQ(ThrottleObserver::PriorityLevel::CRITICAL,
test_observer.last_level());
EXPECT_EQ(ThrottleObserver::PriorityLevel::CRITICAL, service()->level());
EXPECT_EQ(1, test_observer.GetUpdateCountAndReset());
service()->RemoveServiceObserver(&test_observer);
critical_observer()->SetActive(false);
low_observer()->SetActive(true);
EXPECT_EQ(ThrottleObserver::PriorityLevel::CRITICAL,
test_observer.last_level());
EXPECT_EQ(ThrottleObserver::PriorityLevel::LOW, service()->level());
EXPECT_EQ(0, test_observer.GetUpdateCountAndReset());
}
} // namespace chromeos
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment