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