perfetto: Throttle rss_stat event

If the ftrace config sets 'throttle_rss_stat' to true and the device
supports throttling trace events with synthetic events, use the
'synthetic/rss_stat_throttled' event instead of 'rss_stat'

Bug: 145972256
Test: out/android/trace_to_text <trace-w/-throttle_rss_stat>
        | grep rss_stat_throttled
Change-Id: I304999fa53a02f4fdcd9011c2d9fd133c6551319
diff --git a/src/traced/probes/ftrace/ftrace_config_muxer.cc b/src/traced/probes/ftrace/ftrace_config_muxer.cc
index a19564f..9e8ba42 100644
--- a/src/traced/probes/ftrace/ftrace_config_muxer.cc
+++ b/src/traced/probes/ftrace/ftrace_config_muxer.cc
@@ -93,6 +93,12 @@
   *out = std::move(v);
 }
 
+bool SupportsRssStatThrottled(const FtraceProcfs& ftrace_procfs) {
+  const auto trigger_info = ftrace_procfs.ReadEventTrigger("kmem", "rss_stat");
+
+  return trigger_info.find("rss_stat_throttled") != std::string::npos;
+}
+
 // This is just to reduce binary size and stack frame size of the insertions.
 // It effectively undoes STL's set::insert inlining.
 void PERFETTO_NO_INLINE InsertEvent(const char* group,
@@ -407,7 +413,12 @@
       }
 
       if (category == "memory") {
-        InsertEvent("kmem", "rss_stat", &events);
+        // Use rss_stat_throttled if supported
+        if (SupportsRssStatThrottled(*ftrace_)) {
+          InsertEvent("synthetic", "rss_stat_throttled", &events);
+        } else {
+          InsertEvent("kmem", "rss_stat", &events);
+        }
         InsertEvent("kmem", "ion_heap_grow", &events);
         InsertEvent("kmem", "ion_heap_shrink", &events);
         // ion_stat supersedes ion_heap_grow / shrink for kernel 4.19+
@@ -424,6 +435,20 @@
       }
     }
   }
+
+  // If throttle_rss_stat: true, use the rss_stat_throttled event if supported
+  if (request.throttle_rss_stat() && SupportsRssStatThrottled(*ftrace_)) {
+    auto it = std::find_if(
+        events.begin(), events.end(), [](const GroupAndName& event) {
+          return event.group() == "kmem" && event.name() == "rss_stat";
+        });
+
+    if (it != events.end()) {
+      events.erase(it);
+      InsertEvent("synthetic", "rss_stat_throttled", &events);
+    }
+  }
+
   return events;
 }
 
diff --git a/src/traced/probes/ftrace/ftrace_procfs.cc b/src/traced/probes/ftrace/ftrace_procfs.cc
index c6d21d5..e393648 100644
--- a/src/traced/probes/ftrace/ftrace_procfs.cc
+++ b/src/traced/probes/ftrace/ftrace_procfs.cc
@@ -130,6 +130,12 @@
   return ReadFileIntoString(path);
 }
 
+std::string FtraceProcfs::ReadEventTrigger(const std::string& group,
+                                           const std::string& name) const {
+  std::string path = root_ + "events/" + group + "/" + name + "/trigger";
+  return ReadFileIntoString(path);
+}
+
 std::string FtraceProcfs::ReadPrintkFormats() const {
   std::string path = root_ + "printk_formats";
   return ReadFileIntoString(path);
diff --git a/src/traced/probes/ftrace/ftrace_procfs.h b/src/traced/probes/ftrace/ftrace_procfs.h
index 81d3063..6e0791b 100644
--- a/src/traced/probes/ftrace/ftrace_procfs.h
+++ b/src/traced/probes/ftrace/ftrace_procfs.h
@@ -58,6 +58,10 @@
 
   virtual std::string ReadPageHeaderFormat() const;
 
+  // Read the triggers for event with the given |group| and |name|.
+  std::string ReadEventTrigger(const std::string& group,
+                               const std::string& name) const;
+
   // Read the printk formats file.
   std::string ReadPrintkFormats() const;