1 /* 2 * Copyright (C) 2017 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 #ifndef SRC_TRACE_PROCESSOR_TRACE_STORAGE_H_ 18 #define SRC_TRACE_PROCESSOR_TRACE_STORAGE_H_ 19 20 #include <array> 21 #include <deque> 22 #include <map> 23 #include <string> 24 #include <unordered_map> 25 #include <utility> 26 #include <vector> 27 28 #include "perfetto/base/hash.h" 29 #include "perfetto/base/logging.h" 30 #include "perfetto/base/optional.h" 31 #include "perfetto/base/string_view.h" 32 #include "perfetto/base/time.h" 33 #include "perfetto/base/utils.h" 34 #include "src/trace_processor/ftrace_utils.h" 35 #include "src/trace_processor/stats.h" 36 #include "src/trace_processor/string_pool.h" 37 38 namespace perfetto { 39 namespace trace_processor { 40 41 // UniquePid is an offset into |unique_processes_|. This is necessary because 42 // Unix pids are reused and thus not guaranteed to be unique over a long 43 // period of time. 44 using UniquePid = uint32_t; 45 46 // UniqueTid is an offset into |unique_threads_|. Necessary because tids can 47 // be reused. 48 using UniqueTid = uint32_t; 49 50 // StringId is an offset into |string_pool_|. 51 using StringId = StringPool::Id; 52 53 // Identifiers for all the tables in the database. 54 enum TableId : uint8_t { 55 // Intentionally don't have TableId == 0 so that RowId == 0 can refer to an 56 // invalid row id. 57 kCounterValues = 1, 58 kRawEvents = 2, 59 kInstants = 3, 60 kSched = 4, 61 }; 62 63 // The top 8 bits are set to the TableId and the bottom 32 to the row of the 64 // table. 65 using RowId = int64_t; 66 static const RowId kInvalidRowId = 0; 67 68 using ArgSetId = uint32_t; 69 static const ArgSetId kInvalidArgSetId = 0; 70 71 enum RefType { 72 kRefNoRef = 0, 73 kRefUtid = 1, 74 kRefCpuId = 2, 75 kRefIrq = 3, 76 kRefSoftIrq = 4, 77 kRefUpid = 5, 78 kRefMax 79 }; 80 81 const std::vector<const char*>& GetRefTypeStringMap(); 82 83 // Stores a data inside a trace file in a columnar form. This makes it efficient 84 // to read or search across a single field of the trace (e.g. all the thread 85 // names for a given CPU). 86 class TraceStorage { 87 public: 88 TraceStorage(); 89 90 virtual ~TraceStorage(); 91 92 // Information about a unique process seen in a trace. 93 struct Process { ProcessProcess94 explicit Process(uint32_t p) : pid(p) {} 95 int64_t start_ns = 0; 96 StringId name_id = 0; 97 uint32_t pid = 0; 98 base::Optional<UniquePid> pupid; 99 }; 100 101 // Information about a unique thread seen in a trace. 102 struct Thread { ThreadThread103 explicit Thread(uint32_t t) : tid(t) {} 104 int64_t start_ns = 0; 105 StringId name_id = 0; 106 base::Optional<UniquePid> upid; 107 uint32_t tid = 0; 108 }; 109 110 // Generic key value storage which can be referenced by other tables. 111 class Args { 112 public: 113 // Variadic type representing the possible values for the args table. 114 struct Variadic { 115 enum Type { kInt, kString, kReal }; 116 IntegerVariadic117 static Variadic Integer(int64_t int_value) { 118 Variadic variadic; 119 variadic.type = Type::kInt; 120 variadic.int_value = int_value; 121 return variadic; 122 } 123 StringVariadic124 static Variadic String(StringId string_id) { 125 Variadic variadic; 126 variadic.type = Type::kString; 127 variadic.string_value = string_id; 128 return variadic; 129 } 130 RealVariadic131 static Variadic Real(double real_value) { 132 Variadic variadic; 133 variadic.type = Type::kReal; 134 variadic.real_value = real_value; 135 return variadic; 136 } 137 138 Type type; 139 union { 140 int64_t int_value; 141 StringId string_value; 142 double real_value; 143 }; 144 }; 145 146 struct Arg { 147 StringId flat_key = 0; 148 StringId key = 0; 149 Variadic value = Variadic::Integer(0); 150 151 // This is only used by the arg tracker and so is not part of the hash. 152 RowId row_id = 0; 153 }; 154 155 struct ArgHasher { operatorArgHasher156 uint64_t operator()(const Arg& arg) const noexcept { 157 base::Hash hash; 158 hash.Update(arg.key); 159 // We don't hash arg.flat_key because it's a subsequence of arg.key. 160 switch (arg.value.type) { 161 case Variadic::Type::kInt: 162 hash.Update(arg.value.int_value); 163 break; 164 case Variadic::Type::kString: 165 hash.Update(arg.value.string_value); 166 break; 167 case Variadic::Type::kReal: 168 hash.Update(arg.value.real_value); 169 break; 170 } 171 return hash.digest(); 172 } 173 }; 174 set_ids()175 const std::deque<ArgSetId>& set_ids() const { return set_ids_; } flat_keys()176 const std::deque<StringId>& flat_keys() const { return flat_keys_; } keys()177 const std::deque<StringId>& keys() const { return keys_; } arg_values()178 const std::deque<Variadic>& arg_values() const { return arg_values_; } args_count()179 uint32_t args_count() const { 180 return static_cast<uint32_t>(set_ids_.size()); 181 } 182 AddArgSet(const std::vector<Arg> & args,uint32_t begin,uint32_t end)183 ArgSetId AddArgSet(const std::vector<Arg>& args, 184 uint32_t begin, 185 uint32_t end) { 186 base::Hash hash; 187 for (uint32_t i = begin; i < end; i++) { 188 hash.Update(ArgHasher()(args[i])); 189 } 190 191 ArgSetHash digest = hash.digest(); 192 auto it = arg_row_for_hash_.find(digest); 193 if (it != arg_row_for_hash_.end()) { 194 return set_ids_[it->second]; 195 } 196 197 // The +1 ensures that nothing has an id == kInvalidArgSetId == 0. 198 ArgSetId id = static_cast<uint32_t>(arg_row_for_hash_.size()) + 1; 199 arg_row_for_hash_.emplace(digest, args_count()); 200 for (uint32_t i = begin; i < end; i++) { 201 const auto& arg = args[i]; 202 set_ids_.emplace_back(id); 203 flat_keys_.emplace_back(arg.flat_key); 204 keys_.emplace_back(arg.key); 205 arg_values_.emplace_back(arg.value); 206 } 207 return id; 208 } 209 210 private: 211 using ArgSetHash = uint64_t; 212 213 std::deque<ArgSetId> set_ids_; 214 std::deque<StringId> flat_keys_; 215 std::deque<StringId> keys_; 216 std::deque<Variadic> arg_values_; 217 218 std::unordered_map<ArgSetHash, uint32_t> arg_row_for_hash_; 219 }; 220 221 class Slices { 222 public: AddSlice(uint32_t cpu,int64_t start_ns,int64_t duration_ns,UniqueTid utid,ftrace_utils::TaskState end_state,int32_t priority)223 inline size_t AddSlice(uint32_t cpu, 224 int64_t start_ns, 225 int64_t duration_ns, 226 UniqueTid utid, 227 ftrace_utils::TaskState end_state, 228 int32_t priority) { 229 cpus_.emplace_back(cpu); 230 start_ns_.emplace_back(start_ns); 231 durations_.emplace_back(duration_ns); 232 utids_.emplace_back(utid); 233 end_states_.emplace_back(end_state); 234 priorities_.emplace_back(priority); 235 236 if (utid >= rows_for_utids_.size()) 237 rows_for_utids_.resize(utid + 1); 238 rows_for_utids_[utid].emplace_back(slice_count() - 1); 239 return slice_count() - 1; 240 } 241 set_duration(size_t index,int64_t duration_ns)242 void set_duration(size_t index, int64_t duration_ns) { 243 durations_[index] = duration_ns; 244 } 245 set_end_state(size_t index,ftrace_utils::TaskState end_state)246 void set_end_state(size_t index, ftrace_utils::TaskState end_state) { 247 end_states_[index] = end_state; 248 } 249 slice_count()250 size_t slice_count() const { return start_ns_.size(); } 251 cpus()252 const std::deque<uint32_t>& cpus() const { return cpus_; } 253 start_ns()254 const std::deque<int64_t>& start_ns() const { return start_ns_; } 255 durations()256 const std::deque<int64_t>& durations() const { return durations_; } 257 utids()258 const std::deque<UniqueTid>& utids() const { return utids_; } 259 end_state()260 const std::deque<ftrace_utils::TaskState>& end_state() const { 261 return end_states_; 262 } 263 priorities()264 const std::deque<int32_t>& priorities() const { return priorities_; } 265 rows_for_utids()266 const std::deque<std::vector<uint32_t>>& rows_for_utids() const { 267 return rows_for_utids_; 268 } 269 270 private: 271 // Each deque below has the same number of entries (the number of slices 272 // in the trace for the CPU). 273 std::deque<uint32_t> cpus_; 274 std::deque<int64_t> start_ns_; 275 std::deque<int64_t> durations_; 276 std::deque<UniqueTid> utids_; 277 std::deque<ftrace_utils::TaskState> end_states_; 278 std::deque<int32_t> priorities_; 279 280 // One row per utid. 281 std::deque<std::vector<uint32_t>> rows_for_utids_; 282 }; 283 284 class NestableSlices { 285 public: AddSlice(int64_t start_ns,int64_t duration_ns,int64_t ref,RefType type,StringId cat,StringId name,uint8_t depth,int64_t stack_id,int64_t parent_stack_id)286 inline size_t AddSlice(int64_t start_ns, 287 int64_t duration_ns, 288 int64_t ref, 289 RefType type, 290 StringId cat, 291 StringId name, 292 uint8_t depth, 293 int64_t stack_id, 294 int64_t parent_stack_id) { 295 start_ns_.emplace_back(start_ns); 296 durations_.emplace_back(duration_ns); 297 refs_.emplace_back(ref); 298 types_.emplace_back(type); 299 cats_.emplace_back(cat); 300 names_.emplace_back(name); 301 depths_.emplace_back(depth); 302 stack_ids_.emplace_back(stack_id); 303 parent_stack_ids_.emplace_back(parent_stack_id); 304 return slice_count() - 1; 305 } 306 set_duration(size_t index,int64_t duration_ns)307 void set_duration(size_t index, int64_t duration_ns) { 308 durations_[index] = duration_ns; 309 } 310 set_stack_id(size_t index,int64_t stack_id)311 void set_stack_id(size_t index, int64_t stack_id) { 312 stack_ids_[index] = stack_id; 313 } 314 slice_count()315 size_t slice_count() const { return start_ns_.size(); } start_ns()316 const std::deque<int64_t>& start_ns() const { return start_ns_; } durations()317 const std::deque<int64_t>& durations() const { return durations_; } refs()318 const std::deque<int64_t>& refs() const { return refs_; } types()319 const std::deque<RefType>& types() const { return types_; } cats()320 const std::deque<StringId>& cats() const { return cats_; } names()321 const std::deque<StringId>& names() const { return names_; } depths()322 const std::deque<uint8_t>& depths() const { return depths_; } stack_ids()323 const std::deque<int64_t>& stack_ids() const { return stack_ids_; } parent_stack_ids()324 const std::deque<int64_t>& parent_stack_ids() const { 325 return parent_stack_ids_; 326 } 327 328 private: 329 std::deque<int64_t> start_ns_; 330 std::deque<int64_t> durations_; 331 std::deque<int64_t> refs_; 332 std::deque<RefType> types_; 333 std::deque<StringId> cats_; 334 std::deque<StringId> names_; 335 std::deque<uint8_t> depths_; 336 std::deque<int64_t> stack_ids_; 337 std::deque<int64_t> parent_stack_ids_; 338 }; 339 340 class CounterDefinitions { 341 public: 342 using Id = uint32_t; 343 static constexpr Id kInvalidId = std::numeric_limits<Id>::max(); 344 AddCounterDefinition(StringId name_id,int64_t ref,RefType type)345 inline Id AddCounterDefinition(StringId name_id, 346 int64_t ref, 347 RefType type) { 348 base::Hash hash; 349 hash.Update(name_id); 350 hash.Update(ref); 351 hash.Update(type); 352 353 // TODO(lalitm): this is a perf bottleneck and likely we can do something 354 // quite a bit better here. 355 uint64_t digest = hash.digest(); 356 auto it = hash_to_row_idx_.find(digest); 357 if (it != hash_to_row_idx_.end()) 358 return it->second; 359 360 name_ids_.emplace_back(name_id); 361 refs_.emplace_back(ref); 362 types_.emplace_back(type); 363 hash_to_row_idx_.emplace(digest, size() - 1); 364 return size() - 1; 365 } 366 size()367 uint32_t size() const { return static_cast<uint32_t>(name_ids_.size()); } 368 name_ids()369 const std::deque<StringId>& name_ids() const { return name_ids_; } 370 refs()371 const std::deque<int64_t>& refs() const { return refs_; } 372 types()373 const std::deque<RefType>& types() const { return types_; } 374 375 private: 376 std::deque<StringId> name_ids_; 377 std::deque<int64_t> refs_; 378 std::deque<RefType> types_; 379 380 std::unordered_map<uint64_t, uint32_t> hash_to_row_idx_; 381 }; 382 383 class CounterValues { 384 public: AddCounterValue(CounterDefinitions::Id counter_id,int64_t timestamp,double value)385 inline uint32_t AddCounterValue(CounterDefinitions::Id counter_id, 386 int64_t timestamp, 387 double value) { 388 counter_ids_.emplace_back(counter_id); 389 timestamps_.emplace_back(timestamp); 390 values_.emplace_back(value); 391 arg_set_ids_.emplace_back(kInvalidArgSetId); 392 393 if (counter_id != CounterDefinitions::kInvalidId) { 394 if (counter_id >= rows_for_counter_id_.size()) { 395 rows_for_counter_id_.resize(counter_id + 1); 396 } 397 rows_for_counter_id_[counter_id].emplace_back(size() - 1); 398 } 399 return size() - 1; 400 } 401 set_counter_id(uint32_t index,CounterDefinitions::Id counter_id)402 void set_counter_id(uint32_t index, CounterDefinitions::Id counter_id) { 403 PERFETTO_DCHECK(counter_ids_[index] == CounterDefinitions::kInvalidId); 404 405 counter_ids_[index] = counter_id; 406 if (counter_id >= rows_for_counter_id_.size()) { 407 rows_for_counter_id_.resize(counter_id + 1); 408 } 409 410 auto* new_rows = &rows_for_counter_id_[counter_id]; 411 new_rows->insert( 412 std::upper_bound(new_rows->begin(), new_rows->end(), index), index); 413 } 414 set_arg_set_id(uint32_t row,ArgSetId id)415 void set_arg_set_id(uint32_t row, ArgSetId id) { arg_set_ids_[row] = id; } 416 size()417 uint32_t size() const { return static_cast<uint32_t>(counter_ids_.size()); } 418 counter_ids()419 const std::deque<CounterDefinitions::Id>& counter_ids() const { 420 return counter_ids_; 421 } 422 timestamps()423 const std::deque<int64_t>& timestamps() const { return timestamps_; } 424 values()425 const std::deque<double>& values() const { return values_; } 426 arg_set_ids()427 const std::deque<ArgSetId>& arg_set_ids() const { return arg_set_ids_; } 428 rows_for_counter_id()429 const std::deque<std::vector<uint32_t>>& rows_for_counter_id() const { 430 return rows_for_counter_id_; 431 } 432 433 private: 434 std::deque<CounterDefinitions::Id> counter_ids_; 435 std::deque<int64_t> timestamps_; 436 std::deque<double> values_; 437 std::deque<ArgSetId> arg_set_ids_; 438 439 // Indexed by counter_id value and contains the row numbers corresponding to 440 // it. 441 std::deque<std::vector<uint32_t>> rows_for_counter_id_; 442 }; 443 444 class SqlStats { 445 public: 446 static constexpr size_t kMaxLogEntries = 100; 447 uint32_t RecordQueryBegin(const std::string& query, 448 int64_t time_queued, 449 int64_t time_started); 450 void RecordQueryFirstNext(uint32_t row, int64_t time_first_next); 451 void RecordQueryEnd(uint32_t row, int64_t time_end); size()452 size_t size() const { return queries_.size(); } queries()453 const std::deque<std::string>& queries() const { return queries_; } times_queued()454 const std::deque<int64_t>& times_queued() const { return times_queued_; } times_started()455 const std::deque<int64_t>& times_started() const { return times_started_; } times_first_next()456 const std::deque<int64_t>& times_first_next() const { 457 return times_first_next_; 458 } times_ended()459 const std::deque<int64_t>& times_ended() const { return times_ended_; } 460 461 private: 462 uint32_t popped_queries_ = 0; 463 464 std::deque<std::string> queries_; 465 std::deque<int64_t> times_queued_; 466 std::deque<int64_t> times_started_; 467 std::deque<int64_t> times_first_next_; 468 std::deque<int64_t> times_ended_; 469 }; 470 471 class Instants { 472 public: AddInstantEvent(int64_t timestamp,StringId name_id,double value,int64_t ref,RefType type)473 inline uint32_t AddInstantEvent(int64_t timestamp, 474 StringId name_id, 475 double value, 476 int64_t ref, 477 RefType type) { 478 timestamps_.emplace_back(timestamp); 479 name_ids_.emplace_back(name_id); 480 values_.emplace_back(value); 481 refs_.emplace_back(ref); 482 types_.emplace_back(type); 483 arg_set_ids_.emplace_back(kInvalidArgSetId); 484 return static_cast<uint32_t>(instant_count() - 1); 485 } 486 set_ref(uint32_t row,int64_t ref)487 void set_ref(uint32_t row, int64_t ref) { refs_[row] = ref; } 488 set_arg_set_id(uint32_t row,ArgSetId id)489 void set_arg_set_id(uint32_t row, ArgSetId id) { arg_set_ids_[row] = id; } 490 instant_count()491 size_t instant_count() const { return timestamps_.size(); } 492 timestamps()493 const std::deque<int64_t>& timestamps() const { return timestamps_; } 494 name_ids()495 const std::deque<StringId>& name_ids() const { return name_ids_; } 496 values()497 const std::deque<double>& values() const { return values_; } 498 refs()499 const std::deque<int64_t>& refs() const { return refs_; } 500 types()501 const std::deque<RefType>& types() const { return types_; } 502 arg_set_ids()503 const std::deque<ArgSetId>& arg_set_ids() const { return arg_set_ids_; } 504 505 private: 506 std::deque<int64_t> timestamps_; 507 std::deque<StringId> name_ids_; 508 std::deque<double> values_; 509 std::deque<int64_t> refs_; 510 std::deque<RefType> types_; 511 std::deque<ArgSetId> arg_set_ids_; 512 }; 513 514 class RawEvents { 515 public: AddRawEvent(int64_t timestamp,StringId name_id,uint32_t cpu,UniqueTid utid)516 inline RowId AddRawEvent(int64_t timestamp, 517 StringId name_id, 518 uint32_t cpu, 519 UniqueTid utid) { 520 timestamps_.emplace_back(timestamp); 521 name_ids_.emplace_back(name_id); 522 cpus_.emplace_back(cpu); 523 utids_.emplace_back(utid); 524 arg_set_ids_.emplace_back(kInvalidArgSetId); 525 return CreateRowId(TableId::kRawEvents, 526 static_cast<uint32_t>(raw_event_count() - 1)); 527 } 528 set_arg_set_id(uint32_t row,ArgSetId id)529 void set_arg_set_id(uint32_t row, ArgSetId id) { arg_set_ids_[row] = id; } 530 raw_event_count()531 size_t raw_event_count() const { return timestamps_.size(); } 532 timestamps()533 const std::deque<int64_t>& timestamps() const { return timestamps_; } 534 name_ids()535 const std::deque<StringId>& name_ids() const { return name_ids_; } 536 cpus()537 const std::deque<uint32_t>& cpus() const { return cpus_; } 538 utids()539 const std::deque<UniqueTid>& utids() const { return utids_; } 540 arg_set_ids()541 const std::deque<ArgSetId>& arg_set_ids() const { return arg_set_ids_; } 542 543 private: 544 std::deque<int64_t> timestamps_; 545 std::deque<StringId> name_ids_; 546 std::deque<uint32_t> cpus_; 547 std::deque<UniqueTid> utids_; 548 std::deque<ArgSetId> arg_set_ids_; 549 }; 550 551 class AndroidLogs { 552 public: AddLogEvent(int64_t timestamp,UniqueTid utid,uint8_t prio,StringId tag_id,StringId msg_id)553 inline size_t AddLogEvent(int64_t timestamp, 554 UniqueTid utid, 555 uint8_t prio, 556 StringId tag_id, 557 StringId msg_id) { 558 timestamps_.emplace_back(timestamp); 559 utids_.emplace_back(utid); 560 prios_.emplace_back(prio); 561 tag_ids_.emplace_back(tag_id); 562 msg_ids_.emplace_back(msg_id); 563 return size() - 1; 564 } 565 size()566 size_t size() const { return timestamps_.size(); } 567 timestamps()568 const std::deque<int64_t>& timestamps() const { return timestamps_; } utids()569 const std::deque<UniqueTid>& utids() const { return utids_; } prios()570 const std::deque<uint8_t>& prios() const { return prios_; } tag_ids()571 const std::deque<StringId>& tag_ids() const { return tag_ids_; } msg_ids()572 const std::deque<StringId>& msg_ids() const { return msg_ids_; } 573 574 private: 575 std::deque<int64_t> timestamps_; 576 std::deque<UniqueTid> utids_; 577 std::deque<uint8_t> prios_; 578 std::deque<StringId> tag_ids_; 579 std::deque<StringId> msg_ids_; 580 }; 581 582 struct Stats { 583 using IndexMap = std::map<int, int64_t>; 584 int64_t value = 0; 585 IndexMap indexed_values; 586 }; 587 using StatsMap = std::array<Stats, stats::kNumKeys>; 588 589 class HeapProfileFrames { 590 public: 591 struct Row { 592 StringId name_id; 593 int64_t mapping_row; 594 int64_t rel_pc; 595 596 bool operator==(const Row& other) const { 597 return std::tie(name_id, mapping_row, rel_pc) == 598 std::tie(other.name_id, other.mapping_row, other.rel_pc); 599 } 600 }; 601 Insert(const Row & row)602 int64_t Insert(const Row& row) { 603 names_.emplace_back(row.name_id); 604 mappings_.emplace_back(row.mapping_row); 605 rel_pcs_.emplace_back(row.rel_pc); 606 return static_cast<int64_t>(names_.size()) - 1; 607 } 608 names()609 const std::deque<StringId>& names() const { return names_; } mappings()610 const std::deque<int64_t>& mappings() const { return mappings_; } rel_pcs()611 const std::deque<int64_t>& rel_pcs() const { return rel_pcs_; } 612 613 private: 614 std::deque<StringId> names_; 615 std::deque<int64_t> mappings_; 616 std::deque<int64_t> rel_pcs_; 617 }; 618 619 class HeapProfileCallsites { 620 public: 621 struct Row { 622 int64_t depth; 623 int64_t parent_id; 624 int64_t frame_row; 625 626 bool operator==(const Row& other) const { 627 return std::tie(depth, parent_id, frame_row) == 628 std::tie(other.depth, other.parent_id, other.frame_row); 629 } 630 }; 631 Insert(const Row & row)632 int64_t Insert(const Row& row) { 633 frame_depths_.emplace_back(row.depth); 634 parent_callsite_ids_.emplace_back(row.parent_id); 635 frame_ids_.emplace_back(row.frame_row); 636 return static_cast<int64_t>(frame_depths_.size()) - 1; 637 } 638 frame_depths()639 const std::deque<int64_t>& frame_depths() const { return frame_depths_; } parent_callsite_ids()640 const std::deque<int64_t>& parent_callsite_ids() const { 641 return parent_callsite_ids_; 642 } frame_ids()643 const std::deque<int64_t>& frame_ids() const { return frame_ids_; } 644 645 private: 646 std::deque<int64_t> frame_depths_; 647 std::deque<int64_t> parent_callsite_ids_; 648 std::deque<int64_t> frame_ids_; 649 }; 650 651 class HeapProfileMappings { 652 public: 653 struct Row { 654 StringId build_id; 655 int64_t offset; 656 int64_t start; 657 int64_t end; 658 int64_t load_bias; 659 StringId name_id; 660 661 bool operator==(const Row& other) const { 662 return std::tie(build_id, offset, start, end, load_bias, name_id) == 663 std::tie(other.build_id, other.offset, other.start, other.end, 664 other.load_bias, other.name_id); 665 } 666 }; 667 Insert(const Row & row)668 int64_t Insert(const Row& row) { 669 build_ids_.emplace_back(row.build_id); 670 offsets_.emplace_back(row.offset); 671 starts_.emplace_back(row.start); 672 ends_.emplace_back(row.end); 673 load_biases_.emplace_back(row.load_bias); 674 names_.emplace_back(row.name_id); 675 return static_cast<int64_t>(build_ids_.size()) - 1; 676 } 677 build_ids()678 const std::deque<StringId>& build_ids() const { return build_ids_; } offsets()679 const std::deque<int64_t>& offsets() const { return offsets_; } starts()680 const std::deque<int64_t>& starts() const { return starts_; } ends()681 const std::deque<int64_t>& ends() const { return ends_; } load_biases()682 const std::deque<int64_t>& load_biases() const { return load_biases_; } names()683 const std::deque<StringId>& names() const { return names_; } 684 685 private: 686 std::deque<StringId> build_ids_; 687 std::deque<int64_t> offsets_; 688 std::deque<int64_t> starts_; 689 std::deque<int64_t> ends_; 690 std::deque<int64_t> load_biases_; 691 std::deque<StringId> names_; 692 }; 693 694 class HeapProfileAllocations { 695 public: 696 struct Row { 697 int64_t timestamp; 698 int64_t pid; 699 int64_t callsite_id; 700 int64_t count; 701 int64_t size; 702 }; 703 Insert(const Row & row)704 void Insert(const Row& row) { 705 timestamps_.emplace_back(row.timestamp); 706 pids_.emplace_back(row.pid); 707 callsite_ids_.emplace_back(row.callsite_id); 708 counts_.emplace_back(row.count); 709 sizes_.emplace_back(row.size); 710 } 711 timestamps()712 const std::deque<int64_t>& timestamps() const { return timestamps_; } pids()713 const std::deque<int64_t>& pids() const { return pids_; } callsite_ids()714 const std::deque<int64_t>& callsite_ids() const { return callsite_ids_; } counts()715 const std::deque<int64_t>& counts() const { return counts_; } sizes()716 const std::deque<int64_t>& sizes() const { return sizes_; } 717 718 private: 719 std::deque<int64_t> timestamps_; 720 std::deque<int64_t> pids_; 721 std::deque<int64_t> callsite_ids_; 722 std::deque<int64_t> counts_; 723 std::deque<int64_t> sizes_; 724 }; 725 726 void ResetStorage(); 727 AddEmptyThread(uint32_t tid)728 UniqueTid AddEmptyThread(uint32_t tid) { 729 unique_threads_.emplace_back(tid); 730 return static_cast<UniqueTid>(unique_threads_.size() - 1); 731 } 732 AddEmptyProcess(uint32_t pid)733 UniquePid AddEmptyProcess(uint32_t pid) { 734 unique_processes_.emplace_back(pid); 735 return static_cast<UniquePid>(unique_processes_.size() - 1); 736 } 737 738 // Return an unqiue identifier for the contents of each string. 739 // The string is copied internally and can be destroyed after this called. 740 // Virtual for testing. InternString(base::StringView str)741 virtual StringId InternString(base::StringView str) { 742 return string_pool_.InternString(str); 743 } 744 GetMutableProcess(UniquePid upid)745 Process* GetMutableProcess(UniquePid upid) { 746 PERFETTO_DCHECK(upid < unique_processes_.size()); 747 return &unique_processes_[upid]; 748 } 749 GetMutableThread(UniqueTid utid)750 Thread* GetMutableThread(UniqueTid utid) { 751 PERFETTO_DCHECK(utid < unique_threads_.size()); 752 return &unique_threads_[utid]; 753 } 754 755 // Example usage: SetStats(stats::android_log_num_failed, 42); SetStats(size_t key,int64_t value)756 void SetStats(size_t key, int64_t value) { 757 PERFETTO_DCHECK(key < stats::kNumKeys); 758 PERFETTO_DCHECK(stats::kTypes[key] == stats::kSingle); 759 stats_[key].value = value; 760 } 761 762 // Example usage: IncrementStats(stats::android_log_num_failed, -1); 763 void IncrementStats(size_t key, int64_t increment = 1) { 764 PERFETTO_DCHECK(key < stats::kNumKeys); 765 PERFETTO_DCHECK(stats::kTypes[key] == stats::kSingle); 766 stats_[key].value += increment; 767 } 768 769 // Example usage: IncrementIndexedStats(stats::cpu_failure, 1); 770 void IncrementIndexedStats(size_t key, int index, int64_t increment = 1) { 771 PERFETTO_DCHECK(key < stats::kNumKeys); 772 PERFETTO_DCHECK(stats::kTypes[key] == stats::kIndexed); 773 stats_[key].indexed_values[index] += increment; 774 } 775 776 // Example usage: SetIndexedStats(stats::cpu_failure, 1, 42); SetIndexedStats(size_t key,int index,int64_t value)777 void SetIndexedStats(size_t key, int index, int64_t value) { 778 PERFETTO_DCHECK(key < stats::kNumKeys); 779 PERFETTO_DCHECK(stats::kTypes[key] == stats::kIndexed); 780 stats_[key].indexed_values[index] = value; 781 } 782 783 class ScopedStatsTracer { 784 public: ScopedStatsTracer(TraceStorage * storage,size_t key)785 ScopedStatsTracer(TraceStorage* storage, size_t key) 786 : storage_(storage), key_(key), start_ns_(base::GetWallTimeNs()) {} 787 ~ScopedStatsTracer()788 ~ScopedStatsTracer() { 789 if (!storage_) 790 return; 791 auto delta_ns = base::GetWallTimeNs() - start_ns_; 792 storage_->IncrementStats(key_, delta_ns.count()); 793 } 794 ScopedStatsTracer(ScopedStatsTracer && other)795 ScopedStatsTracer(ScopedStatsTracer&& other) noexcept { MoveImpl(&other); } 796 797 ScopedStatsTracer& operator=(ScopedStatsTracer&& other) { 798 MoveImpl(&other); 799 return *this; 800 } 801 802 private: 803 ScopedStatsTracer(const ScopedStatsTracer&) = delete; 804 ScopedStatsTracer& operator=(const ScopedStatsTracer&) = delete; 805 MoveImpl(ScopedStatsTracer * other)806 void MoveImpl(ScopedStatsTracer* other) { 807 storage_ = other->storage_; 808 key_ = other->key_; 809 start_ns_ = other->start_ns_; 810 other->storage_ = nullptr; 811 } 812 813 TraceStorage* storage_; 814 size_t key_; 815 base::TimeNanos start_ns_; 816 }; 817 TraceExecutionTimeIntoStats(size_t key)818 ScopedStatsTracer TraceExecutionTimeIntoStats(size_t key) { 819 return ScopedStatsTracer(this, key); 820 } 821 822 // Reading methods. GetString(StringId id)823 NullTermStringView GetString(StringId id) const { 824 return string_pool_.Get(id); 825 } 826 GetProcess(UniquePid upid)827 const Process& GetProcess(UniquePid upid) const { 828 PERFETTO_DCHECK(upid < unique_processes_.size()); 829 return unique_processes_[upid]; 830 } 831 GetThread(UniqueTid utid)832 const Thread& GetThread(UniqueTid utid) const { 833 // Allow utid == 0 for idle thread retrieval. 834 PERFETTO_DCHECK(utid < unique_threads_.size()); 835 return unique_threads_[utid]; 836 } 837 CreateRowId(TableId table,uint32_t row)838 static RowId CreateRowId(TableId table, uint32_t row) { 839 return (static_cast<RowId>(table) << kRowIdTableShift) | row; 840 } 841 ParseRowId(RowId rowid)842 static std::pair<int8_t /*table*/, uint32_t /*row*/> ParseRowId(RowId rowid) { 843 auto id = static_cast<uint64_t>(rowid); 844 auto table_id = static_cast<uint8_t>(id >> kRowIdTableShift); 845 auto row = static_cast<uint32_t>(id & ((1ull << kRowIdTableShift) - 1)); 846 return std::make_pair(table_id, row); 847 } 848 slices()849 const Slices& slices() const { return slices_; } mutable_slices()850 Slices* mutable_slices() { return &slices_; } 851 nestable_slices()852 const NestableSlices& nestable_slices() const { return nestable_slices_; } mutable_nestable_slices()853 NestableSlices* mutable_nestable_slices() { return &nestable_slices_; } 854 counter_definitions()855 const CounterDefinitions& counter_definitions() const { 856 return counter_definitions_; 857 } mutable_counter_definitions()858 CounterDefinitions* mutable_counter_definitions() { 859 return &counter_definitions_; 860 } 861 counter_values()862 const CounterValues& counter_values() const { return counter_values_; } mutable_counter_values()863 CounterValues* mutable_counter_values() { return &counter_values_; } 864 sql_stats()865 const SqlStats& sql_stats() const { return sql_stats_; } mutable_sql_stats()866 SqlStats* mutable_sql_stats() { return &sql_stats_; } 867 instants()868 const Instants& instants() const { return instants_; } mutable_instants()869 Instants* mutable_instants() { return &instants_; } 870 android_logs()871 const AndroidLogs& android_logs() const { return android_log_; } mutable_android_log()872 AndroidLogs* mutable_android_log() { return &android_log_; } 873 stats()874 const StatsMap& stats() const { return stats_; } 875 args()876 const Args& args() const { return args_; } mutable_args()877 Args* mutable_args() { return &args_; } 878 raw_events()879 const RawEvents& raw_events() const { return raw_events_; } mutable_raw_events()880 RawEvents* mutable_raw_events() { return &raw_events_; } 881 heap_profile_mappings()882 const HeapProfileMappings& heap_profile_mappings() const { 883 return heap_profile_mappings_; 884 } mutable_heap_profile_mappings()885 HeapProfileMappings* mutable_heap_profile_mappings() { 886 return &heap_profile_mappings_; 887 } 888 heap_profile_frames()889 const HeapProfileFrames& heap_profile_frames() const { 890 return heap_profile_frames_; 891 } mutable_heap_profile_frames()892 HeapProfileFrames* mutable_heap_profile_frames() { 893 return &heap_profile_frames_; 894 } 895 heap_profile_callsites()896 const HeapProfileCallsites& heap_profile_callsites() const { 897 return heap_profile_callsites_; 898 } mutable_heap_profile_callsites()899 HeapProfileCallsites* mutable_heap_profile_callsites() { 900 return &heap_profile_callsites_; 901 } 902 heap_profile_allocations()903 const HeapProfileAllocations& heap_profile_allocations() const { 904 return heap_profile_allocations_; 905 } mutable_heap_profile_allocations()906 HeapProfileAllocations* mutable_heap_profile_allocations() { 907 return &heap_profile_allocations_; 908 } 909 string_pool()910 const StringPool& string_pool() const { return string_pool_; } 911 912 // |unique_processes_| always contains at least 1 element becuase the 0th ID 913 // is reserved to indicate an invalid process. process_count()914 size_t process_count() const { return unique_processes_.size(); } 915 916 // |unique_threads_| always contains at least 1 element becuase the 0th ID 917 // is reserved to indicate an invalid thread. thread_count()918 size_t thread_count() const { return unique_threads_.size(); } 919 920 // Number of interned strings in the pool. Includes the empty string w/ ID=0. string_count()921 size_t string_count() const { return string_pool_.size(); } 922 923 // Start / end ts (in nanoseconds) across the parsed trace events. 924 // Returns (0, 0) if the trace is empty. 925 std::pair<int64_t, int64_t> GetTraceTimestampBoundsNs() const; 926 927 private: 928 static constexpr uint8_t kRowIdTableShift = 32; 929 930 using StringHash = uint64_t; 931 932 TraceStorage(const TraceStorage&) = delete; 933 TraceStorage& operator=(const TraceStorage&) = delete; 934 935 TraceStorage(TraceStorage&&) = default; 936 TraceStorage& operator=(TraceStorage&&) = default; 937 938 // Stats about parsing the trace. 939 StatsMap stats_{}; 940 941 // One entry for each CPU in the trace. 942 Slices slices_; 943 944 // Args for all other tables. 945 Args args_; 946 947 // One entry for each unique string in the trace. 948 StringPool string_pool_; 949 950 // One entry for each UniquePid, with UniquePid as the index. 951 // Never hold on to pointers to Process, as vector resize will 952 // invalidate them. 953 std::vector<Process> unique_processes_; 954 955 // One entry for each UniqueTid, with UniqueTid as the index. 956 std::deque<Thread> unique_threads_; 957 958 // Slices coming from userspace events (e.g. Chromium TRACE_EVENT macros). 959 NestableSlices nestable_slices_; 960 961 // The type of counters in the trace. Can be thought of the the "metadata". 962 CounterDefinitions counter_definitions_; 963 964 // The values from the Counter events from the trace. This includes CPU 965 // frequency events as well systrace trace_marker counter events. 966 CounterValues counter_values_; 967 968 SqlStats sql_stats_; 969 970 // These are instantaneous events in the trace. They have no duration 971 // and do not have a value that make sense to track over time. 972 // e.g. signal events 973 Instants instants_; 974 975 // Raw events are every ftrace event in the trace. The raw event includes 976 // the timestamp and the pid. The args for the raw event will be in the 977 // args table. This table can be used to generate a text version of the 978 // trace. 979 RawEvents raw_events_; 980 AndroidLogs android_log_; 981 982 HeapProfileMappings heap_profile_mappings_; 983 HeapProfileFrames heap_profile_frames_; 984 HeapProfileCallsites heap_profile_callsites_; 985 HeapProfileAllocations heap_profile_allocations_; 986 }; 987 988 } // namespace trace_processor 989 } // namespace perfetto 990 991 namespace std { 992 993 template <> 994 struct hash<::perfetto::trace_processor::TraceStorage::HeapProfileFrames::Row> { 995 using argument_type = 996 ::perfetto::trace_processor::TraceStorage::HeapProfileFrames::Row; 997 using result_type = size_t; 998 999 result_type operator()(const argument_type& r) const { 1000 return std::hash<::perfetto::trace_processor::StringId>{}(r.name_id) ^ 1001 std::hash<int64_t>{}(r.mapping_row) ^ std::hash<int64_t>{}(r.rel_pc); 1002 } 1003 }; 1004 1005 template <> 1006 struct hash< 1007 ::perfetto::trace_processor::TraceStorage::HeapProfileCallsites::Row> { 1008 using argument_type = 1009 ::perfetto::trace_processor::TraceStorage::HeapProfileCallsites::Row; 1010 using result_type = size_t; 1011 1012 result_type operator()(const argument_type& r) const { 1013 return std::hash<int64_t>{}(r.depth) ^ std::hash<int64_t>{}(r.parent_id) ^ 1014 std::hash<int64_t>{}(r.frame_row); 1015 } 1016 }; 1017 1018 template <> 1019 struct hash< 1020 ::perfetto::trace_processor::TraceStorage::HeapProfileMappings::Row> { 1021 using argument_type = 1022 ::perfetto::trace_processor::TraceStorage::HeapProfileMappings::Row; 1023 using result_type = size_t; 1024 1025 result_type operator()(const argument_type& r) const { 1026 return std::hash<::perfetto::trace_processor::StringId>{}(r.build_id) ^ 1027 std::hash<int64_t>{}(r.offset) ^ std::hash<int64_t>{}(r.start) ^ 1028 std::hash<int64_t>{}(r.end) ^ std::hash<int64_t>{}(r.load_bias) ^ 1029 std::hash<::perfetto::trace_processor::StringId>{}(r.name_id); 1030 } 1031 }; 1032 1033 } // namespace std 1034 1035 #endif // SRC_TRACE_PROCESSOR_TRACE_STORAGE_H_ 1036