Commit 818ee722 authored by Anqing Zhao's avatar Anqing Zhao Committed by Commit Bot

Add timestamp in reporting cpu utilization and free RAM

Introduce two new data structs in DeviceStatusReportRequest.
- cpu_tuilization_infos : CpuUtilizationInfo
- system_ram_free_infos : SystemFreeRamInfo

They both contains additional timestamp information compared with
existing fields. We plan to deprecate the usage of following two fields
after back-end servers are switched to new implementation.
- cpu_utilization_pct_samples : int32
- system_ram_free_samples : int64

Bug: 1001391
Change-Id: Iae911d3657c75e52c75decbd4b28154e2185a63d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1795245
Commit-Queue: Anqing Zhao <anqing@google.com>
Reviewed-by: default avatarSergey Poromov <poromov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#696018}
parent 71794a47
...@@ -1203,11 +1203,10 @@ void DeviceStatusCollector::SampleResourceUsage() { ...@@ -1203,11 +1203,10 @@ void DeviceStatusCollector::SampleResourceUsage() {
{base::ThreadPool(), base::MayBlock(), base::TaskPriority::BEST_EFFORT}, {base::ThreadPool(), base::MayBlock(), base::TaskPriority::BEST_EFFORT},
cpu_statistics_fetcher_, cpu_statistics_fetcher_,
base::Bind(&DeviceStatusCollector::ReceiveCPUStatistics, base::Bind(&DeviceStatusCollector::ReceiveCPUStatistics,
weak_factory_.GetWeakPtr(), base::Time::Now())); weak_factory_.GetWeakPtr()));
} }
void DeviceStatusCollector::ReceiveCPUStatistics(const base::Time& timestamp, void DeviceStatusCollector::ReceiveCPUStatistics(const std::string& stats) {
const std::string& stats) {
int cpu_usage_percent = 0; int cpu_usage_percent = 0;
if (stats.empty()) { if (stats.empty()) {
DLOG(WARNING) << "Unable to read CPU statistics"; DLOG(WARNING) << "Unable to read CPU statistics";
...@@ -1249,8 +1248,15 @@ void DeviceStatusCollector::ReceiveCPUStatistics(const base::Time& timestamp, ...@@ -1249,8 +1248,15 @@ void DeviceStatusCollector::ReceiveCPUStatistics(const base::Time& timestamp,
} }
DCHECK_LE(cpu_usage_percent, 100); DCHECK_LE(cpu_usage_percent, 100);
// This timestamp is used in both ResourceUsage and SampledData for CPU
// termporary, which is expected to be same according to existing
// implementation.
const base::Time timestamp = base::Time::Now();
ResourceUsage usage = {cpu_usage_percent, ResourceUsage usage = {cpu_usage_percent,
base::SysInfo::AmountOfAvailablePhysicalMemory()}; base::SysInfo::AmountOfAvailablePhysicalMemory(),
timestamp};
resource_usage_.push_back(usage); resource_usage_.push_back(usage);
...@@ -1260,7 +1266,7 @@ void DeviceStatusCollector::ReceiveCPUStatistics(const base::Time& timestamp, ...@@ -1260,7 +1266,7 @@ void DeviceStatusCollector::ReceiveCPUStatistics(const base::Time& timestamp,
resource_usage_.pop_front(); resource_usage_.pop_front();
std::unique_ptr<SampledData> sample = std::make_unique<SampledData>(); std::unique_ptr<SampledData> sample = std::make_unique<SampledData>();
sample->timestamp = base::Time::Now(); sample->timestamp = timestamp;
if (report_power_status_) { if (report_power_status_) {
runtime_probe::ProbeRequest request; runtime_probe::ProbeRequest request;
...@@ -1695,9 +1701,30 @@ bool DeviceStatusCollector::GetHardwareStatus( ...@@ -1695,9 +1701,30 @@ bool DeviceStatusCollector::GetHardwareStatus(
// regular intervals. Unlike CPU temp and volume info these are not one-time // regular intervals. Unlike CPU temp and volume info these are not one-time
// sampled values, hence the difference in logic. // sampled values, hence the difference in logic.
status->set_system_ram_total(base::SysInfo::AmountOfPhysicalMemory()); status->set_system_ram_total(base::SysInfo::AmountOfPhysicalMemory());
status->clear_cpu_utilization_infos();
status->clear_system_ram_free_infos();
// TODO(anqing): remove these two cleanup operations after fields
// 'system_ram_free_samples' and 'cpu_utilization_pct_samples' are deprecated.
status->clear_system_ram_free_samples(); status->clear_system_ram_free_samples();
status->clear_cpu_utilization_pct_samples(); status->clear_cpu_utilization_pct_samples();
for (const ResourceUsage& usage : resource_usage_) { for (const ResourceUsage& usage : resource_usage_) {
const int64_t usage_timestamp = usage.timestamp.ToJavaTime();
em::CpuUtilizationInfo* cpu_utilization_info =
status->add_cpu_utilization_infos();
cpu_utilization_info->set_cpu_utilization_pct(usage.cpu_usage_percent);
cpu_utilization_info->set_timestamp(usage_timestamp);
em::SystemFreeRamInfo* system_ram_free_info =
status->add_system_ram_free_infos();
system_ram_free_info->set_size_in_bytes(usage.bytes_of_ram_free);
system_ram_free_info->set_timestamp(usage_timestamp);
// TODO(anqing): remove these two assignment operations after fields
// 'system_ram_free_samples' and 'cpu_utilization_pct_samples' are
// deprecated.
status->add_cpu_utilization_pct_samples(usage.cpu_usage_percent); status->add_cpu_utilization_pct_samples(usage.cpu_usage_percent);
status->add_system_ram_free_samples(usage.bytes_of_ram_free); status->add_system_ram_free_samples(usage.bytes_of_ram_free);
} }
......
...@@ -301,8 +301,7 @@ class DeviceStatusCollector : public StatusCollector, ...@@ -301,8 +301,7 @@ class DeviceStatusCollector : public StatusCollector,
void UpdateReportingSettings(); void UpdateReportingSettings();
// Callback invoked to update our cpu usage information. // Callback invoked to update our cpu usage information.
void ReceiveCPUStatistics(const base::Time& timestamp, void ReceiveCPUStatistics(const std::string& statistics);
const std::string& statistics);
// Callback for RuntimeProbe that samples probe live data. |callback| will // Callback for RuntimeProbe that samples probe live data. |callback| will
// be called once all sampling is finished. // be called once all sampling is finished.
...@@ -381,6 +380,9 @@ class DeviceStatusCollector : public StatusCollector, ...@@ -381,6 +380,9 @@ class DeviceStatusCollector : public StatusCollector,
// Amount of free RAM (measures raw memory used by processes, not internal // Amount of free RAM (measures raw memory used by processes, not internal
// memory waiting to be reclaimed by GC). // memory waiting to be reclaimed by GC).
int64_t bytes_of_ram_free; int64_t bytes_of_ram_free;
// Sampling timestamp.
base::Time timestamp;
}; };
// Samples of resource usage (contains multiple samples taken // Samples of resource usage (contains multiple samples taken
......
...@@ -1366,6 +1366,44 @@ TEST_F(DeviceStatusCollectorTest, TestAvailableMemory) { ...@@ -1366,6 +1366,44 @@ TEST_F(DeviceStatusCollectorTest, TestAvailableMemory) {
EXPECT_GT(device_status_.system_ram_total(), 0); EXPECT_GT(device_status_.system_ram_total(), 0);
} }
TEST_F(DeviceStatusCollectorTest, TestSystemFreeRamInfo) {
const int sample_count =
static_cast<const int>(DeviceStatusCollector::kMaxResourceUsageSamples);
std::vector<int64_t> timestamp_lowerbounds;
std::vector<int64_t> timestamp_upperbounds;
// Refresh our samples. Sample more than kMaxHardwareSamples times to
// make sure that the code correctly caps the number of cached samples.
status_collector_->RefreshSampleResourceUsage();
base::RunLoop().RunUntilIdle();
for (int i = 0; i < sample_count; ++i) {
timestamp_lowerbounds.push_back(base::Time::Now().ToJavaTime());
status_collector_->RefreshSampleResourceUsage();
base::RunLoop().RunUntilIdle();
timestamp_upperbounds.push_back(base::Time::Now().ToJavaTime());
}
GetStatus();
EXPECT_TRUE(device_status_.has_system_ram_total());
EXPECT_GT(device_status_.system_ram_total(), 0);
EXPECT_EQ(sample_count, device_status_.system_ram_free_infos().size());
for (int i = 0; i < sample_count; ++i) {
// Make sure 0 < free RAM < total Ram.
EXPECT_GT(device_status_.system_ram_free_infos(i).size_in_bytes(), 0);
EXPECT_LT(device_status_.system_ram_free_infos(i).size_in_bytes(),
device_status_.system_ram_total());
// Make sure timestamp is in a valid range though we cannot inject specific
// test values.
EXPECT_GE(device_status_.system_ram_free_infos(i).timestamp(),
timestamp_lowerbounds[i]);
EXPECT_LE(device_status_.system_ram_free_infos(i).timestamp(),
timestamp_upperbounds[i]);
}
}
TEST_F(DeviceStatusCollectorTest, TestCPUSamples) { TEST_F(DeviceStatusCollectorTest, TestCPUSamples) {
// Mock 100% CPU usage. // Mock 100% CPU usage.
std::string full_cpu_usage("cpu 500 0 500 0 0 0 0"); std::string full_cpu_usage("cpu 500 0 500 0 0 0 0");
...@@ -1415,6 +1453,79 @@ TEST_F(DeviceStatusCollectorTest, TestCPUSamples) { ...@@ -1415,6 +1453,79 @@ TEST_F(DeviceStatusCollectorTest, TestCPUSamples) {
EXPECT_EQ(0, device_status_.cpu_utilization_pct_samples().size()); EXPECT_EQ(0, device_status_.cpu_utilization_pct_samples().size());
} }
TEST_F(DeviceStatusCollectorTest, TestCPUInfos) {
// Mock 100% CPU usage.
std::string full_cpu_usage("cpu 500 0 500 0 0 0 0");
int64_t timestamp_lowerbound = base::Time::Now().ToJavaTime();
RestartStatusCollector(
base::BindRepeating(&GetEmptyVolumeInfo),
base::BindRepeating(&GetFakeCPUStatistics, full_cpu_usage),
base::BindRepeating(&GetEmptyCPUTempInfo),
base::BindRepeating(&GetEmptyAndroidStatus),
base::BindRepeating(&GetEmptyTpmStatus),
base::BindRepeating(&GetEmptyEMMCLifetimeEstimation),
base::BindRepeating(&GetEmptyStatefulPartitionInfo));
// Force finishing tasks posted by ctor of DeviceStatusCollector.
content::RunAllTasksUntilIdle();
int64_t timestamp_upperbound = base::Time::Now().ToJavaTime();
GetStatus();
ASSERT_EQ(1, device_status_.cpu_utilization_infos().size());
EXPECT_EQ(100, device_status_.cpu_utilization_infos(0).cpu_utilization_pct());
EXPECT_GE(device_status_.cpu_utilization_infos(0).timestamp(),
timestamp_lowerbound);
EXPECT_LE(device_status_.cpu_utilization_infos(0).timestamp(),
timestamp_upperbound);
// Now sample CPU usage again (active usage counters will not increase
// so should show 0% cpu usage).
timestamp_lowerbound = base::Time::Now().ToJavaTime();
status_collector_->RefreshSampleResourceUsage();
base::RunLoop().RunUntilIdle();
timestamp_upperbound = base::Time::Now().ToJavaTime();
GetStatus();
ASSERT_EQ(2, device_status_.cpu_utilization_infos().size());
EXPECT_EQ(0, device_status_.cpu_utilization_infos(1).cpu_utilization_pct());
EXPECT_GE(device_status_.cpu_utilization_infos(1).timestamp(),
timestamp_lowerbound);
EXPECT_LE(device_status_.cpu_utilization_infos(1).timestamp(),
timestamp_upperbound);
// Now store a bunch of 0% cpu usage and make sure we cap the max number of
// samples.
const int sample_count =
static_cast<const int>(DeviceStatusCollector::kMaxResourceUsageSamples);
std::vector<int64_t> timestamp_lowerbounds;
std::vector<int64_t> timestamp_upperbounds;
for (int i = 0; i < sample_count; ++i) {
timestamp_lowerbounds.push_back(base::Time::Now().ToJavaTime());
status_collector_->RefreshSampleResourceUsage();
base::RunLoop().RunUntilIdle();
timestamp_upperbounds.push_back(base::Time::Now().ToJavaTime());
}
GetStatus();
// Should not be more than kMaxResourceUsageSamples, and they should all show
// the CPU is idle.
EXPECT_EQ(sample_count, device_status_.cpu_utilization_infos().size());
for (int i = 0; i < sample_count; ++i) {
EXPECT_EQ(device_status_.cpu_utilization_infos(i).cpu_utilization_pct(), 0);
// Make sure timestamp is in a valid range though we cannot inject specific
// test values.
EXPECT_GE(device_status_.cpu_utilization_infos(i).timestamp(),
timestamp_lowerbounds[i]);
EXPECT_LE(device_status_.cpu_utilization_infos(i).timestamp(),
timestamp_upperbounds[i]);
}
// Turning off hardware reporting should not report CPU utilization.
scoped_testing_cros_settings_.device_settings()->SetBoolean(
chromeos::kReportDeviceHardwareStatus, false);
GetStatus();
EXPECT_EQ(0, device_status_.cpu_utilization_infos().size());
}
TEST_F(DeviceStatusCollectorTest, TestCPUTemp) { TEST_F(DeviceStatusCollectorTest, TestCPUTemp) {
std::vector<em::CPUTempInfo> expected_temp_info; std::vector<em::CPUTempInfo> expected_temp_info;
int cpu_cnt = 12; int cpu_cnt = 12;
......
...@@ -840,6 +840,24 @@ message VolumeInfo { ...@@ -840,6 +840,24 @@ message VolumeInfo {
optional int64 storage_free = 3; optional int64 storage_free = 3;
} }
// Information about a single CPU utilization.
message CpuUtilizationInfo {
// CPU utilization (0-100).
optional int32 cpu_utilization_pct = 1;
// The timestamp representing time at which the information was collected.
// [timestamp] is milliseconds since Epoch in UTC timezone (Java time).
optional int64 timestamp = 2;
}
// Information about a single free RAM.
message SystemFreeRamInfo {
// Free RAM [in bytes] (unreliable due to GC).
optional int64 size_in_bytes = 1;
// The timestamp representing time at which the information was collected.
// [timestamp] is milliseconds since Epoch in UTC timezone (Java time).
optional int64 timestamp = 2;
}
// Information about a single CPU temperature channel. // Information about a single CPU temperature channel.
message CPUTempInfo { message CPUTempInfo {
// Temperature channel label. // Temperature channel label.
...@@ -998,12 +1016,14 @@ message DeviceStatusReportRequest { ...@@ -998,12 +1016,14 @@ message DeviceStatusReportRequest {
repeated NetworkState network_states = 11; repeated NetworkState network_states = 11;
// Samples of CPU utilization (0-100), sampled once every 120 seconds. // Samples of CPU utilization (0-100), sampled once every 120 seconds.
// To deprecate: Use CpuUtilizationInfo instead.
repeated int32 cpu_utilization_pct_samples = 12; repeated int32 cpu_utilization_pct_samples = 12;
// Total RAM on the device. // Total RAM on the device.
optional int64 system_ram_total = 14; optional int64 system_ram_total = 14;
// Samples of free RAM [in bytes] (unreliable due to GC). // Samples of free RAM [in bytes] (unreliable due to GC).
// To deprecate: Use SystemFreeRamInfo instead.
repeated int64 system_ram_free_samples = 15; repeated int64 system_ram_free_samples = 15;
// Samples of CPU temperatures in Celsius, plus associated labels // Samples of CPU temperatures in Celsius, plus associated labels
...@@ -1048,6 +1068,12 @@ message DeviceStatusReportRequest { ...@@ -1048,6 +1068,12 @@ message DeviceStatusReportRequest {
// Stateful Partition Information for user data. // Stateful Partition Information for user data.
optional StatefulPartitionInfo stateful_partition_info = 29; optional StatefulPartitionInfo stateful_partition_info = 29;
// Samples of CPU utilization (0-100), sampled once every 120 seconds.
repeated CpuUtilizationInfo cpu_utilization_infos = 30;
// Samples of free RAM [in bytes] (unreliable due to GC).
repeated SystemFreeRamInfo system_ram_free_infos = 31;
} }
message OsUpdateStatus { message OsUpdateStatus {
......
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