traced_probes: Add ProcessStatsDataSource
ProcessStatsDataSource should be able to write metadata for processes
which are created while a trace is running. To do this it needs to live
as long as the trace does so this change creates a
ProcessStatsDataSource to mirror the Sink and InodeFileMapDataSource
that exist for the ftrace and inode datasources.
This also pulls ProcessStatsDataSource and associated logic into its
own class: ProbesProducer is getting too big. Finally it adds the
boilerplate for testing ProcessStatsDataSource - but no actual tests.
There is some additional work required to add tests (e.g. creating a
fake TraceWriter impl) and that shouldn't block progress on
ProcessStatsDataSource.
Bug: 73058765
Change-Id: I2bf68166711289df081edd4ee3375b6fd77f4bb0
diff --git a/Android.bp b/Android.bp
index 15f4e94..aad645f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -61,6 +61,7 @@
"src/protozero/scattered_stream_writer.cc",
"src/traced/probes/probes.cc",
"src/traced/probes/probes_producer.cc",
+ "src/traced/probes/process_stats_data_source.cc",
"src/traced/service/service.cc",
"src/tracing/core/chrome_config.cc",
"src/tracing/core/commit_data_request.cc",
@@ -276,6 +277,7 @@
"src/protozero/proto_utils.cc",
"src/protozero/scattered_stream_writer.cc",
"src/traced/probes/probes_producer.cc",
+ "src/traced/probes/process_stats_data_source.cc",
"src/tracing/core/chrome_config.cc",
"src/tracing/core/commit_data_request.cc",
"src/tracing/core/data_source_config.cc",
@@ -3108,6 +3110,8 @@
"src/ipc/test/ipc_integrationtest.cc",
"src/ipc/unix_socket.cc",
"src/ipc/unix_socket_unittest.cc",
+ "src/process_stats/file_utils.cc",
+ "src/process_stats/procfs_utils.cc",
"src/protozero/message.cc",
"src/protozero/message_handle.cc",
"src/protozero/message_handle_unittest.cc",
@@ -3120,6 +3124,9 @@
"src/protozero/test/protozero_conformance_unittest.cc",
"src/traced/probes/filesystem/fs_mount.cc",
"src/traced/probes/filesystem/fs_mount_unittest.cc",
+ "src/traced/probes/probes_producer.cc",
+ "src/traced/probes/process_stats_data_source.cc",
+ "src/traced/probes/process_stats_data_source_unittest.cc",
"src/tracing/core/chrome_config.cc",
"src/tracing/core/commit_data_request.cc",
"src/tracing/core/data_source_config.cc",
diff --git a/BUILD.gn b/BUILD.gn
index 73b166b..92cb14f 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -66,6 +66,7 @@
if (is_linux || is_android) {
deps += [
"src/ftrace_reader:ftrace_reader_unittests",
+ "src/traced/probes:probes_unittests",
"tools/ftrace_proto_gen:ftrace_proto_gen_unittests",
]
}
diff --git a/include/perfetto/tracing/core/trace_writer.h b/include/perfetto/tracing/core/trace_writer.h
index d29930d..85140ee 100644
--- a/include/perfetto/tracing/core/trace_writer.h
+++ b/include/perfetto/tracing/core/trace_writer.h
@@ -18,6 +18,7 @@
#define INCLUDE_PERFETTO_TRACING_CORE_TRACE_WRITER_H_
#include "perfetto/protozero/message_handle.h"
+#include "perfetto/tracing/core/basic_types.h"
namespace perfetto {
diff --git a/src/ftrace_reader/ftrace_config_muxer_unittest.cc b/src/ftrace_reader/ftrace_config_muxer_unittest.cc
index 44c63a0..9a88bae 100644
--- a/src/ftrace_reader/ftrace_config_muxer_unittest.cc
+++ b/src/ftrace_reader/ftrace_config_muxer_unittest.cc
@@ -110,7 +110,7 @@
new ProtoTranslationTable(events, std::move(common_fields)));
}
-TEST(FtraceConfigMuxer, ComputeCpuBufferSizeInPages) {
+TEST(FtraceConfigMuxerTest, ComputeCpuBufferSizeInPages) {
// No buffer size given: good default (128 pages = 512kb).
EXPECT_EQ(ComputeCpuBufferSizeInPages(0), 128u);
// Buffer size given way too big: good default.
diff --git a/src/traced/probes/BUILD.gn b/src/traced/probes/BUILD.gn
index 2e4ea03..51eb46d 100644
--- a/src/traced/probes/BUILD.gn
+++ b/src/traced/probes/BUILD.gn
@@ -38,5 +38,19 @@
sources = [
"probes_producer.cc",
"probes_producer.h",
+ "process_stats_data_source.cc",
+ "process_stats_data_source.h",
+ ]
+}
+
+source_set("probes_unittests") {
+ testonly = true
+ deps = [
+ ":probes_src",
+ "../../../gn:default_deps",
+ "../../../gn:gtest_deps",
+ ]
+ sources = [
+ "process_stats_data_source_unittest.cc",
]
}
diff --git a/src/traced/probes/probes_producer.cc b/src/traced/probes/probes_producer.cc
index 7074f56..0c1025d 100644
--- a/src/traced/probes/probes_producer.cc
+++ b/src/traced/probes/probes_producer.cc
@@ -29,12 +29,8 @@
#include "perfetto/tracing/core/trace_config.h"
#include "perfetto/tracing/core/trace_packet.h"
-#include "src/process_stats/file_utils.h"
-#include "src/process_stats/procfs_utils.h"
-
#include "perfetto/trace/filesystem/inode_file_map.pbzero.h"
#include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
-#include "perfetto/trace/ps/process_tree.pbzero.h"
#include "perfetto/trace/trace_packet.pbzero.h"
namespace perfetto {
@@ -174,34 +170,13 @@
DataSourceInstanceID id,
const DataSourceConfig& source_config) {
PERFETTO_DCHECK(process_stats_sources_.count(id) == 0);
- process_stats_sources_.insert(id);
auto trace_writer = endpoint_->CreateTraceWriter(
static_cast<BufferID>(source_config.target_buffer()));
- procfs_utils::ProcessMap processes;
- auto trace_packet = trace_writer->NewTracePacket();
- protos::pbzero::ProcessTree* process_tree = trace_packet->set_process_tree();
-
- file_utils::ForEachPidInProcPath(
- "/proc", [&processes, &process_tree](int pid) {
- 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);
- }
- });
- trace_packet->Finalize();
+ auto source = std::unique_ptr<ProcessStatsDataSource>(
+ new ProcessStatsDataSource(std::move(trace_writer)));
+ auto it_and_inserted = process_stats_sources_.emplace(id, std::move(source));
+ PERFETTO_DCHECK(it_and_inserted.second);
+ it_and_inserted.first->second->WriteAllProcesses();
}
// static
diff --git a/src/traced/probes/probes_producer.h b/src/traced/probes/probes_producer.h
index 1c7f73a..e323e9d 100644
--- a/src/traced/probes/probes_producer.h
+++ b/src/traced/probes/probes_producer.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#ifndef SRC_TRACED_PROBES_PROBES_PRODUCER_H_
+#define SRC_TRACED_PROBES_PROBES_PRODUCER_H_
+
#include <map>
#include <memory>
#include <utility>
@@ -23,12 +26,10 @@
#include "perfetto/tracing/core/producer.h"
#include "perfetto/tracing/core/trace_writer.h"
#include "perfetto/tracing/ipc/producer_ipc_client.h"
+#include "src/traced/probes/process_stats_data_source.h"
#include "perfetto/trace/filesystem/inode_file_map.pbzero.h"
-#ifndef SRC_TRACED_PROBES_PROBES_PRODUCER_H_
-#define SRC_TRACED_PROBES_PROBES_PRODUCER_H_
-
namespace perfetto {
class ProbesProducer : public Producer {
@@ -113,6 +114,9 @@
kConnected,
};
+ ProbesProducer(const ProbesProducer&) = delete;
+ ProbesProducer& operator=(const ProbesProducer&) = delete;
+
void Connect();
void ResetConnectionBackoff();
void IncreaseConnectionBackoff();
@@ -129,13 +133,15 @@
bool ftrace_creation_failed_ = false;
uint64_t connection_backoff_ms_ = 0;
const char* socket_name_ = nullptr;
- std::set<DataSourceInstanceID> process_stats_sources_;
+ std::map<DataSourceInstanceID, std::unique_ptr<ProcessStatsDataSource>>
+ process_stats_sources_;
std::map<DataSourceInstanceID, std::unique_ptr<SinkDelegate>> delegates_;
std::map<DataSourceInstanceID, base::Watchdog::Timer> watchdogs_;
std::map<DataSourceInstanceID, std::unique_ptr<InodeFileMapDataSource>>
file_map_sources_;
std::map<uint32_t, InodeMap> system_inodes_;
};
+
} // namespace perfetto
#endif // SRC_TRACED_PROBES_PROBES_PRODUCER_H_
diff --git a/src/traced/probes/process_stats_data_source.cc b/src/traced/probes/process_stats_data_source.cc
new file mode 100644
index 0000000..49803fc
--- /dev/null
+++ b/src/traced/probes/process_stats_data_source.cc
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 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 "process_stats_data_source.h"
+
+#include <utility>
+
+#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"
+
+namespace perfetto {
+
+ProcessStatsDataSource::ProcessStatsDataSource(
+ std::unique_ptr<TraceWriter> writer)
+ : writer_(std::move(writer)) {}
+
+ProcessStatsDataSource::~ProcessStatsDataSource() = default;
+
+void ProcessStatsDataSource::WriteAllProcesses() {
+ procfs_utils::ProcessMap processes;
+ auto trace_packet = writer_->NewTracePacket();
+ protos::pbzero::ProcessTree* process_tree = trace_packet->set_process_tree();
+
+ file_utils::ForEachPidInProcPath(
+ "/proc", [&processes, process_tree](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 (!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);
+ }
+ });
+}
+
+} // namespace perfetto
diff --git a/src/traced/probes/process_stats_data_source.h b/src/traced/probes/process_stats_data_source.h
new file mode 100644
index 0000000..b7327a2
--- /dev/null
+++ b/src/traced/probes/process_stats_data_source.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 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_TRACED_PROBES_PROCESS_STATS_DATA_SOURCE_H_
+#define SRC_TRACED_PROBES_PROCESS_STATS_DATA_SOURCE_H_
+
+#include <memory>
+
+#include "perfetto/tracing/core/trace_writer.h"
+
+namespace perfetto {
+
+class ProcessStatsDataSource {
+ public:
+ explicit ProcessStatsDataSource(std::unique_ptr<TraceWriter> writer);
+ ~ProcessStatsDataSource();
+
+ void WriteAllProcesses();
+
+ private:
+ ProcessStatsDataSource(const ProcessStatsDataSource&) = delete;
+ ProcessStatsDataSource& operator=(const ProcessStatsDataSource&) = delete;
+
+ std::unique_ptr<TraceWriter> writer_;
+};
+
+} // namespace perfetto
+
+#endif // SRC_TRACED_PROBES_PROCESS_STATS_DATA_SOURCE_H_
diff --git a/src/traced/probes/process_stats_data_source_unittest.cc b/src/traced/probes/process_stats_data_source_unittest.cc
new file mode 100644
index 0000000..dd7296d
--- /dev/null
+++ b/src/traced/probes/process_stats_data_source_unittest.cc
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 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 "process_stats_data_source.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace perfetto {
+namespace {
+
+// TODO(hjd): Add tests.
+
+} // namespace
+} // namespace perfetto