| // Copyright 2024 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/dbus_schedqos_state_handler.h" |
| |
| #include <memory> |
| |
| #include "base/process/process.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/task_environment.h" |
| #include "base/threading/platform_thread.h" |
| #include "base/time/time.h" |
| #include "chromeos/ash/components/dbus/resourced/fake_resourced_client.h" |
| #include "chromeos/ash/components/dbus/resourced/resourced_client.h" |
| #include "dbus/dbus_result.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/cros_system_api/dbus/resource_manager/dbus-constants.h" |
| |
| using ::testing::ElementsAre; |
| using ::testing::FieldsAre; |
| using ::testing::Pair; |
| using ::testing::UnorderedElementsAre; |
| |
| namespace ash { |
| |
| class DBusSchedQOSStateHandlerTest : public testing::Test { |
| protected: |
| void SetUp() override { |
| resourced_client_ = ResourcedClient::InitializeFake(); |
| handler_.reset(DBusSchedQOSStateHandler::Create( |
| base::SequencedTaskRunner::GetCurrentDefault())); |
| process_ = base::Process::Current(); |
| } |
| |
| void TearDown() override { |
| handler_.reset(); |
| resourced_client_ = nullptr; |
| ResourcedClient::Shutdown(); |
| } |
| |
| // The handler under test. |
| base::Process process_; |
| std::unique_ptr<DBusSchedQOSStateHandler> handler_; |
| raw_ptr<FakeResourcedClient> resourced_client_ = nullptr; |
| |
| base::test::SingleThreadTaskEnvironment task_environment_{ |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME}; |
| }; |
| |
| TEST_F(DBusSchedQOSStateHandlerTest, CanSetProcessPriority) { |
| EXPECT_TRUE(handler_->CanSetProcessPriority()); |
| EXPECT_TRUE(process_.CanSetPriority()); |
| } |
| |
| TEST_F(DBusSchedQOSStateHandlerTest, InitializeProcessPriority) { |
| ASSERT_TRUE(resourced_client_->TriggerServiceAvailable(true)); |
| task_environment_.RunUntilIdle(); |
| ASSERT_EQ(resourced_client_->GetProcessStateHistory().size(), 0ul); |
| |
| process_.InitializePriority(); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_THAT(resourced_client_->GetProcessStateHistory(), |
| ElementsAre(Pair(process_.Pid(), |
| resource_manager::ProcessState::kNormal))); |
| } |
| |
| TEST_F(DBusSchedQOSStateHandlerTest, SetProcessPriority) { |
| ASSERT_TRUE(resourced_client_->TriggerServiceAvailable(true)); |
| task_environment_.RunUntilIdle(); |
| process_.InitializePriority(); |
| base::Process dummy_process = base::Process::Open(1); |
| dummy_process.InitializePriority(); |
| task_environment_.RunUntilIdle(); |
| |
| ASSERT_EQ(resourced_client_->GetProcessStateHistory().size(), 2ul); |
| |
| process_.SetPriority(base::Process::Priority::kUserBlocking); |
| dummy_process.SetPriority(base::Process::Priority::kBestEffort); |
| dummy_process.SetPriority(base::Process::Priority::kUserVisible); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_EQ(resourced_client_->GetProcessStateHistory().size(), 5ul); |
| |
| EXPECT_THAT( |
| absl::MakeSpan(resourced_client_->GetProcessStateHistory()).last(3), |
| ElementsAre( |
| Pair(process_.Pid(), resource_manager::ProcessState::kNormal), |
| Pair(dummy_process.Pid(), |
| resource_manager::ProcessState::kBackground), |
| Pair(dummy_process.Pid(), resource_manager::ProcessState::kNormal))); |
| } |
| |
| TEST_F(DBusSchedQOSStateHandlerTest, |
| SetProcessPriorityBeforeResourcedAvailable) { |
| process_.InitializePriority(); |
| ASSERT_TRUE(process_.SetPriority(base::Process::Priority::kUserBlocking)); |
| base::Process dummy_process1 = base::Process::Open(1); |
| dummy_process1.InitializePriority(); |
| ASSERT_TRUE(dummy_process1.SetPriority(base::Process::Priority::kBestEffort)); |
| // A process with InitializePriority() without SetPriority(). |
| base::Process dummy_process2 = base::Process::Open(2); |
| dummy_process2.InitializePriority(); |
| task_environment_.RunUntilIdle(); |
| |
| ASSERT_EQ(resourced_client_->GetProcessStateHistory().size(), 0ul); |
| |
| ASSERT_TRUE(resourced_client_->TriggerServiceAvailable(true)); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_THAT( |
| resourced_client_->GetProcessStateHistory(), |
| UnorderedElementsAre( |
| Pair(process_.Pid(), resource_manager::ProcessState::kNormal), |
| Pair(dummy_process1.Pid(), |
| resource_manager::ProcessState::kBackground), |
| Pair(dummy_process2.Pid(), resource_manager::ProcessState::kNormal))); |
| |
| ASSERT_TRUE(process_.SetPriority(base::Process::Priority::kBestEffort)); |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(resourced_client_->GetProcessStateHistory().size(), 4ul); |
| EXPECT_THAT( |
| resourced_client_->GetProcessStateHistory()[3], |
| Pair(process_.Pid(), resource_manager::ProcessState::kBackground)); |
| } |
| |
| TEST_F(DBusSchedQOSStateHandlerTest, SetProcessPriorityBeforeInitialize) { |
| ASSERT_TRUE(resourced_client_->TriggerServiceAvailable(true)); |
| task_environment_.RunUntilIdle(); |
| ASSERT_EQ(resourced_client_->GetProcessStateHistory().size(), 0ul); |
| |
| EXPECT_FALSE(process_.SetPriority(base::Process::Priority::kUserBlocking)); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_EQ(resourced_client_->GetProcessStateHistory().size(), 0ul); |
| |
| process_.InitializePriority(); |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(resourced_client_->GetProcessStateHistory().size(), 1ul); |
| |
| ASSERT_TRUE(process_.SetPriority(base::Process::Priority::kBestEffort)); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_EQ(resourced_client_->GetProcessStateHistory().size(), 2ul); |
| |
| EXPECT_THAT( |
| resourced_client_->GetProcessStateHistory()[1], |
| Pair(process_.Pid(), resource_manager::ProcessState::kBackground)); |
| } |
| |
| TEST_F(DBusSchedQOSStateHandlerTest, SetProcessPriorityAfterForgetPriority) { |
| ASSERT_TRUE(resourced_client_->TriggerServiceAvailable(true)); |
| task_environment_.RunUntilIdle(); |
| process_.InitializePriority(); |
| task_environment_.RunUntilIdle(); |
| |
| ASSERT_EQ(resourced_client_->GetProcessStateHistory().size(), 1ul); |
| |
| ASSERT_TRUE(process_.SetPriority(base::Process::Priority::kUserBlocking)); |
| task_environment_.RunUntilIdle(); |
| ASSERT_EQ(resourced_client_->GetProcessStateHistory().size(), 2ul); |
| |
| process_.ForgetPriority(); |
| |
| EXPECT_FALSE(process_.SetPriority(base::Process::Priority::kBestEffort)); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_EQ(resourced_client_->GetProcessStateHistory().size(), 2ul); |
| } |
| |
| TEST_F(DBusSchedQOSStateHandlerTest, SetProcessPriorityRetryOnDisconnect) { |
| process_.InitializePriority(); |
| base::Process dummy_process1 = base::Process::Open(1); |
| dummy_process1.InitializePriority(); |
| base::Process dummy_process2 = base::Process::Open(2); |
| dummy_process2.InitializePriority(); |
| ASSERT_TRUE(resourced_client_->TriggerServiceAvailable(true)); |
| task_environment_.RunUntilIdle(); |
| |
| ASSERT_EQ(resourced_client_->GetProcessStateHistory().size(), 3ul); |
| |
| resourced_client_->SetProcessStateResult( |
| dbus::DBusResult::kErrorServiceUnknown); |
| |
| ASSERT_TRUE(process_.SetPriority(base::Process::Priority::kBestEffort)); |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(resourced_client_->GetProcessStateHistory().size(), 4ul); |
| EXPECT_THAT( |
| resourced_client_->GetProcessStateHistory()[3], |
| Pair(process_.Pid(), resource_manager::ProcessState::kBackground)); |
| EXPECT_EQ(process_.GetPriority(), base::Process::Priority::kBestEffort); |
| |
| EXPECT_TRUE(dummy_process1.SetPriority(base::Process::Priority::kBestEffort)); |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(dummy_process1.GetPriority(), base::Process::Priority::kBestEffort); |
| |
| EXPECT_TRUE( |
| dummy_process1.SetPriority(base::Process::Priority::kUserBlocking)); |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(dummy_process1.GetPriority(), |
| base::Process::Priority::kUserBlocking); |
| |
| // DBus request is not sent until it reconnects to resourced. |
| EXPECT_EQ(resourced_client_->GetProcessStateHistory().size(), 4ul); |
| |
| resourced_client_->SetProcessStateResult(dbus::DBusResult::kSuccess); |
| |
| // When resourced is reconnected, retry the request. |
| EXPECT_TRUE(resourced_client_->TriggerServiceAvailable(true)); |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(resourced_client_->GetProcessStateHistory().size(), 6ul); |
| EXPECT_THAT( |
| absl::MakeSpan(resourced_client_->GetProcessStateHistory()).last(2), |
| UnorderedElementsAre( |
| Pair(process_.Pid(), resource_manager::ProcessState::kBackground), |
| Pair(dummy_process1.Pid(), resource_manager::ProcessState::kNormal))); |
| } |
| |
| TEST_F(DBusSchedQOSStateHandlerTest, SetProcessPriorityUMA) { |
| base::HistogramTester histogram_tester; |
| ASSERT_TRUE(resourced_client_->TriggerServiceAvailable(true)); |
| task_environment_.RunUntilIdle(); |
| |
| resourced_client_->DelaySetProcessStateResult(base::Microseconds(123)); |
| process_.InitializePriority(); |
| task_environment_.RunUntilIdle(); |
| task_environment_.FastForwardBy(base::Microseconds(123)); |
| task_environment_.RunUntilIdle(); |
| |
| histogram_tester.ExpectBucketCount( |
| "Scheduling.DBusSchedQoS.SetProcessStateLatency", 123, 1); |
| |
| resourced_client_->DelaySetProcessStateResult(base::Microseconds(456)); |
| process_.SetPriority(base::Process::Priority::kUserBlocking); |
| task_environment_.RunUntilIdle(); |
| task_environment_.FastForwardBy(base::Microseconds(456)); |
| task_environment_.RunUntilIdle(); |
| |
| histogram_tester.ExpectBucketCount( |
| "Scheduling.DBusSchedQoS.SetProcessStateLatency", 456, 1); |
| } |
| |
| TEST_F(DBusSchedQOSStateHandlerTest, GetProcessPriority) { |
| // Without initializing the priority, the default priority is returned. |
| EXPECT_EQ(process_.GetPriority(), base::Process::Priority::kUserBlocking); |
| |
| process_.InitializePriority(); |
| // Default priority is base::Process::Priority::kUserBlocking. |
| EXPECT_EQ(process_.GetPriority(), base::Process::Priority::kUserBlocking); |
| |
| ASSERT_TRUE(process_.SetPriority(base::Process::Priority::kBestEffort)); |
| // Even before the D-Bus request is sent, the cached priority is updated. |
| EXPECT_EQ(process_.GetPriority(), base::Process::Priority::kBestEffort); |
| ASSERT_EQ(resourced_client_->GetProcessStateHistory().size(), 0ul); |
| |
| ASSERT_TRUE(resourced_client_->TriggerServiceAvailable(true)); |
| task_environment_.RunUntilIdle(); |
| |
| base::Process dummy_process = base::Process::Open(1); |
| dummy_process.InitializePriority(); |
| ASSERT_TRUE(dummy_process.SetPriority(base::Process::Priority::kBestEffort)); |
| ASSERT_TRUE(process_.SetPriority(base::Process::Priority::kUserBlocking)); |
| // Caches priorities of multiple processes. |
| EXPECT_EQ(dummy_process.GetPriority(), base::Process::Priority::kBestEffort); |
| EXPECT_EQ(process_.GetPriority(), base::Process::Priority::kUserBlocking); |
| |
| ASSERT_TRUE(process_.SetPriority(base::Process::Priority::kUserVisible)); |
| // base::Process::Priority::kUserVisible is translated as |
| // base::Process::Priority::kUserBlocking. |
| EXPECT_EQ(process_.GetPriority(), base::Process::Priority::kUserBlocking); |
| |
| process_.ForgetPriority(); |
| dummy_process.ForgetPriority(); |
| // On ForgetPriority(), cached priority is cleared. |
| EXPECT_EQ(process_.GetPriority(), base::Process::Priority::kUserBlocking); |
| EXPECT_EQ(dummy_process.GetPriority(), |
| base::Process::Priority::kUserBlocking); |
| } |
| |
| TEST_F(DBusSchedQOSStateHandlerTest, SetThreadType) { |
| ASSERT_TRUE(resourced_client_->TriggerServiceAvailable(true)); |
| task_environment_.RunUntilIdle(); |
| process_.InitializePriority(); |
| task_environment_.RunUntilIdle(); |
| |
| ASSERT_EQ(resourced_client_->GetThreadStateHistory().size(), 1ul); |
| |
| base::PlatformThread::SetThreadType(process_.Pid(), 100, |
| base::ThreadType::kBackground, |
| base::IsViaIPC(false)); |
| base::PlatformThread::SetThreadType( |
| process_.Pid(), 101, base::ThreadType::kUtility, base::IsViaIPC(false)); |
| base::PlatformThread::SetThreadType(process_.Pid(), 102, |
| base::ThreadType::kResourceEfficient, |
| base::IsViaIPC(false)); |
| base::PlatformThread::SetThreadType( |
| process_.Pid(), 103, base::ThreadType::kDefault, base::IsViaIPC(false)); |
| base::PlatformThread::SetThreadType(process_.Pid(), 104, |
| base::ThreadType::kCompositing, |
| base::IsViaIPC(false)); |
| base::PlatformThread::SetThreadType(process_.Pid(), 105, |
| base::ThreadType::kDisplayCritical, |
| base::IsViaIPC(false)); |
| base::PlatformThread::SetThreadType(process_.Pid(), 106, |
| base::ThreadType::kRealtimeAudio, |
| base::IsViaIPC(false)); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_THAT( |
| resourced_client_->GetThreadStateHistory(), |
| ElementsAre( |
| // InitializePriority() sends request for the main thread. |
| FieldsAre(process_.Pid(), process_.Pid(), |
| resource_manager::ThreadState::kBalanced), |
| FieldsAre(process_.Pid(), 100, |
| resource_manager::ThreadState::kBackground), |
| FieldsAre(process_.Pid(), 101, |
| resource_manager::ThreadState::kUtility), |
| FieldsAre(process_.Pid(), 102, resource_manager::ThreadState::kEco), |
| FieldsAre(process_.Pid(), 103, |
| resource_manager::ThreadState::kBalanced), |
| FieldsAre(process_.Pid(), 104, |
| resource_manager::ThreadState::kUrgent), |
| FieldsAre(process_.Pid(), 105, |
| resource_manager::ThreadState::kUrgent), |
| FieldsAre(process_.Pid(), 106, |
| resource_manager::ThreadState::kUrgentBursty))); |
| } |
| |
| TEST_F(DBusSchedQOSStateHandlerTest, SetThreadTypeBeforeResourcedAvailable) { |
| process_.InitializePriority(); |
| ASSERT_TRUE(process_.SetPriority(base::Process::Priority::kBestEffort)); |
| base::PlatformThread::SetThreadType(process_.Pid(), 100, |
| base::ThreadType::kBackground, |
| base::IsViaIPC(false)); |
| base::PlatformThread::SetThreadType(process_.Pid(), 101, |
| base::ThreadType::kResourceEfficient, |
| base::IsViaIPC(false)); |
| base::PlatformThread::SetThreadType( |
| process_.Pid(), 101, base::ThreadType::kUtility, base::IsViaIPC(false)); |
| base::Process dummy_process1 = base::Process::Open(1); |
| dummy_process1.InitializePriority(); |
| base::PlatformThread::SetThreadType(dummy_process1.Pid(), 102, |
| base::ThreadType::kResourceEfficient, |
| base::IsViaIPC(false)); |
| base::PlatformThread::SetThreadType(dummy_process1.Pid(), 103, |
| base::ThreadType::kDefault, |
| base::IsViaIPC(false)); |
| base::Process dummy_process2 = base::Process::Open(2); |
| dummy_process2.InitializePriority(); |
| task_environment_.RunUntilIdle(); |
| |
| ASSERT_EQ(resourced_client_->GetProcessStateHistory().size(), 0ul); |
| ASSERT_EQ(resourced_client_->GetThreadStateHistory().size(), 0ul); |
| |
| ASSERT_TRUE(resourced_client_->TriggerServiceAvailable(true)); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_THAT( |
| resourced_client_->GetProcessStateHistory(), |
| UnorderedElementsAre( |
| Pair(process_.Pid(), resource_manager::ProcessState::kBackground), |
| Pair(dummy_process1.Pid(), resource_manager::ProcessState::kNormal), |
| Pair(dummy_process2.Pid(), resource_manager::ProcessState::kNormal))); |
| EXPECT_THAT(resourced_client_->GetThreadStateHistory(), |
| UnorderedElementsAre( |
| FieldsAre(process_.Pid(), process_.Pid(), |
| resource_manager::ThreadState::kBalanced), |
| FieldsAre(process_.Pid(), 100, |
| resource_manager::ThreadState::kBackground), |
| FieldsAre(process_.Pid(), 101, |
| resource_manager::ThreadState::kUtility), |
| FieldsAre(dummy_process1.Pid(), dummy_process1.Pid(), |
| resource_manager::ThreadState::kBalanced), |
| FieldsAre(dummy_process1.Pid(), 102, |
| resource_manager::ThreadState::kEco), |
| FieldsAre(dummy_process1.Pid(), 103, |
| resource_manager::ThreadState::kBalanced), |
| FieldsAre(dummy_process2.Pid(), dummy_process2.Pid(), |
| resource_manager::ThreadState::kBalanced))); |
| |
| base::PlatformThread::SetThreadType(process_.Pid(), 101, |
| base::ThreadType::kResourceEfficient, |
| base::IsViaIPC(false)); |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(resourced_client_->GetThreadStateHistory().size(), 8ul); |
| EXPECT_THAT( |
| resourced_client_->GetThreadStateHistory()[7], |
| FieldsAre(process_.Pid(), 101, resource_manager::ThreadState::kEco)); |
| } |
| |
| TEST_F(DBusSchedQOSStateHandlerTest, SetThreadTypeBeforeInitialize) { |
| ASSERT_TRUE(resourced_client_->TriggerServiceAvailable(true)); |
| task_environment_.RunUntilIdle(); |
| |
| ASSERT_EQ(resourced_client_->GetThreadStateHistory().size(), 0ul); |
| |
| base::PlatformThread::SetThreadType(process_.Pid(), 100, |
| base::ThreadType::kBackground, |
| base::IsViaIPC(false)); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_EQ(resourced_client_->GetThreadStateHistory().size(), 0ul); |
| |
| process_.InitializePriority(); |
| task_environment_.RunUntilIdle(); |
| |
| base::PlatformThread::SetThreadType( |
| process_.Pid(), 101, base::ThreadType::kUtility, base::IsViaIPC(false)); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_THAT(resourced_client_->GetThreadStateHistory(), |
| ElementsAre(FieldsAre(process_.Pid(), process_.Pid(), |
| resource_manager::ThreadState::kBalanced), |
| FieldsAre(process_.Pid(), 101, |
| resource_manager::ThreadState::kUtility))); |
| } |
| |
| TEST_F(DBusSchedQOSStateHandlerTest, SetThreadTypeAfterForgetPriority) { |
| ASSERT_TRUE(resourced_client_->TriggerServiceAvailable(true)); |
| task_environment_.RunUntilIdle(); |
| process_.InitializePriority(); |
| task_environment_.RunUntilIdle(); |
| |
| ASSERT_EQ(resourced_client_->GetThreadStateHistory().size(), 1ul); |
| |
| base::PlatformThread::SetThreadType(process_.Pid(), 100, |
| base::ThreadType::kBackground, |
| base::IsViaIPC(false)); |
| task_environment_.RunUntilIdle(); |
| ASSERT_EQ(resourced_client_->GetThreadStateHistory().size(), 2ul); |
| |
| process_.ForgetPriority(); |
| |
| base::PlatformThread::SetThreadType( |
| process_.Pid(), 100, base::ThreadType::kUtility, base::IsViaIPC(false)); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_EQ(resourced_client_->GetThreadStateHistory().size(), 2ul); |
| } |
| |
| TEST_F(DBusSchedQOSStateHandlerTest, SetThreadTypeRetryOnDisconnect) { |
| process_.InitializePriority(); |
| base::Process dummy_process1 = base::Process::Open(1); |
| base::PlatformThread::SetThreadType(process_.Pid(), 100, |
| base::ThreadType::kBackground, |
| base::IsViaIPC(false)); |
| dummy_process1.InitializePriority(); |
| base::Process dummy_process2 = base::Process::Open(2); |
| dummy_process2.InitializePriority(); |
| base::Process dummy_process3 = base::Process::Open(3); |
| dummy_process3.InitializePriority(); |
| ASSERT_TRUE(resourced_client_->TriggerServiceAvailable(true)); |
| task_environment_.RunUntilIdle(); |
| |
| ASSERT_EQ(resourced_client_->GetThreadStateHistory().size(), 5ul); |
| ASSERT_EQ(resourced_client_->GetProcessStateHistory().size(), 4ul); |
| |
| resourced_client_->SetThreadStateResult( |
| dbus::DBusResult::kErrorServiceUnknown); |
| |
| base::PlatformThread::SetThreadType( |
| process_.Pid(), 101, base::ThreadType::kUtility, base::IsViaIPC(false)); |
| task_environment_.RunUntilIdle(); |
| EXPECT_EQ(resourced_client_->GetThreadStateHistory().size(), 6ul); |
| EXPECT_THAT( |
| resourced_client_->GetThreadStateHistory()[5], |
| FieldsAre(process_.Pid(), 101, resource_manager::ThreadState::kUtility)); |
| |
| base::PlatformThread::SetThreadType(process_.Pid(), 102, |
| base::ThreadType::kResourceEfficient, |
| base::IsViaIPC(false)); |
| base::PlatformThread::SetThreadType(dummy_process1.Pid(), 103, |
| base::ThreadType::kUtility, |
| base::IsViaIPC(false)); |
| base::PlatformThread::SetThreadType(dummy_process1.Pid(), 103, |
| base::ThreadType::kRealtimeAudio, |
| base::IsViaIPC(false)); |
| ASSERT_TRUE(process_.SetPriority(base::Process::Priority::kBestEffort)); |
| ASSERT_TRUE( |
| dummy_process2.SetPriority(base::Process::Priority::kUserBlocking)); |
| task_environment_.RunUntilIdle(); |
| |
| // DBus request is not sent until it reconnects to resourced. |
| EXPECT_EQ(resourced_client_->GetProcessStateHistory().size(), 4ul); |
| EXPECT_EQ(resourced_client_->GetThreadStateHistory().size(), 6ul); |
| |
| resourced_client_->SetProcessStateResult(dbus::DBusResult::kSuccess); |
| // When resourced is reconnected, retry the request. |
| EXPECT_TRUE(resourced_client_->TriggerServiceAvailable(true)); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_EQ(resourced_client_->GetProcessStateHistory().size(), 6ul); |
| EXPECT_EQ(resourced_client_->GetThreadStateHistory().size(), 9ul); |
| EXPECT_THAT( |
| absl::MakeSpan(resourced_client_->GetProcessStateHistory()).last(2), |
| UnorderedElementsAre( |
| Pair(process_.Pid(), resource_manager::ProcessState::kBackground), |
| Pair(dummy_process2.Pid(), resource_manager::ProcessState::kNormal))); |
| EXPECT_THAT( |
| absl::MakeSpan(resourced_client_->GetThreadStateHistory()).last(3), |
| UnorderedElementsAre( |
| FieldsAre(process_.Pid(), 101, |
| resource_manager::ThreadState::kUtility), |
| FieldsAre(process_.Pid(), 102, resource_manager::ThreadState::kEco), |
| FieldsAre(dummy_process1.Pid(), 103, |
| resource_manager::ThreadState::kUrgentBursty))); |
| } |
| |
| TEST_F(DBusSchedQOSStateHandlerTest, SetThreadTypeUMA) { |
| base::HistogramTester histogram_tester; |
| ASSERT_TRUE(resourced_client_->TriggerServiceAvailable(true)); |
| task_environment_.RunUntilIdle(); |
| process_.InitializePriority(); |
| task_environment_.RunUntilIdle(); |
| |
| resourced_client_->DelaySetThreadStateResult(base::Microseconds(123)); |
| base::PlatformThread::SetThreadType(process_.Pid(), 100, |
| base::ThreadType::kBackground, |
| base::IsViaIPC(false)); |
| task_environment_.RunUntilIdle(); |
| task_environment_.FastForwardBy(base::Microseconds(123)); |
| task_environment_.RunUntilIdle(); |
| |
| histogram_tester.ExpectBucketCount( |
| "Scheduling.DBusSchedQoS.SetThreadStateLatency", 123, 1); |
| } |
| |
| } // namespace ash |