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 <inttypes.h> 20 #include <algorithm> 21 #include <functional> 22 23 #include "perfetto/base/logging.h" 24 #include "perfetto/base/string_utils.h" 25 #include "perfetto/base/time.h" 26 #include "perfetto/protozero/scattered_heap_buffer.h" 27 #include "src/trace_processor/android_logs_table.h" 28 #include "src/trace_processor/args_table.h" 29 #include "src/trace_processor/args_tracker.h" 30 #include "src/trace_processor/clock_tracker.h" 31 #include "src/trace_processor/counter_definitions_table.h" 32 #include "src/trace_processor/counter_values_table.h" 33 #include "src/trace_processor/event_tracker.h" 34 #include "src/trace_processor/fuchsia_trace_parser.h" 35 #include "src/trace_processor/fuchsia_trace_tokenizer.h" 36 #include "src/trace_processor/heap_profile_tracker.h" 37 #include "src/trace_processor/instants_table.h" 38 #include "src/trace_processor/metrics/metrics.h" 39 #include "src/trace_processor/process_table.h" 40 #include "src/trace_processor/process_tracker.h" 41 #include "src/trace_processor/proto_trace_parser.h" 42 #include "src/trace_processor/proto_trace_tokenizer.h" 43 #include "src/trace_processor/raw_table.h" 44 #include "src/trace_processor/sched_slice_table.h" 45 #include "src/trace_processor/slice_table.h" 46 #include "src/trace_processor/slice_tracker.h" 47 #include "src/trace_processor/span_join_operator_table.h" 48 #include "src/trace_processor/sql_stats_table.h" 49 #include "src/trace_processor/sqlite3_str_split.h" 50 #include "src/trace_processor/stats_table.h" 51 #include "src/trace_processor/string_table.h" 52 #include "src/trace_processor/syscall_tracker.h" 53 #include "src/trace_processor/table.h" 54 #include "src/trace_processor/thread_table.h" 55 #include "src/trace_processor/trace_blob_view.h" 56 #include "src/trace_processor/trace_sorter.h" 57 #include "src/trace_processor/window_operator_table.h" 58 59 #include "perfetto/metrics/android/mem_metric.pbzero.h" 60 #include "perfetto/metrics/metrics.pbzero.h" 61 62 // JSON parsing is only supported in the standalone build. 63 #if PERFETTO_BUILDFLAG(PERFETTO_STANDALONE_BUILD) 64 #include "src/trace_processor/json_trace_parser.h" 65 #include "src/trace_processor/json_trace_tokenizer.h" 66 #endif 67 68 // In Android tree builds, we don't have the percentile module. 69 // Just don't include it. 70 #if !PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) 71 // defined in sqlite_src/ext/misc/percentile.c 72 extern "C" int sqlite3_percentile_init(sqlite3* db, 73 char** error, 74 const sqlite3_api_routines* api); 75 #endif 76 77 namespace perfetto { 78 namespace trace_processor { 79 namespace { 80 81 std::string RemoveWhitespace(const std::string& input) { 82 std::string str(input); 83 str.erase(std::remove_if(str.begin(), str.end(), ::isspace), str.end()); 84 return str; 85 } 86 87 void InitializeSqlite(sqlite3* db) { 88 char* error = nullptr; 89 sqlite3_exec(db, "PRAGMA temp_store=2", 0, 0, &error); 90 if (error) { 91 PERFETTO_FATAL("Error setting pragma temp_store: %s", error); 92 } 93 sqlite3_str_split_init(db); 94 // In Android tree builds, we don't have the percentile module. 95 // Just don't include it. 96 #if !PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD) 97 sqlite3_percentile_init(db, &error, nullptr); 98 if (error) { 99 PERFETTO_ELOG("Error initializing: %s", error); 100 sqlite3_free(error); 101 } 102 #endif 103 } 104 105 void BuildBoundsTable(sqlite3* db, std::pair<int64_t, int64_t> bounds) { 106 char* error = nullptr; 107 sqlite3_exec(db, "DELETE FROM trace_bounds", nullptr, nullptr, &error); 108 if (error) { 109 PERFETTO_ELOG("Error deleting from bounds table: %s", error); 110 sqlite3_free(error); 111 return; 112 } 113 114 char* insert_sql = sqlite3_mprintf("INSERT INTO trace_bounds VALUES(%" PRId64 115 ", %" PRId64 ")", 116 bounds.first, bounds.second); 117 118 sqlite3_exec(db, insert_sql, 0, 0, &error); 119 sqlite3_free(insert_sql); 120 if (error) { 121 PERFETTO_ELOG("Error inserting bounds table: %s", error); 122 sqlite3_free(error); 123 } 124 } 125 126 void CreateBuiltinTables(sqlite3* db) { 127 char* error = nullptr; 128 sqlite3_exec(db, "CREATE TABLE perfetto_tables(name STRING)", 0, 0, &error); 129 if (error) { 130 PERFETTO_ELOG("Error initializing: %s", error); 131 sqlite3_free(error); 132 } 133 sqlite3_exec(db, 134 "CREATE TABLE trace_bounds(start_ts BIG INT, end_ts BIG INT)", 0, 135 0, &error); 136 if (error) { 137 PERFETTO_ELOG("Error initializing: %s", error); 138 sqlite3_free(error); 139 } 140 141 // Initialize the bounds table with some data so even before parsing any data, 142 // we still have a valid table. 143 BuildBoundsTable(db, std::make_pair(0, 0)); 144 } 145 146 void CreateBuiltinViews(sqlite3* db) { 147 char* error = nullptr; 148 sqlite3_exec(db, 149 "CREATE VIEW counters AS " 150 "SELECT * FROM counter_values " 151 "INNER JOIN counter_definitions USING(counter_id);", 152 0, 0, &error); 153 if (error) { 154 PERFETTO_ELOG("Error initializing: %s", error); 155 sqlite3_free(error); 156 } 157 158 sqlite3_exec(db, 159 "CREATE VIEW slice AS " 160 "SELECT " 161 " *, " 162 " CASE ref_type " 163 " WHEN 'utid' THEN ref " 164 " ELSE NULL " 165 " END AS utid " 166 "FROM internal_slice;", 167 0, 0, &error); 168 if (error) { 169 PERFETTO_ELOG("Error initializing: %s", error); 170 sqlite3_free(error); 171 } 172 173 // Legacy view for "slice" table with a deprecated table name. 174 // TODO(eseckler): Remove this view when all users have switched to "slice". 175 sqlite3_exec(db, 176 "CREATE VIEW slices AS " 177 "SELECT * FROM slice;", 178 0, 0, &error); 179 if (error) { 180 PERFETTO_ELOG("Error initializing: %s", error); 181 sqlite3_free(error); 182 } 183 } 184 185 void CreateMetricsFunctions(TraceProcessorImpl* tp, sqlite3* db) { 186 auto ret = sqlite3_create_function_v2(db, "RUN_METRIC", -1, SQLITE_UTF8, tp, 187 metrics::RunMetric, nullptr, nullptr, 188 sqlite_utils::kSqliteStatic); 189 if (ret) { 190 PERFETTO_ELOG("Error initializing RUN_METRIC"); 191 } 192 } 193 194 // Fuchsia traces have a magic number as documented here: 195 // https://fuchsia.googlesource.com/fuchsia/+/HEAD/docs/development/tracing/trace-format/README.md#magic-number-record-trace-info-type-0 196 constexpr uint64_t kFuchsiaMagicNumber = 0x0016547846040010; 197 198 } // namespace 199 200 TraceType GuessTraceType(const uint8_t* data, size_t size) { 201 if (size == 0) 202 return kUnknownTraceType; 203 std::string start(reinterpret_cast<const char*>(data), 204 std::min<size_t>(size, 20)); 205 std::string start_minus_white_space = RemoveWhitespace(start); 206 if (base::StartsWith(start_minus_white_space, "{\"traceEvents\":[")) 207 return kJsonTraceType; 208 if (base::StartsWith(start_minus_white_space, "[{")) 209 return kJsonTraceType; 210 if (size >= 8) { 211 uint64_t first_word = *reinterpret_cast<const uint64_t*>(data); 212 if (first_word == kFuchsiaMagicNumber) 213 return kFuchsiaTraceType; 214 } 215 return ProtoTraceTokenizer::GuessProtoTraceType(data, size); 216 } 217 218 TraceProcessorImpl::TraceProcessorImpl(const Config& cfg) : cfg_(cfg) { 219 sqlite3* db = nullptr; 220 PERFETTO_CHECK(sqlite3_open(":memory:", &db) == SQLITE_OK); 221 InitializeSqlite(db); 222 CreateBuiltinTables(db); 223 CreateBuiltinViews(db); 224 CreateMetricsFunctions(this, db); 225 db_.reset(std::move(db)); 226 227 context_.storage.reset(new TraceStorage()); 228 context_.args_tracker.reset(new ArgsTracker(&context_)); 229 context_.slice_tracker.reset(new SliceTracker(&context_)); 230 context_.event_tracker.reset(new EventTracker(&context_)); 231 context_.process_tracker.reset(new ProcessTracker(&context_)); 232 context_.syscall_tracker.reset(new SyscallTracker(&context_)); 233 context_.clock_tracker.reset(new ClockTracker(&context_)); 234 context_.heap_profile_tracker.reset(new HeapProfileTracker(&context_)); 235 236 ArgsTable::RegisterTable(*db_, context_.storage.get()); 237 ProcessTable::RegisterTable(*db_, context_.storage.get()); 238 SchedSliceTable::RegisterTable(*db_, context_.storage.get()); 239 SliceTable::RegisterTable(*db_, context_.storage.get()); 240 SqlStatsTable::RegisterTable(*db_, context_.storage.get()); 241 StringTable::RegisterTable(*db_, context_.storage.get()); 242 ThreadTable::RegisterTable(*db_, context_.storage.get()); 243 CounterDefinitionsTable::RegisterTable(*db_, context_.storage.get()); 244 CounterValuesTable::RegisterTable(*db_, context_.storage.get()); 245 SpanJoinOperatorTable::RegisterTable(*db_, context_.storage.get()); 246 WindowOperatorTable::RegisterTable(*db_, context_.storage.get()); 247 InstantsTable::RegisterTable(*db_, context_.storage.get()); 248 StatsTable::RegisterTable(*db_, context_.storage.get()); 249 AndroidLogsTable::RegisterTable(*db_, context_.storage.get()); 250 RawTable::RegisterTable(*db_, context_.storage.get()); 251 } 252 253 TraceProcessorImpl::~TraceProcessorImpl() { 254 for (auto* it : iterators_) 255 it->Reset(); 256 } 257 258 bool TraceProcessorImpl::Parse(std::unique_ptr<uint8_t[]> data, size_t size) { 259 if (size == 0) 260 return true; 261 if (unrecoverable_parse_error_) 262 return false; 263 264 // If this is the first Parse() call, guess the trace type and create the 265 // appropriate parser. 266 if (!context_.chunk_reader) { 267 TraceType trace_type; 268 { 269 auto scoped_trace = context_.storage->TraceExecutionTimeIntoStats( 270 stats::guess_trace_type_duration_ns); 271 trace_type = GuessTraceType(data.get(), size); 272 } 273 int64_t window_size_ns = static_cast<int64_t>(cfg_.window_size_ns); 274 switch (trace_type) { 275 case kJsonTraceType: 276 PERFETTO_DLOG("Legacy JSON trace detected"); 277 #if PERFETTO_BUILDFLAG(PERFETTO_STANDALONE_BUILD) 278 context_.chunk_reader.reset(new JsonTraceTokenizer(&context_)); 279 // JSON traces have no guarantees about the order of events in them. 280 window_size_ns = std::numeric_limits<int64_t>::max(); 281 context_.sorter.reset(new TraceSorter(&context_, window_size_ns)); 282 context_.parser.reset(new JsonTraceParser(&context_)); 283 #else 284 PERFETTO_FATAL("JSON traces only supported in standalone mode."); 285 #endif 286 break; 287 case kProtoWithTrackEventsTraceType: 288 case kProtoTraceType: 289 if (trace_type == kProtoWithTrackEventsTraceType) { 290 // TrackEvents can be ordered arbitrarily due to out-of-order absolute 291 // timestamps and cross-packet-sequence events (e.g. async events). 292 window_size_ns = std::numeric_limits<int64_t>::max(); 293 } 294 context_.chunk_reader.reset(new ProtoTraceTokenizer(&context_)); 295 context_.sorter.reset(new TraceSorter(&context_, window_size_ns)); 296 context_.parser.reset(new ProtoTraceParser(&context_)); 297 break; 298 case kFuchsiaTraceType: 299 context_.chunk_reader.reset(new FuchsiaTraceTokenizer(&context_)); 300 context_.sorter.reset(new TraceSorter(&context_, window_size_ns)); 301 context_.parser.reset(new FuchsiaTraceParser(&context_)); 302 break; 303 case kUnknownTraceType: 304 return false; 305 } 306 } 307 308 auto scoped_trace = context_.storage->TraceExecutionTimeIntoStats( 309 stats::parse_trace_duration_ns); 310 bool res = context_.chunk_reader->Parse(std::move(data), size); 311 unrecoverable_parse_error_ |= !res; 312 return res; 313 } 314 315 void TraceProcessorImpl::NotifyEndOfFile() { 316 if (unrecoverable_parse_error_ || !context_.chunk_reader) 317 return; 318 319 context_.sorter->ExtractEventsForced(); 320 context_.event_tracker->FlushPendingEvents(); 321 BuildBoundsTable(*db_, context_.storage->GetTraceTimestampBoundsNs()); 322 } 323 324 TraceProcessor::Iterator TraceProcessorImpl::ExecuteQuery( 325 const std::string& sql, 326 int64_t time_queued) { 327 sqlite3_stmt* raw_stmt; 328 int err = sqlite3_prepare_v2(*db_, sql.c_str(), static_cast<int>(sql.size()), 329 &raw_stmt, nullptr); 330 base::Optional<std::string> error; 331 uint32_t col_count = 0; 332 if (err != SQLITE_OK) { 333 error = sqlite3_errmsg(*db_); 334 } else { 335 col_count = static_cast<uint32_t>(sqlite3_column_count(raw_stmt)); 336 } 337 338 base::TimeNanos t_start = base::GetWallTimeNs(); 339 uint32_t sql_stats_row = 340 context_.storage->mutable_sql_stats()->RecordQueryBegin(sql, time_queued, 341 t_start.count()); 342 343 std::unique_ptr<IteratorImpl> impl(new IteratorImpl( 344 this, *db_, ScopedStmt(raw_stmt), col_count, error, sql_stats_row)); 345 iterators_.emplace_back(impl.get()); 346 return TraceProcessor::Iterator(std::move(impl)); 347 } 348 349 void TraceProcessorImpl::InterruptQuery() { 350 if (!db_) 351 return; 352 query_interrupted_.store(true); 353 sqlite3_interrupt(db_.get()); 354 } 355 356 int TraceProcessorImpl::ComputeMetric( 357 const std::vector<std::string>& metric_names, 358 std::vector<uint8_t>* metrics_proto) { 359 return metrics::ComputeMetrics(this, metric_names, metrics_proto); 360 } 361 362 TraceProcessor::IteratorImpl::IteratorImpl(TraceProcessorImpl* trace_processor, 363 sqlite3* db, 364 ScopedStmt stmt, 365 uint32_t column_count, 366 base::Optional<std::string> error, 367 uint32_t sql_stats_row) 368 : trace_processor_(trace_processor), 369 db_(db), 370 stmt_(std::move(stmt)), 371 column_count_(column_count), 372 error_(error), 373 sql_stats_row_(sql_stats_row) {} 374 375 TraceProcessor::IteratorImpl::~IteratorImpl() { 376 if (trace_processor_) { 377 auto* its = &trace_processor_->iterators_; 378 auto it = std::find(its->begin(), its->end(), this); 379 PERFETTO_CHECK(it != its->end()); 380 its->erase(it); 381 382 base::TimeNanos t_end = base::GetWallTimeNs(); 383 auto* sql_stats = trace_processor_->context_.storage->mutable_sql_stats(); 384 sql_stats->RecordQueryEnd(sql_stats_row_, t_end.count()); 385 } 386 } 387 388 void TraceProcessor::IteratorImpl::Reset() { 389 *this = IteratorImpl(nullptr, nullptr, ScopedStmt(), 0, base::nullopt, 0); 390 } 391 392 void TraceProcessor::IteratorImpl::RecordFirstNextInSqlStats() { 393 base::TimeNanos t_first_next = base::GetWallTimeNs(); 394 auto* sql_stats = trace_processor_->context_.storage->mutable_sql_stats(); 395 sql_stats->RecordQueryFirstNext(sql_stats_row_, t_first_next.count()); 396 } 397 398 } // namespace trace_processor 399 } // namespace perfetto 400