• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/trace_processor/trace_processor_impl.h"
18 
19 #include <algorithm>
20 #include <cstdint>
21 #include <memory>
22 #include <string>
23 #include <type_traits>
24 #include <unordered_map>
25 
26 #include "perfetto/base/logging.h"
27 #include "perfetto/base/status.h"
28 #include "perfetto/base/time.h"
29 #include "perfetto/ext/base/flat_hash_map.h"
30 #include "perfetto/ext/base/scoped_file.h"
31 #include "perfetto/ext/base/string_splitter.h"
32 #include "perfetto/ext/base/string_utils.h"
33 #include "perfetto/trace_processor/basic_types.h"
34 #include "src/trace_processor/importers/android_bugreport/android_bugreport_parser.h"
35 #include "src/trace_processor/importers/common/clock_converter.h"
36 #include "src/trace_processor/importers/common/clock_tracker.h"
37 #include "src/trace_processor/importers/common/metadata_tracker.h"
38 #include "src/trace_processor/importers/ftrace/sched_event_tracker.h"
39 #include "src/trace_processor/importers/fuchsia/fuchsia_trace_parser.h"
40 #include "src/trace_processor/importers/fuchsia/fuchsia_trace_tokenizer.h"
41 #include "src/trace_processor/importers/gzip/gzip_trace_parser.h"
42 #include "src/trace_processor/importers/json/json_trace_parser.h"
43 #include "src/trace_processor/importers/json/json_trace_tokenizer.h"
44 #include "src/trace_processor/importers/json/json_utils.h"
45 #include "src/trace_processor/importers/ninja/ninja_log_parser.h"
46 #include "src/trace_processor/importers/proto/additional_modules.h"
47 #include "src/trace_processor/importers/proto/content_analyzer.h"
48 #include "src/trace_processor/importers/systrace/systrace_trace_parser.h"
49 #include "src/trace_processor/iterator_impl.h"
50 #include "src/trace_processor/prelude/functions/clock_functions.h"
51 #include "src/trace_processor/prelude/functions/create_function.h"
52 #include "src/trace_processor/prelude/functions/create_view_function.h"
53 #include "src/trace_processor/prelude/functions/import.h"
54 #include "src/trace_processor/prelude/functions/layout_functions.h"
55 #include "src/trace_processor/prelude/functions/pprof_functions.h"
56 #include "src/trace_processor/prelude/functions/sql_function.h"
57 #include "src/trace_processor/prelude/functions/sqlite3_str_split.h"
58 #include "src/trace_processor/prelude/functions/stack_functions.h"
59 #include "src/trace_processor/prelude/functions/to_ftrace.h"
60 #include "src/trace_processor/prelude/functions/utils.h"
61 #include "src/trace_processor/prelude/functions/window_functions.h"
62 #include "src/trace_processor/prelude/operators/span_join_operator.h"
63 #include "src/trace_processor/prelude/operators/window_operator.h"
64 #include "src/trace_processor/prelude/table_functions/ancestor.h"
65 #include "src/trace_processor/prelude/table_functions/connected_flow.h"
66 #include "src/trace_processor/prelude/table_functions/descendant.h"
67 #include "src/trace_processor/prelude/table_functions/experimental_annotated_stack.h"
68 #include "src/trace_processor/prelude/table_functions/experimental_counter_dur.h"
69 #include "src/trace_processor/prelude/table_functions/experimental_flamegraph.h"
70 #include "src/trace_processor/prelude/table_functions/experimental_flat_slice.h"
71 #include "src/trace_processor/prelude/table_functions/experimental_sched_upid.h"
72 #include "src/trace_processor/prelude/table_functions/experimental_slice_layout.h"
73 #include "src/trace_processor/prelude/table_functions/table_function.h"
74 #include "src/trace_processor/prelude/table_functions/view.h"
75 #include "src/trace_processor/prelude/tables_views/tables_views.h"
76 #include "src/trace_processor/sqlite/scoped_db.h"
77 #include "src/trace_processor/sqlite/sql_stats_table.h"
78 #include "src/trace_processor/sqlite/sqlite_table.h"
79 #include "src/trace_processor/sqlite/sqlite_utils.h"
80 #include "src/trace_processor/sqlite/stats_table.h"
81 #include "src/trace_processor/tp_metatrace.h"
82 #include "src/trace_processor/types/variadic.h"
83 #include "src/trace_processor/util/protozero_to_text.h"
84 #include "src/trace_processor/util/sql_modules.h"
85 #include "src/trace_processor/util/status_macros.h"
86 
87 #include "protos/perfetto/common/builtin_clock.pbzero.h"
88 #include "protos/perfetto/trace/clock_snapshot.pbzero.h"
89 #include "protos/perfetto/trace/perfetto/perfetto_metatrace.pbzero.h"
90 #include "protos/perfetto/trace/trace.pbzero.h"
91 #include "protos/perfetto/trace/trace_packet.pbzero.h"
92 
93 #include "src/trace_processor/metrics/all_chrome_metrics.descriptor.h"
94 #include "src/trace_processor/metrics/all_webview_metrics.descriptor.h"
95 #include "src/trace_processor/metrics/metrics.descriptor.h"
96 #include "src/trace_processor/metrics/metrics.h"
97 #include "src/trace_processor/metrics/sql/amalgamated_sql_metrics.h"
98 #include "src/trace_processor/stdlib/amalgamated_stdlib.h"
99 
100 namespace perfetto {
101 namespace trace_processor {
102 namespace {
103 
104 const char kAllTablesQuery[] =
105     "SELECT tbl_name, type FROM (SELECT * FROM sqlite_master UNION ALL SELECT "
106     "* FROM sqlite_temp_master)";
107 
108 template <typename SqlFunction, typename Ptr = typename SqlFunction::Context*>
RegisterFunction(SqliteEngine * engine,const char * name,int argc,Ptr context=nullptr,bool deterministic=true)109 void RegisterFunction(SqliteEngine* engine,
110                       const char* name,
111                       int argc,
112                       Ptr context = nullptr,
113                       bool deterministic = true) {
114   auto status = engine->RegisterSqlFunction<SqlFunction>(
115       name, argc, std::move(context), deterministic);
116   if (!status.ok())
117     PERFETTO_ELOG("%s", status.c_message());
118 }
119 
BuildBoundsTable(sqlite3 * db,std::pair<int64_t,int64_t> bounds)120 void BuildBoundsTable(sqlite3* db, std::pair<int64_t, int64_t> bounds) {
121   char* error = nullptr;
122   sqlite3_exec(db, "DELETE FROM trace_bounds", nullptr, nullptr, &error);
123   if (error) {
124     PERFETTO_ELOG("Error deleting from bounds table: %s", error);
125     sqlite3_free(error);
126     return;
127   }
128 
129   base::StackString<1024> sql("INSERT INTO trace_bounds VALUES(%" PRId64
130                               ", %" PRId64 ")",
131                               bounds.first, bounds.second);
132   sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &error);
133   if (error) {
134     PERFETTO_ELOG("Error inserting bounds table: %s", error);
135     sqlite3_free(error);
136   }
137 }
138 
139 struct ValueAtMaxTsContext {
140   bool initialized;
141   int value_type;
142 
143   int64_t max_ts;
144   int64_t int_value_at_max_ts;
145   double double_value_at_max_ts;
146 };
147 
ValueAtMaxTsStep(sqlite3_context * ctx,int,sqlite3_value ** argv)148 void ValueAtMaxTsStep(sqlite3_context* ctx, int, sqlite3_value** argv) {
149   sqlite3_value* ts = argv[0];
150   sqlite3_value* value = argv[1];
151 
152   // Note that sqlite3_aggregate_context zeros the memory for us so all the
153   // variables of the struct should be zero.
154   ValueAtMaxTsContext* fn_ctx = reinterpret_cast<ValueAtMaxTsContext*>(
155       sqlite3_aggregate_context(ctx, sizeof(ValueAtMaxTsContext)));
156 
157   // For performance reasons, we only do the check for the type of ts and value
158   // on the first call of the function.
159   if (PERFETTO_UNLIKELY(!fn_ctx->initialized)) {
160     if (sqlite3_value_type(ts) != SQLITE_INTEGER) {
161       sqlite3_result_error(ctx, "VALUE_AT_MAX_TS: ts passed was not an integer",
162                            -1);
163       return;
164     }
165 
166     fn_ctx->value_type = sqlite3_value_type(value);
167     if (fn_ctx->value_type != SQLITE_INTEGER &&
168         fn_ctx->value_type != SQLITE_FLOAT) {
169       sqlite3_result_error(
170           ctx, "VALUE_AT_MAX_TS: value passed was not an integer or float", -1);
171       return;
172     }
173 
174     fn_ctx->max_ts = std::numeric_limits<int64_t>::min();
175     fn_ctx->initialized = true;
176   }
177 
178   // On dcheck builds however, we check every passed ts and value.
179 #if PERFETTO_DCHECK_IS_ON()
180   if (sqlite3_value_type(ts) != SQLITE_INTEGER) {
181     sqlite3_result_error(ctx, "VALUE_AT_MAX_TS: ts passed was not an integer",
182                          -1);
183     return;
184   }
185   if (sqlite3_value_type(value) != fn_ctx->value_type) {
186     sqlite3_result_error(ctx, "VALUE_AT_MAX_TS: value type is inconsistent",
187                          -1);
188     return;
189   }
190 #endif
191 
192   int64_t ts_int = sqlite3_value_int64(ts);
193   if (PERFETTO_LIKELY(fn_ctx->max_ts <= ts_int)) {
194     fn_ctx->max_ts = ts_int;
195 
196     if (fn_ctx->value_type == SQLITE_INTEGER) {
197       fn_ctx->int_value_at_max_ts = sqlite3_value_int64(value);
198     } else {
199       fn_ctx->double_value_at_max_ts = sqlite3_value_double(value);
200     }
201   }
202 }
203 
ValueAtMaxTsFinal(sqlite3_context * ctx)204 void ValueAtMaxTsFinal(sqlite3_context* ctx) {
205   ValueAtMaxTsContext* fn_ctx =
206       reinterpret_cast<ValueAtMaxTsContext*>(sqlite3_aggregate_context(ctx, 0));
207   if (!fn_ctx) {
208     sqlite3_result_null(ctx);
209     return;
210   }
211   if (fn_ctx->value_type == SQLITE_INTEGER) {
212     sqlite3_result_int64(ctx, fn_ctx->int_value_at_max_ts);
213   } else {
214     sqlite3_result_double(ctx, fn_ctx->double_value_at_max_ts);
215   }
216 }
217 
RegisterValueAtMaxTsFunction(sqlite3 * db)218 void RegisterValueAtMaxTsFunction(sqlite3* db) {
219   auto ret = sqlite3_create_function_v2(
220       db, "VALUE_AT_MAX_TS", 2, SQLITE_UTF8 | SQLITE_DETERMINISTIC, nullptr,
221       nullptr, &ValueAtMaxTsStep, &ValueAtMaxTsFinal, nullptr);
222   if (ret) {
223     PERFETTO_ELOG("Error initializing VALUE_AT_MAX_TS");
224   }
225 }
226 
SanitizeMetricMountPaths(const std::vector<std::string> & mount_paths)227 std::vector<std::string> SanitizeMetricMountPaths(
228     const std::vector<std::string>& mount_paths) {
229   std::vector<std::string> sanitized;
230   for (const auto& path : mount_paths) {
231     if (path.length() == 0)
232       continue;
233     sanitized.push_back(path);
234     if (path.back() != '/')
235       sanitized.back().append("/");
236   }
237   return sanitized;
238 }
239 
SetupMetrics(TraceProcessor * tp,SqliteEngine * engine,std::vector<metrics::SqlMetricFile> * sql_metrics,const std::vector<std::string> & extension_paths)240 void SetupMetrics(TraceProcessor* tp,
241                   SqliteEngine* engine,
242                   std::vector<metrics::SqlMetricFile>* sql_metrics,
243                   const std::vector<std::string>& extension_paths) {
244   const std::vector<std::string> sanitized_extension_paths =
245       SanitizeMetricMountPaths(extension_paths);
246   std::vector<std::string> skip_prefixes;
247   skip_prefixes.reserve(sanitized_extension_paths.size());
248   for (const auto& path : sanitized_extension_paths) {
249     skip_prefixes.push_back(kMetricProtoRoot + path);
250   }
251   tp->ExtendMetricsProto(kMetricsDescriptor.data(), kMetricsDescriptor.size(),
252                          skip_prefixes);
253   tp->ExtendMetricsProto(kAllChromeMetricsDescriptor.data(),
254                          kAllChromeMetricsDescriptor.size(), skip_prefixes);
255   tp->ExtendMetricsProto(kAllWebviewMetricsDescriptor.data(),
256                          kAllWebviewMetricsDescriptor.size(), skip_prefixes);
257 
258   // TODO(lalitm): remove this special casing and change
259   // SanitizeMetricMountPaths if/when we move all protos for builtin metrics to
260   // match extension protos.
261   bool skip_all_sql = std::find(extension_paths.begin(), extension_paths.end(),
262                                 "") != extension_paths.end();
263   if (!skip_all_sql) {
264     for (const auto& file_to_sql : sql_metrics::kFileToSql) {
265       if (base::StartsWithAny(file_to_sql.path, sanitized_extension_paths))
266         continue;
267       tp->RegisterMetric(file_to_sql.path, file_to_sql.sql);
268     }
269   }
270 
271   RegisterFunction<metrics::NullIfEmpty>(engine, "NULL_IF_EMPTY", 1);
272   RegisterFunction<metrics::UnwrapMetricProto>(engine, "UNWRAP_METRIC_PROTO",
273                                                2);
274   RegisterFunction<metrics::RunMetric>(
275       engine, "RUN_METRIC", -1,
276       std::unique_ptr<metrics::RunMetric::Context>(
277           new metrics::RunMetric::Context{tp, sql_metrics}));
278 
279   // TODO(lalitm): migrate this over to using RegisterFunction once aggregate
280   // functions are supported.
281   {
282     auto ret = sqlite3_create_function_v2(
283         engine->db(), "RepeatedField", 1, SQLITE_UTF8, nullptr, nullptr,
284         metrics::RepeatedFieldStep, metrics::RepeatedFieldFinal, nullptr);
285     if (ret)
286       PERFETTO_FATAL("Error initializing RepeatedField");
287   }
288 }
289 
InsertIntoTraceMetricsTable(sqlite3 * db,const std::string & metric_name)290 void InsertIntoTraceMetricsTable(sqlite3* db, const std::string& metric_name) {
291   char* insert_sql = sqlite3_mprintf(
292       "INSERT INTO trace_metrics(name) VALUES('%q')", metric_name.c_str());
293   char* insert_error = nullptr;
294   sqlite3_exec(db, insert_sql, nullptr, nullptr, &insert_error);
295   sqlite3_free(insert_sql);
296   if (insert_error) {
297     PERFETTO_ELOG("Error registering table: %s", insert_error);
298     sqlite3_free(insert_error);
299   }
300 }
301 
IncrementCountForStmt(sqlite3_stmt * stmt,IteratorImpl::StmtMetadata * metadata)302 void IncrementCountForStmt(sqlite3_stmt* stmt,
303                            IteratorImpl::StmtMetadata* metadata) {
304   metadata->statement_count++;
305 
306   // If the stmt is already done, it clearly didn't have any output.
307   if (sqlite_utils::IsStmtDone(stmt))
308     return;
309 
310   if (sqlite3_column_count(stmt) == 1) {
311     sqlite3_value* value = sqlite3_column_value(stmt, 0);
312 
313     // If the "VOID" pointer associated to the return value is not null,
314     // that means this is a function which is forced to return a value
315     // (because all functions in SQLite have to) but doesn't actually
316     // wait to (i.e. it wants to be treated like CREATE TABLE or similar).
317     // Because of this, ignore the return value of this function.
318     // See |WrapSqlFunction| for where this is set.
319     if (sqlite3_value_pointer(value, "VOID") != nullptr) {
320       return;
321     }
322 
323     // If the statement only has a single column and that column is named
324     // "suppress_query_output", treat it as a statement without output for
325     // accounting purposes. This allows an escape hatch for cases where the
326     // user explicitly wants to ignore functions as having output.
327     if (strcmp(sqlite3_column_name(stmt, 0), "suppress_query_output") == 0) {
328       return;
329     }
330   }
331 
332   // Otherwise, the statement has output and so increment the count.
333   metadata->statement_count_with_output++;
334 }
335 
PrepareAndStepUntilLastValidStmt(sqlite3 * db,const std::string & sql,ScopedStmt * output_stmt,IteratorImpl::StmtMetadata * metadata)336 base::Status PrepareAndStepUntilLastValidStmt(
337     sqlite3* db,
338     const std::string& sql,
339     ScopedStmt* output_stmt,
340     IteratorImpl::StmtMetadata* metadata) {
341   ScopedStmt prev_stmt;
342   // A sql string can contain several statements. Some of them might be comment
343   // only, e.g. "SELECT 1; /* comment */; SELECT 2;". Here we process one
344   // statement on each iteration. SQLite's sqlite_prepare_v2 (wrapped by
345   // PrepareStmt) returns on each iteration a pointer to the unprocessed string.
346   //
347   // Unfortunately we cannot call PrepareStmt and tokenize all statements
348   // upfront because sqlite_prepare_v2 also semantically checks the statement
349   // against the schema. In some cases statements might depend on the execution
350   // of previous ones (e.e. CREATE VIEW x; SELECT FROM x; DELETE VIEW x;).
351   //
352   // Also, unfortunately, we need to PrepareStmt to find out if a statement is a
353   // comment or a real statement.
354   //
355   // The logic here is the following:
356   //  - We invoke PrepareStmt on each statement.
357   //  - If the statement is a comment we simply skip it.
358   //  - If the statement is valid, we step once to make sure side effects take
359   //    effect.
360   //  - If we encounter a valid statement afterwards, we step internally through
361   //    all rows of the previous one. This ensures that any further side effects
362   //    take hold *before* we step into the next statement.
363   //  - Once no further non-comment statements are encountered, we return an
364   //    iterator to the last valid statement.
365   for (const char* rem_sql = sql.c_str(); rem_sql && rem_sql[0];) {
366     ScopedStmt cur_stmt;
367     {
368       PERFETTO_TP_TRACE(metatrace::Category::QUERY, "QUERY_PREPARE");
369       const char* tail = nullptr;
370       RETURN_IF_ERROR(sqlite_utils::PrepareStmt(db, rem_sql, &cur_stmt, &tail));
371       rem_sql = tail;
372     }
373 
374     // The only situation where we'd have an ok status but also no prepared
375     // statement is if the statement of SQL we parsed was a pure comment. In
376     // this case, just continue to the next statement.
377     if (!cur_stmt)
378       continue;
379 
380     // Before stepping into |cur_stmt|, we need to finish iterating through
381     // the previous statement so we don't have two clashing statements (e.g.
382     // SELECT * FROM v and DROP VIEW v) partially stepped into.
383     if (prev_stmt) {
384       PERFETTO_TP_TRACE(metatrace::Category::QUERY, "STMT_STEP_UNTIL_DONE",
385                         [&prev_stmt](metatrace::Record* record) {
386                           auto expanded_sql =
387                               sqlite_utils::ExpandedSqlForStmt(*prev_stmt);
388                           record->AddArg("SQL", expanded_sql.get());
389                         });
390       RETURN_IF_ERROR(sqlite_utils::StepStmtUntilDone(prev_stmt.get()));
391     }
392 
393     PERFETTO_DLOG("Executing statement: %s", sqlite3_sql(*cur_stmt));
394 
395     {
396       PERFETTO_TP_TRACE(metatrace::Category::TOPLEVEL, "STMT_FIRST_STEP",
397                         [&cur_stmt](metatrace::Record* record) {
398                           auto expanded_sql =
399                               sqlite_utils::ExpandedSqlForStmt(*cur_stmt);
400                           record->AddArg("SQL", expanded_sql.get());
401                         });
402 
403       // Now step once into |cur_stmt| so that when we prepare the next statment
404       // we will have executed any dependent bytecode in this one.
405       int err = sqlite3_step(*cur_stmt);
406       if (err != SQLITE_ROW && err != SQLITE_DONE) {
407         return base::ErrStatus(
408             "%s", sqlite_utils::FormatErrorMessage(
409                       prev_stmt.get(), base::StringView(sql), db, err)
410                       .c_message());
411       }
412     }
413 
414     // Increment the neecessary counts for the statement.
415     IncrementCountForStmt(cur_stmt.get(), metadata);
416 
417     // Propogate the current statement to the next iteration.
418     prev_stmt = std::move(cur_stmt);
419   }
420 
421   // If we didn't manage to prepare a single statment, that means everything
422   // in the SQL was treated as a comment.
423   if (!prev_stmt)
424     return base::ErrStatus("No valid SQL to run");
425 
426   // Update the output statment and column count.
427   *output_stmt = std::move(prev_stmt);
428   metadata->column_count =
429       static_cast<uint32_t>(sqlite3_column_count(output_stmt->get()));
430   return base::OkStatus();
431 }
432 
TraceTypeToString(TraceType trace_type)433 const char* TraceTypeToString(TraceType trace_type) {
434   switch (trace_type) {
435     case kUnknownTraceType:
436       return "unknown";
437     case kProtoTraceType:
438       return "proto";
439     case kJsonTraceType:
440       return "json";
441     case kFuchsiaTraceType:
442       return "fuchsia";
443     case kSystraceTraceType:
444       return "systrace";
445     case kGzipTraceType:
446       return "gzip";
447     case kCtraceTraceType:
448       return "ctrace";
449     case kNinjaLogTraceType:
450       return "ninja_log";
451     case kAndroidBugreportTraceType:
452       return "android_bugreport";
453   }
454   PERFETTO_FATAL("For GCC");
455 }
456 
457 // Register SQL functions only used in local development instances.
RegisterDevFunctions(SqliteEngine * engine)458 void RegisterDevFunctions(SqliteEngine* engine) {
459   RegisterFunction<WriteFile>(engine, "WRITE_FILE", 2);
460 }
461 
GetStdlibModules()462 sql_modules::NameToModule GetStdlibModules() {
463   sql_modules::NameToModule modules;
464   for (const auto& file_to_sql : stdlib::kFileToSql) {
465     std::string import_key = sql_modules::GetImportKey(file_to_sql.path);
466     std::string module = sql_modules::GetModuleName(import_key);
467     modules.Insert(module, {}).first->push_back({import_key, file_to_sql.sql});
468   }
469   return modules;
470 }
471 
InitializePreludeTablesViews(sqlite3 * db)472 void InitializePreludeTablesViews(sqlite3* db) {
473   for (const auto& file_to_sql : prelude::tables_views::kFileToSql) {
474     char* errmsg_raw = nullptr;
475     int err = sqlite3_exec(db, file_to_sql.sql, nullptr, nullptr, &errmsg_raw);
476     ScopedSqliteString errmsg(errmsg_raw);
477     if (err != SQLITE_OK) {
478       PERFETTO_FATAL("Failed to initialize prelude %s", errmsg_raw);
479     }
480   }
481 }
482 
483 }  // namespace
484 
485 template <typename View>
RegisterView(const View & view)486 void TraceProcessorImpl::RegisterView(const View& view) {
487   RegisterTableFunction(std::unique_ptr<TableFunction>(
488       new ViewTableFunction(&view, View::Name())));
489 }
490 
TraceProcessorImpl(const Config & cfg)491 TraceProcessorImpl::TraceProcessorImpl(const Config& cfg)
492     : TraceProcessorStorageImpl(cfg) {
493   context_.fuchsia_trace_tokenizer.reset(new FuchsiaTraceTokenizer(&context_));
494   context_.fuchsia_trace_parser.reset(new FuchsiaTraceParser(&context_));
495 
496   context_.ninja_log_parser.reset(new NinjaLogParser(&context_));
497 
498   context_.systrace_trace_parser.reset(new SystraceTraceParser(&context_));
499 
500   if (util::IsGzipSupported()) {
501     context_.gzip_trace_parser.reset(new GzipTraceParser(&context_));
502     context_.android_bugreport_parser.reset(
503         new AndroidBugreportParser(&context_));
504   }
505 
506   if (json::IsJsonSupported()) {
507     context_.json_trace_tokenizer.reset(new JsonTraceTokenizer(&context_));
508     context_.json_trace_parser.reset(new JsonTraceParser(&context_));
509   }
510 
511   if (context_.config.analyze_trace_proto_content) {
512     context_.content_analyzer.reset(new ProtoContentAnalyzer(&context_));
513   }
514 
515   sqlite3_str_split_init(engine_.db());
516   RegisterAdditionalModules(&context_);
517 
518   // New style function registration.
519   if (cfg.enable_dev_features) {
520     RegisterDevFunctions(&engine_);
521   }
522   RegisterFunction<Glob>(&engine_, "glob", 2);
523   RegisterFunction<Hash>(&engine_, "HASH", -1);
524   RegisterFunction<Base64Encode>(&engine_, "BASE64_ENCODE", 1);
525   RegisterFunction<Demangle>(&engine_, "DEMANGLE", 1);
526   RegisterFunction<SourceGeq>(&engine_, "SOURCE_GEQ", -1);
527   RegisterFunction<ExportJson>(&engine_, "EXPORT_JSON", 1,
528                                context_.storage.get(), false);
529   RegisterFunction<ExtractArg>(&engine_, "EXTRACT_ARG", 2,
530                                context_.storage.get());
531   RegisterFunction<AbsTimeStr>(&engine_, "ABS_TIME_STR", 1,
532                                context_.clock_converter.get());
533   RegisterFunction<ToMonotonic>(&engine_, "TO_MONOTONIC", 1,
534                                 context_.clock_converter.get());
535   RegisterFunction<CreateFunction>(&engine_, "CREATE_FUNCTION", 3, &engine_);
536   RegisterFunction<CreateViewFunction>(
537       &engine_, "CREATE_VIEW_FUNCTION", 3,
538       std::unique_ptr<CreateViewFunction::Context>(
539           new CreateViewFunction::Context{engine_.db()}));
540   RegisterFunction<Import>(&engine_, "IMPORT", 1,
541                            std::unique_ptr<Import::Context>(new Import::Context{
542                                engine_.db(), this, &sql_modules_}));
543   RegisterFunction<ToFtrace>(
544       &engine_, "TO_FTRACE", 1,
545       std::unique_ptr<ToFtrace::Context>(new ToFtrace::Context{
546           context_.storage.get(), SystraceSerializer(&context_)}));
547 
548   // Old style function registration.
549   // TODO(lalitm): migrate this over to using RegisterFunction once aggregate
550   // functions are supported.
551   RegisterLastNonNullFunction(engine_.db());
552   RegisterValueAtMaxTsFunction(engine_.db());
553   {
554     base::Status status = RegisterStackFunctions(&engine_, &context_);
555     if (!status.ok())
556       PERFETTO_ELOG("%s", status.c_message());
557   }
558   {
559     base::Status status = PprofFunctions::Register(engine_.db(), &context_);
560     if (!status.ok())
561       PERFETTO_ELOG("%s", status.c_message());
562   }
563   {
564     base::Status status = LayoutFunctions::Register(engine_.db(), &context_);
565     if (!status.ok())
566       PERFETTO_ELOG("%s", status.c_message());
567   }
568 
569   const TraceStorage* storage = context_.storage.get();
570 
571   // Operator tables.
572   engine_.RegisterVirtualTableModule<SpanJoinOperatorTable>(
573       "span_join", storage, SqliteTable::TableType::kExplicitCreate, false);
574   engine_.RegisterVirtualTableModule<SpanJoinOperatorTable>(
575       "span_left_join", storage, SqliteTable::TableType::kExplicitCreate,
576       false);
577   engine_.RegisterVirtualTableModule<SpanJoinOperatorTable>(
578       "span_outer_join", storage, SqliteTable::TableType::kExplicitCreate,
579       false);
580   engine_.RegisterVirtualTableModule<WindowOperatorTable>(
581       "window", storage, SqliteTable::TableType::kExplicitCreate, true);
582   RegisterCreateViewFunctionModule(&engine_);
583 
584   // Initalize the tables and views in the prelude.
585   InitializePreludeTablesViews(engine_.db());
586 
587   auto stdlib_modules = GetStdlibModules();
588   for (auto module_it = stdlib_modules.GetIterator(); module_it; ++module_it) {
589     base::Status status =
590         RegisterSqlModule({module_it.key(), module_it.value(), false});
591     if (!status.ok())
592       PERFETTO_ELOG("%s", status.c_message());
593   }
594 
595   SetupMetrics(this, &engine_, &sql_metrics_, cfg.skip_builtin_metric_paths);
596 
597   // Legacy tables.
598   engine_.RegisterVirtualTableModule<SqlStatsTable>(
599       "sqlstats", storage, SqliteTable::TableType::kEponymousOnly, false);
600   engine_.RegisterVirtualTableModule<StatsTable>(
601       "stats", storage, SqliteTable::TableType::kEponymousOnly, false);
602 
603   // Tables dynamically generated at query time.
604   RegisterTableFunction(std::unique_ptr<ExperimentalFlamegraph>(
605       new ExperimentalFlamegraph(&context_)));
606   RegisterTableFunction(std::unique_ptr<ExperimentalCounterDur>(
607       new ExperimentalCounterDur(storage->counter_table())));
608   RegisterTableFunction(std::unique_ptr<ExperimentalSliceLayout>(
609       new ExperimentalSliceLayout(context_.storage.get()->mutable_string_pool(),
610                                   &storage->slice_table())));
611   RegisterTableFunction(std::unique_ptr<Ancestor>(
612       new Ancestor(Ancestor::Type::kSlice, context_.storage.get())));
613   RegisterTableFunction(std::unique_ptr<Ancestor>(new Ancestor(
614       Ancestor::Type::kStackProfileCallsite, context_.storage.get())));
615   RegisterTableFunction(std::unique_ptr<Ancestor>(
616       new Ancestor(Ancestor::Type::kSliceByStack, context_.storage.get())));
617   RegisterTableFunction(std::unique_ptr<Descendant>(
618       new Descendant(Descendant::Type::kSlice, context_.storage.get())));
619   RegisterTableFunction(std::unique_ptr<Descendant>(
620       new Descendant(Descendant::Type::kSliceByStack, context_.storage.get())));
621   RegisterTableFunction(std::unique_ptr<ConnectedFlow>(new ConnectedFlow(
622       ConnectedFlow::Mode::kDirectlyConnectedFlow, context_.storage.get())));
623   RegisterTableFunction(std::unique_ptr<ConnectedFlow>(new ConnectedFlow(
624       ConnectedFlow::Mode::kPrecedingFlow, context_.storage.get())));
625   RegisterTableFunction(std::unique_ptr<ConnectedFlow>(new ConnectedFlow(
626       ConnectedFlow::Mode::kFollowingFlow, context_.storage.get())));
627   RegisterTableFunction(
628       std::unique_ptr<ExperimentalSchedUpid>(new ExperimentalSchedUpid(
629           storage->sched_slice_table(), storage->thread_table())));
630   RegisterTableFunction(std::unique_ptr<ExperimentalAnnotatedStack>(
631       new ExperimentalAnnotatedStack(&context_)));
632   RegisterTableFunction(std::unique_ptr<ExperimentalFlatSlice>(
633       new ExperimentalFlatSlice(&context_)));
634 
635   // Views.
636   RegisterView(storage->thread_slice_view());
637 
638   // New style db-backed tables.
639   // Note: if adding a table here which might potentially contain many rows
640   // (O(rows in sched/slice/counter)), then consider calling ShrinkToFit on
641   // that table in TraceStorage::ShrinkToFitTables.
642   RegisterDbTable(storage->arg_table());
643   RegisterDbTable(storage->raw_table());
644   RegisterDbTable(storage->ftrace_event_table());
645   RegisterDbTable(storage->thread_table());
646   RegisterDbTable(storage->process_table());
647   RegisterDbTable(storage->filedescriptor_table());
648 
649   RegisterDbTable(storage->slice_table());
650   RegisterDbTable(storage->flow_table());
651   RegisterDbTable(storage->slice_table());
652   RegisterDbTable(storage->sched_slice_table());
653   RegisterDbTable(storage->thread_state_table());
654   RegisterDbTable(storage->gpu_slice_table());
655 
656   RegisterDbTable(storage->track_table());
657   RegisterDbTable(storage->thread_track_table());
658   RegisterDbTable(storage->process_track_table());
659   RegisterDbTable(storage->cpu_track_table());
660   RegisterDbTable(storage->gpu_track_table());
661 
662   RegisterDbTable(storage->counter_table());
663 
664   RegisterDbTable(storage->counter_track_table());
665   RegisterDbTable(storage->process_counter_track_table());
666   RegisterDbTable(storage->thread_counter_track_table());
667   RegisterDbTable(storage->cpu_counter_track_table());
668   RegisterDbTable(storage->irq_counter_track_table());
669   RegisterDbTable(storage->softirq_counter_track_table());
670   RegisterDbTable(storage->gpu_counter_track_table());
671   RegisterDbTable(storage->gpu_counter_group_table());
672   RegisterDbTable(storage->perf_counter_track_table());
673   RegisterDbTable(storage->energy_counter_track_table());
674   RegisterDbTable(storage->uid_counter_track_table());
675   RegisterDbTable(storage->energy_per_uid_counter_track_table());
676 
677   RegisterDbTable(storage->heap_graph_object_table());
678   RegisterDbTable(storage->heap_graph_reference_table());
679   RegisterDbTable(storage->heap_graph_class_table());
680 
681   RegisterDbTable(storage->symbol_table());
682   RegisterDbTable(storage->heap_profile_allocation_table());
683   RegisterDbTable(storage->cpu_profile_stack_sample_table());
684   RegisterDbTable(storage->perf_sample_table());
685   RegisterDbTable(storage->stack_profile_callsite_table());
686   RegisterDbTable(storage->stack_profile_mapping_table());
687   RegisterDbTable(storage->stack_profile_frame_table());
688   RegisterDbTable(storage->package_list_table());
689   RegisterDbTable(storage->profiler_smaps_table());
690 
691   RegisterDbTable(storage->android_log_table());
692   RegisterDbTable(storage->android_dumpstate_table());
693   RegisterDbTable(storage->android_game_intervention_list_table());
694 
695   RegisterDbTable(storage->vulkan_memory_allocations_table());
696 
697   RegisterDbTable(storage->graphics_frame_slice_table());
698 
699   RegisterDbTable(storage->expected_frame_timeline_slice_table());
700   RegisterDbTable(storage->actual_frame_timeline_slice_table());
701 
702   RegisterDbTable(storage->metadata_table());
703   RegisterDbTable(storage->cpu_table());
704   RegisterDbTable(storage->cpu_freq_table());
705   RegisterDbTable(storage->clock_snapshot_table());
706 
707   RegisterDbTable(storage->memory_snapshot_table());
708   RegisterDbTable(storage->process_memory_snapshot_table());
709   RegisterDbTable(storage->memory_snapshot_node_table());
710   RegisterDbTable(storage->memory_snapshot_edge_table());
711 
712   RegisterDbTable(storage->experimental_proto_path_table());
713   RegisterDbTable(storage->experimental_proto_content_table());
714 
715   RegisterDbTable(storage->experimental_missing_chrome_processes_table());
716 }
717 
718 TraceProcessorImpl::~TraceProcessorImpl() = default;
719 
Parse(TraceBlobView blob)720 base::Status TraceProcessorImpl::Parse(TraceBlobView blob) {
721   bytes_parsed_ += blob.size();
722   return TraceProcessorStorageImpl::Parse(std::move(blob));
723 }
724 
GetCurrentTraceName()725 std::string TraceProcessorImpl::GetCurrentTraceName() {
726   if (current_trace_name_.empty())
727     return "";
728   auto size = " (" + std::to_string(bytes_parsed_ / 1024 / 1024) + " MB)";
729   return current_trace_name_ + size;
730 }
731 
SetCurrentTraceName(const std::string & name)732 void TraceProcessorImpl::SetCurrentTraceName(const std::string& name) {
733   current_trace_name_ = name;
734 }
735 
Flush()736 void TraceProcessorImpl::Flush() {
737   TraceProcessorStorageImpl::Flush();
738 
739   context_.metadata_tracker->SetMetadata(
740       metadata::trace_size_bytes,
741       Variadic::Integer(static_cast<int64_t>(bytes_parsed_)));
742   const StringId trace_type_id =
743       context_.storage->InternString(TraceTypeToString(context_.trace_type));
744   context_.metadata_tracker->SetMetadata(metadata::trace_type,
745                                          Variadic::String(trace_type_id));
746   BuildBoundsTable(engine_.db(), context_.storage->GetTraceTimestampBoundsNs());
747 }
748 
NotifyEndOfFile()749 void TraceProcessorImpl::NotifyEndOfFile() {
750   if (notify_eof_called_) {
751     PERFETTO_ELOG(
752         "NotifyEndOfFile should only be called once. Try calling Flush instead "
753         "if trying to commit the contents of the trace to tables.");
754     return;
755   }
756   notify_eof_called_ = true;
757 
758   if (current_trace_name_.empty())
759     current_trace_name_ = "Unnamed trace";
760 
761   // Last opportunity to flush all pending data.
762   Flush();
763 
764   TraceProcessorStorageImpl::NotifyEndOfFile();
765 
766   // Create a snapshot list of all tables and views created so far. This is so
767   // later we can drop all extra tables created by the UI and reset to the
768   // original state (see RestoreInitialTables).
769   initial_tables_.clear();
770   auto it = ExecuteQuery(kAllTablesQuery);
771   while (it.Next()) {
772     auto value = it.Get(0);
773     PERFETTO_CHECK(value.type == SqlValue::Type::kString);
774     initial_tables_.push_back(value.string_value);
775   }
776 
777   context_.storage->ShrinkToFitTables();
778 
779   // Rebuild the bounds table once everything has been completed: we do this
780   // so that if any data was added to tables in
781   // TraceProcessorStorageImpl::NotifyEndOfFile, this will be counted in
782   // trace bounds: this is important for parsers like ninja which wait until
783   // the end to flush all their data.
784   BuildBoundsTable(engine_.db(), context_.storage->GetTraceTimestampBoundsNs());
785 
786   TraceProcessorStorageImpl::DestroyContext();
787 }
788 
RestoreInitialTables()789 size_t TraceProcessorImpl::RestoreInitialTables() {
790   // Step 1: figure out what tables/views/indices we need to delete.
791   std::vector<std::pair<std::string, std::string>> deletion_list;
792   std::string msg = "Resetting DB to initial state, deleting table/views:";
793   for (auto it = ExecuteQuery(kAllTablesQuery); it.Next();) {
794     std::string name(it.Get(0).string_value);
795     std::string type(it.Get(1).string_value);
796     if (std::find(initial_tables_.begin(), initial_tables_.end(), name) ==
797         initial_tables_.end()) {
798       msg += " " + name;
799       deletion_list.push_back(std::make_pair(type, name));
800     }
801   }
802 
803   PERFETTO_LOG("%s", msg.c_str());
804 
805   // Step 2: actually delete those tables/views/indices.
806   for (const auto& tn : deletion_list) {
807     std::string query = "DROP " + tn.first + " " + tn.second;
808     auto it = ExecuteQuery(query);
809     while (it.Next()) {
810     }
811     // Index deletion can legitimately fail. If one creates an index "i" on a
812     // table "t" but issues the deletion in the order (t, i), the DROP index i
813     // will fail with "no such index" because deleting the table "t"
814     // automatically deletes all associated indexes.
815     if (!it.Status().ok() && tn.first != "index")
816       PERFETTO_FATAL("%s -> %s", query.c_str(), it.Status().c_message());
817   }
818   return deletion_list.size();
819 }
820 
ExecuteQuery(const std::string & sql)821 Iterator TraceProcessorImpl::ExecuteQuery(const std::string& sql) {
822   PERFETTO_TP_TRACE(metatrace::Category::TOPLEVEL, "QUERY_EXECUTE");
823 
824   uint32_t sql_stats_row =
825       context_.storage->mutable_sql_stats()->RecordQueryBegin(
826           sql, base::GetWallTimeNs().count());
827 
828   ScopedStmt stmt;
829   IteratorImpl::StmtMetadata metadata;
830   base::Status status =
831       PrepareAndStepUntilLastValidStmt(engine_.db(), sql, &stmt, &metadata);
832   PERFETTO_DCHECK((status.ok() && stmt) || (!status.ok() && !stmt));
833 
834   std::unique_ptr<IteratorImpl> impl(
835       new IteratorImpl(this, engine_.db(), status, std::move(stmt),
836                        std::move(metadata), sql_stats_row));
837   return Iterator(std::move(impl));
838 }
839 
InterruptQuery()840 void TraceProcessorImpl::InterruptQuery() {
841   if (!engine_.db())
842     return;
843   query_interrupted_.store(true);
844   sqlite3_interrupt(engine_.db());
845 }
846 
IsRootMetricField(const std::string & metric_name)847 bool TraceProcessorImpl::IsRootMetricField(const std::string& metric_name) {
848   std::optional<uint32_t> desc_idx =
849       pool_.FindDescriptorIdx(".perfetto.protos.TraceMetrics");
850   if (!desc_idx.has_value())
851     return false;
852   auto field_idx = pool_.descriptors()[*desc_idx].FindFieldByName(metric_name);
853   return field_idx != nullptr;
854 }
855 
RegisterSqlModule(SqlModule sql_module)856 base::Status TraceProcessorImpl::RegisterSqlModule(SqlModule sql_module) {
857   sql_modules::RegisteredModule new_module;
858   std::string name = sql_module.name;
859   if (sql_modules_.Find(name) && !sql_module.allow_module_override) {
860     return base::ErrStatus(
861         "Module '%s' is already registered. Choose a different name.\n"
862         "If you want to replace the existing module using trace processor "
863         "shell, you need to pass the --dev flag and use --override-sql-module "
864         "to pass the module path.",
865         name.c_str());
866   }
867   for (auto const& name_and_sql : sql_module.files) {
868     if (sql_modules::GetModuleName(name_and_sql.first) != name) {
869       return base::ErrStatus(
870           "File import key doesn't match the module name. First part of import "
871           "key should be module name. Import key: %s, module name: %s.",
872           name_and_sql.first.c_str(), name.c_str());
873     }
874     new_module.import_key_to_file.Insert(name_and_sql.first,
875                                          {name_and_sql.second, false});
876   }
877   sql_modules_.Insert(name, std::move(new_module));
878   return base::OkStatus();
879 }
880 
RegisterMetric(const std::string & path,const std::string & sql)881 base::Status TraceProcessorImpl::RegisterMetric(const std::string& path,
882                                                 const std::string& sql) {
883   std::string stripped_sql;
884   for (base::StringSplitter sp(sql, '\n'); sp.Next();) {
885     if (strncmp(sp.cur_token(), "--", 2) != 0) {
886       stripped_sql.append(sp.cur_token());
887       stripped_sql.push_back('\n');
888     }
889   }
890 
891   // Check if the metric with the given path already exists and if it does,
892   // just update the SQL associated with it.
893   auto it = std::find_if(
894       sql_metrics_.begin(), sql_metrics_.end(),
895       [&path](const metrics::SqlMetricFile& m) { return m.path == path; });
896   if (it != sql_metrics_.end()) {
897     it->sql = stripped_sql;
898     return base::OkStatus();
899   }
900 
901   auto sep_idx = path.rfind('/');
902   std::string basename =
903       sep_idx == std::string::npos ? path : path.substr(sep_idx + 1);
904 
905   auto sql_idx = basename.rfind(".sql");
906   if (sql_idx == std::string::npos) {
907     return base::ErrStatus("Unable to find .sql extension for metric");
908   }
909   auto no_ext_name = basename.substr(0, sql_idx);
910 
911   metrics::SqlMetricFile metric;
912   metric.path = path;
913   metric.sql = stripped_sql;
914 
915   if (IsRootMetricField(no_ext_name)) {
916     metric.proto_field_name = no_ext_name;
917     metric.output_table_name = no_ext_name + "_output";
918 
919     auto field_it_and_inserted =
920         proto_field_to_sql_metric_path_.emplace(*metric.proto_field_name, path);
921     if (!field_it_and_inserted.second) {
922       // We already had a metric with this field name in the map. However, if
923       // this was the case, we should have found the metric in
924       // |path_to_sql_metric_file_| above if we are simply overriding the
925       // metric. Return an error since this means we have two different SQL
926       // files which are trying to output the same metric.
927       const auto& prev_path = field_it_and_inserted.first->second;
928       PERFETTO_DCHECK(prev_path != path);
929       return base::ErrStatus(
930           "RegisterMetric Error: Metric paths %s (which is already "
931           "registered) "
932           "and %s are both trying to output the proto field %s",
933           prev_path.c_str(), path.c_str(), metric.proto_field_name->c_str());
934     }
935 
936     InsertIntoTraceMetricsTable(engine_.db(), no_ext_name);
937   }
938 
939   sql_metrics_.emplace_back(metric);
940   return base::OkStatus();
941 }
942 
ExtendMetricsProto(const uint8_t * data,size_t size)943 base::Status TraceProcessorImpl::ExtendMetricsProto(const uint8_t* data,
944                                                     size_t size) {
945   return ExtendMetricsProto(data, size, /*skip_prefixes*/ {});
946 }
947 
ExtendMetricsProto(const uint8_t * data,size_t size,const std::vector<std::string> & skip_prefixes)948 base::Status TraceProcessorImpl::ExtendMetricsProto(
949     const uint8_t* data,
950     size_t size,
951     const std::vector<std::string>& skip_prefixes) {
952   base::Status status =
953       pool_.AddFromFileDescriptorSet(data, size, skip_prefixes);
954   if (!status.ok())
955     return status;
956 
957   for (uint32_t i = 0; i < pool_.descriptors().size(); ++i) {
958     // Convert the full name (e.g. .perfetto.protos.TraceMetrics.SubMetric)
959     // into a function name of the form (TraceMetrics_SubMetric).
960     const auto& desc = pool_.descriptors()[i];
961     auto fn_name = desc.full_name().substr(desc.package_name().size() + 1);
962     std::replace(fn_name.begin(), fn_name.end(), '.', '_');
963     RegisterFunction<metrics::BuildProto>(
964         &engine_, fn_name.c_str(), -1,
965         std::unique_ptr<metrics::BuildProto::Context>(
966             new metrics::BuildProto::Context{this, &pool_, i}));
967   }
968   return base::OkStatus();
969 }
970 
ComputeMetric(const std::vector<std::string> & metric_names,std::vector<uint8_t> * metrics_proto)971 base::Status TraceProcessorImpl::ComputeMetric(
972     const std::vector<std::string>& metric_names,
973     std::vector<uint8_t>* metrics_proto) {
974   auto opt_idx = pool_.FindDescriptorIdx(".perfetto.protos.TraceMetrics");
975   if (!opt_idx.has_value())
976     return base::Status("Root metrics proto descriptor not found");
977 
978   const auto& root_descriptor = pool_.descriptors()[opt_idx.value()];
979   return metrics::ComputeMetrics(this, metric_names, sql_metrics_, pool_,
980                                  root_descriptor, metrics_proto);
981 }
982 
ComputeMetricText(const std::vector<std::string> & metric_names,TraceProcessor::MetricResultFormat format,std::string * metrics_string)983 base::Status TraceProcessorImpl::ComputeMetricText(
984     const std::vector<std::string>& metric_names,
985     TraceProcessor::MetricResultFormat format,
986     std::string* metrics_string) {
987   std::vector<uint8_t> metrics_proto;
988   base::Status status = ComputeMetric(metric_names, &metrics_proto);
989   if (!status.ok())
990     return status;
991   switch (format) {
992     case TraceProcessor::MetricResultFormat::kProtoText:
993       *metrics_string = protozero_to_text::ProtozeroToText(
994           pool_, ".perfetto.protos.TraceMetrics",
995           protozero::ConstBytes{metrics_proto.data(), metrics_proto.size()},
996           protozero_to_text::kIncludeNewLines);
997       break;
998     case TraceProcessor::MetricResultFormat::kJson:
999       // TODO(dproy): Implement this.
1000       PERFETTO_FATAL("Json formatted metrics not supported yet.");
1001       break;
1002   }
1003   return status;
1004 }
1005 
GetMetricDescriptors()1006 std::vector<uint8_t> TraceProcessorImpl::GetMetricDescriptors() {
1007   return pool_.SerializeAsDescriptorSet();
1008 }
1009 
EnableMetatrace(MetatraceConfig config)1010 void TraceProcessorImpl::EnableMetatrace(MetatraceConfig config) {
1011   metatrace::Enable(config);
1012 }
1013 
1014 namespace {
1015 
1016 class StringInterner {
1017  public:
StringInterner(protos::pbzero::PerfettoMetatrace & event,base::FlatHashMap<std::string,uint64_t> & interned_strings)1018   StringInterner(protos::pbzero::PerfettoMetatrace& event,
1019                  base::FlatHashMap<std::string, uint64_t>& interned_strings)
1020       : event_(event), interned_strings_(interned_strings) {}
1021 
~StringInterner()1022   ~StringInterner() {
1023     for (const auto& interned_string : new_interned_strings_) {
1024       auto* interned_string_proto = event_.add_interned_strings();
1025       interned_string_proto->set_iid(interned_string.first);
1026       interned_string_proto->set_value(interned_string.second);
1027     }
1028   }
1029 
InternString(const std::string & str)1030   uint64_t InternString(const std::string& str) {
1031     uint64_t new_iid = interned_strings_.size();
1032     auto insert_result = interned_strings_.Insert(str, new_iid);
1033     if (insert_result.second) {
1034       new_interned_strings_.emplace_back(new_iid, str);
1035     }
1036     return *insert_result.first;
1037   }
1038 
1039  private:
1040   protos::pbzero::PerfettoMetatrace& event_;
1041   base::FlatHashMap<std::string, uint64_t>& interned_strings_;
1042 
1043   base::SmallVector<std::pair<uint64_t, std::string>, 16> new_interned_strings_;
1044 };
1045 
1046 }  // namespace
1047 
DisableAndReadMetatrace(std::vector<uint8_t> * trace_proto)1048 base::Status TraceProcessorImpl::DisableAndReadMetatrace(
1049     std::vector<uint8_t>* trace_proto) {
1050   protozero::HeapBuffered<protos::pbzero::Trace> trace;
1051 
1052   {
1053     uint64_t realtime_timestamp = static_cast<uint64_t>(
1054         std::chrono::system_clock::now().time_since_epoch() /
1055         std::chrono::nanoseconds(1));
1056     uint64_t boottime_timestamp = metatrace::TraceTimeNowNs();
1057     auto* clock_snapshot = trace->add_packet()->set_clock_snapshot();
1058     {
1059       auto* realtime_clock = clock_snapshot->add_clocks();
1060       realtime_clock->set_clock_id(
1061           protos::pbzero::BuiltinClock::BUILTIN_CLOCK_REALTIME);
1062       realtime_clock->set_timestamp(realtime_timestamp);
1063     }
1064     {
1065       auto* boottime_clock = clock_snapshot->add_clocks();
1066       boottime_clock->set_clock_id(
1067           protos::pbzero::BuiltinClock::BUILTIN_CLOCK_BOOTTIME);
1068       boottime_clock->set_timestamp(boottime_timestamp);
1069     }
1070   }
1071 
1072   base::FlatHashMap<std::string, uint64_t> interned_strings;
1073   metatrace::DisableAndReadBuffer([&trace, &interned_strings](
1074                                       metatrace::Record* record) {
1075     auto packet = trace->add_packet();
1076     packet->set_timestamp(record->timestamp_ns);
1077     auto* evt = packet->set_perfetto_metatrace();
1078 
1079     StringInterner interner(*evt, interned_strings);
1080 
1081     evt->set_event_name_iid(interner.InternString(record->event_name));
1082     evt->set_event_duration_ns(record->duration_ns);
1083     evt->set_thread_id(1);  // Not really important, just required for the ui.
1084 
1085     if (record->args_buffer_size == 0)
1086       return;
1087 
1088     base::StringSplitter s(
1089         record->args_buffer, record->args_buffer_size, '\0',
1090         base::StringSplitter::EmptyTokenMode::ALLOW_EMPTY_TOKENS);
1091     for (; s.Next();) {
1092       auto* arg_proto = evt->add_args();
1093       arg_proto->set_key_iid(interner.InternString(s.cur_token()));
1094 
1095       bool has_next = s.Next();
1096       PERFETTO_CHECK(has_next);
1097       arg_proto->set_value_iid(interner.InternString(s.cur_token()));
1098     }
1099   });
1100   *trace_proto = trace.SerializeAsArray();
1101   return base::OkStatus();
1102 }
1103 
1104 }  // namespace trace_processor
1105 }  // namespace perfetto
1106