Perf (linux-2.6/tools/perf) trace file reader.
| 589 | |
| 590 | |
| 591 | class TraceReader(object): |
| 592 | """Perf (linux-2.6/tools/perf) trace file reader.""" |
| 593 | |
| 594 | _TRACE_HEADER_MAGIC = int.from_bytes(b"PERFFILE", byteorder="little") |
| 595 | assert _TRACE_HEADER_MAGIC == 4993446653023372624 |
| 596 | _TRACE_HEADER_MAGIC_2 = int.from_bytes(b"PERFILE2", byteorder="little") |
| 597 | assert _TRACE_HEADER_MAGIC_2 == 3622385352885552464 |
| 598 | |
| 599 | def __init__(self, trace_name): |
| 600 | self.trace_file = open(trace_name, "r") |
| 601 | self.trace = mmap.mmap(self.trace_file.fileno(), 0, mmap.MAP_PRIVATE) |
| 602 | self.trace_header = TRACE_HEADER_DESC.Read(self.trace, 0) |
| 603 | if self.trace_header.magic not in (self._TRACE_HEADER_MAGIC, |
| 604 | self._TRACE_HEADER_MAGIC_2): |
| 605 | print("Warning: unsupported trace header magic", file=sys.stderr) |
| 606 | self.offset = self.trace_header.data_offset |
| 607 | self.limit = self.trace_header.data_offset + self.trace_header.data_size |
| 608 | assert self.limit <= self.trace.size(), \ |
| 609 | "Trace data limit exceeds trace file size" |
| 610 | self.header_size = ctypes.sizeof(PERF_EVENT_HEADER_DESC.ctype) |
| 611 | assert self.trace_header.attrs_size != 0, \ |
| 612 | "No perf event attributes found in the trace" |
| 613 | perf_event_attr = PERF_EVENT_ATTR_DESC.Read(self.trace, |
| 614 | self.trace_header.attrs_offset) |
| 615 | self.sample_event_body_desc = self._SampleEventBodyDesc( |
| 616 | perf_event_attr.sample_type) |
| 617 | self.callchain_supported = \ |
| 618 | (perf_event_attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0 |
| 619 | self.ip_struct = None |
| 620 | if self.callchain_supported: |
| 621 | self.ip_struct = Descriptor.CTYPE_MAP[PERF_SAMPLE_EVENT_IP_FORMAT] |
| 622 | self.ip_size = ctypes.sizeof(self.ip_struct) |
| 623 | |
| 624 | def ReadEventHeader(self): |
| 625 | if self.offset >= self.limit: |
| 626 | return None, 0 |
| 627 | offset = self.offset |
| 628 | header = PERF_EVENT_HEADER_DESC.Read(self.trace, self.offset) |
| 629 | self.offset += header.size |
| 630 | return header, offset |
| 631 | |
| 632 | def ReadMmap(self, header, offset): |
| 633 | mmap_info = PERF_MMAP_EVENT_BODY_DESC.Read(self.trace, |
| 634 | offset + self.header_size) |
| 635 | # Read null-terminated filename. |
| 636 | filename = self.trace[offset + self.header_size + ctypes.sizeof(mmap_info): |
| 637 | offset + header.size] |
| 638 | mmap_info.filename = HOST_ROOT + filename[:filename.find(b"\0")].decode() |
| 639 | return mmap_info |
| 640 | |
| 641 | def ReadMmap2(self, header, offset): |
| 642 | mmap_info = PERF_MMAP2_EVENT_BODY_DESC.Read(self.trace, |
| 643 | offset + self.header_size) |
| 644 | # Read null-terminated filename. |
| 645 | filename = self.trace[offset + self.header_size + ctypes.sizeof(mmap_info): |
| 646 | offset + header.size] |
| 647 | mmap_info.filename = HOST_ROOT + filename[:filename.find(b"\0")].decode() |
| 648 | return mmap_info |
no outgoing calls
no test coverage detected
searching dependent graphs…