| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 |
|
| 6 | import os
|
| 7 | import sys
|
| 8 | import re
|
| 9 | import bisect
|
| 10 | import collections
|
| 11 | from dataclasses import dataclass
|
| 12 | from typing import (Dict, Optional)
|
| 13 |
|
| 14 | sys.path.append(os.environ['PERF_EXEC_PATH'] + \
|
| 15 | '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
|
| 16 |
|
| 17 | @dataclass(frozen=True)
|
| 18 | class IomemEntry:
|
| 19 |
|
| 20 | begin: int
|
| 21 | end: int
|
| 22 | indent: int
|
| 23 | label: str
|
| 24 |
|
| 25 | |
| 26 | |
| 27 | iomem: Dict[int, list[IomemEntry]] = collections.defaultdict(list)
|
| 28 | |
| 29 | children: Dict[IomemEntry, set[IomemEntry]] = collections.defaultdict(set)
|
| 30 | |
| 31 | max_indent: int = 0
|
| 32 | |
| 33 | load_mem_type_cnt: Dict[IomemEntry, int] = collections.Counter()
|
| 34 | |
| 35 | event_name: Optional[str] = None
|
| 36 |
|
| 37 | def parse_iomem():
|
| 38 |
|
| 39 | global iomem
|
| 40 | global max_indent
|
| 41 | global children
|
| 42 | with open('/proc/iomem', 'r', encoding='ascii') as f:
|
| 43 | for line in f:
|
| 44 | indent = 0
|
| 45 | while line[indent] == ' ':
|
| 46 | indent += 1
|
| 47 | if indent > max_indent:
|
| 48 | max_indent = indent
|
| 49 | m = re.split('-|:', line, 2)
|
| 50 | begin = int(m[0], 16)
|
| 51 | end = int(m[1], 16)
|
| 52 | label = m[2].strip()
|
| 53 | entry = IomemEntry(begin, end, indent, label)
|
| 54 | |
| 55 | if indent > 0:
|
| 56 | parent = find_memory_type(begin)
|
| 57 | assert parent, f"Given indent expected a parent for {label}"
|
| 58 | children[parent].add(entry)
|
| 59 | iomem[indent].append(entry)
|
| 60 |
|
| 61 | def find_memory_type(phys_addr) -> Optional[IomemEntry]:
|
| 62 |
|
| 63 | for i in range(max_indent, -1, -1):
|
| 64 | if i not in iomem:
|
| 65 | continue
|
| 66 | position = bisect.bisect_right(iomem[i], phys_addr,
|
| 67 | key=lambda entry: entry.begin)
|
| 68 | if position is None:
|
| 69 | continue
|
| 70 | iomem_entry = iomem[i][position-1]
|
| 71 | if iomem_entry.begin <= phys_addr <= iomem_entry.end:
|
| 72 | return iomem_entry
|
| 73 | print(f"Didn't find {phys_addr}")
|
| 74 | return None
|
| 75 |
|
| 76 | def print_memory_type():
|
| 77 | print(f"Event: {event_name}")
|
| 78 | print(f"{'Memory type':<40} {'count':>10} {'percentage':>10}")
|
| 79 | print(f"{'-' * 40:<40} {'-' * 10:>10} {'-' * 10:>10}")
|
| 80 | total = sum(load_mem_type_cnt.values())
|
| 81 | |
| 82 | for i in range(max_indent, -1, -1):
|
| 83 | if i not in iomem:
|
| 84 | continue
|
| 85 | for entry in iomem[i]:
|
| 86 | global children
|
| 87 | for child in children[entry]:
|
| 88 | if load_mem_type_cnt[child] > 0:
|
| 89 | load_mem_type_cnt[entry] += load_mem_type_cnt[child]
|
| 90 |
|
| 91 | def print_entries(entries):
|
| 92 |
|
| 93 | global children
|
| 94 | for entry in sorted(entries,
|
| 95 | key = lambda entry: load_mem_type_cnt[entry],
|
| 96 | reverse = True):
|
| 97 | count = load_mem_type_cnt[entry]
|
| 98 | if count > 0:
|
| 99 | mem_type = ' ' * entry.indent + f"{entry.begin:x}-{entry.end:x} : {entry.label}"
|
| 100 | percent = 100 * count / total
|
| 101 | print(f"{mem_type:<40} {count:>10} {percent:>10.1f}")
|
| 102 | print_entries(children[entry])
|
| 103 |
|
| 104 | print_entries(iomem[0])
|
| 105 |
|
| 106 | def trace_begin():
|
| 107 | parse_iomem()
|
| 108 |
|
| 109 | def trace_end():
|
| 110 | print_memory_type()
|
| 111 |
|
| 112 | def process_event(param_dict):
|
| 113 | if "sample" not in param_dict:
|
| 114 | return
|
| 115 |
|
| 116 | sample = param_dict["sample"]
|
| 117 | if "phys_addr" not in sample:
|
| 118 | return
|
| 119 |
|
| 120 | phys_addr = sample["phys_addr"]
|
| 121 | entry = find_memory_type(phys_addr)
|
| 122 | if entry:
|
| 123 | load_mem_type_cnt[entry] += 1
|
| 124 |
|
| 125 | global event_name
|
| 126 | if event_name is None:
|
| 127 | event_name = param_dict["ev_name"]
|