blob: 211b065a36047bfa5210a9ff52222d7a9dd176bd [file] [log] [blame]
Primiano Tucci401a4732022-01-19 00:26:49 +00001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "perfetto/base/build_config.h"
18
19#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
20 PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX)
21
22#include "perfetto/base/build_config.h"
23#include "perfetto/base/logging.h"
24#include "perfetto/ext/base/file_utils.h"
25#include "perfetto/ext/base/scoped_file.h"
26#include "perfetto/ext/base/string_utils.h"
27#include "perfetto/ext/base/temp_file.h"
28#include "perfetto/ext/base/utils.h"
29#include "perfetto/ext/traced/traced.h"
30#include "perfetto/ext/tracing/core/commit_data_request.h"
31#include "perfetto/ext/tracing/core/trace_packet.h"
32#include "perfetto/ext/tracing/core/tracing_service.h"
33#include "perfetto/protozero/scattered_heap_buffer.h"
34#include "perfetto/tracing/core/tracing_service_state.h"
35#include "src/base/test/test_task_runner.h"
36#include "src/base/test/utils.h"
37#include "src/traced/probes/ftrace/ftrace_controller.h"
38#include "src/traced/probes/ftrace/ftrace_procfs.h"
39#include "test/gtest_and_gmock.h"
40#include "test/test_helper.h"
41
42#include "protos/perfetto/config/test_config.gen.h"
43#include "protos/perfetto/config/trace_config.gen.h"
44#include "protos/perfetto/trace/ftrace/ftrace.gen.h"
45#include "protos/perfetto/trace/ftrace/ftrace_event.gen.h"
46#include "protos/perfetto/trace/ftrace/ftrace_event_bundle.gen.h"
47#include "protos/perfetto/trace/ftrace/ftrace_stats.gen.h"
48#include "protos/perfetto/trace/perfetto/tracing_service_event.gen.h"
49#include "protos/perfetto/trace/test_event.gen.h"
50#include "protos/perfetto/trace/trace.gen.h"
51#include "protos/perfetto/trace/trace_packet.gen.h"
52#include "protos/perfetto/trace/trace_packet.pbzero.h"
53
54#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
55#include "test/android_test_utils.h"
56#endif
57
58namespace perfetto {
59
60namespace {
61
62using ::testing::ContainsRegex;
63using ::testing::Each;
64using ::testing::ElementsAreArray;
65using ::testing::HasSubstr;
66using ::testing::Property;
67using ::testing::SizeIs;
Primiano Tucci36fada32022-03-17 11:35:47 +000068using ::testing::UnorderedElementsAreArray;
Primiano Tucci401a4732022-01-19 00:26:49 +000069
70class PerfettoFtraceIntegrationTest : public ::testing::Test {
71 public:
72 void SetUp() override {
73 ftrace_procfs_ = FtraceProcfs::CreateGuessingMountPoint();
74
75// On android we do expect that tracefs is accessible, both in the case of
76// running as part of traced/probes system daemons and shell. On Linux this is
77// up to the system admin, don't hard fail.
78#if !PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
79 if (!ftrace_procfs_) {
80 PERFETTO_ELOG(
81 "Cannot acces tracefs. On Linux you need to manually run `sudo chown "
82 "-R $USER /sys/kernel/tracing` to enable these tests. Skipping");
83 GTEST_SKIP();
84 } else {
85 // Recent kernels set tracing_on=1 by default. On Android this is
86 // disabled by initrc scripts. Be tolerant on Linux where we don't have
87 // that and force disable ftrace.
88 ftrace_procfs_->SetTracingOn(false);
89 }
90#endif
91 }
92
93 std::unique_ptr<FtraceProcfs> ftrace_procfs_;
94};
95
96} // namespace
97
98TEST_F(PerfettoFtraceIntegrationTest, TestFtraceProducer) {
99 base::TestTaskRunner task_runner;
100
101 TestHelper helper(&task_runner);
102 helper.StartServiceIfRequired();
103
104#if PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
105 ProbesProducerThread probes(GetTestProducerSockName());
106 probes.Connect();
107#endif
108
109 helper.ConnectConsumer();
110 helper.WaitForConsumerConnect();
111
112 TraceConfig trace_config;
Daniele Di Proietto61b97662023-02-21 17:10:58 +0000113 trace_config.add_buffers()->set_size_kb(64);
Primiano Tucci401a4732022-01-19 00:26:49 +0000114 trace_config.set_duration_ms(3000);
115
116 auto* ds_config = trace_config.add_data_sources()->mutable_config();
117 ds_config->set_name("linux.ftrace");
118 ds_config->set_target_buffer(0);
119
120 protos::gen::FtraceConfig ftrace_config;
121 ftrace_config.add_ftrace_events("sched_switch");
122 ftrace_config.add_ftrace_events("bar");
123 ds_config->set_ftrace_config_raw(ftrace_config.SerializeAsString());
124
125 helper.StartTracing(trace_config);
126 helper.WaitForTracingDisabled();
127
128 helper.ReadData();
129 helper.WaitForReadData();
130
131 const auto& packets = helper.trace();
132 ASSERT_GT(packets.size(), 0u);
133
134 for (const auto& packet : packets) {
135 for (int ev = 0; ev < packet.ftrace_events().event_size(); ev++) {
136 ASSERT_TRUE(packet.ftrace_events()
137 .event()[static_cast<size_t>(ev)]
138 .has_sched_switch());
139 }
140 }
141}
142
143TEST_F(PerfettoFtraceIntegrationTest, TestFtraceFlush) {
144 base::TestTaskRunner task_runner;
145
146 TestHelper helper(&task_runner);
147 helper.StartServiceIfRequired();
148
149#if PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
150 ProbesProducerThread probes(GetTestProducerSockName());
151 probes.Connect();
152#endif
153
154 helper.ConnectConsumer();
155 helper.WaitForConsumerConnect();
156
157 // Wait for the traced_probes service to connect. We want to start tracing
158 // only after it connects, otherwise we'll start a tracing session with 0
159 // producers connected (which is valid but not what we want here).
160 helper.WaitForDataSourceConnected("linux.ftrace");
161
162 TraceConfig trace_config;
163 trace_config.add_buffers()->set_size_kb(32);
164 trace_config.set_duration_ms(kDefaultTestTimeoutMs);
165
166 auto* ds_config = trace_config.add_data_sources()->mutable_config();
167 ds_config->set_name("linux.ftrace");
168
169 protos::gen::FtraceConfig ftrace_config;
170 ftrace_config.add_ftrace_events("print");
171 ds_config->set_ftrace_config_raw(ftrace_config.SerializeAsString());
172
173 helper.StartTracing(trace_config);
174
175 // Wait for traced_probes to start.
Chun-Tse Shao1bab45e2023-01-27 12:58:40 -0800176 helper.WaitFor([&] { return ftrace_procfs_->GetTracingOn(); }, "ftrace");
Primiano Tucci401a4732022-01-19 00:26:49 +0000177
178 // Do a first flush just to synchronize with the producer. The problem here
179 // is that, on a Linux workstation, the producer can take several seconds just
180 // to get to the point where it is fully ready. We use the flush ack as a
181 // synchronization point.
182 helper.FlushAndWait(kDefaultTestTimeoutMs);
183
184 const char kMarker[] = "just_one_event";
185 EXPECT_TRUE(ftrace_procfs_->WriteTraceMarker(kMarker));
186
187 // This is the real flush we are testing.
188 helper.FlushAndWait(kDefaultTestTimeoutMs);
189
190 helper.DisableTracing();
191 helper.WaitForTracingDisabled(kDefaultTestTimeoutMs);
192
193 helper.ReadData();
194 helper.WaitForReadData();
195
196 int marker_found = 0;
197 for (const auto& packet : helper.trace()) {
198 for (int i = 0; i < packet.ftrace_events().event_size(); i++) {
199 const auto& ev = packet.ftrace_events().event()[static_cast<size_t>(i)];
200 if (ev.has_print() && ev.print().buf().find(kMarker) != std::string::npos)
201 marker_found++;
202 }
203 }
204 ASSERT_EQ(marker_found, 1);
205}
206
207// Disable this test:
208// 1. On cuttlefish (x86-kvm). It's too slow when running on GCE (b/171771440).
209// We cannot change the length of the production code in
210// CanReadKernelSymbolAddresses() to deal with it.
211// 2. On user (i.e. non-userdebug) builds. As that doesn't work there by design.
212// 3. On ARM builds, because they fail on our CI.
213#if (PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) && defined(__i386__)) || \
214 defined(__arm__)
215#define MAYBE_KernelAddressSymbolization DISABLED_KernelAddressSymbolization
216#else
217#define MAYBE_KernelAddressSymbolization KernelAddressSymbolization
218#endif
219TEST_F(PerfettoFtraceIntegrationTest, MAYBE_KernelAddressSymbolization) {
220 // On Android in-tree builds (TreeHugger): this test must always run to
221 // prevent selinux / property-related regressions. However it can run only on
222 // userdebug.
223 // On standalone builds and Linux, this can be optionally skipped because
224 // there it requires root to lower kptr_restrict.
225#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
226 if (!IsDebuggableBuild())
227 GTEST_SKIP();
228#else
229 if (geteuid() != 0)
230 GTEST_SKIP();
231#endif
232
233 base::TestTaskRunner task_runner;
234
235 TestHelper helper(&task_runner);
236 helper.StartServiceIfRequired();
237
238#if PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
239 ProbesProducerThread probes(GetTestProducerSockName());
240 probes.Connect();
241#endif
242
243 helper.ConnectConsumer();
244 helper.WaitForConsumerConnect();
245
246 TraceConfig trace_config;
Hector Dearmanf4a28dd2023-04-27 12:05:52 +0100247 trace_config.add_buffers()->set_size_kb(64);
Primiano Tucci401a4732022-01-19 00:26:49 +0000248
249 auto* ds_config = trace_config.add_data_sources()->mutable_config();
250 ds_config->set_name("linux.ftrace");
251 protos::gen::FtraceConfig ftrace_cfg;
252 ftrace_cfg.set_symbolize_ksyms(true);
253 ftrace_cfg.set_initialize_ksyms_synchronously_for_testing(true);
254 ds_config->set_ftrace_config_raw(ftrace_cfg.SerializeAsString());
255
256 helper.StartTracing(trace_config);
257
258 // Synchronize with the ftrace data source. The kernel symbol map is loaded
259 // at this point.
260 helper.FlushAndWait(kDefaultTestTimeoutMs);
261 helper.DisableTracing();
262 helper.WaitForTracingDisabled();
263 helper.ReadData();
264 helper.WaitForReadData();
265
266 const auto& packets = helper.trace();
267 ASSERT_GT(packets.size(), 0u);
268
269 int symbols_parsed = -1;
270 for (const auto& packet : packets) {
271 if (!packet.has_ftrace_stats())
272 continue;
273 if (packet.ftrace_stats().phase() != protos::gen::FtraceStats::END_OF_TRACE)
274 continue;
275 symbols_parsed =
276 static_cast<int>(packet.ftrace_stats().kernel_symbols_parsed());
277 }
278 ASSERT_GT(symbols_parsed, 100);
279}
280
Primiano Tucci36fada32022-03-17 11:35:47 +0000281TEST_F(PerfettoFtraceIntegrationTest, ReportFtraceFailuresInStats) {
282 base::TestTaskRunner task_runner;
283
284 TestHelper helper(&task_runner);
285 helper.StartServiceIfRequired();
286
287#if PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
288 ProbesProducerThread probes(GetTestProducerSockName());
289 probes.Connect();
290#endif
291
292 helper.ConnectConsumer();
293 helper.WaitForConsumerConnect();
294
295 // Wait for the traced_probes service to connect. We want to start tracing
296 // only after it connects, otherwise we'll start a tracing session with 0
297 // producers connected (which is valid but not what we want here).
298 helper.WaitForDataSourceConnected("linux.ftrace");
299
300 TraceConfig trace_config;
Daniele Di Proietto827e9402023-06-27 17:34:34 +0000301 TraceConfig::BufferConfig* buf = trace_config.add_buffers();
302 buf->set_size_kb(32);
303 buf->set_fill_policy(TraceConfig::BufferConfig::DISCARD);
Primiano Tucci36fada32022-03-17 11:35:47 +0000304 trace_config.set_duration_ms(1);
305
306 auto* ds_config = trace_config.add_data_sources()->mutable_config();
307 ds_config->set_name("linux.ftrace");
308
309 protos::gen::FtraceConfig ftrace_config;
Daniele Di Proiettod04c69d2023-06-21 19:44:49 +0000310 ftrace_config.add_ftrace_events("sched/sched_switch"); // Good.
Primiano Tucci36fada32022-03-17 11:35:47 +0000311 ftrace_config.add_ftrace_events("sched/does_not_exist"); // Bad.
312 ftrace_config.add_ftrace_events("foobar/i_just_made_this_up"); // Bad.
313 ftrace_config.add_atrace_categories("madeup_atrace_cat"); // Bad.
314 ds_config->set_ftrace_config_raw(ftrace_config.SerializeAsString());
315
316 helper.StartTracing(trace_config);
317 helper.WaitForTracingDisabled(kDefaultTestTimeoutMs);
318
319 helper.ReadData();
320 helper.WaitForReadData();
321 const auto& packets = helper.trace();
322 ASSERT_GT(packets.size(), 0u);
323
Lalit Maganti4e2303c2023-03-29 15:28:36 +0100324 std::optional<protos::gen::FtraceStats> stats;
Primiano Tucci36fada32022-03-17 11:35:47 +0000325 for (const auto& packet : packets) {
326 if (!packet.has_ftrace_stats() ||
327 packet.ftrace_stats().phase() !=
328 protos::gen::FtraceStats::START_OF_TRACE) {
329 continue;
330 }
331 stats = packet.ftrace_stats();
332 }
333 ASSERT_TRUE(stats.has_value());
334 EXPECT_THAT(stats->unknown_ftrace_events(),
335 UnorderedElementsAreArray(
336 {"sched/does_not_exist", "foobar/i_just_made_this_up"}));
337
338 // Atrace is not available on Linux and on the O-based emulator on the CI.
339 if (base::FileExists("/system/bin/atrace")) {
340 EXPECT_THAT(stats->atrace_errors(), HasSubstr("madeup_atrace_cat"));
341 }
342}
343
Primiano Tucci401a4732022-01-19 00:26:49 +0000344} // namespace perfetto
345#endif // OS_ANDROID || OS_LINUX