Commit fcf99555 authored by Edward Lin's avatar Edward Lin Committed by Commit Bot

cros_healthd: add the CPU cache/stress routine

Add the CPU cache routine and the CPU stress routine to cros_healthd.
The CPU cache routine and the CPU stress routine runs the stressapptest to diagnose the CPU.

Bug: b:146513388
Test: unit_tests --gtest_filter=DeviceCommandRunRoutineJobTest.*

Change-Id: I7189344dbce41f09c18debbfe3ca5415526647a4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2041981
Commit-Queue: Maksim Ivanov <emaxx@chromium.org>
Reviewed-by: default avatarMaksim Ivanov <emaxx@chromium.org>
Reviewed-by: default avatarSteven Bennetts <stevenjb@chromium.org>
Reviewed-by: default avatarPaul Moy <pmoy@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarOleh Lamzin <lamzin@google.com>
Cr-Commit-Position: refs/heads/master@{#747214}
parent 39ca5bfe
...@@ -1091,6 +1091,7 @@ Code Aurora Forum <*@codeaurora.org> ...@@ -1091,6 +1091,7 @@ Code Aurora Forum <*@codeaurora.org>
Collabora Limited <*@collabora.com> Collabora Limited <*@collabora.com>
Comodo CA Limited Comodo CA Limited
Cosium <*@cosium.com> Cosium <*@cosium.com>
Dell Technologies Inc. <*@dell.corp-partner.google.com>
Duck Duck Go, Inc. <*@duckduckgo.com> Duck Duck Go, Inc. <*@duckduckgo.com>
Endless Mobile, Inc. <*@endlessm.com> Endless Mobile, Inc. <*@endlessm.com>
Estimote, Inc. <*@estimote.com> Estimote, Inc. <*@estimote.com>
......
...@@ -252,6 +252,50 @@ void DeviceCommandRunRoutineJob::RunImpl(CallbackWithResult succeeded_callback, ...@@ -252,6 +252,50 @@ void DeviceCommandRunRoutineJob::RunImpl(CallbackWithResult succeeded_callback,
std::move(failed_callback))); std::move(failed_callback)));
break; break;
} }
case chromeos::cros_healthd::mojom::DiagnosticRoutineEnum::kCpuCache: {
constexpr char kLengthSecondsFieldName[] = "lengthSeconds";
base::Optional<int> length_seconds =
params_dict_.FindIntKey(kLengthSecondsFieldName);
// The CPU cache routine expects one integer >= 0.
if (!length_seconds.has_value() || length_seconds.value() < 0) {
SYSLOG(ERROR) << "Invalid parameters for CPU cache routine.";
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(failed_callback),
std::make_unique<Payload>(
MakeInvalidParametersResponse())));
break;
}
chromeos::cros_healthd::ServiceConnection::GetInstance()
->RunCpuCacheRoutine(
base::TimeDelta::FromSeconds(length_seconds.value()),
base::BindOnce(
&DeviceCommandRunRoutineJob::OnCrosHealthdResponseReceived,
weak_ptr_factory_.GetWeakPtr(), std::move(succeeded_callback),
std::move(failed_callback)));
break;
}
case chromeos::cros_healthd::mojom::DiagnosticRoutineEnum::kCpuStress: {
constexpr char kLengthSecondsFieldName[] = "lengthSeconds";
base::Optional<int> length_seconds =
params_dict_.FindIntKey(kLengthSecondsFieldName);
// The CPU stress routine expects one integer >= 0.
if (!length_seconds.has_value() || length_seconds.value() < 0) {
SYSLOG(ERROR) << "Invalid parameters for CPU stress routine.";
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(failed_callback),
std::make_unique<Payload>(
MakeInvalidParametersResponse())));
break;
}
chromeos::cros_healthd::ServiceConnection::GetInstance()
->RunCpuStressRoutine(
base::TimeDelta::FromSeconds(length_seconds.value()),
base::BindOnce(
&DeviceCommandRunRoutineJob::OnCrosHealthdResponseReceived,
weak_ptr_factory_.GetWeakPtr(), std::move(succeeded_callback),
std::move(failed_callback)));
break;
}
} }
} }
......
...@@ -48,7 +48,7 @@ constexpr char kMaximumCycleCountFieldName[] = "maximumCycleCount"; ...@@ -48,7 +48,7 @@ constexpr char kMaximumCycleCountFieldName[] = "maximumCycleCount";
constexpr char kPercentBatteryWearAllowedFieldName[] = constexpr char kPercentBatteryWearAllowedFieldName[] =
"percentBatteryWearAllowed"; "percentBatteryWearAllowed";
// String constants identifying the parameter fields for the urandom routine. // String constants identifying the parameter fields for the routine.
constexpr char kLengthSecondsFieldName[] = "lengthSeconds"; constexpr char kLengthSecondsFieldName[] = "lengthSeconds";
// String constants identifying the parameter fields for the AC power routine. // String constants identifying the parameter fields for the AC power routine.
...@@ -744,4 +744,166 @@ TEST_F(DeviceCommandRunRoutineJobTest, RunAcPowerRoutineInvalidExpectedStatus) { ...@@ -744,4 +744,166 @@ TEST_F(DeviceCommandRunRoutineJobTest, RunAcPowerRoutineInvalidExpectedStatus) {
run_loop.Run(); run_loop.Run();
} }
TEST_F(DeviceCommandRunRoutineJobTest, RunCpuCacheRoutineSuccess) {
auto run_routine_response =
chromeos::cros_healthd::mojom::RunRoutineResponse::New(kId, kStatus);
chromeos::cros_healthd::FakeCrosHealthdClient::Get()
->SetRunRoutineResponseForTesting(run_routine_response);
base::Value params_dict(base::Value::Type::DICTIONARY);
params_dict.SetIntKey(kLengthSecondsFieldName,
/*length_seconds=*/2342);
std::unique_ptr<RemoteCommandJob> job =
std::make_unique<DeviceCommandRunRoutineJob>();
InitializeJob(job.get(), kUniqueID, test_start_time_,
base::TimeDelta::FromSeconds(30),
/*terminate_upon_input=*/false,
chromeos::cros_healthd::mojom::DiagnosticRoutineEnum::kCpuCache,
std::move(params_dict));
base::RunLoop run_loop;
bool success =
job->Run(base::Time::Now(), base::TimeTicks::Now(),
base::BindLambdaForTesting([&]() {
EXPECT_EQ(job->status(), RemoteCommandJob::SUCCEEDED);
std::unique_ptr<std::string> payload = job->GetResultPayload();
EXPECT_TRUE(payload);
EXPECT_EQ(CreateSuccessPayload(kId, kStatus), *payload);
run_loop.Quit();
}));
EXPECT_TRUE(success);
run_loop.Run();
}
TEST_F(DeviceCommandRunRoutineJobTest, RunCpuCacheRoutineMissingLengthSeconds) {
// Test that leaving out the lengthSeconds parameter causes the routine to
// fail.
base::Value params_dict(base::Value::Type::DICTIONARY);
std::unique_ptr<RemoteCommandJob> job =
std::make_unique<DeviceCommandRunRoutineJob>();
InitializeJob(job.get(), kUniqueID, test_start_time_,
base::TimeDelta::FromSeconds(30),
/*terminate_upon_input=*/false,
chromeos::cros_healthd::mojom::DiagnosticRoutineEnum::kCpuCache,
std::move(params_dict));
base::RunLoop run_loop;
bool success =
job->Run(base::Time::Now(), base::TimeTicks::Now(),
base::BindLambdaForTesting([&]() {
EXPECT_EQ(job->status(), RemoteCommandJob::FAILED);
std::unique_ptr<std::string> payload = job->GetResultPayload();
EXPECT_TRUE(payload);
EXPECT_EQ(CreateInvalidParametersFailurePayload(), *payload);
run_loop.Quit();
}));
EXPECT_TRUE(success);
run_loop.Run();
}
TEST_F(DeviceCommandRunRoutineJobTest, RunCpuCacheRoutineInvalidLengthSeconds) {
// Test that a negative lengthSeconds parameter causes the routine to fail.
base::Value params_dict(base::Value::Type::DICTIONARY);
params_dict.SetIntKey(kLengthSecondsFieldName,
/*length_seconds=*/-1);
std::unique_ptr<RemoteCommandJob> job =
std::make_unique<DeviceCommandRunRoutineJob>();
InitializeJob(job.get(), kUniqueID, test_start_time_,
base::TimeDelta::FromSeconds(30),
/*terminate_upon_input=*/false,
chromeos::cros_healthd::mojom::DiagnosticRoutineEnum::kCpuCache,
std::move(params_dict));
base::RunLoop run_loop;
bool success =
job->Run(base::Time::Now(), base::TimeTicks::Now(),
base::BindLambdaForTesting([&]() {
EXPECT_EQ(job->status(), RemoteCommandJob::FAILED);
std::unique_ptr<std::string> payload = job->GetResultPayload();
EXPECT_TRUE(payload);
EXPECT_EQ(CreateInvalidParametersFailurePayload(), *payload);
run_loop.Quit();
}));
EXPECT_TRUE(success);
run_loop.Run();
}
TEST_F(DeviceCommandRunRoutineJobTest, RunCpuStressRoutineSuccess) {
auto run_routine_response =
chromeos::cros_healthd::mojom::RunRoutineResponse::New(kId, kStatus);
chromeos::cros_healthd::FakeCrosHealthdClient::Get()
->SetRunRoutineResponseForTesting(run_routine_response);
base::Value params_dict(base::Value::Type::DICTIONARY);
params_dict.SetIntKey(kLengthSecondsFieldName,
/*length_seconds=*/2342);
std::unique_ptr<RemoteCommandJob> job =
std::make_unique<DeviceCommandRunRoutineJob>();
InitializeJob(
job.get(), kUniqueID, test_start_time_, base::TimeDelta::FromSeconds(30),
/*terminate_upon_input=*/false,
chromeos::cros_healthd::mojom::DiagnosticRoutineEnum::kCpuStress,
std::move(params_dict));
base::RunLoop run_loop;
bool success =
job->Run(base::Time::Now(), base::TimeTicks::Now(),
base::BindLambdaForTesting([&]() {
EXPECT_EQ(job->status(), RemoteCommandJob::SUCCEEDED);
std::unique_ptr<std::string> payload = job->GetResultPayload();
EXPECT_TRUE(payload);
EXPECT_EQ(CreateSuccessPayload(kId, kStatus), *payload);
run_loop.Quit();
}));
EXPECT_TRUE(success);
run_loop.Run();
}
TEST_F(DeviceCommandRunRoutineJobTest,
RunCpuStressRoutineMissingLengthSeconds) {
// Test that leaving out the lengthSeconds parameter causes the routine to
// fail.
base::Value params_dict(base::Value::Type::DICTIONARY);
std::unique_ptr<RemoteCommandJob> job =
std::make_unique<DeviceCommandRunRoutineJob>();
InitializeJob(
job.get(), kUniqueID, test_start_time_, base::TimeDelta::FromSeconds(30),
/*terminate_upon_input=*/false,
chromeos::cros_healthd::mojom::DiagnosticRoutineEnum::kCpuStress,
std::move(params_dict));
base::RunLoop run_loop;
bool success =
job->Run(base::Time::Now(), base::TimeTicks::Now(),
base::BindLambdaForTesting([&]() {
EXPECT_EQ(job->status(), RemoteCommandJob::FAILED);
std::unique_ptr<std::string> payload = job->GetResultPayload();
EXPECT_TRUE(payload);
EXPECT_EQ(CreateInvalidParametersFailurePayload(), *payload);
run_loop.Quit();
}));
EXPECT_TRUE(success);
run_loop.Run();
}
TEST_F(DeviceCommandRunRoutineJobTest,
RunCpuStressRoutineInvalidLengthSeconds) {
// Test that a negative lengthSeconds parameter causes the routine to fail.
base::Value params_dict(base::Value::Type::DICTIONARY);
params_dict.SetIntKey(kLengthSecondsFieldName,
/*length_seconds=*/-1);
std::unique_ptr<RemoteCommandJob> job =
std::make_unique<DeviceCommandRunRoutineJob>();
InitializeJob(
job.get(), kUniqueID, test_start_time_, base::TimeDelta::FromSeconds(30),
/*terminate_upon_input=*/false,
chromeos::cros_healthd::mojom::DiagnosticRoutineEnum::kCpuStress,
std::move(params_dict));
base::RunLoop run_loop;
bool success =
job->Run(base::Time::Now(), base::TimeTicks::Now(),
base::BindLambdaForTesting([&]() {
EXPECT_EQ(job->status(), RemoteCommandJob::FAILED);
std::unique_ptr<std::string> payload = job->GetResultPayload();
EXPECT_TRUE(payload);
EXPECT_EQ(CreateInvalidParametersFailurePayload(), *payload);
run_loop.Quit();
}));
EXPECT_TRUE(success);
run_loop.Run();
}
} // namespace policy } // namespace policy
...@@ -70,6 +70,18 @@ void FakeCrosHealthdService::RunAcPowerRoutine( ...@@ -70,6 +70,18 @@ void FakeCrosHealthdService::RunAcPowerRoutine(
std::move(callback).Run(run_routine_response_.Clone()); std::move(callback).Run(run_routine_response_.Clone());
} }
void FakeCrosHealthdService::RunCpuCacheRoutine(
uint32_t length_seconds,
RunCpuCacheRoutineCallback callback) {
std::move(callback).Run(run_routine_response_.Clone());
}
void FakeCrosHealthdService::RunCpuStressRoutine(
uint32_t length_seconds,
RunCpuStressRoutineCallback callback) {
std::move(callback).Run(run_routine_response_.Clone());
}
void FakeCrosHealthdService::ProbeTelemetryInfo( void FakeCrosHealthdService::ProbeTelemetryInfo(
const std::vector<mojom::ProbeCategoryEnum>& categories, const std::vector<mojom::ProbeCategoryEnum>& categories,
ProbeTelemetryInfoCallback callback) { ProbeTelemetryInfoCallback callback) {
......
...@@ -54,6 +54,10 @@ class FakeCrosHealthdService final ...@@ -54,6 +54,10 @@ class FakeCrosHealthdService final
void RunAcPowerRoutine(mojom::AcPowerStatusEnum expected_status, void RunAcPowerRoutine(mojom::AcPowerStatusEnum expected_status,
const base::Optional<std::string>& expected_power_type, const base::Optional<std::string>& expected_power_type,
RunAcPowerRoutineCallback callback) override; RunAcPowerRoutineCallback callback) override;
void RunCpuCacheRoutine(uint32_t length_seconds,
RunCpuCacheRoutineCallback callback) override;
void RunCpuStressRoutine(uint32_t length_seconds,
RunCpuStressRoutineCallback callback) override;
// CrosHealthdProbeService overrides: // CrosHealthdProbeService overrides:
void ProbeTelemetryInfo( void ProbeTelemetryInfo(
......
...@@ -58,6 +58,14 @@ class ServiceConnectionImpl : public ServiceConnection { ...@@ -58,6 +58,14 @@ class ServiceConnectionImpl : public ServiceConnection {
const base::Optional<std::string>& expected_power_type, const base::Optional<std::string>& expected_power_type,
mojom::CrosHealthdDiagnosticsService::RunAcPowerRoutineCallback callback) mojom::CrosHealthdDiagnosticsService::RunAcPowerRoutineCallback callback)
override; override;
void RunCpuCacheRoutine(
const base::TimeDelta& exec_duration,
mojom::CrosHealthdDiagnosticsService::RunCpuCacheRoutineCallback callback)
override;
void RunCpuStressRoutine(
const base::TimeDelta& exec_duration,
mojom::CrosHealthdDiagnosticsService::RunCpuStressRoutineCallback
callback) override;
void ProbeTelemetryInfo( void ProbeTelemetryInfo(
const std::vector<mojom::ProbeCategoryEnum>& categories_to_test, const std::vector<mojom::ProbeCategoryEnum>& categories_to_test,
mojom::CrosHealthdProbeService::ProbeTelemetryInfoCallback callback) mojom::CrosHealthdProbeService::ProbeTelemetryInfoCallback callback)
...@@ -165,6 +173,25 @@ void ServiceConnectionImpl::RunAcPowerRoutine( ...@@ -165,6 +173,25 @@ void ServiceConnectionImpl::RunAcPowerRoutine(
expected_status, expected_power_type, std::move(callback)); expected_status, expected_power_type, std::move(callback));
} }
void ServiceConnectionImpl::RunCpuCacheRoutine(
const base::TimeDelta& exec_duration,
mojom::CrosHealthdDiagnosticsService::RunCpuCacheRoutineCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
BindCrosHealthdDiagnosticsServiceIfNeeded();
cros_healthd_diagnostics_service_->RunCpuCacheRoutine(
exec_duration.InSeconds(), std::move(callback));
}
void ServiceConnectionImpl::RunCpuStressRoutine(
const base::TimeDelta& exec_duration,
mojom::CrosHealthdDiagnosticsService::RunCpuStressRoutineCallback
callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
BindCrosHealthdDiagnosticsServiceIfNeeded();
cros_healthd_diagnostics_service_->RunCpuStressRoutine(
exec_duration.InSeconds(), std::move(callback));
}
void ServiceConnectionImpl::ProbeTelemetryInfo( void ServiceConnectionImpl::ProbeTelemetryInfo(
const std::vector<mojom::ProbeCategoryEnum>& categories_to_test, const std::vector<mojom::ProbeCategoryEnum>& categories_to_test,
mojom::CrosHealthdProbeService::ProbeTelemetryInfoCallback callback) { mojom::CrosHealthdProbeService::ProbeTelemetryInfoCallback callback) {
......
...@@ -81,6 +81,22 @@ class ServiceConnection { ...@@ -81,6 +81,22 @@ class ServiceConnection {
mojom::CrosHealthdDiagnosticsService::RunAcPowerRoutineCallback mojom::CrosHealthdDiagnosticsService::RunAcPowerRoutineCallback
callback) = 0; callback) = 0;
// Requests that cros_healthd runs the CPU cache routine. See
// src/chromeos/service/cros_healthd/public/mojom/cros_healthd.mojom for
// details.
virtual void RunCpuCacheRoutine(
const base::TimeDelta& exec_duration,
mojom::CrosHealthdDiagnosticsService::RunCpuCacheRoutineCallback
callback) = 0;
// Requests that cros_healthd runs the CPU stress routine. See
// src/chromeos/service/cros_healthd/public/mojom/cros_healthd.mojom for
// details.
virtual void RunCpuStressRoutine(
const base::TimeDelta& exec_duration,
mojom::CrosHealthdDiagnosticsService::RunCpuStressRoutineCallback
callback) = 0;
// Gather pieces of information about the platform. See // Gather pieces of information about the platform. See
// src/chromeos/service/cros_healthd/public/mojom/cros_healthd.mojom for // src/chromeos/service/cros_healthd/public/mojom/cros_healthd.mojom for
// details. // details.
......
...@@ -36,6 +36,8 @@ std::vector<mojom::DiagnosticRoutineEnum> MakeAvailableRoutines() { ...@@ -36,6 +36,8 @@ std::vector<mojom::DiagnosticRoutineEnum> MakeAvailableRoutines() {
mojom::DiagnosticRoutineEnum::kBatteryCapacity, mojom::DiagnosticRoutineEnum::kBatteryCapacity,
mojom::DiagnosticRoutineEnum::kBatteryHealth, mojom::DiagnosticRoutineEnum::kBatteryHealth,
mojom::DiagnosticRoutineEnum::kSmartctlCheck, mojom::DiagnosticRoutineEnum::kSmartctlCheck,
mojom::DiagnosticRoutineEnum::kCpuCache,
mojom::DiagnosticRoutineEnum::kCpuStress,
}; };
} }
...@@ -296,6 +298,32 @@ TEST_F(CrosHealthdServiceConnectionTest, RunAcPowerRoutine) { ...@@ -296,6 +298,32 @@ TEST_F(CrosHealthdServiceConnectionTest, RunAcPowerRoutine) {
run_loop.Run(); run_loop.Run();
} }
TEST_F(CrosHealthdServiceConnectionTest, RunCpuCacheRoutine) {
auto response = MakeRunRoutineResponse();
FakeCrosHealthdClient::Get()->SetRunRoutineResponseForTesting(response);
base::RunLoop run_loop;
ServiceConnection::GetInstance()->RunCpuCacheRoutine(
base::TimeDelta().FromSeconds(10),
base::BindLambdaForTesting([&](mojom::RunRoutineResponsePtr response) {
EXPECT_EQ(response, MakeRunRoutineResponse());
run_loop.Quit();
}));
run_loop.Run();
}
TEST_F(CrosHealthdServiceConnectionTest, RunCpuStressRoutine) {
auto response = MakeRunRoutineResponse();
FakeCrosHealthdClient::Get()->SetRunRoutineResponseForTesting(response);
base::RunLoop run_loop;
ServiceConnection::GetInstance()->RunCpuStressRoutine(
base::TimeDelta().FromSeconds(10),
base::BindLambdaForTesting([&](mojom::RunRoutineResponsePtr response) {
EXPECT_EQ(response, MakeRunRoutineResponse());
run_loop.Quit();
}));
run_loop.Run();
}
TEST_F(CrosHealthdServiceConnectionTest, ProbeTelemetryInfo) { TEST_F(CrosHealthdServiceConnectionTest, ProbeTelemetryInfo) {
// Test that we can send a request without categories. // Test that we can send a request without categories.
auto empty_info = mojom::TelemetryInfo::New(); auto empty_info = mojom::TelemetryInfo::New();
......
...@@ -124,6 +124,38 @@ interface CrosHealthdDiagnosticsService { ...@@ -124,6 +124,38 @@ interface CrosHealthdDiagnosticsService {
RunAcPowerRoutine(AcPowerStatusEnum expected_status, RunAcPowerRoutine(AcPowerStatusEnum expected_status,
string? expected_power_type) string? expected_power_type)
=> (RunRoutineResponse response); => (RunRoutineResponse response);
// Requests that the CPU cache routine is created and started on the
// platform. This routine runs the stressapptest to test the CPU caches.
// The routine will pass if the stressapptest returns zero. This routine is
// only available if GetAvailableRoutines returned kCpuCache.
//
// The request:
// * |length_seconds| - length of time, in seconds, to run the CPU cache
// routine. This parameter needs to be strictly greater
// than zero.
//
// The response:
// * |response| - contains a unique identifier and status for the created
// routine.
RunCpuCacheRoutine(uint32 length_seconds)
=> (RunRoutineResponse response);
// Requests that the CPU stress routine is created and started on the
// platform. This routine runs the stressapptest to stress test the CPU.
// The routine will pass if the stressapptest returns zero. This routine is
// only available if GetAvailableRoutines returned kCpuStress.
//
// The request:
// * |length_seconds| - length of time, in seconds, to run the CPU stress
// routine. This parameter needs to be strictly greater
// than zero.
//
// The response:
// * |response| - contains a unique identifier and status for the created
// routine.
RunCpuStressRoutine(uint32 length_seconds)
=> (RunRoutineResponse response);
}; };
// Probe interface exposed by the cros_healthd daemon. // Probe interface exposed by the cros_healthd daemon.
......
...@@ -21,6 +21,8 @@ enum DiagnosticRoutineEnum { ...@@ -21,6 +21,8 @@ enum DiagnosticRoutineEnum {
kUrandom = 2, kUrandom = 2,
kSmartctlCheck = 3, kSmartctlCheck = 3,
kAcPower = 4, kAcPower = 4,
kCpuCache = 5,
kCpuStress = 6,
}; };
// Enumeration of each of the possible statuses for a diagnostics routine. // Enumeration of each of the possible statuses for a diagnostics routine.
......
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