traced_probes: Support on demand proccess info

Bug: 73058765
Change-Id: I62801d558363a66c1683b12cb58ae6b36daf8515
diff --git a/src/process_stats/procfs_utils.cc b/src/process_stats/procfs_utils.cc
index 18e0402..98b949e 100644
--- a/src/process_stats/procfs_utils.cc
+++ b/src/process_stats/procfs_utils.cc
@@ -67,10 +67,9 @@
 std::unique_ptr<ProcessInfo> ReadProcessInfo(int pid) {
   ProcessInfo* process = new ProcessInfo();
   process->pid = pid;
-  char cmdline_buf[256];
   // It's not enough to just null terminate this since cmdline uses null as
   // the argument seperator:
-  memset(cmdline_buf, 0, sizeof(cmdline_buf));
+  char cmdline_buf[256]{};
   ReadProcString(pid, "cmdline", cmdline_buf, sizeof(cmdline_buf));
   if (cmdline_buf[0] == 0) {
     // Nothing in cmdline_buf so read name from /comm instead.
diff --git a/src/traced/probes/probes_producer.cc b/src/traced/probes/probes_producer.cc
index 1a8167c..a18854e 100644
--- a/src/traced/probes/probes_producer.cc
+++ b/src/traced/probes/probes_producer.cc
@@ -274,6 +274,15 @@
     const FtraceMetadata& metadata) {
   trace_packet_->Finalize();
 
+  if (ps_source_ && !metadata.pids.empty()) {
+    const auto& pids = metadata.pids;
+    auto weak_ps_source = ps_source_;
+    task_runner_->PostTask([weak_ps_source, pids] {
+      if (weak_ps_source)
+        weak_ps_source->OnPids(pids);
+    });
+  }
+
   if (file_source_ && !metadata.inode_and_device.empty()) {
     auto inodes = metadata.inode_and_device;
     auto weak_file_source = file_source_;
diff --git a/src/traced/probes/process_stats_data_source.cc b/src/traced/probes/process_stats_data_source.cc
index 556f1f7..a1bffd8 100644
--- a/src/traced/probes/process_stats_data_source.cc
+++ b/src/traced/probes/process_stats_data_source.cc
@@ -20,7 +20,6 @@
 
 #include "perfetto/trace/ps/process_tree.pbzero.h"
 #include "perfetto/trace/trace_packet.pbzero.h"
-#include "perfetto/tracing/core/trace_packet.h"
 #include "src/process_stats/file_utils.h"
 #include "src/process_stats/procfs_utils.h"
 
@@ -39,39 +38,51 @@
 }
 
 void ProcessStatsDataSource::WriteAllProcesses() {
-  procfs_utils::ProcessMap processes;
+  auto trace_packet = writer_->NewTracePacket();
+  auto* trace_packet_ptr = &*trace_packet;
+  std::set<int32_t>* seen_pids = &seen_pids_;
 
-  TraceWriter* writer = writer_.get();
+  file_utils::ForEachPidInProcPath("/proc",
+                                   [trace_packet_ptr, seen_pids](int pid) {
+                                     // ForEachPid will list all processes and
+                                     // threads. Here we want to iterate first
+                                     // only by processes (for which pid ==
+                                     // thread group id)
+                                     if (procfs_utils::ReadTgid(pid) != pid)
+                                       return;
 
-  file_utils::ForEachPidInProcPath("/proc", [&processes, writer](int pid) {
-    // TODO(hjd): Move this out when we support large trace packets.
-    auto trace_packet = writer->NewTracePacket();
-    auto* process_tree = trace_packet->set_process_tree();
-
-    // ForEachPid will list all processes and threads. Here we want to
-    // iterate first only by processes (for which pid == thread group id)
-    if (!processes.count(pid)) {
-      if (procfs_utils::ReadTgid(pid) != pid)
-        return;
-      processes[pid] = procfs_utils::ReadProcessInfo(pid);
-    }
-    ProcessInfo* process = processes[pid].get();
-    procfs_utils::ReadProcessThreads(process);
-    auto* process_writer = process_tree->add_processes();
-    process_writer->set_pid(process->pid);
-    process_writer->set_ppid(process->ppid);
-    for (const auto& field : process->cmdline)
-      process_writer->add_cmdline(field.c_str());
-    for (auto& thread : process->threads) {
-      auto* thread_writer = process_writer->add_threads();
-      thread_writer->set_tid(thread.second.tid);
-      thread_writer->set_name(thread.second.name);
-    }
-  });
+                                     WriteProcess(pid, trace_packet_ptr);
+                                     seen_pids->insert(pid);
+                                   });
 }
 
 void ProcessStatsDataSource::OnPids(const std::vector<int32_t>& pids) {
-  PERFETTO_DLOG("Saw FtraceBundle with %zu pids.", pids.size());
+  auto trace_packet = writer_->NewTracePacket();
+  for (int32_t pid : pids) {
+    auto it_and_inserted = seen_pids_.emplace(pid);
+    if (it_and_inserted.second)
+      WriteProcess(pid, &*trace_packet);
+  }
+}
+
+// static
+void ProcessStatsDataSource::WriteProcess(
+    int32_t pid,
+    protos::pbzero::TracePacket* trace_packet) {
+  auto* process_tree = trace_packet->set_process_tree();
+
+  std::unique_ptr<ProcessInfo> process = procfs_utils::ReadProcessInfo(pid);
+  procfs_utils::ReadProcessThreads(process.get());
+  auto* process_writer = process_tree->add_processes();
+  process_writer->set_pid(process->pid);
+  process_writer->set_ppid(process->ppid);
+  for (const auto& field : process->cmdline)
+    process_writer->add_cmdline(field.c_str());
+  for (auto& thread : process->threads) {
+    auto* thread_writer = process_writer->add_threads();
+    thread_writer->set_tid(thread.second.tid);
+    thread_writer->set_name(thread.second.name);
+  }
 }
 
 }  // namespace perfetto
diff --git a/src/traced/probes/process_stats_data_source.h b/src/traced/probes/process_stats_data_source.h
index 2b691ab..f134bff 100644
--- a/src/traced/probes/process_stats_data_source.h
+++ b/src/traced/probes/process_stats_data_source.h
@@ -18,6 +18,7 @@
 #define SRC_TRACED_PROBES_PROCESS_STATS_DATA_SOURCE_H_
 
 #include <memory>
+#include <set>
 #include <vector>
 
 #include "perfetto/base/weak_ptr.h"
@@ -37,11 +38,15 @@
   void OnPids(const std::vector<int32_t>& pids);
 
  private:
+  static void WriteProcess(int32_t pid, protos::pbzero::TracePacket*);
+
   ProcessStatsDataSource(const ProcessStatsDataSource&) = delete;
   ProcessStatsDataSource& operator=(const ProcessStatsDataSource&) = delete;
 
   const TracingSessionID session_id_;
   std::unique_ptr<TraceWriter> writer_;
+  // TODO(b/76663469): Optimization: use a bitmap.
+  std::set<int32_t> seen_pids_;
   base::WeakPtrFactory<ProcessStatsDataSource> weak_factory_;  // Keep last.
 };
 
diff --git a/test/configs/BUILD.gn b/test/configs/BUILD.gn
index 3923c02..485d4f6 100644
--- a/test/configs/BUILD.gn
+++ b/test/configs/BUILD.gn
@@ -27,6 +27,7 @@
       "atrace.cfg",
       "ftrace.cfg",
       "long_trace.cfg",
+      "processes.cfg",
     ]
 
     outputs = [
diff --git a/test/configs/processes.cfg b/test/configs/processes.cfg
new file mode 100644
index 0000000..f8c24b8
--- /dev/null
+++ b/test/configs/processes.cfg
@@ -0,0 +1,57 @@
+buffers {
+  size_kb: 100024
+  fill_policy: RING_BUFFER
+}
+
+data_sources {
+  config {
+    name: "com.google.perfetto.ftrace"
+    target_buffer: 0
+    ftrace_config {
+      buffer_size_kb: 40 # 4 (page size) * 10
+      drain_period_ms: 200
+      ftrace_events: "sched_process_exec"
+      ftrace_events: "sched_process_exit"
+      ftrace_events: "sched_process_fork"
+      ftrace_events: "sched_process_free"
+      ftrace_events: "sched_process_hang"
+      ftrace_events: "sched_process_wait"
+      ftrace_events: "sched_wakeup_new"
+      ftrace_events: "sched_wakeup"
+      ftrace_events: "sched_waking"
+      ftrace_events: "smbus_read"
+      ftrace_events: "smbus_reply"
+      ftrace_events: "smbus_result"
+      ftrace_events: "smbus_write"
+      ftrace_events: "softirq_entry"
+      ftrace_events: "softirq_exit"
+      ftrace_events: "softirq_raise"
+      ftrace_events: "suspend_resume"
+      ftrace_events: "sync_pt"
+      ftrace_events: "sync_timeline"
+      ftrace_events: "sync_wait"
+      ftrace_events: "task_newtask"
+      ftrace_events: "task_rename"
+      ftrace_events: "tracing_mark_write"
+      ftrace_events: "workqueue_activate_work"
+      ftrace_events: "workqueue_execute_end"
+      ftrace_events: "workqueue_execute_start"
+      ftrace_events: "workqueue_queue_work"
+    }
+  }
+}
+
+data_sources {
+  config {
+    name: "com.google.perfetto.process_stats"
+    target_buffer: 0
+  }
+}
+
+producers {
+  producer_name: "com.google.perfetto.traced_probes"
+  shm_size_kb: 4096
+  page_size_kb: 4
+}
+
+duration_ms: 10000
diff --git a/tools/tmux b/tools/tmux
index a5a5447..1e4b3d4 100755
--- a/tools/tmux
+++ b/tools/tmux
@@ -165,7 +165,7 @@
 
 tmux -2 attach-session -t demo
 
-reset
+reset_tracing
 
 TRACE=$HOME/Downloads/trace
 pull trace /tmp/trace.protobuf