1 /* 2 * Copyright (C) 2015 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 "record.h" 18 19 #include <inttypes.h> 20 #include <algorithm> 21 #include <unordered_map> 22 23 #include <android-base/logging.h> 24 #include <android-base/stringprintf.h> 25 26 #include "dso.h" 27 #include "perf_regs.h" 28 #include "tracing.h" 29 #include "utils.h" 30 31 static std::string RecordTypeToString(int record_type) { 32 static std::unordered_map<int, std::string> record_type_names = { 33 {PERF_RECORD_MMAP, "mmap"}, 34 {PERF_RECORD_LOST, "lost"}, 35 {PERF_RECORD_COMM, "comm"}, 36 {PERF_RECORD_EXIT, "exit"}, 37 {PERF_RECORD_THROTTLE, "throttle"}, 38 {PERF_RECORD_UNTHROTTLE, "unthrottle"}, 39 {PERF_RECORD_FORK, "fork"}, 40 {PERF_RECORD_READ, "read"}, 41 {PERF_RECORD_SAMPLE, "sample"}, 42 {PERF_RECORD_BUILD_ID, "build_id"}, 43 {PERF_RECORD_MMAP2, "mmap2"}, 44 {PERF_RECORD_TRACING_DATA, "tracing_data"}, 45 {SIMPLE_PERF_RECORD_KERNEL_SYMBOL, "kernel_symbol"}, 46 {SIMPLE_PERF_RECORD_DSO, "dso"}, 47 {SIMPLE_PERF_RECORD_SYMBOL, "symbol"}, 48 {SIMPLE_PERF_RECORD_EVENT_ID, "event_id"}, 49 }; 50 51 auto it = record_type_names.find(record_type); 52 if (it != record_type_names.end()) { 53 return it->second; 54 } 55 return android::base::StringPrintf("unknown(%d)", record_type); 56 } 57 58 template <> 59 void MoveToBinaryFormat(const RecordHeader& data, char*& p) { 60 data.MoveToBinaryFormat(p); 61 } 62 63 SampleId::SampleId() { memset(this, 0, sizeof(SampleId)); } 64 65 // Return sample_id size in binary format. 66 size_t SampleId::CreateContent(const perf_event_attr& attr, uint64_t event_id) { 67 sample_id_all = attr.sample_id_all; 68 sample_type = attr.sample_type; 69 id_data.id = event_id; 70 // Other data are not necessary. TODO: Set missing SampleId data. 71 return Size(); 72 } 73 74 void SampleId::ReadFromBinaryFormat(const perf_event_attr& attr, const char* p, 75 const char* end) { 76 sample_id_all = attr.sample_id_all; 77 sample_type = attr.sample_type; 78 if (sample_id_all) { 79 if (sample_type & PERF_SAMPLE_TID) { 80 MoveFromBinaryFormat(tid_data, p); 81 } 82 if (sample_type & PERF_SAMPLE_TIME) { 83 MoveFromBinaryFormat(time_data, p); 84 } 85 if (sample_type & PERF_SAMPLE_ID) { 86 MoveFromBinaryFormat(id_data, p); 87 } 88 if (sample_type & PERF_SAMPLE_STREAM_ID) { 89 MoveFromBinaryFormat(stream_id_data, p); 90 } 91 if (sample_type & PERF_SAMPLE_CPU) { 92 MoveFromBinaryFormat(cpu_data, p); 93 } 94 if (sample_type & PERF_SAMPLE_IDENTIFIER) { 95 MoveFromBinaryFormat(id_data, p); 96 } 97 } 98 CHECK_LE(p, end); 99 if (p < end) { 100 LOG(DEBUG) << "Record SampleId part has " << end - p << " bytes left\n"; 101 } 102 } 103 104 void SampleId::WriteToBinaryFormat(char*& p) const { 105 if (sample_id_all) { 106 if (sample_type & PERF_SAMPLE_TID) { 107 MoveToBinaryFormat(tid_data, p); 108 } 109 if (sample_type & PERF_SAMPLE_TIME) { 110 MoveToBinaryFormat(time_data, p); 111 } 112 if (sample_type & PERF_SAMPLE_ID) { 113 MoveToBinaryFormat(id_data, p); 114 } 115 if (sample_type & PERF_SAMPLE_STREAM_ID) { 116 MoveToBinaryFormat(stream_id_data, p); 117 } 118 if (sample_type & PERF_SAMPLE_CPU) { 119 MoveToBinaryFormat(cpu_data, p); 120 } 121 } 122 } 123 124 void SampleId::Dump(size_t indent) const { 125 if (sample_id_all) { 126 if (sample_type & PERF_SAMPLE_TID) { 127 PrintIndented(indent, "sample_id: pid %u, tid %u\n", tid_data.pid, 128 tid_data.tid); 129 } 130 if (sample_type & PERF_SAMPLE_TIME) { 131 PrintIndented(indent, "sample_id: time %" PRId64 "\n", time_data.time); 132 } 133 if (sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) { 134 PrintIndented(indent, "sample_id: id %" PRId64 "\n", id_data.id); 135 } 136 if (sample_type & PERF_SAMPLE_STREAM_ID) { 137 PrintIndented(indent, "sample_id: stream_id %" PRId64 "\n", 138 stream_id_data.stream_id); 139 } 140 if (sample_type & PERF_SAMPLE_CPU) { 141 PrintIndented(indent, "sample_id: cpu %u, res %u\n", cpu_data.cpu, 142 cpu_data.res); 143 } 144 } 145 } 146 147 size_t SampleId::Size() const { 148 size_t size = 0; 149 if (sample_id_all) { 150 if (sample_type & PERF_SAMPLE_TID) { 151 size += sizeof(PerfSampleTidType); 152 } 153 if (sample_type & PERF_SAMPLE_TIME) { 154 size += sizeof(PerfSampleTimeType); 155 } 156 if (sample_type & PERF_SAMPLE_ID) { 157 size += sizeof(PerfSampleIdType); 158 } 159 if (sample_type & PERF_SAMPLE_STREAM_ID) { 160 size += sizeof(PerfSampleStreamIdType); 161 } 162 if (sample_type & PERF_SAMPLE_CPU) { 163 size += sizeof(PerfSampleCpuType); 164 } 165 if (sample_type & PERF_SAMPLE_IDENTIFIER) { 166 size += sizeof(PerfSampleIdType); 167 } 168 } 169 return size; 170 } 171 172 Record::Record(Record&& other) { 173 header = other.header; 174 sample_id = other.sample_id; 175 binary_ = other.binary_; 176 own_binary_ = other.own_binary_; 177 other.binary_ = nullptr; 178 other.own_binary_ = false; 179 } 180 181 void Record::Dump(size_t indent) const { 182 PrintIndented(indent, "record %s: type %u, misc %u, size %u\n", 183 RecordTypeToString(type()).c_str(), type(), misc(), size()); 184 DumpData(indent + 1); 185 sample_id.Dump(indent + 1); 186 } 187 188 uint64_t Record::Timestamp() const { return sample_id.time_data.time; } 189 uint32_t Record::Cpu() const { return sample_id.cpu_data.cpu; } 190 uint64_t Record::Id() const { return sample_id.id_data.id; } 191 192 void Record::UpdateBinary(const char* new_binary) { 193 if (own_binary_) { 194 delete[] binary_; 195 } 196 own_binary_ = true; 197 binary_ = new_binary; 198 } 199 200 MmapRecord::MmapRecord(const perf_event_attr& attr, const char* p) : Record(p) { 201 const char* end = p + size(); 202 p += header_size(); 203 data = reinterpret_cast<const MmapRecordDataType*>(p); 204 p += sizeof(*data); 205 filename = p; 206 p += Align(strlen(filename) + 1, 8); 207 CHECK_LE(p, end); 208 sample_id.ReadFromBinaryFormat(attr, p, end); 209 } 210 211 MmapRecord::MmapRecord(const perf_event_attr& attr, bool in_kernel, 212 uint32_t pid, uint32_t tid, uint64_t addr, uint64_t len, 213 uint64_t pgoff, const std::string& filename, 214 uint64_t event_id, uint64_t time) { 215 SetTypeAndMisc(PERF_RECORD_MMAP, 216 in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER); 217 sample_id.CreateContent(attr, event_id); 218 sample_id.time_data.time = time; 219 MmapRecordDataType data; 220 data.pid = pid; 221 data.tid = tid; 222 data.addr = addr; 223 data.len = len; 224 data.pgoff = pgoff; 225 SetDataAndFilename(data, filename); 226 } 227 228 void MmapRecord::SetDataAndFilename(const MmapRecordDataType& data, 229 const std::string& filename) { 230 SetSize(header_size() + sizeof(data) + Align(filename.size() + 1, 8) + 231 sample_id.Size()); 232 char* new_binary = new char[size()]; 233 char* p = new_binary; 234 MoveToBinaryFormat(header, p); 235 this->data = reinterpret_cast<MmapRecordDataType*>(p); 236 MoveToBinaryFormat(data, p); 237 this->filename = p; 238 strcpy(p, filename.c_str()); 239 p += Align(filename.size() + 1, 8); 240 sample_id.WriteToBinaryFormat(p); 241 UpdateBinary(new_binary); 242 } 243 244 void MmapRecord::DumpData(size_t indent) const { 245 PrintIndented(indent, 246 "pid %u, tid %u, addr 0x%" PRIx64 ", len 0x%" PRIx64 "\n", 247 data->pid, data->tid, data->addr, data->len); 248 PrintIndented(indent, "pgoff 0x%" PRIx64 ", filename %s\n", data->pgoff, 249 filename); 250 } 251 252 Mmap2Record::Mmap2Record(const perf_event_attr& attr, const char* p) 253 : Record(p) { 254 const char* end = p + size(); 255 p += header_size(); 256 data = reinterpret_cast<const Mmap2RecordDataType*>(p); 257 p += sizeof(*data); 258 filename = p; 259 p += Align(strlen(filename) + 1, 8); 260 CHECK_LE(p, end); 261 sample_id.ReadFromBinaryFormat(attr, p, end); 262 } 263 264 void Mmap2Record::SetDataAndFilename(const Mmap2RecordDataType& data, 265 const std::string& filename) { 266 SetSize(header_size() + sizeof(data) + Align(filename.size() + 1, 8) + 267 sample_id.Size()); 268 char* new_binary = new char[size()]; 269 char* p = new_binary; 270 MoveToBinaryFormat(header, p); 271 this->data = reinterpret_cast<Mmap2RecordDataType*>(p); 272 MoveToBinaryFormat(data, p); 273 this->filename = p; 274 strcpy(p, filename.c_str()); 275 p += Align(filename.size() + 1, 8); 276 sample_id.WriteToBinaryFormat(p); 277 UpdateBinary(new_binary); 278 } 279 280 void Mmap2Record::DumpData(size_t indent) const { 281 PrintIndented(indent, 282 "pid %u, tid %u, addr 0x%" PRIx64 ", len 0x%" PRIx64 "\n", 283 data->pid, data->tid, data->addr, data->len); 284 PrintIndented(indent, "pgoff 0x" PRIx64 ", maj %u, min %u, ino %" PRId64 285 ", ino_generation %" PRIu64 "\n", 286 data->pgoff, data->maj, data->min, data->ino, 287 data->ino_generation); 288 PrintIndented(indent, "prot %u, flags %u, filenames %s\n", data->prot, 289 data->flags, filename); 290 } 291 292 CommRecord::CommRecord(const perf_event_attr& attr, const char* p) : Record(p) { 293 const char* end = p + size(); 294 p += header_size(); 295 data = reinterpret_cast<const CommRecordDataType*>(p); 296 p += sizeof(*data); 297 comm = p; 298 p += Align(strlen(p) + 1, 8); 299 CHECK_LE(p, end); 300 sample_id.ReadFromBinaryFormat(attr, p, end); 301 } 302 303 CommRecord::CommRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid, 304 const std::string& comm, uint64_t event_id, uint64_t time) { 305 SetTypeAndMisc(PERF_RECORD_COMM, 0); 306 CommRecordDataType data; 307 data.pid = pid; 308 data.tid = tid; 309 size_t sample_id_size = sample_id.CreateContent(attr, event_id); 310 sample_id.time_data.time = time; 311 SetSize(header_size() + sizeof(data) + Align(comm.size() + 1, 8) + 312 sample_id_size); 313 char* new_binary = new char[size()]; 314 char* p = new_binary; 315 MoveToBinaryFormat(header, p); 316 this->data = reinterpret_cast<CommRecordDataType*>(p); 317 MoveToBinaryFormat(data, p); 318 this->comm = p; 319 strcpy(p, comm.c_str()); 320 p += Align(comm.size() + 1, 8); 321 sample_id.WriteToBinaryFormat(p); 322 UpdateBinary(new_binary); 323 } 324 325 void CommRecord::DumpData(size_t indent) const { 326 PrintIndented(indent, "pid %u, tid %u, comm %s\n", data->pid, data->tid, 327 comm); 328 } 329 330 ExitOrForkRecord::ExitOrForkRecord(const perf_event_attr& attr, const char* p) 331 : Record(p) { 332 const char* end = p + size(); 333 p += header_size(); 334 data = reinterpret_cast<const ExitOrForkRecordDataType*>(p); 335 p += sizeof(*data); 336 CHECK_LE(p, end); 337 sample_id.ReadFromBinaryFormat(attr, p, end); 338 } 339 340 void ExitOrForkRecord::DumpData(size_t indent) const { 341 PrintIndented(indent, "pid %u, ppid %u, tid %u, ptid %u\n", data->pid, 342 data->ppid, data->tid, data->ptid); 343 } 344 345 ForkRecord::ForkRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid, 346 uint32_t ppid, uint32_t ptid, uint64_t event_id) { 347 SetTypeAndMisc(PERF_RECORD_FORK, 0); 348 ExitOrForkRecordDataType data; 349 data.pid = pid; 350 data.ppid = ppid; 351 data.tid = tid; 352 data.ptid = ptid; 353 data.time = 0; 354 size_t sample_id_size = sample_id.CreateContent(attr, event_id); 355 SetSize(header_size() + sizeof(data) + sample_id_size); 356 char* new_binary = new char[size()]; 357 char* p = new_binary; 358 MoveToBinaryFormat(header, p); 359 this->data = reinterpret_cast<ExitOrForkRecordDataType*>(p); 360 MoveToBinaryFormat(data, p); 361 sample_id.WriteToBinaryFormat(p); 362 UpdateBinary(new_binary); 363 } 364 365 LostRecord::LostRecord(const perf_event_attr& attr, const char* p) : Record(p) { 366 const char* end = p + size(); 367 p += header_size(); 368 MoveFromBinaryFormat(id, p); 369 MoveFromBinaryFormat(lost, p); 370 CHECK_LE(p, end); 371 sample_id.ReadFromBinaryFormat(attr, p, end); 372 } 373 374 void LostRecord::DumpData(size_t indent) const { 375 PrintIndented(indent, "id %" PRIu64 ", lost %" PRIu64 "\n", id, lost); 376 } 377 378 SampleRecord::SampleRecord(const perf_event_attr& attr, const char* p) 379 : Record(p) { 380 const char* end = p + size(); 381 p += header_size(); 382 sample_type = attr.sample_type; 383 384 // Set a default id value to report correctly even if ID is not recorded. 385 id_data.id = 0; 386 if (sample_type & PERF_SAMPLE_IDENTIFIER) { 387 MoveFromBinaryFormat(id_data, p); 388 } 389 if (sample_type & PERF_SAMPLE_IP) { 390 MoveFromBinaryFormat(ip_data, p); 391 } 392 if (sample_type & PERF_SAMPLE_TID) { 393 MoveFromBinaryFormat(tid_data, p); 394 } 395 if (sample_type & PERF_SAMPLE_TIME) { 396 MoveFromBinaryFormat(time_data, p); 397 } 398 if (sample_type & PERF_SAMPLE_ADDR) { 399 MoveFromBinaryFormat(addr_data, p); 400 } 401 if (sample_type & PERF_SAMPLE_ID) { 402 MoveFromBinaryFormat(id_data, p); 403 } 404 if (sample_type & PERF_SAMPLE_STREAM_ID) { 405 MoveFromBinaryFormat(stream_id_data, p); 406 } 407 if (sample_type & PERF_SAMPLE_CPU) { 408 MoveFromBinaryFormat(cpu_data, p); 409 } 410 if (sample_type & PERF_SAMPLE_PERIOD) { 411 MoveFromBinaryFormat(period_data, p); 412 } 413 if (sample_type & PERF_SAMPLE_CALLCHAIN) { 414 MoveFromBinaryFormat(callchain_data.ip_nr, p); 415 callchain_data.ips = reinterpret_cast<const uint64_t*>(p); 416 p += callchain_data.ip_nr * sizeof(uint64_t); 417 } 418 if (sample_type & PERF_SAMPLE_RAW) { 419 MoveFromBinaryFormat(raw_data.size, p); 420 raw_data.data = p; 421 p += raw_data.size; 422 } 423 if (sample_type & PERF_SAMPLE_BRANCH_STACK) { 424 MoveFromBinaryFormat(branch_stack_data.stack_nr, p); 425 branch_stack_data.stack = reinterpret_cast<const BranchStackItemType*>(p); 426 p += branch_stack_data.stack_nr * sizeof(BranchStackItemType); 427 } 428 if (sample_type & PERF_SAMPLE_REGS_USER) { 429 MoveFromBinaryFormat(regs_user_data.abi, p); 430 if (regs_user_data.abi == 0) { 431 regs_user_data.reg_mask = 0; 432 } else { 433 regs_user_data.reg_mask = attr.sample_regs_user; 434 size_t bit_nr = 0; 435 for (size_t i = 0; i < 64; ++i) { 436 if ((regs_user_data.reg_mask >> i) & 1) { 437 bit_nr++; 438 } 439 } 440 regs_user_data.reg_nr = bit_nr; 441 regs_user_data.regs = reinterpret_cast<const uint64_t*>(p); 442 p += bit_nr * sizeof(uint64_t); 443 } 444 } 445 if (sample_type & PERF_SAMPLE_STACK_USER) { 446 MoveFromBinaryFormat(stack_user_data.size, p); 447 if (stack_user_data.size == 0) { 448 stack_user_data.dyn_size = 0; 449 } else { 450 stack_user_data.data = p; 451 p += stack_user_data.size; 452 MoveFromBinaryFormat(stack_user_data.dyn_size, p); 453 } 454 } 455 // TODO: Add parsing of other PERF_SAMPLE_*. 456 CHECK_LE(p, end); 457 if (p < end) { 458 LOG(DEBUG) << "Record has " << end - p << " bytes left\n"; 459 } 460 } 461 462 SampleRecord::SampleRecord(const perf_event_attr& attr, uint64_t id, 463 uint64_t ip, uint32_t pid, uint32_t tid, 464 uint64_t time, uint32_t cpu, uint64_t period, 465 const std::vector<uint64_t>& ips) { 466 SetTypeAndMisc(PERF_RECORD_SAMPLE, PERF_RECORD_MISC_USER); 467 sample_type = attr.sample_type; 468 CHECK_EQ(0u, sample_type & ~(PERF_SAMPLE_IP | PERF_SAMPLE_TID 469 | PERF_SAMPLE_TIME | PERF_SAMPLE_ID | PERF_SAMPLE_CPU 470 | PERF_SAMPLE_PERIOD | PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER 471 | PERF_SAMPLE_STACK_USER)); 472 ip_data.ip = ip; 473 tid_data.pid = pid; 474 tid_data.tid = tid; 475 time_data.time = time; 476 id_data.id = id; 477 cpu_data.cpu = cpu; 478 cpu_data.res = 0; 479 period_data.period = period; 480 callchain_data.ip_nr = ips.size(); 481 raw_data.size = 0; 482 branch_stack_data.stack_nr = 0; 483 regs_user_data.abi = 0; 484 regs_user_data.reg_mask = 0; 485 stack_user_data.size = 0; 486 487 uint32_t size = header_size(); 488 if (sample_type & PERF_SAMPLE_IP) { 489 size += sizeof(ip_data); 490 } 491 if (sample_type & PERF_SAMPLE_TID) { 492 size += sizeof(tid_data); 493 } 494 if (sample_type & PERF_SAMPLE_TIME) { 495 size += sizeof(time_data); 496 } 497 if (sample_type & PERF_SAMPLE_ID) { 498 size += sizeof(id_data); 499 } 500 if (sample_type & PERF_SAMPLE_CPU) { 501 size += sizeof(cpu_data); 502 } 503 if (sample_type & PERF_SAMPLE_PERIOD) { 504 size += sizeof(period_data); 505 } 506 if (sample_type & PERF_SAMPLE_CALLCHAIN) { 507 size += sizeof(uint64_t) * (ips.size() + 1); 508 } 509 if (sample_type & PERF_SAMPLE_REGS_USER) { 510 size += sizeof(uint64_t); 511 } 512 if (sample_type & PERF_SAMPLE_STACK_USER) { 513 size += sizeof(uint64_t); 514 } 515 516 SetSize(size); 517 char* new_binary = new char[size]; 518 char* p = new_binary; 519 MoveToBinaryFormat(header, p); 520 if (sample_type & PERF_SAMPLE_IP) { 521 MoveToBinaryFormat(ip_data, p); 522 } 523 if (sample_type & PERF_SAMPLE_TID) { 524 MoveToBinaryFormat(tid_data, p); 525 } 526 if (sample_type & PERF_SAMPLE_TIME) { 527 MoveToBinaryFormat(time_data, p); 528 } 529 if (sample_type & PERF_SAMPLE_ID) { 530 MoveToBinaryFormat(id_data, p); 531 } 532 if (sample_type & PERF_SAMPLE_CPU) { 533 MoveToBinaryFormat(cpu_data, p); 534 } 535 if (sample_type & PERF_SAMPLE_PERIOD) { 536 MoveToBinaryFormat(period_data, p); 537 } 538 if (sample_type & PERF_SAMPLE_CALLCHAIN) { 539 MoveToBinaryFormat(callchain_data.ip_nr, p); 540 callchain_data.ips = reinterpret_cast<uint64_t*>(p); 541 MoveToBinaryFormat(ips.data(), ips.size(), p); 542 } 543 if (sample_type & PERF_SAMPLE_REGS_USER) { 544 MoveToBinaryFormat(regs_user_data.abi, p); 545 } 546 if (sample_type & PERF_SAMPLE_STACK_USER) { 547 MoveToBinaryFormat(stack_user_data.size, p); 548 } 549 CHECK_EQ(p, new_binary + size); 550 UpdateBinary(new_binary); 551 } 552 553 void SampleRecord::ReplaceRegAndStackWithCallChain( 554 const std::vector<uint64_t>& ips) { 555 uint32_t size_added_in_callchain = sizeof(uint64_t) * (ips.size() + 1); 556 uint32_t size_reduced_in_reg_stack = 557 regs_user_data.reg_nr * sizeof(uint64_t) + stack_user_data.size + 558 sizeof(uint64_t); 559 CHECK_LE(size_added_in_callchain, size_reduced_in_reg_stack); 560 uint32_t size_reduced = size_reduced_in_reg_stack - size_added_in_callchain; 561 SetSize(size() - size_reduced); 562 char* p = const_cast<char*>(binary_); 563 MoveToBinaryFormat(header, p); 564 p = const_cast<char*>(stack_user_data.data + stack_user_data.size + 565 sizeof(uint64_t)) - 566 (size_reduced_in_reg_stack - size_added_in_callchain); 567 stack_user_data.size = 0; 568 regs_user_data.abi = 0; 569 p -= sizeof(uint64_t); 570 *reinterpret_cast<uint64_t*>(p) = stack_user_data.size; 571 p -= sizeof(uint64_t); 572 *reinterpret_cast<uint64_t*>(p) = regs_user_data.abi; 573 if (sample_type & PERF_SAMPLE_BRANCH_STACK) { 574 p -= branch_stack_data.stack_nr * sizeof(BranchStackItemType); 575 memmove(p, branch_stack_data.stack, 576 branch_stack_data.stack_nr * sizeof(BranchStackItemType)); 577 p -= sizeof(uint64_t); 578 *reinterpret_cast<uint64_t*>(p) = branch_stack_data.stack_nr; 579 } 580 if (sample_type & PERF_SAMPLE_RAW) { 581 p -= raw_data.size; 582 memmove(p, raw_data.data, raw_data.size); 583 p -= sizeof(uint32_t); 584 *reinterpret_cast<uint32_t*>(p) = raw_data.size; 585 } 586 p -= ips.size() * sizeof(uint64_t); 587 memcpy(p, ips.data(), ips.size() * sizeof(uint64_t)); 588 p -= sizeof(uint64_t); 589 *reinterpret_cast<uint64_t*>(p) = PERF_CONTEXT_USER; 590 p -= sizeof(uint64_t) * (callchain_data.ip_nr); 591 callchain_data.ips = reinterpret_cast<uint64_t*>(p); 592 callchain_data.ip_nr += ips.size() + 1; 593 p -= sizeof(uint64_t); 594 *reinterpret_cast<uint64_t*>(p) = callchain_data.ip_nr; 595 } 596 597 void SampleRecord::DumpData(size_t indent) const { 598 PrintIndented(indent, "sample_type: 0x%" PRIx64 "\n", sample_type); 599 if (sample_type & PERF_SAMPLE_IP) { 600 PrintIndented(indent, "ip %p\n", reinterpret_cast<void*>(ip_data.ip)); 601 } 602 if (sample_type & PERF_SAMPLE_TID) { 603 PrintIndented(indent, "pid %u, tid %u\n", tid_data.pid, tid_data.tid); 604 } 605 if (sample_type & PERF_SAMPLE_TIME) { 606 PrintIndented(indent, "time %" PRId64 "\n", time_data.time); 607 } 608 if (sample_type & PERF_SAMPLE_ADDR) { 609 PrintIndented(indent, "addr %p\n", reinterpret_cast<void*>(addr_data.addr)); 610 } 611 if (sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) { 612 PrintIndented(indent, "id %" PRId64 "\n", id_data.id); 613 } 614 if (sample_type & PERF_SAMPLE_STREAM_ID) { 615 PrintIndented(indent, "stream_id %" PRId64 "\n", stream_id_data.stream_id); 616 } 617 if (sample_type & PERF_SAMPLE_CPU) { 618 PrintIndented(indent, "cpu %u, res %u\n", cpu_data.cpu, cpu_data.res); 619 } 620 if (sample_type & PERF_SAMPLE_PERIOD) { 621 PrintIndented(indent, "period %" PRId64 "\n", period_data.period); 622 } 623 if (sample_type & PERF_SAMPLE_CALLCHAIN) { 624 PrintIndented(indent, "callchain nr=%" PRIu64 "\n", callchain_data.ip_nr); 625 for (uint64_t i = 0; i < callchain_data.ip_nr; ++i) { 626 PrintIndented(indent + 1, "0x%" PRIx64 "\n", callchain_data.ips[i]); 627 } 628 } 629 if (sample_type & PERF_SAMPLE_RAW) { 630 PrintIndented(indent, "raw size=%zu\n", raw_data.size); 631 const uint32_t* data = reinterpret_cast<const uint32_t*>(raw_data.data); 632 size_t size = raw_data.size / sizeof(uint32_t); 633 for (size_t i = 0; i < size; ++i) { 634 PrintIndented(indent + 1, "0x%08x (%zu)\n", data[i], data[i]); 635 } 636 } 637 if (sample_type & PERF_SAMPLE_BRANCH_STACK) { 638 PrintIndented(indent, "branch_stack nr=%" PRIu64 "\n", 639 branch_stack_data.stack_nr); 640 for (uint64_t i = 0; i < branch_stack_data.stack_nr; ++i) { 641 auto& item = branch_stack_data.stack[i]; 642 PrintIndented(indent + 1, "from 0x%" PRIx64 ", to 0x%" PRIx64 643 ", flags 0x%" PRIx64 "\n", 644 item.from, item.to, item.flags); 645 } 646 } 647 if (sample_type & PERF_SAMPLE_REGS_USER) { 648 PrintIndented(indent, "user regs: abi=%" PRId64 "\n", regs_user_data.abi); 649 for (size_t i = 0, pos = 0; i < 64; ++i) { 650 if ((regs_user_data.reg_mask >> i) & 1) { 651 PrintIndented( 652 indent + 1, "reg (%s) 0x%016" PRIx64 "\n", 653 GetRegName(i, ScopedCurrentArch::GetCurrentArch()).c_str(), 654 regs_user_data.regs[pos++]); 655 } 656 } 657 } 658 if (sample_type & PERF_SAMPLE_STACK_USER) { 659 PrintIndented(indent, "user stack: size %zu dyn_size %" PRIu64 "\n", 660 stack_user_data.size, stack_user_data.dyn_size); 661 const uint64_t* p = reinterpret_cast<const uint64_t*>(stack_user_data.data); 662 const uint64_t* end = p + (stack_user_data.size / sizeof(uint64_t)); 663 while (p < end) { 664 PrintIndented(indent + 1, ""); 665 for (size_t i = 0; i < 4 && p < end; ++i, ++p) { 666 printf(" %016" PRIx64, *p); 667 } 668 printf("\n"); 669 } 670 printf("\n"); 671 } 672 } 673 674 uint64_t SampleRecord::Timestamp() const { return time_data.time; } 675 uint32_t SampleRecord::Cpu() const { return cpu_data.cpu; } 676 uint64_t SampleRecord::Id() const { return id_data.id; } 677 678 BuildIdRecord::BuildIdRecord(const char* p) : Record(p) { 679 const char* end = p + size(); 680 p += header_size(); 681 MoveFromBinaryFormat(pid, p); 682 build_id = BuildId(p, BUILD_ID_SIZE); 683 p += Align(build_id.Size(), 8); 684 filename = p; 685 p += Align(strlen(filename) + 1, 64); 686 CHECK_EQ(p, end); 687 } 688 689 void BuildIdRecord::DumpData(size_t indent) const { 690 PrintIndented(indent, "pid %u\n", pid); 691 PrintIndented(indent, "build_id %s\n", build_id.ToString().c_str()); 692 PrintIndented(indent, "filename %s\n", filename); 693 } 694 695 BuildIdRecord::BuildIdRecord(bool in_kernel, pid_t pid, const BuildId& build_id, 696 const std::string& filename) { 697 SetTypeAndMisc(PERF_RECORD_BUILD_ID, 698 in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER); 699 this->pid = pid; 700 this->build_id = build_id; 701 SetSize(header_size() + sizeof(pid) + Align(build_id.Size(), 8) + 702 Align(filename.size() + 1, 64)); 703 char* new_binary = new char[size()]; 704 char* p = new_binary; 705 MoveToBinaryFormat(header, p); 706 MoveToBinaryFormat(pid, p); 707 memcpy(p, build_id.Data(), build_id.Size()); 708 p += Align(build_id.Size(), 8); 709 this->filename = p; 710 strcpy(p, filename.c_str()); 711 UpdateBinary(new_binary); 712 } 713 714 KernelSymbolRecord::KernelSymbolRecord(const char* p) : Record(p) { 715 const char* end = p + size(); 716 p += header_size(); 717 MoveFromBinaryFormat(kallsyms_size, p); 718 kallsyms = p; 719 p += Align(kallsyms_size, 8); 720 CHECK_EQ(p, end); 721 } 722 723 void KernelSymbolRecord::DumpData(size_t indent) const { 724 PrintIndented(indent, "kallsyms: %s\n", 725 std::string(kallsyms, kallsyms + kallsyms_size).c_str()); 726 } 727 728 KernelSymbolRecord::KernelSymbolRecord(const std::string& kallsyms) { 729 SetTypeAndMisc(SIMPLE_PERF_RECORD_KERNEL_SYMBOL, 0); 730 kallsyms_size = kallsyms.size(); 731 SetSize(header_size() + 4 + Align(kallsyms.size(), 8)); 732 char* new_binary = new char[size()]; 733 char* p = new_binary; 734 MoveToBinaryFormat(header, p); 735 MoveToBinaryFormat(kallsyms_size, p); 736 this->kallsyms = p; 737 memcpy(p, kallsyms.data(), kallsyms_size); 738 UpdateBinary(new_binary); 739 } 740 741 DsoRecord::DsoRecord(const char* p) : Record(p) { 742 const char* end = p + size(); 743 p += header_size(); 744 MoveFromBinaryFormat(dso_type, p); 745 MoveFromBinaryFormat(dso_id, p); 746 MoveFromBinaryFormat(min_vaddr, p); 747 dso_name = p; 748 p += Align(strlen(dso_name) + 1, 8); 749 CHECK_EQ(p, end); 750 } 751 752 DsoRecord::DsoRecord(uint64_t dso_type, uint64_t dso_id, 753 const std::string& dso_name, uint64_t min_vaddr) { 754 SetTypeAndMisc(SIMPLE_PERF_RECORD_DSO, 0); 755 this->dso_type = dso_type; 756 this->dso_id = dso_id; 757 this->min_vaddr = min_vaddr; 758 SetSize(header_size() + 3 * sizeof(uint64_t) + Align(dso_name.size() + 1, 8)); 759 char* new_binary = new char[size()]; 760 char* p = new_binary; 761 MoveToBinaryFormat(header, p); 762 MoveToBinaryFormat(dso_type, p); 763 MoveToBinaryFormat(dso_id, p); 764 MoveToBinaryFormat(min_vaddr, p); 765 this->dso_name = p; 766 strcpy(p, dso_name.c_str()); 767 UpdateBinary(new_binary); 768 } 769 770 void DsoRecord::DumpData(size_t indent) const { 771 PrintIndented(indent, "dso_type: %s(%" PRIu64 ")\n", 772 DsoTypeToString(static_cast<DsoType>(dso_type)), dso_type); 773 PrintIndented(indent, "dso_id: %" PRIu64 "\n", dso_id); 774 PrintIndented(indent, "min_vaddr: 0x%" PRIx64 "\n", min_vaddr); 775 PrintIndented(indent, "dso_name: %s\n", dso_name); 776 } 777 778 SymbolRecord::SymbolRecord(const char* p) : Record(p) { 779 const char* end = p + size(); 780 p += header_size(); 781 MoveFromBinaryFormat(addr, p); 782 MoveFromBinaryFormat(len, p); 783 MoveFromBinaryFormat(dso_id, p); 784 name = p; 785 p += Align(strlen(name) + 1, 8); 786 CHECK_EQ(p, end); 787 } 788 789 SymbolRecord::SymbolRecord(uint64_t addr, uint64_t len, const std::string& name, 790 uint64_t dso_id) { 791 SetTypeAndMisc(SIMPLE_PERF_RECORD_SYMBOL, 0); 792 this->addr = addr; 793 this->len = len; 794 this->dso_id = dso_id; 795 SetSize(header_size() + 3 * sizeof(uint64_t) + Align(name.size() + 1, 8)); 796 char* new_binary = new char[size()]; 797 char* p = new_binary; 798 MoveToBinaryFormat(header, p); 799 MoveToBinaryFormat(addr, p); 800 MoveToBinaryFormat(len, p); 801 MoveToBinaryFormat(dso_id, p); 802 this->name = p; 803 strcpy(p, name.c_str()); 804 UpdateBinary(new_binary); 805 } 806 807 void SymbolRecord::DumpData(size_t indent) const { 808 PrintIndented(indent, "name: %s\n", name); 809 PrintIndented(indent, "addr: 0x%" PRIx64 "\n", addr); 810 PrintIndented(indent, "len: 0x%" PRIx64 "\n", len); 811 PrintIndented(indent, "dso_id: %" PRIu64 "\n", dso_id); 812 } 813 814 TracingDataRecord::TracingDataRecord(const char* p) : Record(p) { 815 const char* end = p + size(); 816 p += header_size(); 817 MoveFromBinaryFormat(data_size, p); 818 data = p; 819 p += Align(data_size, 64); 820 CHECK_EQ(p, end); 821 } 822 823 TracingDataRecord::TracingDataRecord(const std::vector<char>& tracing_data) { 824 SetTypeAndMisc(PERF_RECORD_TRACING_DATA, 0); 825 data_size = tracing_data.size(); 826 SetSize(header_size() + sizeof(uint32_t) + Align(tracing_data.size(), 64)); 827 char* new_binary = new char[size()]; 828 char* p = new_binary; 829 MoveToBinaryFormat(header, p); 830 MoveToBinaryFormat(data_size, p); 831 data = p; 832 memcpy(p, tracing_data.data(), data_size); 833 UpdateBinary(new_binary); 834 } 835 836 void TracingDataRecord::DumpData(size_t indent) const { 837 Tracing tracing(std::vector<char>(data, data + data_size)); 838 tracing.Dump(indent); 839 } 840 841 EventIdRecord::EventIdRecord(const char* p) : Record(p) { 842 const char* end = p + size(); 843 p += header_size(); 844 MoveFromBinaryFormat(count, p); 845 data = reinterpret_cast<const EventIdData*>(p); 846 p += sizeof(data[0]) * count; 847 CHECK_EQ(p, end); 848 } 849 850 EventIdRecord::EventIdRecord(const std::vector<uint64_t>& data) { 851 SetTypeAndMisc(SIMPLE_PERF_RECORD_EVENT_ID, 0); 852 SetSize(header_size() + sizeof(uint64_t) * (1 + data.size())); 853 char* new_binary = new char[size()]; 854 char* p = new_binary; 855 MoveToBinaryFormat(header, p); 856 count = data.size() / 2; 857 MoveToBinaryFormat(count, p); 858 this->data = reinterpret_cast<EventIdData*>(p); 859 memcpy(p, data.data(), sizeof(uint64_t) * data.size()); 860 UpdateBinary(new_binary); 861 } 862 863 void EventIdRecord::DumpData(size_t indent) const { 864 PrintIndented(indent, "count: %" PRIu64 "\n", count); 865 for (size_t i = 0; i < count; ++i) { 866 PrintIndented(indent, "attr_id[%" PRIu64 "]: %" PRIu64 "\n", i, 867 data[i].attr_id); 868 PrintIndented(indent, "event_id[%" PRIu64 "]: %" PRIu64 "\n", i, 869 data[i].event_id); 870 } 871 } 872 873 UnknownRecord::UnknownRecord(const char* p) : Record(p) { 874 p += header_size(); 875 data = p; 876 } 877 878 void UnknownRecord::DumpData(size_t) const {} 879 880 std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr, 881 uint32_t type, const char* p) { 882 switch (type) { 883 case PERF_RECORD_MMAP: 884 return std::unique_ptr<Record>(new MmapRecord(attr, p)); 885 case PERF_RECORD_MMAP2: 886 return std::unique_ptr<Record>(new Mmap2Record(attr, p)); 887 case PERF_RECORD_COMM: 888 return std::unique_ptr<Record>(new CommRecord(attr, p)); 889 case PERF_RECORD_EXIT: 890 return std::unique_ptr<Record>(new ExitRecord(attr, p)); 891 case PERF_RECORD_FORK: 892 return std::unique_ptr<Record>(new ForkRecord(attr, p)); 893 case PERF_RECORD_LOST: 894 return std::unique_ptr<Record>(new LostRecord(attr, p)); 895 case PERF_RECORD_SAMPLE: 896 return std::unique_ptr<Record>(new SampleRecord(attr, p)); 897 case PERF_RECORD_TRACING_DATA: 898 return std::unique_ptr<Record>(new TracingDataRecord(p)); 899 case SIMPLE_PERF_RECORD_KERNEL_SYMBOL: 900 return std::unique_ptr<Record>(new KernelSymbolRecord(p)); 901 case SIMPLE_PERF_RECORD_DSO: 902 return std::unique_ptr<Record>(new DsoRecord(p)); 903 case SIMPLE_PERF_RECORD_SYMBOL: 904 return std::unique_ptr<Record>(new SymbolRecord(p)); 905 case SIMPLE_PERF_RECORD_EVENT_ID: 906 return std::unique_ptr<Record>(new EventIdRecord(p)); 907 default: 908 return std::unique_ptr<Record>(new UnknownRecord(p)); 909 } 910 } 911 912 std::unique_ptr<Record> ReadRecordFromOwnedBuffer(const perf_event_attr& attr, 913 uint32_t type, 914 const char* p) { 915 std::unique_ptr<Record> record = ReadRecordFromBuffer(attr, type, p); 916 if (record != nullptr) { 917 record->OwnBinary(); 918 } else { 919 delete[] p; 920 } 921 return record; 922 } 923 924 std::vector<std::unique_ptr<Record>> ReadRecordsFromBuffer( 925 const perf_event_attr& attr, const char* buf, size_t buf_size) { 926 std::vector<std::unique_ptr<Record>> result; 927 const char* p = buf; 928 const char* end = buf + buf_size; 929 while (p < end) { 930 RecordHeader header(p); 931 CHECK_LE(p + header.size, end); 932 CHECK_NE(0u, header.size); 933 result.push_back(ReadRecordFromBuffer(attr, header.type, p)); 934 p += header.size; 935 } 936 return result; 937 } 938 939 std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr, 940 const char* p) { 941 auto header = reinterpret_cast<const perf_event_header*>(p); 942 return ReadRecordFromBuffer(attr, header->type, p); 943 } 944 945 bool RecordCache::RecordWithSeq::IsHappensBefore( 946 const RecordWithSeq& other) const { 947 bool is_sample = (record->type() == PERF_RECORD_SAMPLE); 948 bool is_other_sample = (other.record->type() == PERF_RECORD_SAMPLE); 949 uint64_t time = record->Timestamp(); 950 uint64_t other_time = other.record->Timestamp(); 951 // The record with smaller time happens first. 952 if (time != other_time) { 953 return time < other_time; 954 } 955 // If happening at the same time, make non-sample records before sample 956 // records, because non-sample records may contain useful information to 957 // parse sample records. 958 if (is_sample != is_other_sample) { 959 return is_sample ? false : true; 960 } 961 // Otherwise, use the same order as they enter the cache. 962 return seq < other.seq; 963 } 964 965 bool RecordCache::RecordComparator::operator()(const RecordWithSeq& r1, 966 const RecordWithSeq& r2) { 967 return r2.IsHappensBefore(r1); 968 } 969 970 RecordCache::RecordCache(bool has_timestamp, size_t min_cache_size, 971 uint64_t min_time_diff_in_ns) 972 : has_timestamp_(has_timestamp), 973 min_cache_size_(min_cache_size), 974 min_time_diff_in_ns_(min_time_diff_in_ns), 975 last_time_(0), 976 cur_seq_(0), 977 queue_(RecordComparator()) {} 978 979 RecordCache::~RecordCache() { PopAll(); } 980 981 void RecordCache::Push(std::unique_ptr<Record> record) { 982 if (has_timestamp_) { 983 last_time_ = std::max(last_time_, record->Timestamp()); 984 } 985 queue_.push(RecordWithSeq(cur_seq_++, record.release())); 986 } 987 988 void RecordCache::Push(std::vector<std::unique_ptr<Record>> records) { 989 for (auto& r : records) { 990 Push(std::move(r)); 991 } 992 } 993 994 std::unique_ptr<Record> RecordCache::Pop() { 995 if (queue_.size() < min_cache_size_) { 996 return nullptr; 997 } 998 Record* r = queue_.top().record; 999 if (has_timestamp_) { 1000 if (r->Timestamp() + min_time_diff_in_ns_ > last_time_) { 1001 return nullptr; 1002 } 1003 } 1004 queue_.pop(); 1005 return std::unique_ptr<Record>(r); 1006 } 1007 1008 std::vector<std::unique_ptr<Record>> RecordCache::PopAll() { 1009 std::vector<std::unique_ptr<Record>> result; 1010 while (!queue_.empty()) { 1011 result.emplace_back(queue_.top().record); 1012 queue_.pop(); 1013 } 1014 return result; 1015 } 1016 1017 std::unique_ptr<Record> RecordCache::ForcedPop() { 1018 if (queue_.empty()) { 1019 return nullptr; 1020 } 1021 Record* r = queue_.top().record; 1022 queue_.pop(); 1023 return std::unique_ptr<Record>(r); 1024 } 1025