thermal: perfetto/ftrace: Parse thermal_exynos temp and cdev

Add support to parse ThermalExynosAcpmBulk and
ThermalExynosAcpmHighOverhead ftrace events and extract temperature and
cdev target of acpm thermal_zones

For ThermalExynosAcpmBulk extract timestamp from within the event
instead of relying on ftrace timestamp.

Move all thermal related events into one common file.

Bug: 257482511
Test: run ui/run-dev-server
Change-Id: I1ed41715fdade307ee359a9c763fade5c4f9ff52
diff --git a/Android.bp b/Android.bp
index 51e8609..9ca083d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12111,6 +12111,7 @@
         "src/trace_processor/importers/ftrace/mali_gpu_event_tracker.cc",
         "src/trace_processor/importers/ftrace/pkvm_hyp_cpu_tracker.cc",
         "src/trace_processor/importers/ftrace/rss_stat_tracker.cc",
+        "src/trace_processor/importers/ftrace/thermal_tracker.cc",
         "src/trace_processor/importers/ftrace/v4l2_tracker.cc",
         "src/trace_processor/importers/ftrace/virtio_gpu_tracker.cc",
         "src/trace_processor/importers/ftrace/virtio_video_tracker.cc",
diff --git a/BUILD b/BUILD
index 1f39840..19c6276 100644
--- a/BUILD
+++ b/BUILD
@@ -1588,6 +1588,8 @@
         "src/trace_processor/importers/ftrace/pkvm_hyp_cpu_tracker.h",
         "src/trace_processor/importers/ftrace/rss_stat_tracker.cc",
         "src/trace_processor/importers/ftrace/rss_stat_tracker.h",
+        "src/trace_processor/importers/ftrace/thermal_tracker.cc",
+        "src/trace_processor/importers/ftrace/thermal_tracker.h",
         "src/trace_processor/importers/ftrace/v4l2_tracker.cc",
         "src/trace_processor/importers/ftrace/v4l2_tracker.h",
         "src/trace_processor/importers/ftrace/virtio_gpu_tracker.cc",
diff --git a/src/trace_processor/importers/ftrace/BUILD.gn b/src/trace_processor/importers/ftrace/BUILD.gn
index 3a533d1..19354a7 100644
--- a/src/trace_processor/importers/ftrace/BUILD.gn
+++ b/src/trace_processor/importers/ftrace/BUILD.gn
@@ -51,6 +51,8 @@
     "pkvm_hyp_cpu_tracker.h",
     "rss_stat_tracker.cc",
     "rss_stat_tracker.h",
+    "thermal_tracker.cc",
+    "thermal_tracker.h",
     "v4l2_tracker.cc",
     "v4l2_tracker.h",
     "virtio_gpu_tracker.cc",
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc
index ba8a259..a46002f 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc
@@ -85,7 +85,6 @@
 #include "protos/perfetto/trace/ftrace/systrace.pbzero.h"
 #include "protos/perfetto/trace/ftrace/task.pbzero.h"
 #include "protos/perfetto/trace/ftrace/tcp.pbzero.h"
-#include "protos/perfetto/trace/ftrace/thermal.pbzero.h"
 #include "protos/perfetto/trace/ftrace/trusty.pbzero.h"
 #include "protos/perfetto/trace/ftrace/ufs.pbzero.h"
 #include "protos/perfetto/trace/ftrace/vmscan.pbzero.h"
@@ -244,6 +243,7 @@
       mali_gpu_event_tracker_(context),
       pkvm_hyp_cpu_tracker_(context),
       gpu_work_period_tracker_(context),
+      thermal_tracker_(context),
       sched_wakeup_name_id_(context->storage->InternString("sched_wakeup")),
       sched_waking_name_id_(context->storage->InternString("sched_waking")),
       cpu_id_(context->storage->InternString("cpu")),
@@ -874,11 +874,20 @@
         break;
       }
       case FtraceEvent::kThermalTemperatureFieldNumber: {
-        ParseThermalTemperature(ts, fld_bytes);
+        thermal_tracker_.ParseThermalTemperature(ts, fld_bytes);
+        break;
+      }
+      case FtraceEvent::kThermalExynosAcpmBulkFieldNumber: {
+        thermal_tracker_.ParseThermalExynosAcpmBulk(fld_bytes);
+        break;
+      }
+      case FtraceEvent::kThermalExynosAcpmHighOverheadFieldNumber: {
+        thermal_tracker_.ParseThermalExynosAcpmHighOverhead(
+            ts, fld_bytes);
         break;
       }
       case FtraceEvent::kCdevUpdateFieldNumber: {
-        ParseCdevUpdate(ts, fld_bytes);
+        thermal_tracker_.ParseCdevUpdate(ts, fld_bytes);
         break;
       }
       case FtraceEvent::kSchedBlockedReasonFieldNumber: {
@@ -2381,32 +2390,6 @@
       timestamp, static_cast<double>(gpu_mem_total.size()), track);
 }
 
-void FtraceParser::ParseThermalTemperature(int64_t timestamp,
-                                           protozero::ConstBytes blob) {
-  protos::pbzero::ThermalTemperatureFtraceEvent::Decoder event(blob.data,
-                                                               blob.size);
-  base::StringView thermal_zone = event.thermal_zone();
-  base::StackString<255> counter_name(
-      "%.*s Temperature", int(thermal_zone.size()), thermal_zone.data());
-  StringId name = context_->storage->InternString(counter_name.string_view());
-  TrackId track = context_->track_tracker->InternGlobalCounterTrack(
-      TrackTracker::Group::kThermals, name);
-  context_->event_tracker->PushCounter(timestamp, event.temp(), track);
-}
-
-void FtraceParser::ParseCdevUpdate(int64_t timestamp,
-                                   protozero::ConstBytes blob) {
-  protos::pbzero::CdevUpdateFtraceEvent::Decoder event(blob.data, blob.size);
-  base::StringView type = event.type();
-  base::StackString<255> counter_name("%.*s Cooling Device", int(type.size()),
-                                      type.data());
-  StringId name = context_->storage->InternString(counter_name.string_view());
-  TrackId track = context_->track_tracker->InternGlobalCounterTrack(
-      TrackTracker::Group::kThermals, name);
-  context_->event_tracker->PushCounter(
-      timestamp, static_cast<double>(event.target()), track);
-}
-
 void FtraceParser::ParseSchedBlockedReason(
     protozero::ConstBytes blob,
     PacketSequenceStateGeneration* seq_state) {
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.h b/src/trace_processor/importers/ftrace/ftrace_parser.h
index 619b8d4..86c7114 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.h
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.h
@@ -35,6 +35,7 @@
 #include "src/trace_processor/importers/ftrace/mali_gpu_event_tracker.h"
 #include "src/trace_processor/importers/ftrace/pkvm_hyp_cpu_tracker.h"
 #include "src/trace_processor/importers/ftrace/rss_stat_tracker.h"
+#include "src/trace_processor/importers/ftrace/thermal_tracker.h"
 #include "src/trace_processor/importers/ftrace/virtio_gpu_tracker.h"
 #include "src/trace_processor/types/trace_processor_context.h"
 
@@ -201,8 +202,6 @@
                          protozero::ConstBytes);
   void ParseSoftIrqExit(uint32_t cpu, int64_t timestamp, protozero::ConstBytes);
   void ParseGpuMemTotal(int64_t timestamp, protozero::ConstBytes);
-  void ParseThermalTemperature(int64_t timestamp, protozero::ConstBytes);
-  void ParseCdevUpdate(int64_t timestamp, protozero::ConstBytes);
   void ParseSchedBlockedReason(protozero::ConstBytes,
                                PacketSequenceStateGeneration*);
   void ParseFastRpcDmaStat(int64_t timestamp,
@@ -312,6 +311,7 @@
   MaliGpuEventTracker mali_gpu_event_tracker_;
   PkvmHypervisorCpuTracker pkvm_hyp_cpu_tracker_;
   GpuWorkPeriodTracker gpu_work_period_tracker_;
+  ThermalTracker thermal_tracker_;
 
   const StringId sched_wakeup_name_id_;
   const StringId sched_waking_name_id_;
diff --git a/src/trace_processor/importers/ftrace/ftrace_tokenizer.cc b/src/trace_processor/importers/ftrace/ftrace_tokenizer.cc
index 00656fa..0220986 100644
--- a/src/trace_processor/importers/ftrace/ftrace_tokenizer.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_tokenizer.cc
@@ -34,6 +34,7 @@
 #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
 #include "protos/perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
 #include "protos/perfetto/trace/ftrace/power.pbzero.h"
+#include "protos/perfetto/trace/ftrace/thermal_exynos.pbzero.h"
 
 namespace perfetto {
 namespace trace_processor {
@@ -265,7 +266,12 @@
 
   if (PERFETTO_UNLIKELY(
           event_id == protos::pbzero::FtraceEvent::kGpuWorkPeriodFieldNumber)) {
-    TokenizeFtraceGpuWorkPeriod(cpu, std::move(event), state);
+    TokenizeFtraceGpuWorkPeriod(cpu, std::move(event), std::move(state));
+    return;
+  } else if (PERFETTO_UNLIKELY(event_id ==
+                               protos::pbzero::FtraceEvent::
+                                   kThermalExynosAcpmBulkFieldNumber)) {
+    TokenizeFtraceThermalExynosAcpmBulk(cpu, std::move(event), std::move(state));
     return;
   }
 
@@ -468,5 +474,33 @@
                                     std::move(state), context_->machine_id());
 }
 
+void FtraceTokenizer::TokenizeFtraceThermalExynosAcpmBulk(
+    uint32_t cpu, TraceBlobView event,
+    RefPtr<PacketSequenceStateGeneration> state) {
+  // Special handling of valid thermal_exynos_acpm_bulk tracepoint events which
+  // contains the right timestamp value nested inside the event data.
+  const uint8_t* data = event.data();
+  const size_t length = event.length();
+
+  ProtoDecoder decoder(data, length);
+  auto ts_field = decoder.FindField(
+      protos::pbzero::FtraceEvent::kThermalExynosAcpmBulkFieldNumber);
+  if (!ts_field.valid()) {
+    context_->storage->IncrementStats(stats::ftrace_bundle_tokenizer_errors);
+    return;
+  }
+
+  protos::pbzero::ThermalExynosAcpmBulkFtraceEvent::Decoder
+      thermal_exynos_acpm_bulk_event(ts_field.data(), ts_field.size());
+  if (!thermal_exynos_acpm_bulk_event.has_timestamp()) {
+    context_->storage->IncrementStats(stats::ftrace_bundle_tokenizer_errors);
+    return;
+  }
+  int64_t timestamp =
+      static_cast<int64_t>(thermal_exynos_acpm_bulk_event.timestamp());
+  context_->sorter->PushFtraceEvent(cpu, timestamp, std::move(event),
+                                    std::move(state), context_->machine_id());
+}
+
 }  // namespace trace_processor
 }  // namespace perfetto
diff --git a/src/trace_processor/importers/ftrace/ftrace_tokenizer.h b/src/trace_processor/importers/ftrace/ftrace_tokenizer.h
index d53504e..e0b4f7c 100644
--- a/src/trace_processor/importers/ftrace/ftrace_tokenizer.h
+++ b/src/trace_processor/importers/ftrace/ftrace_tokenizer.h
@@ -64,6 +64,9 @@
   void TokenizeFtraceGpuWorkPeriod(uint32_t cpu,
                                    TraceBlobView event,
                                    RefPtr<PacketSequenceStateGeneration> state);
+  void TokenizeFtraceThermalExynosAcpmBulk(uint32_t cpu,
+                                   TraceBlobView event,
+                                   RefPtr<PacketSequenceStateGeneration> state);
 
   void DlogWithLimit(const base::Status& status) {
     static std::atomic<uint32_t> dlog_count(0);
diff --git a/src/trace_processor/importers/ftrace/thermal_tracker.cc b/src/trace_processor/importers/ftrace/thermal_tracker.cc
new file mode 100644
index 0000000..4e1e367
--- /dev/null
+++ b/src/trace_processor/importers/ftrace/thermal_tracker.cc
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2024 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 "perfetto/ext/base/string_utils.h"
+#include "protos/perfetto/trace/ftrace/thermal.pbzero.h"
+#include "protos/perfetto/trace/ftrace/thermal_exynos.pbzero.h"
+#include "src/trace_processor/importers/common/event_tracker.h"
+#include "src/trace_processor/importers/common/track_tracker.h"
+#include "src/trace_processor/importers/ftrace/thermal_tracker.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+constexpr const char* kTemperatureSuffix = "Temperature";
+constexpr const char* kCoolingDeviceSuffix = "Cooling Device";
+
+ThermalTracker::ThermalTracker(TraceProcessorContext* context)
+    : context_(context) {
+  const std::array<const char*, kAcpmThermalZones> acpm_thermal_zones = {
+      "BIG", "MID", "LITTLE", "GPU", "ISP", "TPU", "AUR",
+  };
+  for (size_t i = 0; i < kAcpmThermalZones; i++) {
+    base::StackString<32> temperature_counter("%s %s", acpm_thermal_zones[i],
+                                              kTemperatureSuffix);
+    acpm_temperature_counters_[i] =
+        context_->storage->InternString(temperature_counter.string_view());
+    base::StackString<32> cooling_device_counter(
+        "Tj-%s %s", acpm_thermal_zones[i], kCoolingDeviceSuffix);
+    acpm_cooling_device_counters_[i] =
+        context_->storage->InternString(cooling_device_counter.string_view());
+  }
+}
+
+void ThermalTracker::ParseThermalTemperature(int64_t timestamp,
+                                             protozero::ConstBytes blob) {
+  protos::pbzero::ThermalTemperatureFtraceEvent::Decoder event(blob);
+  base::StringView tz = event.thermal_zone();
+  base::StackString<255> counter_name("%.*s %s", static_cast<int>(tz.size()),
+                                      tz.data(), kTemperatureSuffix);
+  StringId counter_id =
+      context_->storage->InternString(counter_name.string_view());
+  PushCounter(timestamp, counter_id, static_cast<double>(event.temp()));
+}
+
+void ThermalTracker::ParseCdevUpdate(int64_t timestamp,
+                                     protozero::ConstBytes blob) {
+  protos::pbzero::CdevUpdateFtraceEvent::Decoder event(blob);
+  base::StringView cdev = event.type();
+  base::StackString<255> counter_name("%.*s %s", static_cast<int>(cdev.size()),
+                                      cdev.data(), kCoolingDeviceSuffix);
+  StringId counter_id =
+      context_->storage->InternString(counter_name.string_view());
+  PushCounter(timestamp, counter_id, static_cast<double>(event.target()));
+}
+
+void ThermalTracker::ParseThermalExynosAcpmBulk(protozero::ConstBytes blob) {
+  protos::pbzero::ThermalExynosAcpmBulkFtraceEvent::Decoder event(blob);
+  auto tz_id = static_cast<size_t>(event.tz_id());
+  if (tz_id >= kAcpmThermalZones) {
+    context_->storage->IncrementStats(
+        stats::ftrace_thermal_exynos_acpm_unknown_tz_id);
+    return;
+  }
+  auto timestamp = static_cast<int64_t>(event.timestamp());
+  // Record acpm tz's temperature.
+  PushCounter(timestamp, acpm_temperature_counters_[tz_id],
+              static_cast<double>(event.current_temp()));
+  // Record cdev target of acpm tz's cooling device.
+  PushCounter(timestamp, acpm_cooling_device_counters_[tz_id],
+              static_cast<double>(event.cdev_state()));
+}
+
+void ThermalTracker::ParseThermalExynosAcpmHighOverhead(
+    int64_t timestamp, protozero::ConstBytes blob) {
+  protos::pbzero::ThermalExynosAcpmHighOverheadFtraceEvent::Decoder event(blob);
+  auto tz_id = static_cast<size_t>(event.tz_id());
+  if (tz_id >= kAcpmThermalZones) {
+    context_->storage->IncrementStats(
+        stats::ftrace_thermal_exynos_acpm_unknown_tz_id);
+    return;
+  }
+  // Record acpm tz's temperature.
+  PushCounter(timestamp, acpm_temperature_counters_[tz_id],
+              static_cast<double>(event.current_temp()));
+  // Record cdev target of acpm tz's cooling device.
+  PushCounter(timestamp, acpm_cooling_device_counters_[tz_id],
+              static_cast<double>(event.cdev_state()));
+}
+
+void ThermalTracker::PushCounter(int64_t timestamp, StringId counter_id,
+                                 double value) {
+  TrackId track = context_->track_tracker->InternGlobalCounterTrack(
+      TrackTracker::Group::kThermals, counter_id);
+  context_->event_tracker->PushCounter(timestamp, value, track);
+}
+
+}  // namespace trace_processor
+}  // namespace perfetto
diff --git a/src/trace_processor/importers/ftrace/thermal_tracker.h b/src/trace_processor/importers/ftrace/thermal_tracker.h
new file mode 100644
index 0000000..ff04f6e
--- /dev/null
+++ b/src/trace_processor/importers/ftrace/thermal_tracker.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_THERMAL_TRACKER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_THERMAL_TRACKER_H_
+
+#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/util/descriptors.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class TraceProcessorContext;
+
+class ThermalTracker {
+ public:
+  explicit ThermalTracker(TraceProcessorContext*);
+  void ParseThermalTemperature(int64_t timestamp, protozero::ConstBytes blob);
+  void ParseCdevUpdate(int64_t timestamp, protozero::ConstBytes);
+  void ParseThermalExynosAcpmBulk(protozero::ConstBytes blob);
+  void ParseThermalExynosAcpmHighOverhead(int64_t timestamp,
+                                          protozero::ConstBytes blob);
+
+ private:
+  static constexpr size_t kAcpmThermalZones = 7;
+
+  TraceProcessorContext* context_;
+
+  // Maintain mapping of acpm tz_id's to their corresponding temperature and
+  // cooling device counter ids.
+  std::array<StringId, kAcpmThermalZones> acpm_temperature_counters_;
+  std::array<StringId, kAcpmThermalZones> acpm_cooling_device_counters_;
+
+  void PushCounter(int64_t timestamp, StringId counter_name, double value);
+};
+
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_THERMAL_TRACKER_H_
diff --git a/src/trace_processor/storage/stats.h b/src/trace_processor/storage/stats.h
index 0584d84..9067b09 100644
--- a/src/trace_processor/storage/stats.h
+++ b/src/trace_processor/storage/stats.h
@@ -74,6 +74,8 @@
        "enable. See ftrace_setup_errors in the metadata table for details."),  \
   F(ftrace_abi_errors_skipped_zero_data_length,                                \
                                           kSingle,  kInfo,     kAnalysis, ""), \
+  F(ftrace_thermal_exynos_acpm_unknown_tz_id,                                  \
+                                          kSingle,  kError,    kAnalysis, ""), \
   F(fuchsia_non_numeric_counters,         kSingle,  kError,    kAnalysis, ""), \
   F(fuchsia_timestamp_overflow,           kSingle,  kError,    kAnalysis, ""), \
   F(fuchsia_invalid_event,                kSingle,  kError,    kAnalysis, ""), \
@@ -362,7 +364,7 @@
   // being reflected in the stats table.
   kTrace,
 
-  // The counter is genrated when importing / processing the trace in the trace
+  // The counter is generated when importing / processing the trace in the trace
   // processor.
   kAnalysis
 };