summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-12-02 00:22:21 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-12-02 00:22:21 +0000
commit344e34ae44225c918a422c8217dbc76c7ff17296 (patch)
tree5dcd8026d92de6a753dfe8c1a9b1c88018f4a836
parentae50908ab9a4c78f2b1a90661e257774a840ea5f (diff)
parentd4fe1ba8b5cf5ac32282b98c4941bf4dcd6fadce (diff)
downloadpixel-android13-d4-release.tar.gz
Change-Id: I8b2448a69bb1dd519677f1c1e771bb3fd92ecbd8
-rw-r--r--pixelstats/Android.bp1
-rw-r--r--pixelstats/SysfsCollector.cpp237
-rw-r--r--pixelstats/TempResidencyReporter.cpp176
-rw-r--r--pixelstats/include/pixelstats/SysfsCollector.h23
-rw-r--r--pixelstats/include/pixelstats/TempResidencyReporter.h50
-rw-r--r--pixelstats/pixelatoms.proto140
6 files changed, 620 insertions, 7 deletions
diff --git a/pixelstats/Android.bp b/pixelstats/Android.bp
index eadd8a96..ae49b535 100644
--- a/pixelstats/Android.bp
+++ b/pixelstats/Android.bp
@@ -73,6 +73,7 @@ cc_library {
"StatsHelper.cpp",
"SysfsCollector.cpp",
"ThermalStatsReporter.cpp",
+ "TempResidencyReporter.cpp",
"UeventListener.cpp",
"WirelessChargeStats.cpp",
"WlcReporter.cpp",
diff --git a/pixelstats/SysfsCollector.cpp b/pixelstats/SysfsCollector.cpp
index 8e5c709c..203ff0f7 100644
--- a/pixelstats/SysfsCollector.cpp
+++ b/pixelstats/SysfsCollector.cpp
@@ -55,10 +55,13 @@ using android::hardware::google::pixel::PixelAtoms::ThermalDfsStats;
using android::hardware::google::pixel::PixelAtoms::VendorAudioHardwareStatsReported;
using android::hardware::google::pixel::PixelAtoms::VendorChargeCycles;
using android::hardware::google::pixel::PixelAtoms::VendorHardwareFailed;
+using android::hardware::google::pixel::PixelAtoms::VendorLongIRQStatsReported;
+using android::hardware::google::pixel::PixelAtoms::VendorResumeLatencyStats;
using android::hardware::google::pixel::PixelAtoms::VendorSlowIo;
using android::hardware::google::pixel::PixelAtoms::VendorSpeakerImpedance;
using android::hardware::google::pixel::PixelAtoms::VendorSpeakerStatsReported;
using android::hardware::google::pixel::PixelAtoms::VendorSpeechDspStat;
+using android::hardware::google::pixel::PixelAtoms::VendorTempResidencyStats;
using android::hardware::google::pixel::PixelAtoms::ZramBdStat;
using android::hardware::google::pixel::PixelAtoms::ZramMmStat;
@@ -89,7 +92,10 @@ SysfsCollector::SysfsCollector(const struct SysfsPaths &sysfs_paths)
kBlockStatsLength(sysfs_paths.BlockStatsLength),
kAmsRatePath(sysfs_paths.AmsRatePath),
kThermalStatsPaths(sysfs_paths.ThermalStatsPaths),
- kCCARatePath(sysfs_paths.CCARatePath) {}
+ kCCARatePath(sysfs_paths.CCARatePath),
+ kTempResidencyPath(sysfs_paths.TempResidencyPath),
+ kLongIRQMetricsPath(sysfs_paths.LongIRQMetricsPath),
+ kResumeLatencyMetricsPath(sysfs_paths.ResumeLatencyMetricsPath) {}
bool SysfsCollector::ReadFileToInt(const std::string &path, int *val) {
return ReadFileToInt(path.c_str(), val);
@@ -814,6 +820,10 @@ void SysfsCollector::logBlockStatsReported(const std::shared_ptr<IStats> &stats_
}
}
+void SysfsCollector::logTempResidencyStats(const std::shared_ptr<IStats> &stats_client) {
+ temp_residency_reporter_.logTempResidencyStats(stats_client, kTempResidencyPath);
+}
+
void SysfsCollector::reportZramMmStat(const std::shared_ptr<IStats> &stats_client) {
std::string file_contents;
if (!kZramMmStatPath) {
@@ -1044,6 +1054,228 @@ void SysfsCollector::logVendorAudioHardwareStats(const std::shared_ptr<IStats> &
ALOGE("Unable to report VendorAudioHardwareStatsReported to Stats service");
}
+/**
+ * Logs the Resume Latency stats.
+ */
+void SysfsCollector::logVendorResumeLatencyStats(const std::shared_ptr<IStats> &stats_client) {
+ std::string file_contents;
+ if (!kResumeLatencyMetricsPath) {
+ ALOGE("ResumeLatencyMetrics path not specified");
+ return;
+ }
+ if (!ReadFileToString(kResumeLatencyMetricsPath, &file_contents)) {
+ ALOGE("Unable to ResumeLatencyMetric %s - %s", kResumeLatencyMetricsPath, strerror(errno));
+ return;
+ }
+
+ int offset = 0;
+ int bytes_read;
+ const char *data = file_contents.c_str();
+ int data_len = file_contents.length();
+
+ int curr_bucket_cnt;
+ if (!sscanf(data + offset, "Resume Latency Bucket Count: %d\n%n", &curr_bucket_cnt,
+ &bytes_read))
+ return;
+ offset += bytes_read;
+ if (offset >= data_len)
+ return;
+
+ int64_t max_latency;
+ if (!sscanf(data + offset, "Max Resume Latency: %ld\n%n", &max_latency, &bytes_read))
+ return;
+ offset += bytes_read;
+ if (offset >= data_len)
+ return;
+
+ uint64_t sum_latency;
+ if (!sscanf(data + offset, "Sum Resume Latency: %lu\n%n", &sum_latency, &bytes_read))
+ return;
+ offset += bytes_read;
+ if (offset >= data_len)
+ return;
+
+ if (curr_bucket_cnt > kMaxResumeLatencyBuckets)
+ return;
+ if (curr_bucket_cnt != prev_data.bucket_cnt) {
+ prev_data.resume_latency_buckets.clear();
+ }
+
+ int64_t total_latency_cnt = 0;
+ int64_t count;
+ int index = 2;
+ std::vector<VendorAtomValue> values(curr_bucket_cnt + 2);
+ VendorAtomValue tmp;
+ // Iterate over resume latency buckets to get latency count within some latency thresholds
+ while (sscanf(data + offset, "%*ld - %*ldms ====> %ld\n%n", &count, &bytes_read) == 1 ||
+ sscanf(data + offset, "%*ld - infms ====> %ld\n%n", &count, &bytes_read) == 1) {
+ offset += bytes_read;
+ if (offset >= data_len && (index + 1 < curr_bucket_cnt + 2))
+ return;
+ if (curr_bucket_cnt == prev_data.bucket_cnt) {
+ tmp.set<VendorAtomValue::longValue>(count -
+ prev_data.resume_latency_buckets[index - 2]);
+ prev_data.resume_latency_buckets[index - 2] = count;
+ } else {
+ tmp.set<VendorAtomValue::longValue>(count);
+ prev_data.resume_latency_buckets.push_back(count);
+ }
+ if (index >= curr_bucket_cnt + 2)
+ return;
+ values[index] = tmp;
+ index += 1;
+ total_latency_cnt += count;
+ }
+ tmp.set<VendorAtomValue::longValue>(max_latency);
+ values[0] = tmp;
+ if ((sum_latency - prev_data.resume_latency_sum_ms < 0) ||
+ (total_latency_cnt - prev_data.resume_count <= 0)) {
+ tmp.set<VendorAtomValue::longValue>(-1);
+ ALOGI("average resume latency get overflow");
+ } else {
+ tmp.set<VendorAtomValue::longValue>(
+ (int64_t)(sum_latency - prev_data.resume_latency_sum_ms) /
+ (total_latency_cnt - prev_data.resume_count));
+ }
+ values[1] = tmp;
+
+ prev_data.resume_latency_sum_ms = sum_latency;
+ prev_data.resume_count = total_latency_cnt;
+ prev_data.bucket_cnt = curr_bucket_cnt;
+ // Send vendor atom to IStats HAL
+ VendorAtom event = {.reverseDomainName = "",
+ .atomId = PixelAtoms::Atom::kVendorResumeLatencyStats,
+ .values = std::move(values)};
+ const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
+ if (!ret.isOk())
+ ALOGE("Unable to report VendorResumeLatencyStats to Stats service");
+}
+
+bool cmp(const std::pair<int, int64_t> &a, const std::pair<int, int64_t> &b) {
+ return a.second > b.second;
+}
+
+/**
+ * Sort irq stats by irq latency, and load top 5 irq stats.
+ */
+void process_irqatom_values(std::vector<std::pair<int, int64_t>> sorted_pair,
+ std::vector<VendorAtomValue> *values) {
+ VendorAtomValue tmp;
+ sort(sorted_pair.begin(), sorted_pair.end(), cmp);
+ int irq_stats_size = sorted_pair.size();
+ for (int i = 0; i < 5; i++) {
+ if (irq_stats_size < 5 && i >= irq_stats_size) {
+ tmp.set<VendorAtomValue::longValue>(-1);
+ values->push_back(tmp);
+ tmp.set<VendorAtomValue::longValue>(0);
+ values->push_back(tmp);
+ } else {
+ tmp.set<VendorAtomValue::longValue>(sorted_pair[i].first);
+ values->push_back(tmp);
+ tmp.set<VendorAtomValue::longValue>(sorted_pair[i].second);
+ values->push_back(tmp);
+ }
+ }
+}
+
+/**
+ * Logs the Long irq stats.
+ */
+void SysfsCollector::logVendorLongIRQStatsReported(const std::shared_ptr<IStats> &stats_client) {
+ std::string file_contents;
+ if (!kLongIRQMetricsPath) {
+ ALOGV("LongIRQ path not specified");
+ return;
+ }
+ if (!ReadFileToString(kLongIRQMetricsPath, &file_contents)) {
+ ALOGE("Unable to LongIRQ %s - %s", kLongIRQMetricsPath, strerror(errno));
+ return;
+ }
+ int offset = 0;
+ int bytes_read;
+ const char *data = file_contents.c_str();
+ int data_len = file_contents.length();
+ // Get, process, store softirq stats
+ std::vector<std::pair<int, int64_t>> sorted_softirq_pair;
+ int64_t softirq_count;
+ if (sscanf(data + offset, "long SOFTIRQ count: %ld\n%n", &softirq_count, &bytes_read) != 1)
+ return;
+ offset += bytes_read;
+ if (offset >= data_len)
+ return;
+ std::vector<VendorAtomValue> values;
+ VendorAtomValue tmp;
+ if (softirq_count - prev_data.softirq_count < 0) {
+ tmp.set<VendorAtomValue::intValue>(-1);
+ ALOGI("long softirq count get overflow");
+ } else {
+ tmp.set<VendorAtomValue::longValue>(softirq_count - prev_data.softirq_count);
+ }
+ values.push_back(tmp);
+
+ if (sscanf(data + offset, "long SOFTIRQ detail (num, latency):\n%n", &bytes_read) != 0)
+ return;
+ offset += bytes_read;
+ if (offset >= data_len)
+ return;
+
+ // Iterate over softirq stats and record top 5 long softirq
+ int64_t softirq_latency;
+ int softirq_num;
+ while (sscanf(data + offset, "%d %ld\n%n", &softirq_num, &softirq_latency, &bytes_read) == 2) {
+ sorted_softirq_pair.push_back(std::make_pair(softirq_num, softirq_latency));
+ offset += bytes_read;
+ if (offset >= data_len)
+ return;
+ }
+ process_irqatom_values(sorted_softirq_pair, &values);
+
+ // Get, process, store irq stats
+ std::vector<std::pair<int, int64_t>> sorted_irq_pair;
+ int64_t irq_count;
+ if (sscanf(data + offset, "long IRQ count: %ld\n%n", &irq_count, &bytes_read) != 1)
+ return;
+ offset += bytes_read;
+ if (offset >= data_len)
+ return;
+ if (irq_count - prev_data.irq_count < 0) {
+ tmp.set<VendorAtomValue::intValue>(-1);
+ ALOGI("long irq count get overflow");
+ } else {
+ tmp.set<VendorAtomValue::longValue>(irq_count - prev_data.irq_count);
+ }
+ values.push_back(tmp);
+
+ if (sscanf(data + offset, "long IRQ detail (num, latency):\n%n", &bytes_read) != 0)
+ return;
+ offset += bytes_read;
+ if (offset >= data_len)
+ return;
+
+ int64_t irq_latency;
+ int irq_num;
+ int index = 0;
+ // Iterate over softirq stats and record top 5 long irq
+ while (sscanf(data + offset, "%d %ld\n%n", &irq_num, &irq_latency, &bytes_read) == 2) {
+ sorted_irq_pair.push_back(std::make_pair(irq_num, irq_latency));
+ offset += bytes_read;
+ if (offset >= data_len && index < 5)
+ return;
+ index += 1;
+ }
+ process_irqatom_values(sorted_irq_pair, &values);
+
+ prev_data.softirq_count = softirq_count;
+ prev_data.irq_count = irq_count;
+ // Send vendor atom to IStats HAL
+ VendorAtom event = {.reverseDomainName = "",
+ .atomId = PixelAtoms::Atom::kVendorLongIrqStatsReported,
+ .values = std::move(values)};
+ const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
+ if (!ret.isOk())
+ ALOGE("Unable to report kVendorLongIRQStatsReported to Stats service");
+}
+
void SysfsCollector::logPerDay() {
const std::shared_ptr<IStats> stats_client = getStatsService();
if (!stats_client) {
@@ -1075,6 +1307,9 @@ void SysfsCollector::logPerDay() {
mm_metrics_reporter_.logPixelMmMetricsPerDay(stats_client);
logVendorAudioHardwareStats(stats_client);
logThermalStats(stats_client);
+ logTempResidencyStats(stats_client);
+ logVendorLongIRQStatsReported(stats_client);
+ logVendorResumeLatencyStats(stats_client);
}
void SysfsCollector::aggregatePer5Min() {
diff --git a/pixelstats/TempResidencyReporter.cpp b/pixelstats/TempResidencyReporter.cpp
new file mode 100644
index 00000000..baa1d4a5
--- /dev/null
+++ b/pixelstats/TempResidencyReporter.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "pixelstats: TempResidencyStats"
+
+#include <aidl/android/frameworks/stats/IStats.h>
+#include <android-base/chrono_utils.h>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android/binder_manager.h>
+#include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
+#include <pixelstats/TempResidencyReporter.h>
+#include <utils/Log.h>
+
+#include <cinttypes>
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+
+using aidl::android::frameworks::stats::IStats;
+using aidl::android::frameworks::stats::VendorAtom;
+using aidl::android::frameworks::stats::VendorAtomValue;
+using android::base::ReadFileToString;
+using android::hardware::google::pixel::PixelAtoms::ThermalDfsStats;
+
+/**
+ * Parse file_contents and read residency stats into cur_stats.
+ */
+bool parse_file_contents(std::string file_contents,
+ std::map<std::string, std::vector<int64_t>> *cur_stats) {
+ const char *data = file_contents.c_str();
+ int data_len = file_contents.length();
+ char sensor_name[32];
+ int offset = 0;
+ int bytes_read;
+
+ while (sscanf(data + offset, "THERMAL ZONE: %31s\n%n", sensor_name, &bytes_read) == 1) {
+ int64_t temp_res_value;
+ int num_stats_buckets;
+ int index = 0;
+ offset += bytes_read;
+ if (offset >= data_len)
+ return false;
+
+ std::string sensor_name_str = sensor_name;
+
+ if (!sscanf(data + offset, "NUM_TEMP_RESIDENCY_BUCKETS: %d\n%n", &num_stats_buckets,
+ &bytes_read))
+ return false;
+ offset += bytes_read;
+ if (offset >= data_len)
+ return false;
+ while (index < num_stats_buckets) {
+ if (sscanf(data + offset, "-inf - %*d ====> %ldms\n%n", &temp_res_value, &bytes_read) !=
+ 1 &&
+ sscanf(data + offset, "%*d - %*d ====> %ldms\n%n", &temp_res_value, &bytes_read) !=
+ 1 &&
+ sscanf(data + offset, "%*d - inf ====> %ldms\n\n%n", &temp_res_value,
+ &bytes_read) != 1)
+ return false;
+
+ (*cur_stats)[sensor_name_str].push_back(temp_res_value);
+ index++;
+
+ offset += bytes_read;
+ if ((offset >= data_len) && (index < num_stats_buckets))
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * Logs the Temperature residency stats for every thermal zone.
+ */
+void TempResidencyReporter::logTempResidencyStats(const std::shared_ptr<IStats> &stats_client,
+ const char *const temperature_residency_path) {
+ if (!temperature_residency_path) {
+ ALOGV("TempResidencyStatsPath path not specified");
+ return;
+ }
+ std::string file_contents;
+ if (!ReadFileToString(temperature_residency_path, &file_contents)) {
+ ALOGE("Unable to read TempResidencyStatsPath %s - %s", temperature_residency_path,
+ strerror(errno));
+ return;
+ }
+ std::map<std::string, std::vector<int64_t>> cur_stats_map;
+ if (!parse_file_contents(file_contents, &cur_stats_map)) {
+ ALOGE("Fail to parse TempResidencyStatsPath");
+ return;
+ }
+ if (!cur_stats_map.size())
+ return;
+ ::android::base::boot_clock::time_point curTime = ::android::base::boot_clock::now();
+ int64_t since_last_update_ms =
+ std::chrono::duration_cast<std::chrono::milliseconds>(curTime - prevTime).count();
+
+ auto cur_stats_map_iterator = cur_stats_map.begin();
+ VendorAtomValue tmp_atom_value;
+
+ // Iterate through cur_stats_map by sensor_name
+ while (cur_stats_map_iterator != cur_stats_map.end()) {
+ std::vector<VendorAtomValue> values;
+ std::string sensor_name_str = cur_stats_map_iterator->first;
+ std::vector<int64_t> residency_stats = cur_stats_map_iterator->second;
+ tmp_atom_value.set<VendorAtomValue::stringValue>(sensor_name_str);
+ values.push_back(tmp_atom_value);
+ tmp_atom_value.set<VendorAtomValue::longValue>(since_last_update_ms);
+ values.push_back(tmp_atom_value);
+
+ bool key_in_map = (prev_stats.find(sensor_name_str)) != prev_stats.end();
+ bool stat_len_match = (residency_stats.size() == prev_stats[sensor_name_str].size());
+ if (key_in_map && !stat_len_match)
+ prev_stats[sensor_name_str].clear();
+
+ int64_t sum_residency = 0;
+ if (residency_stats.size() > kMaxBucketLen) {
+ cur_stats_map_iterator++;
+ continue;
+ }
+ // Iterate over every temperature residency buckets
+ for (int index = 0; index < residency_stats.size(); index++) {
+ // Get diff if stats arr length match previous stats
+ // Otherwise use raw stats as temperature residency stats per day
+ if (key_in_map && stat_len_match) {
+ int64_t diff_residency =
+ residency_stats[index] - prev_stats[sensor_name_str][index];
+ tmp_atom_value.set<VendorAtomValue::longValue>(diff_residency);
+ sum_residency += diff_residency;
+ prev_stats[sensor_name_str][index] = residency_stats[index];
+ } else {
+ tmp_atom_value.set<VendorAtomValue::longValue>(residency_stats[index]);
+ sum_residency += residency_stats[index];
+ prev_stats[sensor_name_str].push_back(residency_stats[index]);
+ }
+ values.push_back(tmp_atom_value);
+ }
+ if (abs(since_last_update_ms - sum_residency) > kMaxResidencyDiffMs)
+ ALOGI("Thermal zone: %s Temperature residency stats not good!\ndevice sum_residency: "
+ "%ldms, since_last_update_ms %ldms\n",
+ sensor_name_str.c_str(), sum_residency, since_last_update_ms);
+
+ // Send vendor atom to IStats HAL
+ VendorAtom event = {.reverseDomainName = "",
+ .atomId = PixelAtoms::Atom::kVendorTempResidencyStats,
+ .values = std::move(values)};
+ ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
+ if (!ret.isOk())
+ ALOGE("Unable to report VendorTempResidencyStats to Stats service");
+
+ cur_stats_map_iterator++;
+ }
+ prevTime = curTime;
+}
+
+} // namespace pixel
+} // namespace google
+} // namespace hardware
+} // namespace android
diff --git a/pixelstats/include/pixelstats/SysfsCollector.h b/pixelstats/include/pixelstats/SysfsCollector.h
index f487dda0..df4a3315 100644
--- a/pixelstats/include/pixelstats/SysfsCollector.h
+++ b/pixelstats/include/pixelstats/SysfsCollector.h
@@ -24,6 +24,7 @@
#include "BatteryHealthReporter.h"
#include "MitigationStatsReporter.h"
#include "MmMetricsReporter.h"
+#include "TempResidencyReporter.h"
#include "ThermalStatsReporter.h"
namespace android {
@@ -65,6 +66,9 @@ class SysfsCollector {
const char *const AmsRatePath;
const std::vector<std::string> ThermalStatsPaths;
const char *const CCARatePath;
+ const char *const TempResidencyPath;
+ const char *const LongIRQMetricsPath;
+ const char *const ResumeLatencyMetricsPath;
};
SysfsCollector(const struct SysfsPaths &paths);
@@ -100,10 +104,13 @@ class SysfsCollector {
void reportSlowIoFromFile(const std::shared_ptr<IStats> &stats_client, const char *path,
const VendorSlowIo::IoOperation &operation_s);
+ void logTempResidencyStats(const std::shared_ptr<IStats> &stats_client);
void reportZramMmStat(const std::shared_ptr<IStats> &stats_client);
void reportZramBdStat(const std::shared_ptr<IStats> &stats_client);
int getReclaimedSegments(const std::string &mode);
void logVendorAudioHardwareStats(const std::shared_ptr<IStats> &stats_client);
+ void logVendorLongIRQStatsReported(const std::shared_ptr<IStats> &stats_client);
+ void logVendorResumeLatencyStats(const std::shared_ptr<IStats> &stats_client);
const char *const kSlowioReadCntPath;
const char *const kSlowioWriteCntPath;
@@ -132,13 +139,16 @@ class SysfsCollector {
const char *const kAmsRatePath;
const std::vector<std::string> kThermalStatsPaths;
const char *const kCCARatePath;
+ const char *const kTempResidencyPath;
+ const char *const kLongIRQMetricsPath;
+ const char *const kResumeLatencyMetricsPath;
BatteryEEPROMReporter battery_EEPROM_reporter_;
MmMetricsReporter mm_metrics_reporter_;
MitigationStatsReporter mitigation_stats_reporter_;
ThermalStatsReporter thermal_stats_reporter_;
BatteryHealthReporter battery_health_reporter_;
-
+ TempResidencyReporter temp_residency_reporter_;
// Proto messages are 1-indexed and VendorAtom field numbers start at 2, so
// store everything in the values array at the index of the field number
// -2.
@@ -146,6 +156,17 @@ class SysfsCollector {
bool log_once_reported = false;
int64_t prev_huge_pages_since_boot_ = -1;
+
+ struct perf_metrics_data {
+ int64_t softirq_count;
+ int64_t irq_count;
+ uint64_t resume_latency_sum_ms;
+ int64_t resume_count;
+ std::vector<int64_t> resume_latency_buckets;
+ int bucket_cnt;
+ };
+ struct perf_metrics_data prev_data;
+ const int kMaxResumeLatencyBuckets = 36;
};
} // namespace pixel
diff --git a/pixelstats/include/pixelstats/TempResidencyReporter.h b/pixelstats/include/pixelstats/TempResidencyReporter.h
new file mode 100644
index 00000000..07e33433
--- /dev/null
+++ b/pixelstats/include/pixelstats/TempResidencyReporter.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/frameworks/stats/IStats.h>
+#include <android-base/chrono_utils.h>
+#include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
+
+#include <string>
+
+namespace android {
+namespace hardware {
+namespace google {
+namespace pixel {
+
+using aidl::android::frameworks::stats::IStats;
+using aidl::android::frameworks::stats::VendorAtomValue;
+
+/**
+ * A class to upload Pixel TempResidency Stats metrics
+ */
+class TempResidencyReporter {
+ public:
+ void logTempResidencyStats(const std::shared_ptr<IStats> &stats_client,
+ const char *const temperature_residency_path);
+
+ private:
+ std::map<std::string, std::vector<int64_t>> prev_stats;
+ ::android::base::boot_clock::time_point prevTime =
+ ::android::base::boot_clock::time_point::min();
+ const int kMaxBucketLen = 20;
+ const int kMaxResidencyDiffMs = 3000;
+};
+
+} // namespace pixel
+} // namespace google
+} // namespace hardware
+} // namespace android
diff --git a/pixelstats/pixelatoms.proto b/pixelstats/pixelatoms.proto
index e4d98bfd..433768a3 100644
--- a/pixelstats/pixelatoms.proto
+++ b/pixelstats/pixelatoms.proto
@@ -84,6 +84,9 @@ message Atom {
VendorAudioHardwareStatsReported vendor_audio_hardware_stats_reported = 105041;
ThermalDfsStats thermal_dfs_stats = 105042;
+ VendorLongIRQStatsReported vendor_long_irq_stats_reported = 105043;
+ VendorResumeLatencyStats vendor_resume_latency_stats = 105044;
+ VendorTempResidencyStats vendor_temp_residency_stats = 105045;
}
// AOSP atom ID range ends at 109999
}
@@ -1158,11 +1161,11 @@ message BatteryHealthStatus {
optional int32 health_algorithm = 2;
enum HealthStatus {
- UNKNOWN = 0; // The health status is unknown due to a SW limitation or issue
- NOMINAL = 1; // The battery is operating as expected
- MARGINAL = 2; // The battery may need replacement soon
- NEEDS_REPLACEMENT = 3; // The battery needs replacement
- FAILED = 4; // The battery has failed and no longer operates as expected
+ UNKNOWN = -1; // The health status is unknown due to a SW limitation or issue
+ NOMINAL = 0; // The battery is operating as expected
+ MARGINAL = 1; // The battery may need replacement soon
+ NEEDS_REPLACEMENT = 2; // The battery needs replacement
+ FAILED = 3; // The battery has failed and no longer operates as expected
}
// HealthStatus calculated using health_index, health_perf_index.
@@ -1281,3 +1284,130 @@ message VendorAudioHardwareStatsReported {
/* cca_enable: UI enable & algorithm is inactive. (C2) */
optional int32 rate_of_cca_enable_per_day = 4;
}
+
+/*
+ * Logs vendor stats about long IRQs.
+ *
+ * IRQ is considered long when it exceeds a threshold (currently 1 ms).
+ * Stats include top 5 slowest IRQs: their numbers and the worst latency.
+ * Stats are reset after every report.
+ */
+message VendorLongIRQStatsReported {
+ optional string reverse_domain_name = 1;
+
+ // Count of long soft IRQ since last report.
+ optional int64 long_softirq_count = 2;
+
+ optional int64 top1_softirq_num = 3;
+ optional int64 top1_softirq_latency_us = 4;
+ optional int64 top2_softirq_num = 5;
+ optional int64 top2_softirq_latency_us = 6;
+ optional int64 top3_softirq_num = 7;
+ optional int64 top3_softirq_latency_us = 8;
+ optional int64 top4_softirq_num = 9;
+ optional int64 top4_softirq_latency_us = 10;
+ optional int64 top5_softirq_num = 11;
+ optional int64 top5_softirq_latency_us = 12;
+
+ // Count of long IRQ since last report.
+ optional int64 long_irq_count = 13;
+
+ optional int64 top1_irq_num = 14;
+ optional int64 top1_irq_latency_us = 15;
+ optional int64 top2_irq_num = 16;
+ optional int64 top2_irq_latency_us = 17;
+ optional int64 top3_irq_num = 18;
+ optional int64 top3_irq_latency_us = 19;
+ optional int64 top4_irq_num = 20;
+ optional int64 top4_irq_latency_us = 21;
+ optional int64 top5_irq_num = 22;
+ optional int64 top5_irq_latency_us = 23;
+}
+
+/**
+ * Logs the Temperature residency stats per thermal zone.
+ */
+message VendorTempResidencyStats {
+ optional string reverse_domain_name = 1;
+ // Thermal zone name
+ optional string sensor_name = 2;
+
+ // Time since last collect of this thermal zone
+ optional int64 since_last_update_ms = 3;
+
+ // Temperature residency stats is measured by time in ms that a temperature zone's temperature
+ // lay within some temperature thresholds
+ // e.g.
+ // With temperature thresholds predefined as thresholds_i, thresholds_i+1,
+ // temp_residency_ms_bucket_i measures how much time the sensor lay within this two thresholds
+ optional int64 temp_residency_ms_bucket_1 = 4;
+ optional int64 temp_residency_ms_bucket_2 = 5;
+ optional int64 temp_residency_ms_bucket_3 = 6;
+ optional int64 temp_residency_ms_bucket_4 = 7;
+ optional int64 temp_residency_ms_bucket_5 = 8;
+ optional int64 temp_residency_ms_bucket_6 = 9;
+ optional int64 temp_residency_ms_bucket_7 = 10;
+ optional int64 temp_residency_ms_bucket_8 = 11;
+ optional int64 temp_residency_ms_bucket_9 = 12;
+ optional int64 temp_residency_ms_bucket_10 = 13;
+ optional int64 temp_residency_ms_bucket_11 = 14;
+ optional int64 temp_residency_ms_bucket_12 = 15;
+ optional int64 temp_residency_ms_bucket_13 = 16;
+ optional int64 temp_residency_ms_bucket_14 = 17;
+ optional int64 temp_residency_ms_bucket_15 = 18;
+ optional int64 temp_residency_ms_bucket_16 = 19;
+ optional int64 temp_residency_ms_bucket_17 = 20;
+ optional int64 temp_residency_ms_bucket_18 = 21;
+ optional int64 temp_residency_ms_bucket_19 = 22;
+ optional int64 temp_residency_ms_bucket_20 = 23;
+}
+
+/**
+ * Logs the Resume Latency stats.
+ */
+message VendorResumeLatencyStats {
+ optional string reverse_domain_name = 1;
+ optional int64 max_latency_ms = 2;
+ optional int64 avg_latency_ms = 3;
+
+ // Resume Latency stats is measured by count of resumes that lay within some latency thresholds
+ // e.g.
+ // With resume times thresholds predefined as thresholds_i, thresholds_i+1,
+ // resume_count_bucket_i measures count of resumes that lay within this two thresholds
+ optional int64 resume_count_bucket_1 = 4;
+ optional int64 resume_count_bucket_2 = 5;
+ optional int64 resume_count_bucket_3 = 6;
+ optional int64 resume_count_bucket_4 = 7;
+ optional int64 resume_count_bucket_5 = 8;
+ optional int64 resume_count_bucket_6 = 9;
+ optional int64 resume_count_bucket_7 = 10;
+ optional int64 resume_count_bucket_8 = 11;
+ optional int64 resume_count_bucket_9 = 12;
+ optional int64 resume_count_bucket_10 = 13;
+ optional int64 resume_count_bucket_11 = 14;
+ optional int64 resume_count_bucket_12 = 15;
+ optional int64 resume_count_bucket_13 = 16;
+ optional int64 resume_count_bucket_14 = 17;
+ optional int64 resume_count_bucket_15 = 18;
+ optional int64 resume_count_bucket_16 = 19;
+ optional int64 resume_count_bucket_17 = 20;
+ optional int64 resume_count_bucket_18 = 21;
+ optional int64 resume_count_bucket_19 = 22;
+ optional int64 resume_count_bucket_20 = 23;
+ optional int64 resume_count_bucket_21 = 24;
+ optional int64 resume_count_bucket_22 = 25;
+ optional int64 resume_count_bucket_23 = 26;
+ optional int64 resume_count_bucket_24 = 27;
+ optional int64 resume_count_bucket_25 = 28;
+ optional int64 resume_count_bucket_26 = 29;
+ optional int64 resume_count_bucket_27 = 30;
+ optional int64 resume_count_bucket_28 = 31;
+ optional int64 resume_count_bucket_29 = 32;
+ optional int64 resume_count_bucket_30 = 33;
+ optional int64 resume_count_bucket_31 = 34;
+ optional int64 resume_count_bucket_32 = 35;
+ optional int64 resume_count_bucket_33 = 36;
+ optional int64 resume_count_bucket_34 = 37;
+ optional int64 resume_count_bucket_35 = 38;
+ optional int64 resume_count_bucket_36 = 39;
+}