Merge "Improve ftrace_config_muxer_unittest" into main
diff --git a/src/traced/probes/ftrace/atrace_wrapper.cc b/src/traced/probes/ftrace/atrace_wrapper.cc
index 7254325..1a64544 100644
--- a/src/traced/probes/ftrace/atrace_wrapper.cc
+++ b/src/traced/probes/ftrace/atrace_wrapper.cc
@@ -38,9 +38,6 @@
namespace {
-RunAtraceFunction g_run_atrace_for_testing = nullptr;
-std::optional<bool> g_is_old_atrace_for_testing{};
-
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
// Args should include "atrace" for argv[0].
bool ExecvAtrace(const std::vector<std::string>& args,
@@ -174,25 +171,23 @@
} // namespace
-bool RunAtrace(const std::vector<std::string>& args,
- std::string* atrace_errors) {
- if (g_run_atrace_for_testing)
- return g_run_atrace_for_testing(args, atrace_errors);
+AtraceWrapper::~AtraceWrapper() = default;
+
+AtraceWrapperImpl::~AtraceWrapperImpl() = default;
+
+bool AtraceWrapperImpl::RunAtrace(const std::vector<std::string>& args,
+ std::string* atrace_errors) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
return ExecvAtrace(args, atrace_errors);
#else
+ base::ignore_result(args);
+ base::ignore_result(atrace_errors);
PERFETTO_LOG("Atrace only supported on Android.");
return false;
#endif
}
-void SetRunAtraceForTesting(RunAtraceFunction f) {
- g_run_atrace_for_testing = f;
-}
-
-bool IsOldAtrace() {
- if (g_is_old_atrace_for_testing.has_value())
- return *g_is_old_atrace_for_testing;
+bool AtraceWrapperImpl::IsOldAtrace() {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
!PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
// Sideloaded case. We could be sideloaded on a modern device or an older one.
@@ -207,12 +202,4 @@
#endif
}
-void SetIsOldAtraceForTesting(bool value) {
- g_is_old_atrace_for_testing = value;
-}
-
-void ClearIsOldAtraceForTesting() {
- g_is_old_atrace_for_testing.reset();
-}
-
} // namespace perfetto
diff --git a/src/traced/probes/ftrace/atrace_wrapper.h b/src/traced/probes/ftrace/atrace_wrapper.h
index 29847aa..5c6a148 100644
--- a/src/traced/probes/ftrace/atrace_wrapper.h
+++ b/src/traced/probes/ftrace/atrace_wrapper.h
@@ -18,27 +18,30 @@
#define SRC_TRACED_PROBES_FTRACE_ATRACE_WRAPPER_H_
#include <string>
-#include <type_traits>
#include <vector>
namespace perfetto {
-using RunAtraceFunction =
- std::add_pointer<bool(const std::vector<std::string>& /*args*/,
- std::string* /*atrace_errors*/)>::type;
+class AtraceWrapper {
+ public:
+ virtual ~AtraceWrapper();
+ // When we are sideloaded on an old version of Android (pre P), we cannot use
+ // atrace --only_userspace because that option doesn't exist. In that case we:
+ // - Just use atrace --async_start/stop, which will cause atrace to also
+ // poke at ftrace.
+ // - Suppress the checks for "somebody else enabled ftrace unexpectedly".
+ virtual bool IsOldAtrace() = 0;
+ virtual bool RunAtrace(const std::vector<std::string>& args,
+ std::string* atrace_errors) = 0;
+};
-// When we are sideloaded on an old version of Android (pre P), we cannot use
-// atrace --only_userspace because that option doesn't exist. In that case we:
-// - Just use atrace --async_start/stop, which will cause atrace to also
-// poke at ftrace.
-// - Suppress the checks for "somebody else enabled ftrace unexpectedly".
-bool IsOldAtrace();
-void SetIsOldAtraceForTesting(bool);
-void ClearIsOldAtraceForTesting();
-
-bool RunAtrace(const std::vector<std::string>& args,
- std::string* atrace_errors);
-void SetRunAtraceForTesting(RunAtraceFunction);
+class AtraceWrapperImpl : public AtraceWrapper {
+ public:
+ ~AtraceWrapperImpl() override;
+ bool IsOldAtrace() override;
+ bool RunAtrace(const std::vector<std::string>& args,
+ std::string* atrace_errors) override;
+};
} // namespace perfetto
diff --git a/src/traced/probes/ftrace/ftrace_config_muxer.cc b/src/traced/probes/ftrace/ftrace_config_muxer.cc
index 3e2b9ab..e4d8a19 100644
--- a/src/traced/probes/ftrace/ftrace_config_muxer.cc
+++ b/src/traced/probes/ftrace/ftrace_config_muxer.cc
@@ -579,11 +579,13 @@
FtraceConfigMuxer::FtraceConfigMuxer(
FtraceProcfs* ftrace,
+ AtraceWrapper* atrace_wrapper,
ProtoTranslationTable* table,
SyscallTable syscalls,
std::map<std::string, std::vector<GroupAndName>> vendor_events,
bool secondary_instance)
: ftrace_(ftrace),
+ atrace_wrapper_(atrace_wrapper),
table_(table),
syscalls_(std::move(syscalls)),
current_state_(),
@@ -654,7 +656,7 @@
"atrace_apps options as they affect global state");
return false;
}
- if (IsOldAtrace() && !ds_configs_.empty()) {
+ if (atrace_wrapper_->IsOldAtrace() && !ds_configs_.empty()) {
PERFETTO_ELOG(
"Concurrent atrace sessions are not supported before Android P, "
"bailing out.");
@@ -1040,7 +1042,6 @@
}
}
-// static
bool FtraceConfigMuxer::StartAtrace(const std::vector<std::string>& apps,
const std::vector<std::string>& categories,
std::string* atrace_errors) {
@@ -1049,7 +1050,7 @@
std::vector<std::string> args;
args.push_back("atrace"); // argv0 for exec()
args.push_back("--async_start");
- if (!IsOldAtrace())
+ if (!atrace_wrapper_->IsOldAtrace())
args.push_back("--only_userspace");
for (const auto& category : categories)
@@ -1066,7 +1067,7 @@
args.push_back(arg);
}
- bool result = RunAtrace(args, atrace_errors);
+ bool result = atrace_wrapper_->RunAtrace(args, atrace_errors);
PERFETTO_DLOG("...done (%s)", result ? "success" : "fail");
return result;
}
@@ -1077,9 +1078,9 @@
PERFETTO_DLOG("Stop atrace...");
std::vector<std::string> args{"atrace", "--async_stop"};
- if (!IsOldAtrace())
+ if (!atrace_wrapper_->IsOldAtrace())
args.push_back("--only_userspace");
- if (RunAtrace(args, /*atrace_errors=*/nullptr)) {
+ if (atrace_wrapper_->RunAtrace(args, /*atrace_errors=*/nullptr)) {
current_state_.atrace_categories.clear();
current_state_.atrace_apps.clear();
current_state_.atrace_on = false;
diff --git a/src/traced/probes/ftrace/ftrace_config_muxer.h b/src/traced/probes/ftrace/ftrace_config_muxer.h
index e11efb0..4c3f10b 100644
--- a/src/traced/probes/ftrace/ftrace_config_muxer.h
+++ b/src/traced/probes/ftrace/ftrace_config_muxer.h
@@ -22,6 +22,7 @@
#include <set>
#include "src/kernel_utils/syscall_table.h"
+#include "src/traced/probes/ftrace/atrace_wrapper.h"
#include "src/traced/probes/ftrace/compact_sched.h"
#include "src/traced/probes/ftrace/ftrace_config_utils.h"
#include "src/traced/probes/ftrace/ftrace_print_filter.h"
@@ -106,6 +107,7 @@
// should outlive this instance.
FtraceConfigMuxer(
FtraceProcfs* ftrace,
+ AtraceWrapper* atrace_wrapper,
ProtoTranslationTable* table,
SyscallTable syscalls,
std::map<std::string, std::vector<GroupAndName>> vendor_events,
@@ -174,10 +176,6 @@
const SyscallTable& syscalls);
private:
- static bool StartAtrace(const std::vector<std::string>& apps,
- const std::vector<std::string>& categories,
- std::string* atrace_errors);
-
struct FtraceState {
EventFilter ftrace_events;
std::set<size_t> syscall_filter; // syscall ids or kAllSyscallsId
@@ -198,6 +196,9 @@
void SetupBufferSize(const FtraceConfig& request);
bool UpdateBufferPercent();
void UpdateAtrace(const FtraceConfig& request, std::string* atrace_errors);
+ bool StartAtrace(const std::vector<std::string>& apps,
+ const std::vector<std::string>& categories,
+ std::string* atrace_errors);
void DisableAtrace();
// This processes the config to get the exact events.
@@ -226,6 +227,7 @@
bool SetSyscallEventFilter(const EventFilter& extra_syscalls);
FtraceProcfs* ftrace_;
+ AtraceWrapper* atrace_wrapper_;
ProtoTranslationTable* table_;
SyscallTable syscalls_;
diff --git a/src/traced/probes/ftrace/ftrace_config_muxer_unittest.cc b/src/traced/probes/ftrace/ftrace_config_muxer_unittest.cc
index 3ef5635..513d851 100644
--- a/src/traced/probes/ftrace/ftrace_config_muxer_unittest.cc
+++ b/src/traced/probes/ftrace/ftrace_config_muxer_unittest.cc
@@ -93,19 +93,10 @@
(const, override));
};
-struct MockRunAtrace {
- MockRunAtrace() {
- static MockRunAtrace* instance;
- instance = this;
- SetRunAtraceForTesting(
- [](const std::vector<std::string>& args, std::string* atrace_errors) {
- return instance->RunAtrace(args, atrace_errors);
- });
- }
-
- ~MockRunAtrace() { SetRunAtraceForTesting(nullptr); }
-
+class MockAtraceWrapper : public AtraceWrapper {
+ public:
MOCK_METHOD(bool, RunAtrace, (const std::vector<std::string>&, std::string*));
+ MOCK_METHOD(bool, IsOldAtrace, ());
};
class MockProtoTranslationTable : public ProtoTranslationTable {
@@ -131,22 +122,66 @@
(const, override));
};
+TEST(ComputeCpuBufferSizeInPagesTest, DifferentCases) {
+ constexpr auto test = ComputeCpuBufferSizeInPages;
+ auto KbToPages = [](uint64_t kb) {
+ return kb * 1024 / base::GetSysPageSize();
+ };
+ auto kMaxBufSizePages = KbToPages(64 * 1024);
+ int64_t kNoRamInfo = 0;
+ bool kExactSize = false;
+ bool kLowerBoundSize = true;
+ int64_t kLowRamPages =
+ static_cast<int64_t>(KbToPages(3 * (1ULL << 20) + 512 * (1ULL << 10)));
+ int64_t kHighRamPages =
+ static_cast<int64_t>(KbToPages(7 * (1ULL << 20) + 512 * (1ULL << 10)));
+
+ // No buffer size given: good default.
+ EXPECT_EQ(test(0, kExactSize, kNoRamInfo), KbToPages(2048));
+ // Default depends on device ram size.
+ EXPECT_EQ(test(0, kExactSize, kLowRamPages), KbToPages(2048));
+ EXPECT_EQ(test(0, kExactSize, kHighRamPages), KbToPages(8192));
+
+ // buffer_size_lower_bound lets us choose a higher default than given.
+ // default > requested:
+ EXPECT_EQ(test(4096, kExactSize, kHighRamPages), KbToPages(4096));
+ EXPECT_EQ(test(4096, kLowerBoundSize, kHighRamPages), KbToPages(8192));
+ // requested > default:
+ EXPECT_EQ(test(4096, kExactSize, kLowRamPages), KbToPages(4096));
+ EXPECT_EQ(test(4096, kLowerBoundSize, kLowRamPages), KbToPages(4096));
+ // requested > default:
+ EXPECT_EQ(test(16384, kExactSize, kHighRamPages), KbToPages(16384));
+ EXPECT_EQ(test(16384, kLowerBoundSize, kHighRamPages), KbToPages(16384));
+
+ // Buffer size given way too big: good default.
+ EXPECT_EQ(test(10 * (1ULL << 20), kExactSize, kNoRamInfo), kMaxBufSizePages);
+ EXPECT_EQ(test(512 * 1024, kExactSize, kNoRamInfo), kMaxBufSizePages);
+
+ // Your size ends up with less than 1 page per cpu -> 1 page.
+ EXPECT_EQ(test(3, kExactSize, kNoRamInfo), 1u);
+ // You picked a good size -> your size rounded to nearest page.
+ EXPECT_EQ(test(42, kExactSize, kNoRamInfo), KbToPages(42));
+
+ // Sysconf returning an error is ok.
+ EXPECT_EQ(test(0, kExactSize, -1), KbToPages(2048));
+ EXPECT_EQ(test(4096, kExactSize, -1), KbToPages(4096));
+}
+
+// Base fixture that provides some dependencies but doesn't construct a
+// FtraceConfigMuxer.
class FtraceConfigMuxerTest : public ::testing::Test {
protected:
- void SetUp() override {
- // Don't probe for older SDK levels, that would relax the atrace-related
- // checks on older versions of Android (But some tests here test those).
- // We want the unittests to behave consistently (as if we were on a post P
- // device) regardless of the Android versions they run on.
- SetIsOldAtraceForTesting(false);
+ FtraceConfigMuxerTest() {
+ ON_CALL(atrace_wrapper_, RunAtrace).WillByDefault(Return(true));
+ ON_CALL(atrace_wrapper_, IsOldAtrace).WillByDefault(Return(false));
}
- void TearDown() override { ClearIsOldAtraceForTesting(); }
+
std::unique_ptr<MockProtoTranslationTable> GetMockTable() {
std::vector<Field> common_fields;
std::vector<Event> events;
return std::unique_ptr<MockProtoTranslationTable>(
new MockProtoTranslationTable(
- &table_procfs_, events, std::move(common_fields),
+ &ftrace_, events, std::move(common_fields),
ProtoTranslationTable::DefaultPageHeaderSpecForTesting(),
InvalidCompactSchedEventFormatForTesting()));
}
@@ -225,956 +260,25 @@
}
return std::unique_ptr<ProtoTranslationTable>(new ProtoTranslationTable(
- &table_procfs_, events, std::move(common_fields),
+ &ftrace_, events, std::move(common_fields),
ProtoTranslationTable::DefaultPageHeaderSpecForTesting(),
compact_format, PrintkMap()));
}
- NiceMock<MockFtraceProcfs> table_procfs_;
- std::unique_ptr<ProtoTranslationTable> table_ = CreateFakeTable();
+ NiceMock<MockFtraceProcfs> ftrace_;
+ NiceMock<MockAtraceWrapper> atrace_wrapper_;
};
-TEST_F(FtraceConfigMuxerTest, ComputeCpuBufferSizeInPages) {
- constexpr auto test = ComputeCpuBufferSizeInPages;
- auto KbToPages = [](uint64_t kb) {
- return kb * 1024 / base::GetSysPageSize();
- };
- auto kMaxBufSizePages = KbToPages(64 * 1024);
- int64_t kNoRamInfo = 0;
- bool kExactSize = false;
- bool kLowerBoundSize = true;
- int64_t kLowRamPages =
- static_cast<int64_t>(KbToPages(3 * (1ULL << 20) + 512 * (1ULL << 10)));
- int64_t kHighRamPages =
- static_cast<int64_t>(KbToPages(7 * (1ULL << 20) + 512 * (1ULL << 10)));
-
- // No buffer size given: good default.
- EXPECT_EQ(test(0, kExactSize, kNoRamInfo), KbToPages(2048));
- // Default depends on device ram size.
- EXPECT_EQ(test(0, kExactSize, kLowRamPages), KbToPages(2048));
- EXPECT_EQ(test(0, kExactSize, kHighRamPages), KbToPages(8192));
-
- // buffer_size_lower_bound lets us choose a higher default than given.
- // default > requested:
- EXPECT_EQ(test(4096, kExactSize, kHighRamPages), KbToPages(4096));
- EXPECT_EQ(test(4096, kLowerBoundSize, kHighRamPages), KbToPages(8192));
- // requested > default:
- EXPECT_EQ(test(4096, kExactSize, kLowRamPages), KbToPages(4096));
- EXPECT_EQ(test(4096, kLowerBoundSize, kLowRamPages), KbToPages(4096));
- // requested > default:
- EXPECT_EQ(test(16384, kExactSize, kHighRamPages), KbToPages(16384));
- EXPECT_EQ(test(16384, kLowerBoundSize, kHighRamPages), KbToPages(16384));
-
- // Buffer size given way too big: good default.
- EXPECT_EQ(test(10 * (1ULL << 20), kExactSize, kNoRamInfo), kMaxBufSizePages);
- EXPECT_EQ(test(512 * 1024, kExactSize, kNoRamInfo), kMaxBufSizePages);
-
- // Your size ends up with less than 1 page per cpu -> 1 page.
- EXPECT_EQ(test(3, kExactSize, kNoRamInfo), 1u);
- // You picked a good size -> your size rounded to nearest page.
- EXPECT_EQ(test(42, kExactSize, kNoRamInfo), KbToPages(42));
-
- // Sysconf returning an error is ok.
- EXPECT_EQ(test(0, kExactSize, -1), KbToPages(2048));
- EXPECT_EQ(test(4096, kExactSize, -1), KbToPages(4096));
-}
-
-TEST_F(FtraceConfigMuxerTest, GenericSyscallFiltering) {
+TEST_F(FtraceConfigMuxerTest, SecondaryInstanceDoNotSupportAtrace) {
auto fake_table = CreateFakeTable();
- NiceMock<MockFtraceProcfs> ftrace;
-
- FtraceConfig config = CreateFtraceConfig({"raw_syscalls/sys_enter"});
- *config.add_syscall_events() = "sys_open";
- *config.add_syscall_events() = "sys_read";
-
- FtraceConfigMuxer model(&ftrace, fake_table.get(), GetSyscallTable(), {});
-
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("[local] global boot"));
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .Times(AnyNumber());
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillOnce(Return("nop"));
- EXPECT_CALL(ftrace, ReadOneCharFromFile("/root/tracing_on"))
- .WillOnce(Return('1'));
- EXPECT_CALL(ftrace, WriteToFile(_, _)).WillRepeatedly(Return(true));
- EXPECT_CALL(ftrace, WriteToFile("/root/events/raw_syscalls/sys_enter/filter",
- "id == 0 || id == 1"));
- EXPECT_CALL(ftrace, WriteToFile("/root/events/raw_syscalls/sys_exit/filter",
- "id == 0 || id == 1"));
-
- FtraceConfigId id = 37;
- ASSERT_TRUE(model.SetupConfig(id, config));
- ASSERT_TRUE(model.ActivateConfig(id));
-
- const std::set<size_t>& filter = model.GetSyscallFilterForTesting();
- ASSERT_THAT(filter, UnorderedElementsAre(0, 1));
-}
-
-TEST_F(FtraceConfigMuxerTest, UnknownSyscallFilter) {
- auto fake_table = CreateFakeTable();
- NiceMock<MockFtraceProcfs> ftrace;
- FtraceConfigMuxer model(&ftrace, fake_table.get(), GetSyscallTable(), {});
-
- FtraceConfig config = CreateFtraceConfig({"raw_syscalls/sys_enter"});
- config.add_syscall_events("sys_open");
- config.add_syscall_events("sys_not_a_call");
-
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("[local] global boot"));
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .Times(AnyNumber());
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillOnce(Return("nop"));
- EXPECT_CALL(ftrace, ReadOneCharFromFile("/root/tracing_on"))
- .WillOnce(Return('1'));
-
- // Unknown syscall is ignored.
- ASSERT_TRUE(model.SetupConfig(/*id = */ 73, config));
- ASSERT_THAT(model.GetSyscallFilterForTesting(), UnorderedElementsAre(0));
-}
-
-TEST_F(FtraceConfigMuxerTest, SyscallFilterMuxing) {
- auto fake_table = CreateFakeTable();
- NiceMock<MockFtraceProcfs> ftrace;
- FtraceConfigMuxer model(&ftrace, fake_table.get(), GetSyscallTable(), {});
-
- FtraceConfig empty_config = CreateFtraceConfig({});
-
- FtraceConfig syscall_config = empty_config;
- syscall_config.add_ftrace_events("raw_syscalls/sys_enter");
-
- FtraceConfig syscall_open_config = syscall_config;
- syscall_open_config.add_syscall_events("sys_open");
-
- FtraceConfig syscall_read_config = syscall_config;
- syscall_read_config.add_syscall_events("sys_read");
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
-
- // Expect no filter for non-syscall config.
- ASSERT_TRUE(model.SetupConfig(/* id= */ 179239, empty_config));
- ASSERT_THAT(model.GetSyscallFilterForTesting(), UnorderedElementsAre());
-
- // Expect no filter for syscall config with no specified events.
- FtraceConfigId syscall_id = 73;
- ASSERT_TRUE(model.SetupConfig(syscall_id, syscall_config));
- ASSERT_THAT(model.GetSyscallFilterForTesting(), UnorderedElementsAre());
-
- // Still expect no filter to satisfy this and the above.
- FtraceConfigId syscall_open_id = 101;
- ASSERT_TRUE(model.SetupConfig(syscall_open_id, syscall_open_config));
- ASSERT_THAT(model.GetSyscallFilterForTesting(), UnorderedElementsAre());
-
- // After removing the generic syscall trace, only the one with filter is left.
- ASSERT_TRUE(model.RemoveConfig(syscall_id));
- ASSERT_THAT(model.GetSyscallFilterForTesting(), UnorderedElementsAre(0));
-
- // With sys_read and sys_open traced separately, filter includes both.
- FtraceConfigId syscall_read_id = 57;
- ASSERT_TRUE(model.SetupConfig(syscall_read_id, syscall_read_config));
- ASSERT_THAT(model.GetSyscallFilterForTesting(), UnorderedElementsAre(0, 1));
-
- // After removing configs with filters, filter is reset to empty.
- ASSERT_TRUE(model.RemoveConfig(syscall_open_id));
- ASSERT_TRUE(model.RemoveConfig(syscall_read_id));
- ASSERT_THAT(model.GetSyscallFilterForTesting(), UnorderedElementsAre());
-}
-
-TEST_F(FtraceConfigMuxerTest, AddGenericEvent) {
- auto mock_table = GetMockTable();
- MockFtraceProcfs ftrace;
-
- FtraceConfig config = CreateFtraceConfig({"power/cpu_frequency"});
-
- FtraceConfigMuxer model(&ftrace, mock_table.get(), GetSyscallTable(), {});
-
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillOnce(Return("nop"));
- EXPECT_CALL(ftrace, ReadOneCharFromFile("/root/tracing_on"))
- .WillOnce(Return('1'));
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "0"));
- EXPECT_CALL(ftrace, WriteToFile("/root/events/enable", "0"));
- EXPECT_CALL(ftrace, ClearFile("/root/trace"));
- EXPECT_CALL(ftrace, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("[local] global boot"));
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .Times(AnyNumber());
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_size_kb", _));
- EXPECT_CALL(ftrace, WriteToFile("/root/trace_clock", "boot"));
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/power/cpu_frequency/enable", "1"));
- EXPECT_CALL(*mock_table, GetEvent(GroupAndName("power", "cpu_frequency")))
- .Times(AnyNumber());
-
- static constexpr int kExpectedEventId = 77;
- Event event_to_return;
- event_to_return.name = "cpu_frequency";
- event_to_return.group = "power";
- event_to_return.ftrace_event_id = kExpectedEventId;
- ON_CALL(*mock_table, GetOrCreateEvent(GroupAndName("power", "cpu_frequency")))
- .WillByDefault(Return(&event_to_return));
- EXPECT_CALL(*mock_table,
- GetOrCreateEvent(GroupAndName("power", "cpu_frequency")));
-
- FtraceConfigId id = 7;
- ASSERT_TRUE(model.SetupConfig(id, config));
-
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "1"));
- ASSERT_TRUE(model.ActivateConfig(id));
-
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
- ASSERT_TRUE(ds_config);
- ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
- ElementsAreArray({kExpectedEventId}));
-
- const EventFilter* central_filter = model.GetCentralEventFilterForTesting();
- ASSERT_THAT(central_filter->GetEnabledEvents(),
- ElementsAreArray({kExpectedEventId}));
-}
-
-TEST_F(FtraceConfigMuxerTest, AddSameNameEvents) {
- auto mock_table = GetMockTable();
- NiceMock<MockFtraceProcfs> ftrace;
-
- FtraceConfig config = CreateFtraceConfig({"group_one/foo", "group_two/foo"});
-
- FtraceConfigMuxer model(&ftrace, mock_table.get(), GetSyscallTable(), {});
-
- static constexpr int kEventId1 = 1;
- Event event1;
- event1.name = "foo";
- event1.group = "group_one";
- event1.ftrace_event_id = kEventId1;
- ON_CALL(*mock_table, GetOrCreateEvent(GroupAndName("group_one", "foo")))
- .WillByDefault(Return(&event1));
- EXPECT_CALL(*mock_table, GetOrCreateEvent(GroupAndName("group_one", "foo")));
-
- static constexpr int kEventId2 = 2;
- Event event2;
- event2.name = "foo";
- event2.group = "group_two";
- event2.ftrace_event_id = kEventId2;
- ON_CALL(*mock_table, GetOrCreateEvent(GroupAndName("group_two", "foo")))
- .WillByDefault(Return(&event2));
- EXPECT_CALL(*mock_table, GetOrCreateEvent(GroupAndName("group_two", "foo")));
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
-
- FtraceConfigId id = 5;
- ASSERT_TRUE(model.SetupConfig(id, config));
- ASSERT_TRUE(model.ActivateConfig(id));
-
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
- ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
- ElementsAreArray({kEventId1, kEventId2}));
-
- const EventFilter* central_filter = model.GetCentralEventFilterForTesting();
- ASSERT_THAT(central_filter->GetEnabledEvents(),
- ElementsAreArray({kEventId1, kEventId2}));
-}
-
-TEST_F(FtraceConfigMuxerTest, AddAllEvents) {
- auto mock_table = GetMockTable();
- MockFtraceProcfs ftrace;
-
- FtraceConfig config = CreateFtraceConfig({"sched/*"});
-
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillOnce(Return("nop"));
- EXPECT_CALL(ftrace, ReadOneCharFromFile("/root/tracing_on"))
- .WillOnce(Return('1'));
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "0"));
- EXPECT_CALL(ftrace, WriteToFile("/root/events/enable", "0"));
- EXPECT_CALL(ftrace, ClearFile("/root/trace"));
- EXPECT_CALL(ftrace, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("[local] global boot"));
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .Times(AnyNumber());
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_size_kb", _));
- EXPECT_CALL(ftrace, WriteToFile("/root/trace_clock", "boot"));
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/sched/sched_switch/enable", "1"));
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/sched/sched_new_event/enable", "1"));
-
- FtraceConfigMuxer model(&ftrace, mock_table.get(), GetSyscallTable(), {});
- std::set<std::string> n = {"sched_switch", "sched_new_event"};
- ON_CALL(ftrace, GetEventNamesForGroup("events/sched"))
- .WillByDefault(Return(n));
- EXPECT_CALL(ftrace, GetEventNamesForGroup("events/sched")).Times(1);
-
- // Non-generic event.
- static constexpr int kSchedSwitchEventId = 1;
- Event sched_switch = {"sched_switch", "sched", {}, 0, 0, 0};
- sched_switch.ftrace_event_id = kSchedSwitchEventId;
- ON_CALL(*mock_table, GetOrCreateEvent(GroupAndName("sched", "sched_switch")))
- .WillByDefault(Return(&sched_switch));
- EXPECT_CALL(*mock_table,
- GetOrCreateEvent(GroupAndName("sched", "sched_switch")))
- .Times(AnyNumber());
-
- // Generic event.
- static constexpr int kGenericEventId = 2;
- Event event_to_return;
- event_to_return.name = "sched_new_event";
- event_to_return.group = "sched";
- event_to_return.ftrace_event_id = kGenericEventId;
- ON_CALL(*mock_table,
- GetOrCreateEvent(GroupAndName("sched", "sched_new_event")))
- .WillByDefault(Return(&event_to_return));
- EXPECT_CALL(*mock_table,
- GetOrCreateEvent(GroupAndName("sched", "sched_new_event")));
-
- FtraceConfigId id = 13;
- ASSERT_TRUE(model.SetupConfig(id, config));
- ASSERT_TRUE(id);
-
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "1"));
- ASSERT_TRUE(model.ActivateConfig(id));
-
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
- ASSERT_TRUE(ds_config);
- ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
- ElementsAreArray({kSchedSwitchEventId, kGenericEventId}));
-
- const EventFilter* central_filter = model.GetCentralEventFilterForTesting();
- ASSERT_THAT(central_filter->GetEnabledEvents(),
- ElementsAreArray({kSchedSwitchEventId, kGenericEventId}));
-}
-
-TEST_F(FtraceConfigMuxerTest, TwoWildcardGroups) {
- auto mock_table = GetMockTable();
- NiceMock<MockFtraceProcfs> ftrace;
-
- FtraceConfig config = CreateFtraceConfig({"group_one/*", "group_two/*"});
-
- FtraceConfigMuxer model(&ftrace, mock_table.get(), GetSyscallTable(), {});
-
- std::set<std::string> event_names = {"foo"};
- ON_CALL(ftrace, GetEventNamesForGroup("events/group_one"))
- .WillByDefault(Return(event_names));
- EXPECT_CALL(ftrace, GetEventNamesForGroup("events/group_one"))
- .Times(AnyNumber());
-
- ON_CALL(ftrace, GetEventNamesForGroup("events/group_two"))
- .WillByDefault(Return(event_names));
- EXPECT_CALL(ftrace, GetEventNamesForGroup("events/group_two"))
- .Times(AnyNumber());
-
- static constexpr int kEventId1 = 1;
- Event event1;
- event1.name = "foo";
- event1.group = "group_one";
- event1.ftrace_event_id = kEventId1;
- ON_CALL(*mock_table, GetOrCreateEvent(GroupAndName("group_one", "foo")))
- .WillByDefault(Return(&event1));
- EXPECT_CALL(*mock_table, GetOrCreateEvent(GroupAndName("group_one", "foo")));
-
- static constexpr int kEventId2 = 2;
- Event event2;
- event2.name = "foo";
- event2.group = "group_two";
- event2.ftrace_event_id = kEventId2;
- ON_CALL(*mock_table, GetOrCreateEvent(GroupAndName("group_two", "foo")))
- .WillByDefault(Return(&event2));
- EXPECT_CALL(*mock_table, GetOrCreateEvent(GroupAndName("group_two", "foo")));
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
-
- FtraceConfigId id = 23;
- ASSERT_TRUE(model.SetupConfig(id, config));
- ASSERT_TRUE(model.ActivateConfig(id));
-
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
- ASSERT_TRUE(ds_config);
- ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
- ElementsAreArray({kEventId1, kEventId2}));
-
- const EventFilter* central_filter = model.GetCentralEventFilterForTesting();
- ASSERT_THAT(central_filter->GetEnabledEvents(),
- ElementsAreArray({kEventId1, kEventId2}));
-}
-
-TEST_F(FtraceConfigMuxerTest, TurnFtraceOnOff) {
- MockFtraceProcfs ftrace;
-
- FtraceConfig config = CreateFtraceConfig({"sched_switch", "foo"});
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillOnce(Return("nop"));
- EXPECT_CALL(ftrace, ReadOneCharFromFile("/root/tracing_on"))
- .WillOnce(Return('1'));
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "0"));
- EXPECT_CALL(ftrace, WriteToFile("/root/events/enable", "0"));
- EXPECT_CALL(ftrace, ClearFile("/root/trace"));
- EXPECT_CALL(ftrace, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("[local] global boot"));
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .Times(AnyNumber());
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_size_kb", _));
- EXPECT_CALL(ftrace, WriteToFile("/root/trace_clock", "boot"));
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/sched/sched_switch/enable", "1"));
-
- FtraceConfigId id = 97;
- ASSERT_TRUE(model.SetupConfig(id, config));
-
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "1"));
- ASSERT_TRUE(model.ActivateConfig(id));
-
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
- ASSERT_TRUE(ds_config);
- ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
- ElementsAreArray({kFakeSchedSwitchEventId}));
-
- const EventFilter* central_filter = model.GetCentralEventFilterForTesting();
- ASSERT_THAT(central_filter->GetEnabledEvents(),
- ElementsAreArray({kFakeSchedSwitchEventId}));
-
- ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&ftrace));
- EXPECT_CALL(ftrace, NumberOfCpus()).Times(AnyNumber());
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_percent", _))
- .WillRepeatedly(Return(true));
-
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/sched/sched_switch/enable", "0"));
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "0"));
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_size_kb", PageSizeKb()));
- EXPECT_CALL(ftrace, WriteToFile("/root/events/enable", "0"));
- EXPECT_CALL(ftrace, ClearFile("/root/trace"));
- EXPECT_CALL(ftrace, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "1"));
-
- ASSERT_TRUE(model.RemoveConfig(id));
-}
-
-TEST_F(FtraceConfigMuxerTest, FtraceIsAlreadyOn) {
- MockFtraceProcfs ftrace;
-
- FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- // If someone is using ftrace already don't stomp on what they are doing.
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillOnce(Return("function"));
- ASSERT_FALSE(model.SetupConfig(/* id= */ 123, config));
-}
-
-TEST_F(FtraceConfigMuxerTest, Atrace) {
- NiceMock<MockFtraceProcfs> ftrace;
- MockRunAtrace atrace;
+ FtraceConfigMuxer model(&ftrace_, &atrace_wrapper_, fake_table.get(),
+ GetSyscallTable(), {},
+ /* secondary_instance= */ true);
FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
*config.add_atrace_categories() = "sched";
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
- EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "sched"}),
- _))
- .WillOnce(Return(true));
-
- FtraceConfigId id = 57;
- ASSERT_TRUE(model.SetupConfig(id, config));
-
- // "ftrace" group events are always enabled, and therefore the "print" event
- // will show up in the per data source event filter (as we want to record it),
- // but not the central filter (as we're not enabling/disabling it).
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
- ASSERT_TRUE(ds_config);
- EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
- Contains(kFakeSchedSwitchEventId));
- EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
- Contains(kFakePrintEventId));
-
- const EventFilter* central_filter = model.GetCentralEventFilterForTesting();
- EXPECT_THAT(central_filter->GetEnabledEvents(),
- Contains(kFakeSchedSwitchEventId));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(
- ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id));
-}
-
-TEST_F(FtraceConfigMuxerTest, AtraceTwoApps) {
- NiceMock<MockFtraceProcfs> ftrace;
- MockRunAtrace atrace;
-
- FtraceConfig config = CreateFtraceConfig({});
- *config.add_atrace_apps() = "com.google.android.gms.persistent";
- *config.add_atrace_apps() = "com.google.android.gms";
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
- EXPECT_CALL(
- atrace,
- RunAtrace(
- ElementsAreArray(
- {"atrace", "--async_start", "--only_userspace", "-a",
- "com.google.android.gms,com.google.android.gms.persistent"}),
- _))
- .WillOnce(Return(true));
-
- FtraceConfigId id = 97;
- ASSERT_TRUE(model.SetupConfig(id, config));
-
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
- ASSERT_TRUE(ds_config);
- ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
- Contains(kFakePrintEventId));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(
- ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id));
-}
-
-TEST_F(FtraceConfigMuxerTest, AtraceMultipleConfigs) {
- NiceMock<MockFtraceProcfs> ftrace;
- MockRunAtrace atrace;
-
- FtraceConfig config_a = CreateFtraceConfig({});
- *config_a.add_atrace_apps() = "app_a";
- *config_a.add_atrace_categories() = "cat_a";
-
- FtraceConfig config_b = CreateFtraceConfig({});
- *config_b.add_atrace_apps() = "app_b";
- *config_b.add_atrace_categories() = "cat_b";
-
- FtraceConfig config_c = CreateFtraceConfig({});
- *config_c.add_atrace_apps() = "app_c";
- *config_c.add_atrace_categories() = "cat_c";
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
- EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "cat_a",
- "-a", "app_a"}),
- _))
- .WillOnce(Return(true));
- FtraceConfigId id_a = 3;
- ASSERT_TRUE(model.SetupConfig(id_a, config_a));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
- "cat_a", "cat_b", "-a", "app_a,app_b"}),
- _))
- .WillOnce(Return(true));
- FtraceConfigId id_b = 13;
- ASSERT_TRUE(model.SetupConfig(id_b, config_b));
-
- EXPECT_CALL(atrace,
- RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "cat_a", "cat_b",
- "cat_c", "-a", "app_a,app_b,app_c"}),
- _))
- .WillOnce(Return(true));
- FtraceConfigId id_c = 23;
- ASSERT_TRUE(model.SetupConfig(id_c, config_c));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
- "cat_a", "cat_c", "-a", "app_a,app_c"}),
- _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id_b));
-
- EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "cat_c",
- "-a", "app_c"}),
- _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id_a));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(
- ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id_c));
-}
-
-TEST_F(FtraceConfigMuxerTest, AtraceFailedConfig) {
- NiceMock<MockFtraceProcfs> ftrace;
- MockRunAtrace atrace;
-
- FtraceConfig config_a = CreateFtraceConfig({});
- *config_a.add_atrace_apps() = "app_1";
- *config_a.add_atrace_apps() = "app_2";
- *config_a.add_atrace_categories() = "cat_1";
- *config_a.add_atrace_categories() = "cat_2";
-
- FtraceConfig config_b = CreateFtraceConfig({});
- *config_b.add_atrace_apps() = "app_fail";
- *config_b.add_atrace_categories() = "cat_fail";
-
- FtraceConfig config_c = CreateFtraceConfig({});
- *config_c.add_atrace_apps() = "app_1";
- *config_c.add_atrace_apps() = "app_3";
- *config_c.add_atrace_categories() = "cat_1";
- *config_c.add_atrace_categories() = "cat_3";
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
- EXPECT_CALL(
- atrace,
- RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
- "cat_1", "cat_2", "-a", "app_1,app_2"}),
- _))
- .WillOnce(Return(true));
- FtraceConfigId id_a = 7;
- ASSERT_TRUE(model.SetupConfig(id_a, config_a));
-
- EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "cat_1",
- "cat_2", "cat_fail", "-a",
- "app_1,app_2,app_fail"}),
- _))
- .WillOnce(Return(false));
- FtraceConfigId id_b = 17;
- ASSERT_TRUE(model.SetupConfig(id_b, config_b));
-
- EXPECT_CALL(atrace,
- RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "cat_1", "cat_2",
- "cat_3", "-a", "app_1,app_2,app_3"}),
- _))
- .WillOnce(Return(true));
- FtraceConfigId id_c = 47;
- ASSERT_TRUE(model.SetupConfig(id_c, config_c));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
- "cat_1", "cat_2", "-a", "app_1,app_2"}),
- _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id_c));
-
- // Removing the config we failed to enable doesn't change the atrace state
- // so we don't expect a call here.
- ASSERT_TRUE(model.RemoveConfig(id_b));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(
- ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id_a));
-}
-
-TEST_F(FtraceConfigMuxerTest, AtraceDuplicateConfigs) {
- NiceMock<MockFtraceProcfs> ftrace;
- MockRunAtrace atrace;
-
- FtraceConfig config_a = CreateFtraceConfig({});
- *config_a.add_atrace_apps() = "app_1";
- *config_a.add_atrace_categories() = "cat_1";
-
- FtraceConfig config_b = CreateFtraceConfig({});
- *config_b.add_atrace_apps() = "app_1";
- *config_b.add_atrace_categories() = "cat_1";
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
- EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "cat_1",
- "-a", "app_1"}),
- _))
- .WillOnce(Return(true));
- FtraceConfigId id_a = 19;
- ASSERT_TRUE(model.SetupConfig(id_a, config_a));
-
- FtraceConfigId id_b = 29;
- ASSERT_TRUE(model.SetupConfig(id_b, config_b));
-
- ASSERT_TRUE(model.RemoveConfig(id_a));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(
- ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id_b));
-}
-
-TEST_F(FtraceConfigMuxerTest, AtraceAndFtraceConfigs) {
- NiceMock<MockFtraceProcfs> ftrace;
- MockRunAtrace atrace;
-
- FtraceConfig config_a = CreateFtraceConfig({"sched/sched_cpu_hotplug"});
-
- FtraceConfig config_b = CreateFtraceConfig({"sched/sched_switch"});
- *config_b.add_atrace_categories() = "b";
-
- FtraceConfig config_c = CreateFtraceConfig({"sched/sched_switch"});
-
- FtraceConfig config_d = CreateFtraceConfig({"sched/sched_cpu_hotplug"});
- *config_d.add_atrace_categories() = "d";
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
- FtraceConfigId id_a = 179;
- ASSERT_TRUE(model.SetupConfig(id_a, config_a));
-
- EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "b"}),
- _))
- .WillOnce(Return(true));
- FtraceConfigId id_b = 239;
- ASSERT_TRUE(model.SetupConfig(id_b, config_b));
-
- FtraceConfigId id_c = 101;
- ASSERT_TRUE(model.SetupConfig(id_c, config_c));
-
- EXPECT_CALL(atrace,
- RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "b", "d"}),
- _))
- .WillOnce(Return(true));
- FtraceConfigId id_d = 47;
- ASSERT_TRUE(model.SetupConfig(id_d, config_d));
-
- EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "b"}),
- _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id_d));
-
- ASSERT_TRUE(model.RemoveConfig(id_c));
-
- EXPECT_CALL(
- atrace,
- RunAtrace(
- ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
- .WillOnce(Return(true));
- ASSERT_TRUE(model.RemoveConfig(id_b));
-
- ASSERT_TRUE(model.RemoveConfig(id_a));
-}
-
-TEST_F(FtraceConfigMuxerTest, AtraceErrorsPropagated) {
- NiceMock<MockFtraceProcfs> ftrace;
- MockRunAtrace atrace;
-
- FtraceConfig config = CreateFtraceConfig({});
- *config.add_atrace_categories() = "cat_1";
- *config.add_atrace_categories() = "cat_2";
-
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
- .WillByDefault(Return("0"));
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- EXPECT_CALL(atrace, RunAtrace(ElementsAreArray({"atrace", "--async_start",
- "--only_userspace", "cat_1",
- "cat_2"}),
- _))
- .WillOnce(Invoke([](const std::vector<std::string>&, std::string* err) {
- EXPECT_NE(err, nullptr);
- if (err)
- err->append("foo\nbar\n");
- return true;
- }));
-
- FtraceSetupErrors errors{};
- FtraceConfigId id_a = 23;
- ASSERT_TRUE(model.SetupConfig(id_a, config, &errors));
- EXPECT_EQ(errors.atrace_errors, "foo\nbar\n");
-}
-
-TEST_F(FtraceConfigMuxerTest, SetupClockForTesting) {
- MockFtraceProcfs ftrace;
- FtraceConfig config;
-
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
- namespace pb0 = protos::pbzero;
-
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .Times(AnyNumber());
-
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("[local] global boot"));
- EXPECT_CALL(ftrace, WriteToFile("/root/trace_clock", "boot"));
- model.SetupClockForTesting(config);
- // unspecified = boot.
- EXPECT_EQ(model.ftrace_clock(),
- static_cast<int>(pb0::FTRACE_CLOCK_UNSPECIFIED));
-
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("[local] global"));
- EXPECT_CALL(ftrace, WriteToFile("/root/trace_clock", "global"));
- model.SetupClockForTesting(config);
- EXPECT_EQ(model.ftrace_clock(), static_cast<int>(pb0::FTRACE_CLOCK_GLOBAL));
-
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return(""));
- model.SetupClockForTesting(config);
- EXPECT_EQ(model.ftrace_clock(), static_cast<int>(pb0::FTRACE_CLOCK_UNKNOWN));
-
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("local [global]"));
- model.SetupClockForTesting(config);
- EXPECT_EQ(model.ftrace_clock(), static_cast<int>(pb0::FTRACE_CLOCK_GLOBAL));
-}
-
-TEST_F(FtraceConfigMuxerTest, GetFtraceEvents) {
- MockFtraceProcfs ftrace;
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
- std::set<GroupAndName> events =
- model.GetFtraceEventsForTesting(config, table_.get());
-
- EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_switch")));
- EXPECT_THAT(events, Not(Contains(GroupAndName("ftrace", "print"))));
-}
-
-TEST_F(FtraceConfigMuxerTest, GetFtraceEventsAtrace) {
- MockFtraceProcfs ftrace;
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- FtraceConfig config = CreateFtraceConfig({});
- *config.add_atrace_categories() = "sched";
- std::set<GroupAndName> events =
- model.GetFtraceEventsForTesting(config, table_.get());
-
- EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_switch")));
- EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_cpu_hotplug")));
- EXPECT_THAT(events, Contains(GroupAndName("ftrace", "print")));
-}
-
-TEST_F(FtraceConfigMuxerTest, GetFtraceEventsAtraceCategories) {
- MockFtraceProcfs ftrace;
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
- FtraceConfig config = CreateFtraceConfig({});
- *config.add_atrace_categories() = "sched";
- *config.add_atrace_categories() = "memreclaim";
- std::set<GroupAndName> events =
- model.GetFtraceEventsForTesting(config, table_.get());
-
- EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_switch")));
- EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_cpu_hotplug")));
- EXPECT_THAT(events, Contains(GroupAndName("cgroup", "cgroup_mkdir")));
- EXPECT_THAT(events, Contains(GroupAndName("vmscan",
- "mm_vmscan_direct_reclaim_begin")));
- EXPECT_THAT(events,
- Contains(GroupAndName("lowmemorykiller", "lowmemory_kill")));
- EXPECT_THAT(events, Contains(GroupAndName("ftrace", "print")));
-}
-
-// Tests the enabling fallback logic that tries to use the "set_event" interface
-// if writing the individual xxx/enable file fails.
-TEST_F(FtraceConfigMuxerTest, FallbackOnSetEvent) {
- MockFtraceProcfs ftrace;
- FtraceConfig config =
- CreateFtraceConfig({"sched/sched_switch", "cgroup/cgroup_mkdir"});
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_percent", _))
- .WillRepeatedly(Return(true));
-
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
- .WillOnce(Return("nop"));
- EXPECT_CALL(ftrace, ReadOneCharFromFile("/root/tracing_on"))
- .WillOnce(Return('1'));
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "0"));
- EXPECT_CALL(ftrace, WriteToFile("/root/events/enable", "0"));
- EXPECT_CALL(ftrace, ClearFile("/root/trace"));
- EXPECT_CALL(ftrace, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .WillByDefault(Return("[local] global boot"));
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
- .Times(AnyNumber());
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_size_kb", _));
- EXPECT_CALL(ftrace, WriteToFile("/root/trace_clock", "boot"));
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/sched/sched_switch/enable", "1"));
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/cgroup/cgroup_mkdir/enable", "1"))
- .WillOnce(Return(false));
- EXPECT_CALL(ftrace, AppendToFile("/root/set_event", "cgroup:cgroup_mkdir"))
- .WillOnce(Return(true));
- FtraceConfigId id = 97;
- ASSERT_TRUE(model.SetupConfig(id, config));
-
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "1"));
- ASSERT_TRUE(model.ActivateConfig(id));
-
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
- ASSERT_TRUE(ds_config);
- EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
- Contains(kFakeSchedSwitchEventId));
- EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
- Contains(kCgroupMkdirEventId));
-
- const EventFilter* central_filter = model.GetCentralEventFilterForTesting();
- EXPECT_THAT(central_filter->GetEnabledEvents(),
- Contains(kFakeSchedSwitchEventId));
- EXPECT_THAT(central_filter->GetEnabledEvents(),
- Contains(kCgroupMkdirEventId));
-
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/sched/sched_switch/enable", "0"));
- EXPECT_CALL(ftrace,
- WriteToFile("/root/events/cgroup/cgroup_mkdir/enable", "0"))
- .WillOnce(Return(false));
- EXPECT_CALL(ftrace, AppendToFile("/root/set_event", "!cgroup:cgroup_mkdir"))
- .WillOnce(Return(true));
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "0"));
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_size_kb", PageSizeKb()));
- EXPECT_CALL(ftrace, WriteToFile("/root/events/enable", "0"));
- EXPECT_CALL(ftrace, ClearFile("/root/trace"));
- EXPECT_CALL(ftrace, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
- EXPECT_CALL(ftrace, WriteToFile("/root/tracing_on", "1"));
- ASSERT_TRUE(model.RemoveConfig(id));
+ ASSERT_FALSE(model.SetupConfig(/* id= */ 73, config));
}
TEST_F(FtraceConfigMuxerTest, CompactSchedConfig) {
@@ -1185,13 +289,14 @@
auto valid_compact_format = CompactSchedEventFormat{
/*format_valid=*/true, format_with_id, CompactSchedWakingFormat{}};
- NiceMock<MockFtraceProcfs> ftrace;
- table_ = CreateFakeTable(valid_compact_format);
- FtraceConfigMuxer muxer(&ftrace, table_.get(), GetSyscallTable(), {});
+ std::unique_ptr<ProtoTranslationTable> table =
+ CreateFakeTable(valid_compact_format);
+ FtraceConfigMuxer muxer(&ftrace_, &atrace_wrapper_, table.get(),
+ GetSyscallTable(), {});
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
.WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
.WillByDefault(Return("0"));
{
@@ -1246,38 +351,659 @@
}
}
-TEST_F(FtraceConfigMuxerTest, CompactSchedConfigWithInvalidFormat) {
- NiceMock<MockFtraceProcfs> ftrace;
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
+// Fixture that constructs a FtraceConfigMuxer with a fake
+// ProtoTranslationTable.
+class FtraceConfigMuxerFakeTableTest : public FtraceConfigMuxerTest {
+ protected:
+ std::unique_ptr<ProtoTranslationTable> table_ = CreateFakeTable();
+ FtraceConfigMuxer model_ = FtraceConfigMuxer(&ftrace_,
+ &atrace_wrapper_,
+ table_.get(),
+ GetSyscallTable(),
+ {});
+};
+TEST_F(FtraceConfigMuxerFakeTableTest, GenericSyscallFiltering) {
+ FtraceConfig config = CreateFtraceConfig({"raw_syscalls/sys_enter"});
+ *config.add_syscall_events() = "sys_open";
+ *config.add_syscall_events() = "sys_read";
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("[local] global boot"));
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .Times(AnyNumber());
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillOnce(Return("nop"));
+ EXPECT_CALL(ftrace_, ReadOneCharFromFile("/root/tracing_on"))
+ .WillOnce(Return('1'));
+ EXPECT_CALL(ftrace_, WriteToFile(_, _)).WillRepeatedly(Return(true));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/events/raw_syscalls/sys_enter/filter",
+ "id == 0 || id == 1"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/events/raw_syscalls/sys_exit/filter",
+ "id == 0 || id == 1"));
+
+ FtraceConfigId id = 37;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+ ASSERT_TRUE(model_.ActivateConfig(id));
+
+ const std::set<size_t>& filter = model_.GetSyscallFilterForTesting();
+ ASSERT_THAT(filter, UnorderedElementsAre(0, 1));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, UnknownSyscallFilter) {
+ FtraceConfig config = CreateFtraceConfig({"raw_syscalls/sys_enter"});
+ config.add_syscall_events("sys_open");
+ config.add_syscall_events("sys_not_a_call");
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("[local] global boot"));
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .Times(AnyNumber());
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillOnce(Return("nop"));
+ EXPECT_CALL(ftrace_, ReadOneCharFromFile("/root/tracing_on"))
+ .WillOnce(Return('1'));
+
+ // Unknown syscall is ignored.
+ ASSERT_TRUE(model_.SetupConfig(/*id = */ 73, config));
+ ASSERT_THAT(model_.GetSyscallFilterForTesting(), UnorderedElementsAre(0));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, SyscallFilterMuxing) {
+ FtraceConfig empty_config = CreateFtraceConfig({});
+
+ FtraceConfig syscall_config = empty_config;
+ syscall_config.add_ftrace_events("raw_syscalls/sys_enter");
+
+ FtraceConfig syscall_open_config = syscall_config;
+ syscall_open_config.add_syscall_events("sys_open");
+
+ FtraceConfig syscall_read_config = syscall_config;
+ syscall_read_config.add_syscall_events("sys_read");
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+
+ // Expect no filter for non-syscall config.
+ ASSERT_TRUE(model_.SetupConfig(/* id= */ 179239, empty_config));
+ ASSERT_THAT(model_.GetSyscallFilterForTesting(), UnorderedElementsAre());
+
+ // Expect no filter for syscall config with no specified events.
+ FtraceConfigId syscall_id = 73;
+ ASSERT_TRUE(model_.SetupConfig(syscall_id, syscall_config));
+ ASSERT_THAT(model_.GetSyscallFilterForTesting(), UnorderedElementsAre());
+
+ // Still expect no filter to satisfy this and the above.
+ FtraceConfigId syscall_open_id = 101;
+ ASSERT_TRUE(model_.SetupConfig(syscall_open_id, syscall_open_config));
+ ASSERT_THAT(model_.GetSyscallFilterForTesting(), UnorderedElementsAre());
+
+ // After removing the generic syscall trace, only the one with filter is left.
+ ASSERT_TRUE(model_.RemoveConfig(syscall_id));
+ ASSERT_THAT(model_.GetSyscallFilterForTesting(), UnorderedElementsAre(0));
+
+ // With sys_read and sys_open traced separately, filter includes both.
+ FtraceConfigId syscall_read_id = 57;
+ ASSERT_TRUE(model_.SetupConfig(syscall_read_id, syscall_read_config));
+ ASSERT_THAT(model_.GetSyscallFilterForTesting(), UnorderedElementsAre(0, 1));
+
+ // After removing configs with filters, filter is reset to empty.
+ ASSERT_TRUE(model_.RemoveConfig(syscall_open_id));
+ ASSERT_TRUE(model_.RemoveConfig(syscall_read_id));
+ ASSERT_THAT(model_.GetSyscallFilterForTesting(), UnorderedElementsAre());
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, TurnFtraceOnOff) {
+ FtraceConfig config = CreateFtraceConfig({"sched_switch", "foo"});
+
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillOnce(Return("nop"));
+ EXPECT_CALL(ftrace_, ReadOneCharFromFile("/root/tracing_on"))
+ .WillOnce(Return('1'));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "0"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/events/enable", "0"));
+ EXPECT_CALL(ftrace_, ClearFile("/root/trace"));
+ EXPECT_CALL(ftrace_, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("[local] global boot"));
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .Times(AnyNumber());
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_size_kb", _));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/trace_clock", "boot"));
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/sched/sched_switch/enable", "1"));
+
+ FtraceConfigId id = 97;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "1"));
+ ASSERT_TRUE(model_.ActivateConfig(id));
+
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
+ ASSERT_TRUE(ds_config);
+ ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ ElementsAreArray({kFakeSchedSwitchEventId}));
+
+ const EventFilter* central_filter = model_.GetCentralEventFilterForTesting();
+ ASSERT_THAT(central_filter->GetEnabledEvents(),
+ ElementsAreArray({kFakeSchedSwitchEventId}));
+
+ ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&ftrace_));
+ EXPECT_CALL(ftrace_, NumberOfCpus()).Times(AnyNumber());
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_percent", _))
+ .WillRepeatedly(Return(true));
+
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/sched/sched_switch/enable", "0"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "0"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_size_kb", PageSizeKb()));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/events/enable", "0"));
+ EXPECT_CALL(ftrace_, ClearFile("/root/trace"));
+ EXPECT_CALL(ftrace_, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "1"));
+
+ ASSERT_TRUE(model_.RemoveConfig(id));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, FtraceIsAlreadyOn) {
+ FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
+
+ // If someone is using ftrace already don't stomp on what they are doing.
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillOnce(Return("function"));
+ ASSERT_FALSE(model_.SetupConfig(/* id= */ 123, config));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, Atrace) {
+ FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
+ *config.add_atrace_categories() = "sched";
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+ EXPECT_CALL(atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start",
+ "--only_userspace", "sched"}),
+ _))
+ .WillOnce(Return(true));
+
+ FtraceConfigId id = 57;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+
+ // "ftrace" group events are always enabled, and therefore the "print" event
+ // will show up in the per data source event filter (as we want to record it),
+ // but not the central filter (as we're not enabling/disabling it).
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
+ ASSERT_TRUE(ds_config);
+ EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ Contains(kFakeSchedSwitchEventId));
+ EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ Contains(kFakePrintEventId));
+
+ const EventFilter* central_filter = model_.GetCentralEventFilterForTesting();
+ EXPECT_THAT(central_filter->GetEnabledEvents(),
+ Contains(kFakeSchedSwitchEventId));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(
+ ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, AtraceTwoApps) {
+ FtraceConfig config = CreateFtraceConfig({});
+ *config.add_atrace_apps() = "com.google.android.gms.persistent";
+ *config.add_atrace_apps() = "com.google.android.gms";
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(
+ ElementsAreArray(
+ {"atrace", "--async_start", "--only_userspace", "-a",
+ "com.google.android.gms,com.google.android.gms.persistent"}),
+ _))
+ .WillOnce(Return(true));
+
+ FtraceConfigId id = 97;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
+ ASSERT_TRUE(ds_config);
+ ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ Contains(kFakePrintEventId));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(
+ ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, AtraceMultipleConfigs) {
+ FtraceConfig config_a = CreateFtraceConfig({});
+ *config_a.add_atrace_apps() = "app_a";
+ *config_a.add_atrace_categories() = "cat_a";
+
+ FtraceConfig config_b = CreateFtraceConfig({});
+ *config_b.add_atrace_apps() = "app_b";
+ *config_b.add_atrace_categories() = "cat_b";
+
+ FtraceConfig config_c = CreateFtraceConfig({});
+ *config_c.add_atrace_apps() = "app_c";
+ *config_c.add_atrace_categories() = "cat_c";
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_a", "-a", "app_a"}),
+ _))
+ .WillOnce(Return(true));
+ FtraceConfigId id_a = 3;
+ ASSERT_TRUE(model_.SetupConfig(id_a, config_a));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_a", "cat_b", "-a", "app_a,app_b"}),
+ _))
+ .WillOnce(Return(true));
+ FtraceConfigId id_b = 13;
+ ASSERT_TRUE(model_.SetupConfig(id_b, config_b));
+
+ EXPECT_CALL(atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start",
+ "--only_userspace", "cat_a", "cat_b",
+ "cat_c", "-a", "app_a,app_b,app_c"}),
+ _))
+ .WillOnce(Return(true));
+ FtraceConfigId id_c = 23;
+ ASSERT_TRUE(model_.SetupConfig(id_c, config_c));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_a", "cat_c", "-a", "app_a,app_c"}),
+ _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id_b));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_c", "-a", "app_c"}),
+ _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id_a));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(
+ ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id_c));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, AtraceFailedConfig) {
+ FtraceConfig config_a = CreateFtraceConfig({});
+ *config_a.add_atrace_apps() = "app_1";
+ *config_a.add_atrace_apps() = "app_2";
+ *config_a.add_atrace_categories() = "cat_1";
+ *config_a.add_atrace_categories() = "cat_2";
+
+ FtraceConfig config_b = CreateFtraceConfig({});
+ *config_b.add_atrace_apps() = "app_fail";
+ *config_b.add_atrace_categories() = "cat_fail";
+
+ FtraceConfig config_c = CreateFtraceConfig({});
+ *config_c.add_atrace_apps() = "app_1";
+ *config_c.add_atrace_apps() = "app_3";
+ *config_c.add_atrace_categories() = "cat_1";
+ *config_c.add_atrace_categories() = "cat_3";
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_1", "cat_2", "-a", "app_1,app_2"}),
+ _))
+ .WillOnce(Return(true));
+ FtraceConfigId id_a = 7;
+ ASSERT_TRUE(model_.SetupConfig(id_a, config_a));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_1", "cat_2", "cat_fail", "-a",
+ "app_1,app_2,app_fail"}),
+ _))
+ .WillOnce(Return(false));
+ FtraceConfigId id_b = 17;
+ ASSERT_TRUE(model_.SetupConfig(id_b, config_b));
+
+ EXPECT_CALL(atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start",
+ "--only_userspace", "cat_1", "cat_2",
+ "cat_3", "-a", "app_1,app_2,app_3"}),
+ _))
+ .WillOnce(Return(true));
+ FtraceConfigId id_c = 47;
+ ASSERT_TRUE(model_.SetupConfig(id_c, config_c));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_1", "cat_2", "-a", "app_1,app_2"}),
+ _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id_c));
+
+ // Removing the config we failed to enable doesn't change the atrace state
+ // so we don't expect a call here.
+ ASSERT_TRUE(model_.RemoveConfig(id_b));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(
+ ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id_a));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, AtraceDuplicateConfigs) {
+ FtraceConfig config_a = CreateFtraceConfig({});
+ *config_a.add_atrace_apps() = "app_1";
+ *config_a.add_atrace_categories() = "cat_1";
+
+ FtraceConfig config_b = CreateFtraceConfig({});
+ *config_b.add_atrace_apps() = "app_1";
+ *config_b.add_atrace_categories() = "cat_1";
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_1", "-a", "app_1"}),
+ _))
+ .WillOnce(Return(true));
+ FtraceConfigId id_a = 19;
+ ASSERT_TRUE(model_.SetupConfig(id_a, config_a));
+
+ FtraceConfigId id_b = 29;
+ ASSERT_TRUE(model_.SetupConfig(id_b, config_b));
+
+ ASSERT_TRUE(model_.RemoveConfig(id_a));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(
+ ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id_b));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, AtraceAndFtraceConfigs) {
+ FtraceConfig config_a = CreateFtraceConfig({"sched/sched_cpu_hotplug"});
+
+ FtraceConfig config_b = CreateFtraceConfig({"sched/sched_switch"});
+ *config_b.add_atrace_categories() = "b";
+
+ FtraceConfig config_c = CreateFtraceConfig({"sched/sched_switch"});
+
+ FtraceConfig config_d = CreateFtraceConfig({"sched/sched_cpu_hotplug"});
+ *config_d.add_atrace_categories() = "d";
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+ FtraceConfigId id_a = 179;
+ ASSERT_TRUE(model_.SetupConfig(id_a, config_a));
+
+ EXPECT_CALL(atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start",
+ "--only_userspace", "b"}),
+ _))
+ .WillOnce(Return(true));
+ FtraceConfigId id_b = 239;
+ ASSERT_TRUE(model_.SetupConfig(id_b, config_b));
+
+ FtraceConfigId id_c = 101;
+ ASSERT_TRUE(model_.SetupConfig(id_c, config_c));
+
+ EXPECT_CALL(atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start",
+ "--only_userspace", "b", "d"}),
+ _))
+ .WillOnce(Return(true));
+ FtraceConfigId id_d = 47;
+ ASSERT_TRUE(model_.SetupConfig(id_d, config_d));
+
+ EXPECT_CALL(atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start",
+ "--only_userspace", "b"}),
+ _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id_d));
+
+ ASSERT_TRUE(model_.RemoveConfig(id_c));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(
+ ElementsAreArray({"atrace", "--async_stop", "--only_userspace"}), _))
+ .WillOnce(Return(true));
+ ASSERT_TRUE(model_.RemoveConfig(id_b));
+
+ ASSERT_TRUE(model_.RemoveConfig(id_a));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, AtraceErrorsPropagated) {
+ FtraceConfig config = CreateFtraceConfig({});
+ *config.add_atrace_categories() = "cat_1";
+ *config.add_atrace_categories() = "cat_2";
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+
+ EXPECT_CALL(
+ atrace_wrapper_,
+ RunAtrace(ElementsAreArray({"atrace", "--async_start", "--only_userspace",
+ "cat_1", "cat_2"}),
+ _))
+ .WillOnce(Invoke([](const std::vector<std::string>&, std::string* err) {
+ EXPECT_NE(err, nullptr);
+ if (err)
+ err->append("foo\nbar\n");
+ return true;
+ }));
+
+ FtraceSetupErrors errors{};
+ FtraceConfigId id_a = 23;
+ ASSERT_TRUE(model_.SetupConfig(id_a, config, &errors));
+ EXPECT_EQ(errors.atrace_errors, "foo\nbar\n");
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, SetupClockForTesting) {
+ FtraceConfig config;
+
+ namespace pb0 = protos::pbzero;
+
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .Times(AnyNumber());
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("[local] global boot"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/trace_clock", "boot"));
+ model_.SetupClockForTesting(config);
+ // unspecified = boot.
+ EXPECT_EQ(model_.ftrace_clock(),
+ static_cast<int>(pb0::FTRACE_CLOCK_UNSPECIFIED));
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("[local] global"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/trace_clock", "global"));
+ model_.SetupClockForTesting(config);
+ EXPECT_EQ(model_.ftrace_clock(), static_cast<int>(pb0::FTRACE_CLOCK_GLOBAL));
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return(""));
+ model_.SetupClockForTesting(config);
+ EXPECT_EQ(model_.ftrace_clock(), static_cast<int>(pb0::FTRACE_CLOCK_UNKNOWN));
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("local [global]"));
+ model_.SetupClockForTesting(config);
+ EXPECT_EQ(model_.ftrace_clock(), static_cast<int>(pb0::FTRACE_CLOCK_GLOBAL));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, GetFtraceEvents) {
+ FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
+ std::set<GroupAndName> events =
+ model_.GetFtraceEventsForTesting(config, table_.get());
+
+ EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_switch")));
+ EXPECT_THAT(events, Not(Contains(GroupAndName("ftrace", "print"))));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, GetFtraceEventsAtrace) {
+ FtraceConfig config = CreateFtraceConfig({});
+ *config.add_atrace_categories() = "sched";
+ std::set<GroupAndName> events =
+ model_.GetFtraceEventsForTesting(config, table_.get());
+
+ EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_switch")));
+ EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_cpu_hotplug")));
+ EXPECT_THAT(events, Contains(GroupAndName("ftrace", "print")));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, GetFtraceEventsAtraceCategories) {
+ FtraceConfig config = CreateFtraceConfig({});
+ *config.add_atrace_categories() = "sched";
+ *config.add_atrace_categories() = "memreclaim";
+ std::set<GroupAndName> events =
+ model_.GetFtraceEventsForTesting(config, table_.get());
+
+ EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_switch")));
+ EXPECT_THAT(events, Contains(GroupAndName("sched", "sched_cpu_hotplug")));
+ EXPECT_THAT(events, Contains(GroupAndName("cgroup", "cgroup_mkdir")));
+ EXPECT_THAT(events, Contains(GroupAndName("vmscan",
+ "mm_vmscan_direct_reclaim_begin")));
+ EXPECT_THAT(events,
+ Contains(GroupAndName("lowmemorykiller", "lowmemory_kill")));
+ EXPECT_THAT(events, Contains(GroupAndName("ftrace", "print")));
+}
+
+// Tests the enabling fallback logic that tries to use the "set_event" interface
+// if writing the individual xxx/enable file fails.
+TEST_F(FtraceConfigMuxerFakeTableTest, FallbackOnSetEvent) {
+ FtraceConfig config =
+ CreateFtraceConfig({"sched/sched_switch", "cgroup/cgroup_mkdir"});
+
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_percent", _))
+ .WillRepeatedly(Return(true));
+
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillOnce(Return("nop"));
+ EXPECT_CALL(ftrace_, ReadOneCharFromFile("/root/tracing_on"))
+ .WillOnce(Return('1'));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "0"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/events/enable", "0"));
+ EXPECT_CALL(ftrace_, ClearFile("/root/trace"));
+ EXPECT_CALL(ftrace_, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("[local] global boot"));
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .Times(AnyNumber());
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_size_kb", _));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/trace_clock", "boot"));
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/sched/sched_switch/enable", "1"));
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/cgroup/cgroup_mkdir/enable", "1"))
+ .WillOnce(Return(false));
+ EXPECT_CALL(ftrace_, AppendToFile("/root/set_event", "cgroup:cgroup_mkdir"))
+ .WillOnce(Return(true));
+ FtraceConfigId id = 97;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "1"));
+ ASSERT_TRUE(model_.ActivateConfig(id));
+
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
+ ASSERT_TRUE(ds_config);
+ EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ Contains(kFakeSchedSwitchEventId));
+ EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ Contains(kCgroupMkdirEventId));
+
+ const EventFilter* central_filter = model_.GetCentralEventFilterForTesting();
+ EXPECT_THAT(central_filter->GetEnabledEvents(),
+ Contains(kFakeSchedSwitchEventId));
+ EXPECT_THAT(central_filter->GetEnabledEvents(),
+ Contains(kCgroupMkdirEventId));
+
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/sched/sched_switch/enable", "0"));
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/cgroup/cgroup_mkdir/enable", "0"))
+ .WillOnce(Return(false));
+ EXPECT_CALL(ftrace_, AppendToFile("/root/set_event", "!cgroup:cgroup_mkdir"))
+ .WillOnce(Return(true));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "0"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_size_kb", PageSizeKb()));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/events/enable", "0"));
+ EXPECT_CALL(ftrace_, ClearFile("/root/trace"));
+ EXPECT_CALL(ftrace_, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "1"));
+ ASSERT_TRUE(model_.RemoveConfig(id));
+}
+
+TEST_F(FtraceConfigMuxerFakeTableTest, CompactSchedConfigWithInvalidFormat) {
// Request compact encoding.
FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
config.mutable_compact_sched()->set_enabled(true);
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
.WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
.WillByDefault(Return("0"));
FtraceConfigId id = 67;
- ASSERT_TRUE(model.SetupConfig(id, config));
+ ASSERT_TRUE(model_.SetupConfig(id, config));
// The translation table says that the scheduling events' format didn't match
// compile-time assumptions, so we won't enable compact events even if
// requested.
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
ASSERT_TRUE(ds_config);
EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
Contains(kFakeSchedSwitchEventId));
EXPECT_FALSE(ds_config->compact_sched.enabled);
}
-TEST_F(FtraceConfigMuxerTest, SkipGenericEventsOption) {
- NiceMock<MockFtraceProcfs> ftrace;
- FtraceConfigMuxer model(&ftrace, table_.get(), GetSyscallTable(), {});
-
+TEST_F(FtraceConfigMuxerFakeTableTest, SkipGenericEventsOption) {
static constexpr int kFtraceGenericEventId = 42;
- ON_CALL(table_procfs_, ReadEventFormat("sched", "generic"))
+ ON_CALL(ftrace_, ReadEventFormat("sched", "generic"))
.WillByDefault(Return(R"(name: generic
ID: 42
format:
@@ -1297,15 +1023,15 @@
CreateFtraceConfig({"sched/sched_switch", "sched/generic"});
config_with_disable.set_disable_generic_events(true);
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
.WillByDefault(Return("nop"));
- ON_CALL(ftrace, ReadFileIntoString("/root/events/enable"))
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
.WillByDefault(Return("0"));
{
FtraceConfigId id = 123;
- ASSERT_TRUE(model.SetupConfig(id, config_default));
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
+ ASSERT_TRUE(model_.SetupConfig(id, config_default));
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
ASSERT_TRUE(ds_config);
// Both events enabled for the data source by default.
EXPECT_THAT(
@@ -1314,8 +1040,8 @@
}
{
FtraceConfigId id = 321;
- ASSERT_TRUE(model.SetupConfig(id, config_with_disable));
- const FtraceDataSourceConfig* ds_config = model.GetDataSourceConfig(id);
+ ASSERT_TRUE(model_.SetupConfig(id, config_with_disable));
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
ASSERT_TRUE(ds_config);
// Only the statically known event is enabled.
EXPECT_THAT(ds_config->event_filter.GetEnabledEvents(),
@@ -1323,11 +1049,7 @@
}
}
-TEST_F(FtraceConfigMuxerTest, Funcgraph) {
- auto fake_table = CreateFakeTable();
- NiceMock<MockFtraceProcfs> ftrace;
- FtraceConfigMuxer model(&ftrace, fake_table.get(), GetSyscallTable(), {});
-
+TEST_F(FtraceConfigMuxerFakeTableTest, Funcgraph) {
FtraceConfig config;
config.set_enable_function_graph(true);
*config.add_function_filters() = "sched*";
@@ -1336,76 +1058,276 @@
*config.add_function_graph_roots() = "sched*";
*config.add_function_graph_roots() = "*mm_fault";
- ON_CALL(ftrace, ReadFileIntoString("/root/current_tracer"))
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
.WillByDefault(Return("nop"));
- EXPECT_CALL(ftrace, WriteToFile(_, _)).WillRepeatedly(Return(true));
+ EXPECT_CALL(ftrace_, WriteToFile(_, _)).WillRepeatedly(Return(true));
- EXPECT_CALL(ftrace, ClearFile("/root/trace"));
- EXPECT_CALL(ftrace, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
+ EXPECT_CALL(ftrace_, ClearFile("/root/trace"));
+ EXPECT_CALL(ftrace_, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
// Set up config, assert that the tracefs writes happened:
- EXPECT_CALL(ftrace, ClearFile("/root/set_ftrace_filter"));
- EXPECT_CALL(ftrace, ClearFile("/root/set_graph_function"));
- EXPECT_CALL(ftrace, AppendToFile("/root/set_ftrace_filter",
- "sched*\nhandle_mm_fault"))
+ EXPECT_CALL(ftrace_, ClearFile("/root/set_ftrace_filter"));
+ EXPECT_CALL(ftrace_, ClearFile("/root/set_graph_function"));
+ EXPECT_CALL(ftrace_, AppendToFile("/root/set_ftrace_filter",
+ "sched*\nhandle_mm_fault"))
.WillOnce(Return(true));
- EXPECT_CALL(ftrace,
+ EXPECT_CALL(ftrace_,
AppendToFile("/root/set_graph_function", "sched*\n*mm_fault"))
.WillOnce(Return(true));
- EXPECT_CALL(ftrace, WriteToFile("/root/current_tracer", "function_graph"))
+ EXPECT_CALL(ftrace_, WriteToFile("/root/current_tracer", "function_graph"))
.WillOnce(Return(true));
FtraceConfigId id = 43;
- ASSERT_TRUE(model.SetupConfig(id, config));
- ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&ftrace));
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+ ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&ftrace_));
// Toggle config on and off, tracer won't be reset yet:
- ASSERT_TRUE(model.ActivateConfig(id));
- ASSERT_TRUE(model.RemoveConfig(id));
- ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&ftrace));
+ ASSERT_TRUE(model_.ActivateConfig(id));
+ ASSERT_TRUE(model_.RemoveConfig(id));
+ ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&ftrace_));
// Emulate ftrace_controller's call to ResetCurrentTracer (see impl comments
// for why RemoveConfig is insufficient).
- EXPECT_CALL(ftrace, ClearFile("/root/set_ftrace_filter"));
- EXPECT_CALL(ftrace, ClearFile("/root/set_graph_function"));
- EXPECT_CALL(ftrace, WriteToFile("/root/current_tracer", "nop"))
+ EXPECT_CALL(ftrace_, ClearFile("/root/set_ftrace_filter"));
+ EXPECT_CALL(ftrace_, ClearFile("/root/set_graph_function"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/current_tracer", "nop"))
.WillOnce(Return(true));
- ASSERT_TRUE(model.ResetCurrentTracer());
- ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&ftrace));
+ ASSERT_TRUE(model_.ResetCurrentTracer());
+ ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&ftrace_));
}
-TEST_F(FtraceConfigMuxerTest, SecondaryInstanceDoNotSupportAtrace) {
- auto fake_table = CreateFakeTable();
- NiceMock<MockFtraceProcfs> ftrace;
- FtraceConfigMuxer model(&ftrace, fake_table.get(), GetSyscallTable(), {},
- /* secondary_instance= */ true);
-
- FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
- *config.add_atrace_categories() = "sched";
-
- ASSERT_FALSE(model.SetupConfig(/* id= */ 73, config));
-}
-
-TEST_F(FtraceConfigMuxerTest, PreserveFtraceBufferNotSetBufferSizeKb) {
- auto fake_table = CreateFakeTable();
- NiceMock<MockFtraceProcfs> ftrace;
- FtraceConfigMuxer model(&ftrace, fake_table.get(), GetSyscallTable(), {},
- /* secondary_instance= */ false);
-
+TEST_F(FtraceConfigMuxerFakeTableTest, PreserveFtraceBufferNotSetBufferSizeKb) {
FtraceConfig config = CreateFtraceConfig({"sched/sched_switch"});
config.set_preserve_ftrace_buffer(true);
- EXPECT_CALL(ftrace, ReadOneCharFromFile("/root/tracing_on"))
+ EXPECT_CALL(ftrace_, ReadOneCharFromFile("/root/tracing_on"))
.WillOnce(Return('1'));
- ON_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
.WillByDefault(Return("[local] global boot"));
- EXPECT_CALL(ftrace, ReadFileIntoString("/root/trace_clock"))
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
.Times(AnyNumber());
- EXPECT_CALL(ftrace, WriteToFile("/root/buffer_size_kb", _)).Times(0);
- EXPECT_CALL(ftrace,
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_size_kb", _)).Times(0);
+ EXPECT_CALL(ftrace_,
WriteToFile("/root/events/sched/sched_switch/enable", "1"));
FtraceConfigId id = 44;
- ASSERT_TRUE(model.SetupConfig(id, config));
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+}
+
+// Fixture that constructs a FtraceConfigMuxer with a mock
+// ProtoTranslationTable.
+class FtraceConfigMuxerMockTableTest : public FtraceConfigMuxerTest {
+ protected:
+ std::unique_ptr<MockProtoTranslationTable> mock_table_ = GetMockTable();
+ FtraceConfigMuxer model_ = FtraceConfigMuxer(&ftrace_,
+ &atrace_wrapper_,
+ mock_table_.get(),
+ GetSyscallTable(),
+ {});
+};
+
+TEST_F(FtraceConfigMuxerMockTableTest, AddGenericEvent) {
+ FtraceConfig config = CreateFtraceConfig({"power/cpu_frequency"});
+
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillOnce(Return("nop"));
+ EXPECT_CALL(ftrace_, ReadOneCharFromFile("/root/tracing_on"))
+ .WillOnce(Return('1'));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "0"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/events/enable", "0"));
+ EXPECT_CALL(ftrace_, ClearFile("/root/trace"));
+ EXPECT_CALL(ftrace_, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("[local] global boot"));
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .Times(AnyNumber());
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_size_kb", _));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/trace_clock", "boot"));
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/power/cpu_frequency/enable", "1"));
+ EXPECT_CALL(*mock_table_, GetEvent(GroupAndName("power", "cpu_frequency")))
+ .Times(AnyNumber());
+
+ static constexpr int kExpectedEventId = 77;
+ Event event_to_return;
+ event_to_return.name = "cpu_frequency";
+ event_to_return.group = "power";
+ event_to_return.ftrace_event_id = kExpectedEventId;
+ ON_CALL(*mock_table_,
+ GetOrCreateEvent(GroupAndName("power", "cpu_frequency")))
+ .WillByDefault(Return(&event_to_return));
+ EXPECT_CALL(*mock_table_,
+ GetOrCreateEvent(GroupAndName("power", "cpu_frequency")));
+
+ FtraceConfigId id = 7;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "1"));
+ ASSERT_TRUE(model_.ActivateConfig(id));
+
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
+ ASSERT_TRUE(ds_config);
+ ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ ElementsAreArray({kExpectedEventId}));
+
+ const EventFilter* central_filter = model_.GetCentralEventFilterForTesting();
+ ASSERT_THAT(central_filter->GetEnabledEvents(),
+ ElementsAreArray({kExpectedEventId}));
+}
+
+TEST_F(FtraceConfigMuxerMockTableTest, AddAllEvents) {
+ FtraceConfig config = CreateFtraceConfig({"sched/*"});
+
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillOnce(Return("nop"));
+ EXPECT_CALL(ftrace_, ReadOneCharFromFile("/root/tracing_on"))
+ .WillOnce(Return('1'));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "0"));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/events/enable", "0"));
+ EXPECT_CALL(ftrace_, ClearFile("/root/trace"));
+ EXPECT_CALL(ftrace_, ClearFile(MatchesRegex("/root/per_cpu/cpu[0-9]/trace")));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .WillByDefault(Return("[local] global boot"));
+ EXPECT_CALL(ftrace_, ReadFileIntoString("/root/trace_clock"))
+ .Times(AnyNumber());
+ EXPECT_CALL(ftrace_, WriteToFile("/root/buffer_size_kb", _));
+ EXPECT_CALL(ftrace_, WriteToFile("/root/trace_clock", "boot"));
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/sched/sched_switch/enable", "1"));
+ EXPECT_CALL(ftrace_,
+ WriteToFile("/root/events/sched/sched_new_event/enable", "1"));
+
+ std::set<std::string> n = {"sched_switch", "sched_new_event"};
+ ON_CALL(ftrace_, GetEventNamesForGroup("events/sched"))
+ .WillByDefault(Return(n));
+ EXPECT_CALL(ftrace_, GetEventNamesForGroup("events/sched")).Times(1);
+
+ // Non-generic event.
+ static constexpr int kSchedSwitchEventId = 1;
+ Event sched_switch = {"sched_switch", "sched", {}, 0, 0, 0};
+ sched_switch.ftrace_event_id = kSchedSwitchEventId;
+ ON_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("sched", "sched_switch")))
+ .WillByDefault(Return(&sched_switch));
+ EXPECT_CALL(*mock_table_,
+ GetOrCreateEvent(GroupAndName("sched", "sched_switch")))
+ .Times(AnyNumber());
+
+ // Generic event.
+ static constexpr int kGenericEventId = 2;
+ Event event_to_return;
+ event_to_return.name = "sched_new_event";
+ event_to_return.group = "sched";
+ event_to_return.ftrace_event_id = kGenericEventId;
+ ON_CALL(*mock_table_,
+ GetOrCreateEvent(GroupAndName("sched", "sched_new_event")))
+ .WillByDefault(Return(&event_to_return));
+ EXPECT_CALL(*mock_table_,
+ GetOrCreateEvent(GroupAndName("sched", "sched_new_event")));
+
+ FtraceConfigId id = 13;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+ ASSERT_TRUE(id);
+
+ EXPECT_CALL(ftrace_, WriteToFile("/root/tracing_on", "1"));
+ ASSERT_TRUE(model_.ActivateConfig(id));
+
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
+ ASSERT_TRUE(ds_config);
+ ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ ElementsAreArray({kSchedSwitchEventId, kGenericEventId}));
+
+ const EventFilter* central_filter = model_.GetCentralEventFilterForTesting();
+ ASSERT_THAT(central_filter->GetEnabledEvents(),
+ ElementsAreArray({kSchedSwitchEventId, kGenericEventId}));
+}
+
+TEST_F(FtraceConfigMuxerMockTableTest, TwoWildcardGroups) {
+ FtraceConfig config = CreateFtraceConfig({"group_one/*", "group_two/*"});
+
+ std::set<std::string> event_names = {"foo"};
+ ON_CALL(ftrace_, GetEventNamesForGroup("events/group_one"))
+ .WillByDefault(Return(event_names));
+ EXPECT_CALL(ftrace_, GetEventNamesForGroup("events/group_one"))
+ .Times(AnyNumber());
+
+ ON_CALL(ftrace_, GetEventNamesForGroup("events/group_two"))
+ .WillByDefault(Return(event_names));
+ EXPECT_CALL(ftrace_, GetEventNamesForGroup("events/group_two"))
+ .Times(AnyNumber());
+
+ static constexpr int kEventId1 = 1;
+ Event event1;
+ event1.name = "foo";
+ event1.group = "group_one";
+ event1.ftrace_event_id = kEventId1;
+ ON_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("group_one", "foo")))
+ .WillByDefault(Return(&event1));
+ EXPECT_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("group_one", "foo")));
+
+ static constexpr int kEventId2 = 2;
+ Event event2;
+ event2.name = "foo";
+ event2.group = "group_two";
+ event2.ftrace_event_id = kEventId2;
+ ON_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("group_two", "foo")))
+ .WillByDefault(Return(&event2));
+ EXPECT_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("group_two", "foo")));
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+
+ FtraceConfigId id = 23;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+ ASSERT_TRUE(model_.ActivateConfig(id));
+
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
+ ASSERT_TRUE(ds_config);
+ ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ ElementsAreArray({kEventId1, kEventId2}));
+
+ const EventFilter* central_filter = model_.GetCentralEventFilterForTesting();
+ ASSERT_THAT(central_filter->GetEnabledEvents(),
+ ElementsAreArray({kEventId1, kEventId2}));
+}
+
+TEST_F(FtraceConfigMuxerMockTableTest, AddSameNameEvents) {
+ FtraceConfig config = CreateFtraceConfig({"group_one/foo", "group_two/foo"});
+
+ static constexpr int kEventId1 = 1;
+ Event event1;
+ event1.name = "foo";
+ event1.group = "group_one";
+ event1.ftrace_event_id = kEventId1;
+ ON_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("group_one", "foo")))
+ .WillByDefault(Return(&event1));
+ EXPECT_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("group_one", "foo")));
+
+ static constexpr int kEventId2 = 2;
+ Event event2;
+ event2.name = "foo";
+ event2.group = "group_two";
+ event2.ftrace_event_id = kEventId2;
+ ON_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("group_two", "foo")))
+ .WillByDefault(Return(&event2));
+ EXPECT_CALL(*mock_table_, GetOrCreateEvent(GroupAndName("group_two", "foo")));
+
+ ON_CALL(ftrace_, ReadFileIntoString("/root/current_tracer"))
+ .WillByDefault(Return("nop"));
+ ON_CALL(ftrace_, ReadFileIntoString("/root/events/enable"))
+ .WillByDefault(Return("0"));
+
+ FtraceConfigId id = 5;
+ ASSERT_TRUE(model_.SetupConfig(id, config));
+ ASSERT_TRUE(model_.ActivateConfig(id));
+
+ const FtraceDataSourceConfig* ds_config = model_.GetDataSourceConfig(id);
+ ASSERT_THAT(ds_config->event_filter.GetEnabledEvents(),
+ ElementsAreArray({kEventId1, kEventId2}));
+
+ const EventFilter* central_filter = model_.GetCentralEventFilterForTesting();
+ ASSERT_THAT(central_filter->GetEnabledEvents(),
+ ElementsAreArray({kEventId1, kEventId2}));
}
} // namespace
diff --git a/src/traced/probes/ftrace/ftrace_controller.cc b/src/traced/probes/ftrace/ftrace_controller.cc
index ad924fa..750629d 100644
--- a/src/traced/probes/ftrace/ftrace_controller.cc
+++ b/src/traced/probes/ftrace/ftrace_controller.cc
@@ -179,25 +179,31 @@
if (!table)
return nullptr;
+ auto atrace_wrapper = std::make_unique<AtraceWrapperImpl>();
+
std::map<std::string, std::vector<GroupAndName>> vendor_evts =
GetAtraceVendorEvents(ftrace_procfs.get());
SyscallTable syscalls = SyscallTable::FromCurrentArch();
auto muxer = std::make_unique<FtraceConfigMuxer>(
- ftrace_procfs.get(), table.get(), std::move(syscalls), vendor_evts);
- return std::unique_ptr<FtraceController>(
- new FtraceController(std::move(ftrace_procfs), std::move(table),
- std::move(muxer), runner, observer));
+ ftrace_procfs.get(), atrace_wrapper.get(), table.get(),
+ std::move(syscalls), vendor_evts);
+ return std::unique_ptr<FtraceController>(new FtraceController(
+ std::move(ftrace_procfs), std::move(table), std::move(atrace_wrapper),
+ std::move(muxer), runner, observer));
}
-FtraceController::FtraceController(std::unique_ptr<FtraceProcfs> ftrace_procfs,
- std::unique_ptr<ProtoTranslationTable> table,
- std::unique_ptr<FtraceConfigMuxer> muxer,
- base::TaskRunner* task_runner,
- Observer* observer)
+FtraceController::FtraceController(
+ std::unique_ptr<FtraceProcfs> ftrace_procfs,
+ std::unique_ptr<ProtoTranslationTable> table,
+ std::unique_ptr<AtraceWrapper> atrace_wrapper,
+ std::unique_ptr<FtraceConfigMuxer> muxer,
+ base::TaskRunner* task_runner,
+ Observer* observer)
: task_runner_(task_runner),
observer_(observer),
+ atrace_wrapper_(std::move(atrace_wrapper)),
primary_(std::move(ftrace_procfs), std::move(table), std::move(muxer)),
weak_factory_(this) {}
@@ -816,7 +822,8 @@
auto syscalls = SyscallTable::FromCurrentArch();
auto muxer = std::make_unique<FtraceConfigMuxer>(
- ftrace_procfs.get(), table.get(), std::move(syscalls), vendor_evts,
+ ftrace_procfs.get(), atrace_wrapper_.get(), table.get(),
+ std::move(syscalls), vendor_evts,
/* secondary_instance= */ true);
return std::make_unique<FtraceInstanceState>(
std::move(ftrace_procfs), std::move(table), std::move(muxer));
diff --git a/src/traced/probes/ftrace/ftrace_controller.h b/src/traced/probes/ftrace/ftrace_controller.h
index 1e7c575..a858dfe 100644
--- a/src/traced/probes/ftrace/ftrace_controller.h
+++ b/src/traced/probes/ftrace/ftrace_controller.h
@@ -29,6 +29,7 @@
#include "perfetto/ext/base/weak_ptr.h"
#include "perfetto/ext/tracing/core/basic_types.h"
#include "src/kallsyms/lazy_kernel_symbolizer.h"
+#include "src/traced/probes/ftrace/atrace_wrapper.h"
#include "src/traced/probes/ftrace/cpu_reader.h"
#include "src/traced/probes/ftrace/ftrace_config_utils.h"
@@ -99,6 +100,7 @@
FtraceController(std::unique_ptr<FtraceProcfs>,
std::unique_ptr<ProtoTranslationTable>,
+ std::unique_ptr<AtraceWrapper>,
std::unique_ptr<FtraceConfigMuxer>,
base::TaskRunner*,
Observer*);
@@ -123,6 +125,8 @@
virtual uint64_t NowMs() const;
+ AtraceWrapper* atrace_wrapper() const { return atrace_wrapper_.get(); }
+
private:
friend class TestFtraceController;
enum class PollSupport { kUntested, kSupported, kUnsupported };
@@ -168,6 +172,7 @@
bool retain_ksyms_on_stop_ = false;
PollSupport buffer_watermark_support_ = PollSupport::kUntested;
std::set<FtraceDataSource*> data_sources_;
+ std::unique_ptr<AtraceWrapper> atrace_wrapper_;
// Default tracefs instance (normally /sys/kernel/tracing) is valid for as
// long as the controller is valid.
// Secondary instances (i.e. /sys/kernel/tracing/instances/...) are created
diff --git a/src/traced/probes/ftrace/ftrace_controller_unittest.cc b/src/traced/probes/ftrace/ftrace_controller_unittest.cc
index 28ca2d4..1a3538e 100644
--- a/src/traced/probes/ftrace/ftrace_controller_unittest.cc
+++ b/src/traced/probes/ftrace/ftrace_controller_unittest.cc
@@ -102,9 +102,10 @@
}
std::unique_ptr<FtraceConfigMuxer> FakeMuxer(FtraceProcfs* ftrace,
+ AtraceWrapper* atrace_wrapper,
ProtoTranslationTable* table) {
return std::unique_ptr<FtraceConfigMuxer>(new FtraceConfigMuxer(
- ftrace, table, SyscallTable(Architecture::kUnknown), {}));
+ ftrace, atrace_wrapper, table, SyscallTable(Architecture::kUnknown), {}));
}
class MockFtraceProcfs : public FtraceProcfs {
@@ -201,6 +202,12 @@
std::string current_tracer_ = "nop";
};
+class MockAtraceWrapper : public AtraceWrapper {
+ public:
+ MOCK_METHOD(bool, RunAtrace, (const std::vector<std::string>&, std::string*));
+ MOCK_METHOD(bool, IsOldAtrace, ());
+};
+
} // namespace
class TestFtraceController : public FtraceController,
@@ -208,11 +215,13 @@
public:
TestFtraceController(std::unique_ptr<MockFtraceProcfs> ftrace_procfs,
std::unique_ptr<Table> table,
+ std::unique_ptr<AtraceWrapper> atrace_wrapper,
std::unique_ptr<FtraceConfigMuxer> muxer,
std::unique_ptr<MockTaskRunner> runner,
MockFtraceProcfs* raw_procfs)
: FtraceController(std::move(ftrace_procfs),
std::move(table),
+ std::move(atrace_wrapper),
std::move(muxer),
runner.get(),
/*observer=*/this),
@@ -256,7 +265,7 @@
PERFETTO_CHECK(ftrace_procfs);
auto table = FakeTable(ftrace_procfs.get());
- auto muxer = FakeMuxer(ftrace_procfs.get(), table.get());
+ auto muxer = FakeMuxer(ftrace_procfs.get(), atrace_wrapper(), table.get());
return std::unique_ptr<FtraceController::FtraceInstanceState>(
new FtraceController::FtraceInstanceState(
std::move(ftrace_procfs), std::move(table), std::move(muxer)));
@@ -289,14 +298,17 @@
new MockFtraceProcfs("/root/", cpu_count));
}
+ std::unique_ptr<AtraceWrapper> atrace_wrapper;
+
auto table = FakeTable(ftrace_procfs.get());
- auto muxer = FakeMuxer(ftrace_procfs.get(), table.get());
+ auto muxer =
+ FakeMuxer(ftrace_procfs.get(), atrace_wrapper.get(), table.get());
MockFtraceProcfs* raw_procfs = ftrace_procfs.get();
return std::unique_ptr<TestFtraceController>(new TestFtraceController(
- std::move(ftrace_procfs), std::move(table), std::move(muxer),
- std::move(runner), raw_procfs));
+ std::move(ftrace_procfs), std::move(table), std::move(atrace_wrapper),
+ std::move(muxer), std::move(runner), raw_procfs));
}
} // namespace