2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <unordered_map>
23 #include <android-base/logging.h>
24 #include <android-base/stringprintf.h>
27 #include "perf_regs.h"
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"},
51 auto it = record_type_names.find(record_type);
52 if (it != record_type_names.end()) {
55 return android::base::StringPrintf("unknown(%d)", record_type);
59 void MoveToBinaryFormat(const RecordHeader& data, char*& p) {
60 data.MoveToBinaryFormat(p);
63 SampleId::SampleId() { memset(this, 0, sizeof(SampleId)); }
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.
74 void SampleId::ReadFromBinaryFormat(const perf_event_attr& attr, const char* p,
76 sample_id_all = attr.sample_id_all;
77 sample_type = attr.sample_type;
79 if (sample_type & PERF_SAMPLE_TID) {
80 MoveFromBinaryFormat(tid_data, p);
82 if (sample_type & PERF_SAMPLE_TIME) {
83 MoveFromBinaryFormat(time_data, p);
85 if (sample_type & PERF_SAMPLE_ID) {
86 MoveFromBinaryFormat(id_data, p);
88 if (sample_type & PERF_SAMPLE_STREAM_ID) {
89 MoveFromBinaryFormat(stream_id_data, p);
91 if (sample_type & PERF_SAMPLE_CPU) {
92 MoveFromBinaryFormat(cpu_data, p);
94 if (sample_type & PERF_SAMPLE_IDENTIFIER) {
95 MoveFromBinaryFormat(id_data, p);
100 LOG(DEBUG) << "Record SampleId part has " << end - p << " bytes left\n";
104 void SampleId::WriteToBinaryFormat(char*& p) const {
106 if (sample_type & PERF_SAMPLE_TID) {
107 MoveToBinaryFormat(tid_data, p);
109 if (sample_type & PERF_SAMPLE_TIME) {
110 MoveToBinaryFormat(time_data, p);
112 if (sample_type & PERF_SAMPLE_ID) {
113 MoveToBinaryFormat(id_data, p);
115 if (sample_type & PERF_SAMPLE_STREAM_ID) {
116 MoveToBinaryFormat(stream_id_data, p);
118 if (sample_type & PERF_SAMPLE_CPU) {
119 MoveToBinaryFormat(cpu_data, p);
124 void SampleId::Dump(size_t indent) const {
126 if (sample_type & PERF_SAMPLE_TID) {
127 PrintIndented(indent, "sample_id: pid %u, tid %u\n", tid_data.pid,
130 if (sample_type & PERF_SAMPLE_TIME) {
131 PrintIndented(indent, "sample_id: time %" PRId64 "\n", time_data.time);
133 if (sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
134 PrintIndented(indent, "sample_id: id %" PRId64 "\n", id_data.id);
136 if (sample_type & PERF_SAMPLE_STREAM_ID) {
137 PrintIndented(indent, "sample_id: stream_id %" PRId64 "\n",
138 stream_id_data.stream_id);
140 if (sample_type & PERF_SAMPLE_CPU) {
141 PrintIndented(indent, "sample_id: cpu %u, res %u\n", cpu_data.cpu,
147 size_t SampleId::Size() const {
150 if (sample_type & PERF_SAMPLE_TID) {
151 size += sizeof(PerfSampleTidType);
153 if (sample_type & PERF_SAMPLE_TIME) {
154 size += sizeof(PerfSampleTimeType);
156 if (sample_type & PERF_SAMPLE_ID) {
157 size += sizeof(PerfSampleIdType);
159 if (sample_type & PERF_SAMPLE_STREAM_ID) {
160 size += sizeof(PerfSampleStreamIdType);
162 if (sample_type & PERF_SAMPLE_CPU) {
163 size += sizeof(PerfSampleCpuType);
165 if (sample_type & PERF_SAMPLE_IDENTIFIER) {
166 size += sizeof(PerfSampleIdType);
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;
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);
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; }
192 void Record::UpdateBinary(const char* new_binary) {
197 binary_ = new_binary;
200 MmapRecord::MmapRecord(const perf_event_attr& attr, const char* p) : Record(p) {
201 const char* end = p + size();
203 data = reinterpret_cast<const MmapRecordDataType*>(p);
206 p += Align(strlen(filename) + 1, 8);
208 sample_id.ReadFromBinaryFormat(attr, p, end);
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;
225 SetDataAndFilename(data, filename);
228 void MmapRecord::SetDataAndFilename(const MmapRecordDataType& data,
229 const std::string& filename) {
230 SetSize(header_size() + sizeof(data) + Align(filename.size() + 1, 8) +
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);
238 strcpy(p, filename.c_str());
239 p += Align(filename.size() + 1, 8);
240 sample_id.WriteToBinaryFormat(p);
241 UpdateBinary(new_binary);
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,
252 Mmap2Record::Mmap2Record(const perf_event_attr& attr, const char* p)
254 const char* end = p + size();
256 data = reinterpret_cast<const Mmap2RecordDataType*>(p);
259 p += Align(strlen(filename) + 1, 8);
261 sample_id.ReadFromBinaryFormat(attr, p, end);
264 void Mmap2Record::SetDataAndFilename(const Mmap2RecordDataType& data,
265 const std::string& filename) {
266 SetSize(header_size() + sizeof(data) + Align(filename.size() + 1, 8) +
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);
274 strcpy(p, filename.c_str());
275 p += Align(filename.size() + 1, 8);
276 sample_id.WriteToBinaryFormat(p);
277 UpdateBinary(new_binary);
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);
292 CommRecord::CommRecord(const perf_event_attr& attr, const char* p) : Record(p) {
293 const char* end = p + size();
295 data = reinterpret_cast<const CommRecordDataType*>(p);
298 p += Align(strlen(p) + 1, 8);
300 sample_id.ReadFromBinaryFormat(attr, p, end);
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;
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) +
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);
319 strcpy(p, comm.c_str());
320 p += Align(comm.size() + 1, 8);
321 sample_id.WriteToBinaryFormat(p);
322 UpdateBinary(new_binary);
325 void CommRecord::DumpData(size_t indent) const {
326 PrintIndented(indent, "pid %u, tid %u, comm %s\n", data->pid, data->tid,
330 ExitOrForkRecord::ExitOrForkRecord(const perf_event_attr& attr, const char* p)
332 const char* end = p + size();
334 data = reinterpret_cast<const ExitOrForkRecordDataType*>(p);
337 sample_id.ReadFromBinaryFormat(attr, p, end);
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);
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;
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);
365 LostRecord::LostRecord(const perf_event_attr& attr, const char* p) : Record(p) {
366 const char* end = p + size();
368 MoveFromBinaryFormat(id, p);
369 MoveFromBinaryFormat(lost, p);
371 sample_id.ReadFromBinaryFormat(attr, p, end);
374 void LostRecord::DumpData(size_t indent) const {
375 PrintIndented(indent, "id %" PRIu64 ", lost %" PRIu64 "\n", id, lost);
378 SampleRecord::SampleRecord(const perf_event_attr& attr, const char* p)
380 const char* end = p + size();
382 sample_type = attr.sample_type;
384 // Set a default id value to report correctly even if ID is not recorded.
386 if (sample_type & PERF_SAMPLE_IDENTIFIER) {
387 MoveFromBinaryFormat(id_data, p);
389 if (sample_type & PERF_SAMPLE_IP) {
390 MoveFromBinaryFormat(ip_data, p);
392 if (sample_type & PERF_SAMPLE_TID) {
393 MoveFromBinaryFormat(tid_data, p);
395 if (sample_type & PERF_SAMPLE_TIME) {
396 MoveFromBinaryFormat(time_data, p);
398 if (sample_type & PERF_SAMPLE_ADDR) {
399 MoveFromBinaryFormat(addr_data, p);
401 if (sample_type & PERF_SAMPLE_ID) {
402 MoveFromBinaryFormat(id_data, p);
404 if (sample_type & PERF_SAMPLE_STREAM_ID) {
405 MoveFromBinaryFormat(stream_id_data, p);
407 if (sample_type & PERF_SAMPLE_CPU) {
408 MoveFromBinaryFormat(cpu_data, p);
410 if (sample_type & PERF_SAMPLE_PERIOD) {
411 MoveFromBinaryFormat(period_data, p);
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);
418 if (sample_type & PERF_SAMPLE_RAW) {
419 MoveFromBinaryFormat(raw_data.size, p);
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);
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;
433 regs_user_data.reg_mask = attr.sample_regs_user;
435 for (size_t i = 0; i < 64; ++i) {
436 if ((regs_user_data.reg_mask >> i) & 1) {
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);
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;
450 stack_user_data.data = p;
451 p += stack_user_data.size;
452 MoveFromBinaryFormat(stack_user_data.dyn_size, p);
455 // TODO: Add parsing of other PERF_SAMPLE_*.
458 LOG(DEBUG) << "Record has " << end - p << " bytes left\n";
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));
475 time_data.time = time;
479 period_data.period = period;
480 callchain_data.ip_nr = ips.size();
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;
487 uint32_t size = header_size();
488 if (sample_type & PERF_SAMPLE_IP) {
489 size += sizeof(ip_data);
491 if (sample_type & PERF_SAMPLE_TID) {
492 size += sizeof(tid_data);
494 if (sample_type & PERF_SAMPLE_TIME) {
495 size += sizeof(time_data);
497 if (sample_type & PERF_SAMPLE_ID) {
498 size += sizeof(id_data);
500 if (sample_type & PERF_SAMPLE_CPU) {
501 size += sizeof(cpu_data);
503 if (sample_type & PERF_SAMPLE_PERIOD) {
504 size += sizeof(period_data);
506 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
507 size += sizeof(uint64_t) * (ips.size() + 1);
509 if (sample_type & PERF_SAMPLE_REGS_USER) {
510 size += sizeof(uint64_t);
512 if (sample_type & PERF_SAMPLE_STACK_USER) {
513 size += sizeof(uint64_t);
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);
523 if (sample_type & PERF_SAMPLE_TID) {
524 MoveToBinaryFormat(tid_data, p);
526 if (sample_type & PERF_SAMPLE_TIME) {
527 MoveToBinaryFormat(time_data, p);
529 if (sample_type & PERF_SAMPLE_ID) {
530 MoveToBinaryFormat(id_data, p);
532 if (sample_type & PERF_SAMPLE_CPU) {
533 MoveToBinaryFormat(cpu_data, p);
535 if (sample_type & PERF_SAMPLE_PERIOD) {
536 MoveToBinaryFormat(period_data, p);
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);
543 if (sample_type & PERF_SAMPLE_REGS_USER) {
544 MoveToBinaryFormat(regs_user_data.abi, p);
546 if (sample_type & PERF_SAMPLE_STACK_USER) {
547 MoveToBinaryFormat(stack_user_data.size, p);
549 CHECK_EQ(p, new_binary + size);
550 UpdateBinary(new_binary);
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 +
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 +
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;
580 if (sample_type & PERF_SAMPLE_RAW) {
582 memmove(p, raw_data.data, raw_data.size);
583 p -= sizeof(uint32_t);
584 *reinterpret_cast<uint32_t*>(p) = raw_data.size;
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;
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));
602 if (sample_type & PERF_SAMPLE_TID) {
603 PrintIndented(indent, "pid %u, tid %u\n", tid_data.pid, tid_data.tid);
605 if (sample_type & PERF_SAMPLE_TIME) {
606 PrintIndented(indent, "time %" PRId64 "\n", time_data.time);
608 if (sample_type & PERF_SAMPLE_ADDR) {
609 PrintIndented(indent, "addr %p\n", reinterpret_cast<void*>(addr_data.addr));
611 if (sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
612 PrintIndented(indent, "id %" PRId64 "\n", id_data.id);
614 if (sample_type & PERF_SAMPLE_STREAM_ID) {
615 PrintIndented(indent, "stream_id %" PRId64 "\n", stream_id_data.stream_id);
617 if (sample_type & PERF_SAMPLE_CPU) {
618 PrintIndented(indent, "cpu %u, res %u\n", cpu_data.cpu, cpu_data.res);
620 if (sample_type & PERF_SAMPLE_PERIOD) {
621 PrintIndented(indent, "period %" PRId64 "\n", period_data.period);
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]);
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]);
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);
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) {
652 indent + 1, "reg (%s) 0x%016" PRIx64 "\n",
653 GetRegName(i, ScopedCurrentArch::GetCurrentArch()).c_str(),
654 regs_user_data.regs[pos++]);
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));
664 PrintIndented(indent + 1, "");
665 for (size_t i = 0; i < 4 && p < end; ++i, ++p) {
666 printf(" %016" PRIx64, *p);
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; }
678 BuildIdRecord::BuildIdRecord(const char* p) : Record(p) {
679 const char* end = p + size();
681 MoveFromBinaryFormat(pid, p);
682 build_id = BuildId(p, BUILD_ID_SIZE);
683 p += Align(build_id.Size(), 8);
685 p += Align(strlen(filename) + 1, 64);
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);
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);
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);
710 strcpy(p, filename.c_str());
711 UpdateBinary(new_binary);
714 KernelSymbolRecord::KernelSymbolRecord(const char* p) : Record(p) {
715 const char* end = p + size();
717 MoveFromBinaryFormat(kallsyms_size, p);
719 p += Align(kallsyms_size, 8);
723 void KernelSymbolRecord::DumpData(size_t indent) const {
724 PrintIndented(indent, "kallsyms: %s\n",
725 std::string(kallsyms, kallsyms + kallsyms_size).c_str());
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);
737 memcpy(p, kallsyms.data(), kallsyms_size);
738 UpdateBinary(new_binary);
741 DsoRecord::DsoRecord(const char* p) : Record(p) {
742 const char* end = p + size();
744 MoveFromBinaryFormat(dso_type, p);
745 MoveFromBinaryFormat(dso_id, p);
746 MoveFromBinaryFormat(min_vaddr, p);
748 p += Align(strlen(dso_name) + 1, 8);
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);
766 strcpy(p, dso_name.c_str());
767 UpdateBinary(new_binary);
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);
778 SymbolRecord::SymbolRecord(const char* p) : Record(p) {
779 const char* end = p + size();
781 MoveFromBinaryFormat(addr, p);
782 MoveFromBinaryFormat(len, p);
783 MoveFromBinaryFormat(dso_id, p);
785 p += Align(strlen(name) + 1, 8);
789 SymbolRecord::SymbolRecord(uint64_t addr, uint64_t len, const std::string& name,
791 SetTypeAndMisc(SIMPLE_PERF_RECORD_SYMBOL, 0);
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);
803 strcpy(p, name.c_str());
804 UpdateBinary(new_binary);
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);
814 TracingDataRecord::TracingDataRecord(const char* p) : Record(p) {
815 const char* end = p + size();
817 MoveFromBinaryFormat(data_size, p);
819 p += Align(data_size, 64);
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);
832 memcpy(p, tracing_data.data(), data_size);
833 UpdateBinary(new_binary);
836 void TracingDataRecord::DumpData(size_t indent) const {
837 Tracing tracing(std::vector<char>(data, data + data_size));
838 tracing.Dump(indent);
841 EventIdRecord::EventIdRecord(const char* p) : Record(p) {
842 const char* end = p + size();
844 MoveFromBinaryFormat(count, p);
845 data = reinterpret_cast<const EventIdData*>(p);
846 p += sizeof(data[0]) * count;
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);
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,
868 PrintIndented(indent, "event_id[%" PRIu64 "]: %" PRIu64 "\n", i,
873 UnknownRecord::UnknownRecord(const char* p) : Record(p) {
878 void UnknownRecord::DumpData(size_t) const {}
880 std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr,
881 uint32_t type, const char* p) {
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));
908 return std::unique_ptr<Record>(new UnknownRecord(p));
912 std::unique_ptr<Record> ReadRecordFromOwnedBuffer(const perf_event_attr& attr,
915 std::unique_ptr<Record> record = ReadRecordFromBuffer(attr, type, p);
916 if (record != nullptr) {
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;
928 const char* end = buf + buf_size;
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));
939 std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr,
941 auto header = reinterpret_cast<const perf_event_header*>(p);
942 return ReadRecordFromBuffer(attr, header->type, p);
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;
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;
961 // Otherwise, use the same order as they enter the cache.
962 return seq < other.seq;
965 bool RecordCache::RecordComparator::operator()(const RecordWithSeq& r1,
966 const RecordWithSeq& r2) {
967 return r2.IsHappensBefore(r1);
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),
977 queue_(RecordComparator()) {}
979 RecordCache::~RecordCache() { PopAll(); }
981 void RecordCache::Push(std::unique_ptr<Record> record) {
982 if (has_timestamp_) {
983 last_time_ = std::max(last_time_, record->Timestamp());
985 queue_.push(RecordWithSeq(cur_seq_++, record.release()));
988 void RecordCache::Push(std::vector<std::unique_ptr<Record>> records) {
989 for (auto& r : records) {
994 std::unique_ptr<Record> RecordCache::Pop() {
995 if (queue_.size() < min_cache_size_) {
998 Record* r = queue_.top().record;
999 if (has_timestamp_) {
1000 if (r->Timestamp() + min_time_diff_in_ns_ > last_time_) {
1005 return std::unique_ptr<Record>(r);
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);
1017 std::unique_ptr<Record> RecordCache::ForcedPop() {
1018 if (queue_.empty()) {
1021 Record* r = queue_.top().record;
1023 return std::unique_ptr<Record>(r);