Add support for hyp events in perfetto cmd
So far we only add basic support for "hyp" category, which will result
in the following ftrace config to collect all known hyp events:
```
instance_name: "hyp"
ftrace_events: "hyp/*"
```
If needed, in the future we can add support for only tracing specific
hypervisor events.
Bug: 249050813
Test: perfetto_unittests
Change-Id: I1c303e6312a7eb36083cf38488bfe98a813f4363
diff --git a/src/perfetto_cmd/config.cc b/src/perfetto_cmd/config.cc
index 1313dcf..4169eea 100644
--- a/src/perfetto_cmd/config.cc
+++ b/src/perfetto_cmd/config.cc
@@ -118,10 +118,13 @@
std::vector<std::string> ftrace_events;
std::vector<std::string> atrace_categories;
std::vector<std::string> atrace_apps = options.atrace_apps;
+ bool has_hyp_category = false;
for (const auto& category : options.categories) {
if (base::Contains(category, '/')) {
ftrace_events.push_back(category);
+ } else if (category == "hyp") {
+ has_hyp_category = true;
} else {
atrace_categories.push_back(category);
}
@@ -153,17 +156,33 @@
if (max_file_size_kb)
config->set_write_into_file(true);
config->add_buffers()->set_size_kb(static_cast<unsigned int>(buffer_size_kb));
- auto* ds_config = config->add_data_sources()->mutable_config();
- ds_config->set_name("linux.ftrace");
- protos::gen::FtraceConfig ftrace_cfg;
- for (const auto& evt : ftrace_events)
- ftrace_cfg.add_ftrace_events(evt);
- for (const auto& cat : atrace_categories)
- ftrace_cfg.add_atrace_categories(cat);
- for (const auto& app : atrace_apps)
- ftrace_cfg.add_atrace_apps(app);
- ftrace_cfg.set_symbolize_ksyms(true);
- ds_config->set_ftrace_config_raw(ftrace_cfg.SerializeAsString());
+
+ if (!ftrace_events.empty() || !atrace_categories.empty() ||
+ !atrace_apps.empty()) {
+ auto* ds_config = config->add_data_sources()->mutable_config();
+ ds_config->set_name("linux.ftrace");
+ protos::gen::FtraceConfig ftrace_cfg;
+ for (const auto& evt : ftrace_events)
+ ftrace_cfg.add_ftrace_events(evt);
+ for (const auto& cat : atrace_categories)
+ ftrace_cfg.add_atrace_categories(cat);
+ for (const auto& app : atrace_apps)
+ ftrace_cfg.add_atrace_apps(app);
+ ftrace_cfg.set_symbolize_ksyms(true);
+ ds_config->set_ftrace_config_raw(ftrace_cfg.SerializeAsString());
+ }
+
+ // pKVM hypervisor events are coming from a separate special instance called
+ // "hyp", we need a separate config for it.
+ if (has_hyp_category) {
+ auto* ds_config = config->add_data_sources()->mutable_config();
+ ds_config->set_name("linux.ftrace");
+ protos::gen::FtraceConfig ftrace_cfg;
+ ftrace_cfg.set_instance_name("hyp");
+ // Collect all known hypervisor traces.
+ ftrace_cfg.add_ftrace_events("hyp/*");
+ ds_config->set_ftrace_config_raw(ftrace_cfg.SerializeAsString());
+ }
auto* ps_config = config->add_data_sources()->mutable_config();
ps_config->set_name("linux.process_stats");
diff --git a/src/perfetto_cmd/config_unittest.cc b/src/perfetto_cmd/config_unittest.cc
index 5435c8a..f7a6c2c 100644
--- a/src/perfetto_cmd/config_unittest.cc
+++ b/src/perfetto_cmd/config_unittest.cc
@@ -152,5 +152,49 @@
EXPECT_THAT(ftrace.atrace_apps(), Contains("com.android.chrome"));
}
+TEST_F(CreateConfigFromOptionsTest, OnlyHypervisorTraces) {
+ options.buffer_size = "100mb";
+ options.time = "10s";
+ options.categories.push_back("hyp");
+ ASSERT_TRUE(CreateConfigFromOptions(options, &config));
+ EXPECT_EQ(config.duration_ms(), 10 * 1000u);
+ EXPECT_EQ(config.buffers()[0].size_kb(), 100 * 1024u);
+ EXPECT_EQ(config.data_sources()[0].config().name(), "linux.ftrace");
+ protos::gen::FtraceConfig ftrace;
+ ASSERT_TRUE(ftrace.ParseFromString(
+ config.data_sources()[0].config().ftrace_config_raw()));
+ EXPECT_THAT(ftrace.ftrace_events(), Contains("hyp/*"));
+ ASSERT_EQ(ftrace.instance_name(), "hyp");
+}
+
+TEST_F(CreateConfigFromOptionsTest, BothHypervisorAndHostFtraceTraces) {
+ options.buffer_size = "100mb";
+ options.time = "10s";
+ options.categories.push_back("hyp");
+ options.categories.push_back("sw");
+ options.categories.push_back("sched/sched_switch");
+ ASSERT_TRUE(CreateConfigFromOptions(options, &config));
+ EXPECT_EQ(config.duration_ms(), 10 * 1000u);
+ EXPECT_EQ(config.buffers()[0].size_kb(), 100 * 1024u);
+ EXPECT_EQ(config.buffers()[0].size_kb(), 100 * 1024u);
+ EXPECT_EQ(config.data_sources()[0].config().name(), "linux.ftrace");
+ {
+ protos::gen::FtraceConfig ftrace;
+ ASSERT_TRUE(ftrace.ParseFromString(
+ config.data_sources()[0].config().ftrace_config_raw()));
+ EXPECT_THAT(ftrace.ftrace_events(), Contains("sched/sched_switch"));
+ EXPECT_THAT(ftrace.atrace_categories(), Contains("sw"));
+ EXPECT_TRUE(ftrace.symbolize_ksyms());
+ }
+ EXPECT_EQ(config.data_sources()[1].config().name(), "linux.ftrace");
+ {
+ protos::gen::FtraceConfig ftrace;
+ ASSERT_TRUE(ftrace.ParseFromString(
+ config.data_sources()[1].config().ftrace_config_raw()));
+ EXPECT_THAT(ftrace.ftrace_events(), Contains("hyp/*"));
+ ASSERT_EQ(ftrace.instance_name(), "hyp");
+ }
+}
+
} // namespace
} // namespace perfetto