1 /*
2 * Copyright (C) 2018 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 <cstdint>
18 #include <cstdio>
19 #include <cstring>
20 #include <memory>
21 #include <random>
22 #include <string>
23 #include <utility>
24 #include <vector>
25
26 #include "perfetto/base/build_config.h"
27 #include "perfetto/base/logging.h"
28 #include "perfetto/base/status.h"
29 #include "perfetto/ext/base/scoped_file.h"
30 #include "perfetto/ext/base/string_utils.h"
31 #include "perfetto/trace_processor/basic_types.h"
32 #include "perfetto/trace_processor/iterator.h"
33 #include "perfetto/trace_processor/status.h"
34 #include "perfetto/trace_processor/trace_blob.h"
35 #include "perfetto/trace_processor/trace_blob_view.h"
36 #include "perfetto/trace_processor/trace_processor.h"
37 #include "protos/perfetto/common/descriptor.pbzero.h"
38 #include "protos/perfetto/trace_processor/trace_processor.pbzero.h"
39
40 #include "src/base/test/status_matchers.h"
41 #include "src/base/test/utils.h"
42 #include "test/gtest_and_gmock.h"
43
44 namespace perfetto::trace_processor {
45 namespace {
46
47 using testing::HasSubstr;
48
49 constexpr size_t kMaxChunkSize = 4ul * 1024 * 1024;
50
TEST(TraceProcessorCustomConfigTest,SkipInternalMetricsMatchingMountPath)51 TEST(TraceProcessorCustomConfigTest, SkipInternalMetricsMatchingMountPath) {
52 auto config = Config();
53 config.skip_builtin_metric_paths = {"android/"};
54 auto processor = TraceProcessor::CreateInstance(config);
55 ASSERT_OK(processor->NotifyEndOfFile());
56
57 // Check that andorid metrics have not been loaded.
58 auto it = processor->ExecuteQuery(
59 "select count(*) from trace_metrics "
60 "where name = 'android_cpu';");
61 ASSERT_TRUE(it.Next());
62 ASSERT_EQ(it.Get(0).type, SqlValue::kLong);
63 ASSERT_EQ(it.Get(0).long_value, 0);
64
65 // Check that other metrics have been loaded.
66 it = processor->ExecuteQuery(
67 "select count(*) from trace_metrics "
68 "where name = 'trace_metadata';");
69 ASSERT_TRUE(it.Next());
70 ASSERT_EQ(it.Get(0).type, SqlValue::kLong);
71 ASSERT_EQ(it.Get(0).long_value, 1);
72 }
73
TEST(TraceProcessorCustomConfigTest,EmptyStringSkipsAllMetrics)74 TEST(TraceProcessorCustomConfigTest, EmptyStringSkipsAllMetrics) {
75 auto config = Config();
76 config.skip_builtin_metric_paths = {""};
77 auto processor = TraceProcessor::CreateInstance(config);
78 ASSERT_OK(processor->NotifyEndOfFile());
79
80 // Check that other metrics have been loaded.
81 auto it = processor->ExecuteQuery(
82 "select count(*) from trace_metrics "
83 "where name = 'trace_metadata';");
84 ASSERT_TRUE(it.Next());
85 ASSERT_EQ(it.Get(0).type, SqlValue::kLong);
86 ASSERT_EQ(it.Get(0).long_value, 0);
87 }
88
TEST(TraceProcessorCustomConfigTest,HandlesMalformedMountPath)89 TEST(TraceProcessorCustomConfigTest, HandlesMalformedMountPath) {
90 auto config = Config();
91 config.skip_builtin_metric_paths = {"androi"};
92 auto processor = TraceProcessor::CreateInstance(config);
93 ASSERT_OK(processor->NotifyEndOfFile());
94
95 // Check that andorid metrics have been loaded.
96 auto it = processor->ExecuteQuery(
97 "select count(*) from trace_metrics "
98 "where name = 'android_cpu';");
99 ASSERT_TRUE(it.Next());
100 ASSERT_EQ(it.Get(0).type, SqlValue::kLong);
101 ASSERT_EQ(it.Get(0).long_value, 1);
102 }
103
104 class TraceProcessorIntegrationTest : public ::testing::Test {
105 public:
TraceProcessorIntegrationTest()106 TraceProcessorIntegrationTest()
107 : processor_(TraceProcessor::CreateInstance(Config())) {}
108
109 protected:
LoadTrace(const char * name,size_t min_chunk_size=512,size_t max_chunk_size=kMaxChunkSize)110 base::Status LoadTrace(const char* name,
111 size_t min_chunk_size = 512,
112 size_t max_chunk_size = kMaxChunkSize) {
113 EXPECT_LE(min_chunk_size, max_chunk_size);
114 base::ScopedFstream f(
115 fopen(base::GetTestDataPath(std::string("test/data/") + name).c_str(),
116 "rbe"));
117 std::minstd_rand0 rnd_engine(0);
118 std::uniform_int_distribution<size_t> dist(min_chunk_size, max_chunk_size);
119 while (!feof(*f)) {
120 size_t chunk_size = dist(rnd_engine);
121 std::unique_ptr<uint8_t[]> buf(new uint8_t[chunk_size]);
122 auto rsize = fread(reinterpret_cast<char*>(buf.get()), 1, chunk_size, *f);
123 auto status = processor_->Parse(std::move(buf), rsize);
124 if (!status.ok())
125 return status;
126 }
127 return NotifyEndOfFile();
128 }
NotifyEndOfFile()129 base::Status NotifyEndOfFile() { return processor_->NotifyEndOfFile(); }
130
Query(const std::string & query)131 Iterator Query(const std::string& query) {
132 return processor_->ExecuteQuery(query);
133 }
134
Processor()135 TraceProcessor* Processor() { return processor_.get(); }
136
RestoreInitialTables()137 size_t RestoreInitialTables() { return processor_->RestoreInitialTables(); }
138
139 private:
140 std::unique_ptr<TraceProcessor> processor_;
141 };
142
TEST_F(TraceProcessorIntegrationTest,AndroidSchedAndPs)143 TEST_F(TraceProcessorIntegrationTest, AndroidSchedAndPs) {
144 ASSERT_TRUE(LoadTrace("android_sched_and_ps.pb").ok());
145 auto it = Query(
146 "select count(*), max(ts) - min(ts) from sched "
147 "where dur != 0 and utid != 0");
148 ASSERT_TRUE(it.Next());
149 ASSERT_EQ(it.Get(0).type, SqlValue::kLong);
150 ASSERT_EQ(it.Get(0).long_value, 139793);
151 ASSERT_EQ(it.Get(1).type, SqlValue::kLong);
152 ASSERT_EQ(it.Get(1).long_value, 19684308497);
153 ASSERT_FALSE(it.Next());
154 }
155
TEST_F(TraceProcessorIntegrationTest,TraceBounds)156 TEST_F(TraceProcessorIntegrationTest, TraceBounds) {
157 ASSERT_TRUE(LoadTrace("android_sched_and_ps.pb").ok());
158 auto it = Query("select start_ts, end_ts from trace_bounds");
159 ASSERT_TRUE(it.Next());
160 ASSERT_EQ(it.Get(0).type, SqlValue::kLong);
161 ASSERT_EQ(it.Get(0).long_value, 81473009948313);
162 ASSERT_EQ(it.Get(1).type, SqlValue::kLong);
163 ASSERT_EQ(it.Get(1).long_value, 81492700784311);
164 ASSERT_FALSE(it.Next());
165 }
166
167 // Tests that the duration of the last slice is accounted in the computation
168 // of the trace boundaries. Linux ftraces tend to hide this problem because
169 // after the last sched_switch there's always a "wake" event which causes the
170 // raw table to fix the bounds.
TEST_F(TraceProcessorIntegrationTest,TraceBoundsUserspaceOnly)171 TEST_F(TraceProcessorIntegrationTest, TraceBoundsUserspaceOnly) {
172 ASSERT_TRUE(LoadTrace("sfgate.json").ok());
173 auto it = Query("select start_ts, end_ts from trace_bounds");
174 ASSERT_TRUE(it.Next());
175 ASSERT_EQ(it.Get(0).type, SqlValue::kLong);
176 ASSERT_EQ(it.Get(0).long_value, 2213649212614000);
177 ASSERT_EQ(it.Get(1).type, SqlValue::kLong);
178 ASSERT_EQ(it.Get(1).long_value, 2213689745140000);
179 ASSERT_FALSE(it.Next());
180 }
181
TEST_F(TraceProcessorIntegrationTest,Hash)182 TEST_F(TraceProcessorIntegrationTest, Hash) {
183 auto it = Query("select HASH()");
184 ASSERT_TRUE(it.Next());
185 ASSERT_EQ(it.Get(0).long_value, static_cast<int64_t>(0xcbf29ce484222325));
186
187 it = Query("select HASH('test')");
188 ASSERT_TRUE(it.Next());
189 ASSERT_EQ(it.Get(0).long_value, static_cast<int64_t>(0xf9e6e6ef197c2b25));
190
191 it = Query("select HASH('test', 1)");
192 ASSERT_TRUE(it.Next());
193 ASSERT_EQ(it.Get(0).long_value, static_cast<int64_t>(0xa9cb070fdc15f7a4));
194 }
195
196 #if !PERFETTO_BUILDFLAG(PERFETTO_LLVM_DEMANGLE) && \
197 !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
198 #define MAYBE_Demangle DISABLED_Demangle
199 #else
200 #define MAYBE_Demangle Demangle
201 #endif
TEST_F(TraceProcessorIntegrationTest,MAYBE_Demangle)202 TEST_F(TraceProcessorIntegrationTest, MAYBE_Demangle) {
203 auto it = Query("select DEMANGLE('_Znwm')");
204 ASSERT_TRUE(it.Next());
205 EXPECT_STRCASEEQ(it.Get(0).string_value, "operator new(unsigned long)");
206
207 it = Query("select DEMANGLE('_ZN3art6Thread14CreateCallbackEPv')");
208 ASSERT_TRUE(it.Next());
209 EXPECT_STRCASEEQ(it.Get(0).string_value,
210 "art::Thread::CreateCallback(void*)");
211
212 it = Query("select DEMANGLE('test')");
213 ASSERT_TRUE(it.Next());
214 EXPECT_TRUE(it.Get(0).is_null());
215 }
216
217 #if !PERFETTO_BUILDFLAG(PERFETTO_LLVM_DEMANGLE)
218 #define MAYBE_DemangleRust DISABLED_DemangleRust
219 #else
220 #define MAYBE_DemangleRust DemangleRust
221 #endif
TEST_F(TraceProcessorIntegrationTest,MAYBE_DemangleRust)222 TEST_F(TraceProcessorIntegrationTest, MAYBE_DemangleRust) {
223 auto it = Query(
224 "select DEMANGLE("
225 "'_RNvNvMs0_NtNtNtCsg1Z12QU66Yk_3std3sys4unix6threadNtB7_"
226 "6Thread3new12thread_start')");
227 ASSERT_TRUE(it.Next());
228 EXPECT_STRCASEEQ(it.Get(0).string_value,
229 "<std::sys::unix::thread::Thread>::new::thread_start");
230
231 it = Query("select DEMANGLE('_RNvCsdV139EorvfX_14keystore2_main4main')");
232 ASSERT_TRUE(it.Next());
233 ASSERT_STRCASEEQ(it.Get(0).string_value, "keystore2_main::main");
234
235 it = Query("select DEMANGLE('_R')");
236 ASSERT_TRUE(it.Next());
237 ASSERT_TRUE(it.Get(0).is_null());
238 }
239
240 #if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
TEST_F(TraceProcessorIntegrationTest,Sfgate)241 TEST_F(TraceProcessorIntegrationTest, Sfgate) {
242 ASSERT_TRUE(LoadTrace("sfgate.json", strlen("{\"traceEvents\":[")).ok());
243 auto it = Query(
244 "select count(*), max(ts) - min(ts) "
245 "from slice s inner join thread_track t "
246 "on s.track_id = t.id where utid != 0");
247 ASSERT_TRUE(it.Next());
248 ASSERT_EQ(it.Get(0).type, SqlValue::kLong);
249 ASSERT_EQ(it.Get(0).long_value, 43357);
250 ASSERT_EQ(it.Get(1).type, SqlValue::kLong);
251 ASSERT_EQ(it.Get(1).long_value, 40532506000);
252 ASSERT_FALSE(it.Next());
253 }
254
TEST_F(TraceProcessorIntegrationTest,UnsortedTrace)255 TEST_F(TraceProcessorIntegrationTest, UnsortedTrace) {
256 ASSERT_TRUE(
257 LoadTrace("unsorted_trace.json", strlen("{\"traceEvents\":[")).ok());
258 auto it = Query("select ts, depth from slice order by ts");
259 ASSERT_TRUE(it.Next());
260 ASSERT_EQ(it.Get(0).type, SqlValue::kLong);
261 ASSERT_EQ(it.Get(0).long_value, 50000);
262 ASSERT_EQ(it.Get(1).type, SqlValue::kLong);
263 ASSERT_EQ(it.Get(1).long_value, 0);
264 ASSERT_TRUE(it.Next());
265 ASSERT_EQ(it.Get(0).type, SqlValue::kLong);
266 ASSERT_EQ(it.Get(0).long_value, 100000);
267 ASSERT_EQ(it.Get(1).type, SqlValue::kLong);
268 ASSERT_EQ(it.Get(1).long_value, 1);
269 ASSERT_FALSE(it.Next());
270 }
271
TEST_F(TraceProcessorIntegrationTest,SerializeMetricDescriptors)272 TEST_F(TraceProcessorIntegrationTest, SerializeMetricDescriptors) {
273 std::vector<uint8_t> desc_set_bytes = Processor()->GetMetricDescriptors();
274 protos::pbzero::DescriptorSet::Decoder desc_set(desc_set_bytes.data(),
275 desc_set_bytes.size());
276
277 ASSERT_TRUE(desc_set.has_descriptors());
278 int trace_metrics_count = 0;
279 for (auto desc = desc_set.descriptors(); desc; ++desc) {
280 protos::pbzero::DescriptorProto::Decoder proto_desc(*desc);
281 if (proto_desc.name().ToStdString() == ".perfetto.protos.TraceMetrics") {
282 ASSERT_TRUE(proto_desc.has_field());
283 trace_metrics_count++;
284 }
285 }
286
287 // There should be exactly one definition of TraceMetrics. This can be not
288 // true if we're not deduping descriptors properly.
289 ASSERT_EQ(trace_metrics_count, 1);
290 }
291
TEST_F(TraceProcessorIntegrationTest,ComputeMetricsFormattedExtension)292 TEST_F(TraceProcessorIntegrationTest, ComputeMetricsFormattedExtension) {
293 ASSERT_OK(NotifyEndOfFile());
294
295 std::string metric_output;
296 base::Status status = Processor()->ComputeMetricText(
297 std::vector<std::string>{"test_chrome_metric"},
298 TraceProcessor::MetricResultFormat::kProtoText, &metric_output);
299 ASSERT_TRUE(status.ok());
300 // Extension fields are output as [fully.qualified.name].
301 ASSERT_EQ(metric_output,
302 "[perfetto.protos.test_chrome_metric] {\n"
303 " test_value: 1\n"
304 "}");
305 }
306
TEST_F(TraceProcessorIntegrationTest,ComputeMetricsFormattedNoExtension)307 TEST_F(TraceProcessorIntegrationTest, ComputeMetricsFormattedNoExtension) {
308 ASSERT_OK(NotifyEndOfFile());
309
310 std::string metric_output;
311 ASSERT_OK(Processor()->ComputeMetricText(
312 std::vector<std::string>{"trace_metadata"},
313 TraceProcessor::MetricResultFormat::kProtoText, &metric_output));
314 // Check that metric result starts with trace_metadata field. Since this is
315 // not an extension field, the field name is not fully qualified.
316 ASSERT_TRUE(metric_output.rfind("trace_metadata {") == 0);
317 }
318
319 // TODO(hjd): Add trace to test_data.
TEST_F(TraceProcessorIntegrationTest,DISABLED_AndroidBuildTrace)320 TEST_F(TraceProcessorIntegrationTest, DISABLED_AndroidBuildTrace) {
321 ASSERT_TRUE(LoadTrace("android_build_trace.json", strlen("[\n{")).ok());
322 }
323
TEST_F(TraceProcessorIntegrationTest,DISABLED_Clusterfuzz14357)324 TEST_F(TraceProcessorIntegrationTest, DISABLED_Clusterfuzz14357) {
325 ASSERT_FALSE(LoadTrace("clusterfuzz_14357", 4096).ok());
326 }
327 #endif // PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
328
TEST_F(TraceProcessorIntegrationTest,Clusterfuzz14730)329 TEST_F(TraceProcessorIntegrationTest, Clusterfuzz14730) {
330 ASSERT_TRUE(LoadTrace("clusterfuzz_14730", 4096).ok());
331 }
332
TEST_F(TraceProcessorIntegrationTest,Clusterfuzz14753)333 TEST_F(TraceProcessorIntegrationTest, Clusterfuzz14753) {
334 ASSERT_TRUE(LoadTrace("clusterfuzz_14753", 4096).ok());
335 }
336
TEST_F(TraceProcessorIntegrationTest,Clusterfuzz14762)337 TEST_F(TraceProcessorIntegrationTest, Clusterfuzz14762) {
338 ASSERT_TRUE(LoadTrace("clusterfuzz_14762", 4096ul * 1024).ok());
339 auto it = Query("select sum(value) from stats where severity = 'error';");
340 ASSERT_TRUE(it.Next());
341 ASSERT_GT(it.Get(0).long_value, 0);
342 }
343
TEST_F(TraceProcessorIntegrationTest,Clusterfuzz14767)344 TEST_F(TraceProcessorIntegrationTest, Clusterfuzz14767) {
345 ASSERT_TRUE(LoadTrace("clusterfuzz_14767", 4096ul * 1024).ok());
346 auto it = Query("select sum(value) from stats where severity = 'error';");
347 ASSERT_TRUE(it.Next());
348 ASSERT_GT(it.Get(0).long_value, 0);
349 }
350
TEST_F(TraceProcessorIntegrationTest,Clusterfuzz14799)351 TEST_F(TraceProcessorIntegrationTest, Clusterfuzz14799) {
352 ASSERT_TRUE(LoadTrace("clusterfuzz_14799", 4096ul * 1024).ok());
353 auto it = Query("select sum(value) from stats where severity = 'error';");
354 ASSERT_TRUE(it.Next());
355 ASSERT_GT(it.Get(0).long_value, 0);
356 }
357
TEST_F(TraceProcessorIntegrationTest,Clusterfuzz15252)358 TEST_F(TraceProcessorIntegrationTest, Clusterfuzz15252) {
359 ASSERT_TRUE(LoadTrace("clusterfuzz_15252", 4096).ok());
360 }
361
TEST_F(TraceProcessorIntegrationTest,Clusterfuzz17805)362 TEST_F(TraceProcessorIntegrationTest, Clusterfuzz17805) {
363 // This trace is garbage but is detected as a systrace. However, it should
364 // still parse successfully as we try to be graceful with encountering random
365 // data in systrace as they can have arbitrary print events from the kernel.
366 ASSERT_TRUE(LoadTrace("clusterfuzz_17805", 4096).ok());
367 }
368
369 // Failing on DCHECKs during import because the traces aren't really valid.
370 #if PERFETTO_DCHECK_IS_ON()
371 #define MAYBE_Clusterfuzz20215 DISABLED_Clusterfuzz20215
372 #define MAYBE_Clusterfuzz20292 DISABLED_Clusterfuzz20292
373 #define MAYBE_Clusterfuzz21178 DISABLED_Clusterfuzz21178
374 #define MAYBE_Clusterfuzz21890 DISABLED_Clusterfuzz21890
375 #define MAYBE_Clusterfuzz23053 DISABLED_Clusterfuzz23053
376 #define MAYBE_Clusterfuzz28338 DISABLED_Clusterfuzz28338
377 #define MAYBE_Clusterfuzz28766 DISABLED_Clusterfuzz28766
378 #else // PERFETTO_DCHECK_IS_ON()
379 #define MAYBE_Clusterfuzz20215 Clusterfuzz20215
380 #define MAYBE_Clusterfuzz20292 Clusterfuzz20292
381 #define MAYBE_Clusterfuzz21178 Clusterfuzz21178
382 #define MAYBE_Clusterfuzz21890 Clusterfuzz21890
383 #define MAYBE_Clusterfuzz23053 Clusterfuzz23053
384 #define MAYBE_Clusterfuzz28338 Clusterfuzz28338
385 #define MAYBE_Clusterfuzz28766 Clusterfuzz28766
386 #endif // PERFETTO_DCHECK_IS_ON()
387
TEST_F(TraceProcessorIntegrationTest,MAYBE_Clusterfuzz20215)388 TEST_F(TraceProcessorIntegrationTest, MAYBE_Clusterfuzz20215) {
389 ASSERT_TRUE(LoadTrace("clusterfuzz_20215", 4096).ok());
390 }
391
TEST_F(TraceProcessorIntegrationTest,MAYBE_Clusterfuzz20292)392 TEST_F(TraceProcessorIntegrationTest, MAYBE_Clusterfuzz20292) {
393 ASSERT_FALSE(LoadTrace("clusterfuzz_20292", 4096).ok());
394 }
395
TEST_F(TraceProcessorIntegrationTest,MAYBE_Clusterfuzz21178)396 TEST_F(TraceProcessorIntegrationTest, MAYBE_Clusterfuzz21178) {
397 ASSERT_TRUE(LoadTrace("clusterfuzz_21178", 4096).ok());
398 }
399
TEST_F(TraceProcessorIntegrationTest,MAYBE_Clusterfuzz21890)400 TEST_F(TraceProcessorIntegrationTest, MAYBE_Clusterfuzz21890) {
401 ASSERT_FALSE(LoadTrace("clusterfuzz_21890", 4096).ok());
402 }
403
TEST_F(TraceProcessorIntegrationTest,MAYBE_Clusterfuzz23053)404 TEST_F(TraceProcessorIntegrationTest, MAYBE_Clusterfuzz23053) {
405 ASSERT_FALSE(LoadTrace("clusterfuzz_23053", 4096).ok());
406 }
407
TEST_F(TraceProcessorIntegrationTest,MAYBE_Clusterfuzz28338)408 TEST_F(TraceProcessorIntegrationTest, MAYBE_Clusterfuzz28338) {
409 ASSERT_TRUE(LoadTrace("clusterfuzz_28338", 4096).ok());
410 }
411
TEST_F(TraceProcessorIntegrationTest,MAYBE_Clusterfuzz28766)412 TEST_F(TraceProcessorIntegrationTest, MAYBE_Clusterfuzz28766) {
413 ASSERT_TRUE(LoadTrace("clusterfuzz_28766", 4096).ok());
414 }
415
TEST_F(TraceProcessorIntegrationTest,RestoreInitialTablesInvariant)416 TEST_F(TraceProcessorIntegrationTest, RestoreInitialTablesInvariant) {
417 ASSERT_OK(NotifyEndOfFile());
418 uint64_t first_restore = RestoreInitialTables();
419 ASSERT_EQ(RestoreInitialTables(), first_restore);
420 }
421
TEST_F(TraceProcessorIntegrationTest,RestoreInitialTablesPerfettoSql)422 TEST_F(TraceProcessorIntegrationTest, RestoreInitialTablesPerfettoSql) {
423 ASSERT_OK(NotifyEndOfFile());
424 RestoreInitialTables();
425
426 for (int repeat = 0; repeat < 3; repeat++) {
427 ASSERT_EQ(RestoreInitialTables(), 0u);
428
429 // 1. Perfetto table
430 {
431 auto it = Query("CREATE PERFETTO TABLE obj1 AS SELECT 1 AS col;");
432 it.Next();
433 ASSERT_TRUE(it.Status().ok());
434 }
435 // 2. Perfetto view
436 {
437 auto it = Query("CREATE PERFETTO VIEW obj2 AS SELECT * FROM stats;");
438 it.Next();
439 ASSERT_TRUE(it.Status().ok());
440 }
441 // 3. Runtime function
442 {
443 auto it =
444 Query("CREATE PERFETTO FUNCTION obj3() RETURNS INT AS SELECT 1;");
445 it.Next();
446 ASSERT_TRUE(it.Status().ok());
447 }
448 // 4. Runtime table function
449 {
450 auto it = Query(
451 "CREATE PERFETTO FUNCTION obj4() RETURNS TABLE(col INT) AS SELECT 1 "
452 "AS col;");
453 it.Next();
454 ASSERT_TRUE(it.Status().ok());
455 }
456 // 5. Macro
457 {
458 auto it = Query("CREATE PERFETTO MACRO obj5(a Expr) returns Expr AS $a;");
459 it.Next();
460 ASSERT_TRUE(it.Status().ok());
461 }
462 {
463 auto it = Query("obj5!(SELECT 1);");
464 it.Next();
465 ASSERT_TRUE(it.Status().ok());
466 }
467 ASSERT_EQ(RestoreInitialTables(), 5u);
468 }
469 }
470
TEST_F(TraceProcessorIntegrationTest,RestoreInitialTablesStandardSqlite)471 TEST_F(TraceProcessorIntegrationTest, RestoreInitialTablesStandardSqlite) {
472 ASSERT_OK(NotifyEndOfFile());
473 RestoreInitialTables();
474
475 for (int repeat = 0; repeat < 3; repeat++) {
476 ASSERT_EQ(RestoreInitialTables(), 0u);
477 {
478 auto it = Query("CREATE TABLE obj1(unused text);");
479 it.Next();
480 ASSERT_TRUE(it.Status().ok());
481 }
482 {
483 auto it = Query("CREATE TEMPORARY TABLE obj2(unused text);");
484 it.Next();
485 ASSERT_TRUE(it.Status().ok());
486 }
487 // Add a view
488 {
489 auto it = Query("CREATE VIEW obj3 AS SELECT * FROM stats;");
490 it.Next();
491 ASSERT_TRUE(it.Status().ok());
492 }
493 ASSERT_EQ(RestoreInitialTables(), 3u);
494 }
495 }
496
TEST_F(TraceProcessorIntegrationTest,RestoreInitialTablesModules)497 TEST_F(TraceProcessorIntegrationTest, RestoreInitialTablesModules) {
498 ASSERT_OK(NotifyEndOfFile());
499 RestoreInitialTables();
500
501 for (int repeat = 0; repeat < 3; repeat++) {
502 ASSERT_EQ(RestoreInitialTables(), 0u);
503 {
504 auto it = Query("INCLUDE PERFETTO MODULE time.conversion;");
505 it.Next();
506 ASSERT_TRUE(it.Status().ok());
507 }
508 {
509 auto it = Query("SELECT trace_start();");
510 it.Next();
511 ASSERT_TRUE(it.Status().ok());
512 }
513 RestoreInitialTables();
514 }
515 }
516
TEST_F(TraceProcessorIntegrationTest,RestoreInitialTablesSpanJoin)517 TEST_F(TraceProcessorIntegrationTest, RestoreInitialTablesSpanJoin) {
518 ASSERT_OK(NotifyEndOfFile());
519 RestoreInitialTables();
520
521 for (int repeat = 0; repeat < 3; repeat++) {
522 ASSERT_EQ(RestoreInitialTables(), 0u);
523 {
524 auto it = Query(
525 "CREATE TABLE t1(ts BIGINT, dur BIGINT, PRIMARY KEY (ts, dur)) "
526 "WITHOUT ROWID;");
527 it.Next();
528 ASSERT_TRUE(it.Status().ok());
529 }
530 {
531 auto it = Query(
532 "CREATE TABLE t2(ts BIGINT, dur BIGINT, PRIMARY KEY (ts, dur)) "
533 "WITHOUT ROWID;");
534 it.Next();
535 ASSERT_TRUE(it.Status().ok());
536 }
537 {
538 auto it = Query("INSERT INTO t2(ts, dur) VALUES(1, 2), (5, 0), (1, 1);");
539 it.Next();
540 ASSERT_TRUE(it.Status().ok());
541 }
542 {
543 auto it = Query("CREATE VIRTUAL TABLE sp USING span_join(t1, t2);;");
544 it.Next();
545 ASSERT_TRUE(it.Status().ok());
546 }
547 {
548 auto it = Query("SELECT ts, dur FROM sp;");
549 it.Next();
550 ASSERT_TRUE(it.Status().ok());
551 }
552 ASSERT_EQ(RestoreInitialTables(), 3u);
553 }
554 }
555
TEST_F(TraceProcessorIntegrationTest,RestoreInitialTablesWithClause)556 TEST_F(TraceProcessorIntegrationTest, RestoreInitialTablesWithClause) {
557 ASSERT_OK(NotifyEndOfFile());
558 RestoreInitialTables();
559
560 for (int repeat = 0; repeat < 3; repeat++) {
561 ASSERT_EQ(RestoreInitialTables(), 0u);
562 {
563 auto it = Query(
564 "CREATE PERFETTO TABLE foo AS WITH bar AS (SELECT * FROM slice) "
565 "SELECT ts FROM bar;");
566 it.Next();
567 ASSERT_TRUE(it.Status().ok());
568 }
569 ASSERT_EQ(RestoreInitialTables(), 1u);
570 }
571 }
572
TEST_F(TraceProcessorIntegrationTest,RestoreInitialTablesIndex)573 TEST_F(TraceProcessorIntegrationTest, RestoreInitialTablesIndex) {
574 ASSERT_OK(NotifyEndOfFile());
575 RestoreInitialTables();
576
577 for (int repeat = 0; repeat < 3; repeat++) {
578 ASSERT_EQ(RestoreInitialTables(), 0u);
579 {
580 auto it = Query("CREATE TABLE foo AS SELECT * FROM slice;");
581 it.Next();
582 ASSERT_TRUE(it.Status().ok());
583 }
584 {
585 auto it = Query("CREATE INDEX ind ON foo (ts, track_id);");
586 it.Next();
587 ASSERT_TRUE(it.Status().ok());
588 }
589 ASSERT_EQ(RestoreInitialTables(), 2u);
590 }
591 }
592
TEST_F(TraceProcessorIntegrationTest,RestoreInitialTablesTraceBounds)593 TEST_F(TraceProcessorIntegrationTest, RestoreInitialTablesTraceBounds) {
594 ASSERT_TRUE(LoadTrace("android_sched_and_ps.pb").ok());
595 {
596 auto it = Query("SELECT * from trace_bounds;");
597 it.Next();
598 ASSERT_TRUE(it.Status().ok());
599 ASSERT_EQ(it.Get(0).AsLong(), 81473009948313l);
600 }
601
602 ASSERT_EQ(RestoreInitialTables(), 0u);
603 {
604 auto it = Query("SELECT * from trace_bounds;");
605 it.Next();
606 ASSERT_TRUE(it.Status().ok());
607 ASSERT_EQ(it.Get(0).AsLong(), 81473009948313l);
608 }
609 }
610
TEST_F(TraceProcessorIntegrationTest,RestoreInitialTablesDependents)611 TEST_F(TraceProcessorIntegrationTest, RestoreInitialTablesDependents) {
612 ASSERT_OK(NotifyEndOfFile());
613 {
614 auto it = Query("create perfetto table foo as select 1 as x");
615 ASSERT_FALSE(it.Next());
616 ASSERT_TRUE(it.Status().ok());
617
618 it = Query("create perfetto function f() returns INT as select * from foo");
619 ASSERT_FALSE(it.Next());
620 ASSERT_TRUE(it.Status().ok());
621
622 it = Query("SELECT f()");
623 ASSERT_TRUE(it.Next());
624 ASSERT_FALSE(it.Next());
625 ASSERT_TRUE(it.Status().ok());
626 }
627
628 ASSERT_EQ(RestoreInitialTables(), 2u);
629 }
630
TEST_F(TraceProcessorIntegrationTest,RestoreDependentFunction)631 TEST_F(TraceProcessorIntegrationTest, RestoreDependentFunction) {
632 ASSERT_OK(NotifyEndOfFile());
633 {
634 auto it =
635 Query("create perfetto function foo0() returns INT as select 1 as x");
636 ASSERT_FALSE(it.Next());
637 ASSERT_TRUE(it.Status().ok());
638 }
639 for (int i = 1; i < 100; ++i) {
640 base::StackString<1024> sql(
641 "create perfetto function foo%d() returns INT as select foo%d()", i,
642 i - 1);
643 auto it = Query(sql.c_str());
644 ASSERT_FALSE(it.Next());
645 ASSERT_TRUE(it.Status().ok()) << it.Status().c_message();
646 }
647
648 ASSERT_EQ(RestoreInitialTables(), 100u);
649 }
650
TEST_F(TraceProcessorIntegrationTest,RestoreDependentTableFunction)651 TEST_F(TraceProcessorIntegrationTest, RestoreDependentTableFunction) {
652 ASSERT_OK(NotifyEndOfFile());
653 {
654 auto it = Query(
655 "create perfetto function foo0() returns TABLE(x INT) "
656 " as select 1 as x");
657 ASSERT_FALSE(it.Next());
658 ASSERT_TRUE(it.Status().ok());
659 }
660 for (int i = 1; i < 100; ++i) {
661 base::StackString<1024> sql(
662 "create perfetto function foo%d() returns TABLE(x INT) "
663 " as select * from foo%d()",
664 i, i - 1);
665 auto it = Query(sql.c_str());
666 ASSERT_FALSE(it.Next());
667 ASSERT_TRUE(it.Status().ok()) << it.Status().c_message();
668 }
669
670 ASSERT_EQ(RestoreInitialTables(), 100u);
671 }
672
673 // This test checks that a ninja trace is tokenized properly even if read in
674 // small chunks of 1KB each. The values used in the test have been cross-checked
675 // with opening the same trace with ninjatracing + chrome://tracing.
TEST_F(TraceProcessorIntegrationTest,NinjaLog)676 TEST_F(TraceProcessorIntegrationTest, NinjaLog) {
677 ASSERT_TRUE(LoadTrace("ninja_log", 1024).ok());
678 auto it = Query("select count(*) from process where name glob 'Build';");
679 ASSERT_TRUE(it.Next());
680 ASSERT_EQ(it.Get(0).long_value, 1);
681
682 it = Query(
683 "select count(*) from thread left join process using(upid) where "
684 "thread.name like 'Worker%' and process.pid=1");
685 ASSERT_TRUE(it.Next());
686 ASSERT_EQ(it.Get(0).long_value, 28);
687
688 it = Query(
689 "create view slices_1st_build as select slices.* from slices left "
690 "join thread_track on(slices.track_id == thread_track.id) left join "
691 "thread using(utid) left join process using(upid) where pid=1");
692 it.Next();
693 ASSERT_TRUE(it.Status().ok());
694
695 it = Query("select (max(ts) - min(ts)) / 1000000 from slices_1st_build");
696 ASSERT_TRUE(it.Next());
697 ASSERT_EQ(it.Get(0).long_value, 44697);
698
699 it = Query("select name from slices_1st_build order by ts desc limit 1");
700 ASSERT_TRUE(it.Next());
701 ASSERT_STREQ(it.Get(0).string_value, "trace_processor_shell");
702
703 it = Query("select sum(dur) / 1000000 from slices_1st_build");
704 ASSERT_TRUE(it.Next());
705 ASSERT_EQ(it.Get(0).long_value, 837192);
706 }
707
708 /*
709 * This trace does not have a uuid. The uuid will be generated from the first
710 * 4096 bytes, which will be read in one chunk.
711 */
TEST_F(TraceProcessorIntegrationTest,TraceWithoutUuidReadInOneChunk)712 TEST_F(TraceProcessorIntegrationTest, TraceWithoutUuidReadInOneChunk) {
713 ASSERT_TRUE(LoadTrace("example_android_trace_30s.pb", kMaxChunkSize).ok());
714 auto it = Query("select str_value from metadata where name = 'trace_uuid'");
715 ASSERT_TRUE(it.Next());
716 EXPECT_STREQ(it.Get(0).string_value, "00000000-0000-0000-8906-ebb53e1d0738");
717 }
718
719 /*
720 * This trace does not have a uuid. The uuid will be generated from the first
721 * 4096 bytes, which will be read in multiple chunks.
722 */
TEST_F(TraceProcessorIntegrationTest,TraceWithoutUuidReadInMultipleChuncks)723 TEST_F(TraceProcessorIntegrationTest, TraceWithoutUuidReadInMultipleChuncks) {
724 ASSERT_TRUE(LoadTrace("example_android_trace_30s.pb", 512, 2048).ok());
725 auto it = Query("select str_value from metadata where name = 'trace_uuid'");
726 ASSERT_TRUE(it.Next());
727 EXPECT_STREQ(it.Get(0).string_value, "00000000-0000-0000-8906-ebb53e1d0738");
728 }
729
730 /*
731 * This trace has a uuid. It will not be overriden by the hash of the first 4096
732 * bytes.
733 */
TEST_F(TraceProcessorIntegrationTest,TraceWithUuidReadInParts)734 TEST_F(TraceProcessorIntegrationTest, TraceWithUuidReadInParts) {
735 ASSERT_TRUE(LoadTrace("trace_with_uuid.pftrace", 512, 2048).ok());
736 auto it = Query("select str_value from metadata where name = 'trace_uuid'");
737 ASSERT_TRUE(it.Next());
738 EXPECT_STREQ(it.Get(0).string_value, "123e4567-e89b-12d3-a456-426655443322");
739 }
740
TEST_F(TraceProcessorIntegrationTest,ErrorMessageExecuteQuery)741 TEST_F(TraceProcessorIntegrationTest, ErrorMessageExecuteQuery) {
742 ASSERT_OK(NotifyEndOfFile());
743 auto it = Query("select t from slice");
744 ASSERT_FALSE(it.Next());
745 ASSERT_FALSE(it.Status().ok());
746
747 ASSERT_THAT(it.Status().message(),
748 testing::Eq(R"(Traceback (most recent call last):
749 File "stdin" line 1 col 8
750 select t from slice
751 ^
752 no such column: t)"));
753 }
754
TEST_F(TraceProcessorIntegrationTest,ErrorMessageMetricFile)755 TEST_F(TraceProcessorIntegrationTest, ErrorMessageMetricFile) {
756 ASSERT_OK(NotifyEndOfFile());
757 ASSERT_TRUE(
758 Processor()->RegisterMetric("foo/bar.sql", "select t from slice").ok());
759
760 auto it = Query("select RUN_METRIC('foo/bar.sql');");
761 ASSERT_FALSE(it.Next());
762 ASSERT_FALSE(it.Status().ok());
763
764 ASSERT_EQ(it.Status().message(),
765 R"(Traceback (most recent call last):
766 File "stdin" line 1 col 1
767 select RUN_METRIC('foo/bar.sql');
768 ^
769 Metric file "foo/bar.sql" line 1 col 8
770 select t from slice
771 ^
772 no such column: t)");
773 }
774
TEST_F(TraceProcessorIntegrationTest,ErrorMessageModule)775 TEST_F(TraceProcessorIntegrationTest, ErrorMessageModule) {
776 ASSERT_OK(NotifyEndOfFile());
777 SqlPackage module;
778 module.name = "foo";
779 module.modules.push_back(std::make_pair("foo.bar", "select t from slice"));
780
781 ASSERT_TRUE(Processor()->RegisterSqlPackage(module).ok());
782
783 auto it = Query("include perfetto module foo.bar;");
784 ASSERT_FALSE(it.Next());
785 ASSERT_FALSE(it.Status().ok());
786
787 ASSERT_EQ(it.Status().message(),
788 R"(Traceback (most recent call last):
789 File "stdin" line 1 col 1
790 include perfetto module foo.bar
791 ^
792 Module include "foo.bar" line 1 col 8
793 select t from slice
794 ^
795 no such column: t)");
796 }
797
TEST_F(TraceProcessorIntegrationTest,FunctionRegistrationError)798 TEST_F(TraceProcessorIntegrationTest, FunctionRegistrationError) {
799 auto it =
800 Query("create perfetto function f() returns INT as select * from foo");
801 ASSERT_FALSE(it.Next());
802 ASSERT_FALSE(it.Status().ok());
803
804 it = Query("SELECT foo()");
805 ASSERT_FALSE(it.Next());
806 ASSERT_FALSE(it.Status().ok());
807
808 it = Query("create perfetto function f() returns INT as select 1");
809 ASSERT_FALSE(it.Next());
810 ASSERT_TRUE(it.Status().ok());
811 }
812
TEST_F(TraceProcessorIntegrationTest,CreateTableDuplicateNames)813 TEST_F(TraceProcessorIntegrationTest, CreateTableDuplicateNames) {
814 auto it = Query(
815 "create perfetto table foo select 1 as duplicate_a, 2 as duplicate_a, 3 "
816 "as duplicate_b, 4 as duplicate_b");
817 ASSERT_FALSE(it.Next());
818 ASSERT_FALSE(it.Status().ok());
819 ASSERT_THAT(it.Status().message(), HasSubstr("duplicate_a"));
820 ASSERT_THAT(it.Status().message(), HasSubstr("duplicate_b"));
821 }
822
TEST_F(TraceProcessorIntegrationTest,InvalidTrace)823 TEST_F(TraceProcessorIntegrationTest, InvalidTrace) {
824 constexpr char kBadData[] = "\0\0\0\0";
825 EXPECT_FALSE(Processor()
826 ->Parse(TraceBlobView(
827 TraceBlob::CopyFrom(kBadData, sizeof(kBadData))))
828 .ok());
829 NotifyEndOfFile();
830 }
831
TEST_F(TraceProcessorIntegrationTest,NoNotifyEndOfFileCalled)832 TEST_F(TraceProcessorIntegrationTest, NoNotifyEndOfFileCalled) {
833 constexpr char kProtoData[] = "\x0a";
834 EXPECT_TRUE(Processor()
835 ->Parse(TraceBlobView(
836 TraceBlob::CopyFrom(kProtoData, sizeof(kProtoData))))
837 .ok());
838 }
839
840 } // namespace
841 } // namespace perfetto::trace_processor
842