141013f0cSKan Liang# mem-phys-addr.py: Resolve physical address samples 241013f0cSKan Liang# SPDX-License-Identifier: GPL-2.0 341013f0cSKan Liang# 441013f0cSKan Liang# Copyright (c) 2018, Intel Corporation. 541013f0cSKan Liang 641013f0cSKan Liangimport os 741013f0cSKan Liangimport sys 841013f0cSKan Liangimport re 941013f0cSKan Liangimport bisect 1041013f0cSKan Liangimport collections 11*d78e20c0SIan Rogersfrom dataclasses import dataclass 12*d78e20c0SIan Rogersfrom typing import (Dict, Optional) 1341013f0cSKan Liang 1441013f0cSKan Liangsys.path.append(os.environ['PERF_EXEC_PATH'] + \ 1541013f0cSKan Liang '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') 1641013f0cSKan Liang 17*d78e20c0SIan Rogers@dataclass(frozen=True) 18*d78e20c0SIan Rogersclass IomemEntry: 19*d78e20c0SIan Rogers """Read from a line in /proc/iomem""" 20*d78e20c0SIan Rogers begin: int 21*d78e20c0SIan Rogers end: int 22*d78e20c0SIan Rogers indent: int 23*d78e20c0SIan Rogers label: str 24*d78e20c0SIan Rogers 25*d78e20c0SIan Rogers# Physical memory layout from /proc/iomem. Key is the indent and then 26*d78e20c0SIan Rogers# a list of ranges. 27*d78e20c0SIan Rogersiomem: Dict[int, list[IomemEntry]] = collections.defaultdict(list) 28*d78e20c0SIan Rogers# Child nodes from the iomem parent. 29*d78e20c0SIan Rogerschildren: Dict[IomemEntry, set[IomemEntry]] = collections.defaultdict(set) 30*d78e20c0SIan Rogers# Maximum indent seen before an entry in the iomem file. 31*d78e20c0SIan Rogersmax_indent: int = 0 32*d78e20c0SIan Rogers# Count for each range of memory. 33*d78e20c0SIan Rogersload_mem_type_cnt: Dict[IomemEntry, int] = collections.Counter() 34*d78e20c0SIan Rogers# Perf event name set from the first sample in the data. 35*d78e20c0SIan Rogersevent_name: Optional[str] = None 3641013f0cSKan Liang 3741013f0cSKan Liangdef parse_iomem(): 38*d78e20c0SIan Rogers """Populate iomem from /proc/iomem file""" 39*d78e20c0SIan Rogers global iomem 40*d78e20c0SIan Rogers global max_indent 41*d78e20c0SIan Rogers global children 42*d78e20c0SIan Rogers with open('/proc/iomem', 'r', encoding='ascii') as f: 43*d78e20c0SIan Rogers for line in f: 44*d78e20c0SIan Rogers indent = 0 45*d78e20c0SIan Rogers while line[indent] == ' ': 46*d78e20c0SIan Rogers indent += 1 47*d78e20c0SIan Rogers if indent > max_indent: 48*d78e20c0SIan Rogers max_indent = indent 49*d78e20c0SIan Rogers m = re.split('-|:', line, 2) 50*d78e20c0SIan Rogers begin = int(m[0], 16) 51*d78e20c0SIan Rogers end = int(m[1], 16) 52*d78e20c0SIan Rogers label = m[2].strip() 53*d78e20c0SIan Rogers entry = IomemEntry(begin, end, indent, label) 54*d78e20c0SIan Rogers # Before adding entry, search for a parent node using its begin. 55*d78e20c0SIan Rogers if indent > 0: 56*d78e20c0SIan Rogers parent = find_memory_type(begin) 57*d78e20c0SIan Rogers assert parent, f"Given indent expected a parent for {label}" 58*d78e20c0SIan Rogers children[parent].add(entry) 59*d78e20c0SIan Rogers iomem[indent].append(entry) 60*d78e20c0SIan Rogers 61*d78e20c0SIan Rogersdef find_memory_type(phys_addr) -> Optional[IomemEntry]: 62*d78e20c0SIan Rogers """Search iomem for the range containing phys_addr with the maximum indent""" 63*d78e20c0SIan Rogers for i in range(max_indent, -1, -1): 64*d78e20c0SIan Rogers if i not in iomem: 65*d78e20c0SIan Rogers continue 66*d78e20c0SIan Rogers position = bisect.bisect_right(iomem[i], phys_addr, 67*d78e20c0SIan Rogers key=lambda entry: entry.begin) 68*d78e20c0SIan Rogers if position is None: 69*d78e20c0SIan Rogers continue 70*d78e20c0SIan Rogers iomem_entry = iomem[i][position-1] 71*d78e20c0SIan Rogers if iomem_entry.begin <= phys_addr <= iomem_entry.end: 72*d78e20c0SIan Rogers return iomem_entry 73*d78e20c0SIan Rogers print(f"Didn't find {phys_addr}") 74*d78e20c0SIan Rogers return None 7541013f0cSKan Liang 7641013f0cSKan Liangdef print_memory_type(): 77*d78e20c0SIan Rogers print(f"Event: {event_name}") 78*d78e20c0SIan Rogers print(f"{'Memory type':<40} {'count':>10} {'percentage':>10}") 79*d78e20c0SIan Rogers print(f"{'-' * 40:<40} {'-' * 10:>10} {'-' * 10:>10}") 8041013f0cSKan Liang total = sum(load_mem_type_cnt.values()) 81*d78e20c0SIan Rogers # Add count from children into the parent. 82*d78e20c0SIan Rogers for i in range(max_indent, -1, -1): 83*d78e20c0SIan Rogers if i not in iomem: 84*d78e20c0SIan Rogers continue 85*d78e20c0SIan Rogers for entry in iomem[i]: 86*d78e20c0SIan Rogers global children 87*d78e20c0SIan Rogers for child in children[entry]: 88*d78e20c0SIan Rogers if load_mem_type_cnt[child] > 0: 89*d78e20c0SIan Rogers load_mem_type_cnt[entry] += load_mem_type_cnt[child] 90*d78e20c0SIan Rogers 91*d78e20c0SIan Rogers def print_entries(entries): 92*d78e20c0SIan Rogers """Print counts from parents down to their children""" 93*d78e20c0SIan Rogers global children 94*d78e20c0SIan Rogers for entry in sorted(entries, 95*d78e20c0SIan Rogers key = lambda entry: load_mem_type_cnt[entry], 96*d78e20c0SIan Rogers reverse = True): 97*d78e20c0SIan Rogers count = load_mem_type_cnt[entry] 98*d78e20c0SIan Rogers if count > 0: 99*d78e20c0SIan Rogers mem_type = ' ' * entry.indent + f"{entry.begin:x}-{entry.end:x} : {entry.label}" 100*d78e20c0SIan Rogers percent = 100 * count / total 101*d78e20c0SIan Rogers print(f"{mem_type:<40} {count:>10} {percent:>10.1f}") 102*d78e20c0SIan Rogers print_entries(children[entry]) 103*d78e20c0SIan Rogers 104*d78e20c0SIan Rogers print_entries(iomem[0]) 10541013f0cSKan Liang 10641013f0cSKan Liangdef trace_begin(): 10741013f0cSKan Liang parse_iomem() 10841013f0cSKan Liang 10941013f0cSKan Liangdef trace_end(): 11041013f0cSKan Liang print_memory_type() 11141013f0cSKan Liang 11241013f0cSKan Liangdef process_event(param_dict): 113*d78e20c0SIan Rogers if "sample" not in param_dict: 114*d78e20c0SIan Rogers return 115*d78e20c0SIan Rogers 11641013f0cSKan Liang sample = param_dict["sample"] 117*d78e20c0SIan Rogers if "phys_addr" not in sample: 118*d78e20c0SIan Rogers return 119*d78e20c0SIan Rogers 12041013f0cSKan Liang phys_addr = sample["phys_addr"] 121*d78e20c0SIan Rogers entry = find_memory_type(phys_addr) 122*d78e20c0SIan Rogers if entry: 123*d78e20c0SIan Rogers load_mem_type_cnt[entry] += 1 12441013f0cSKan Liang 12541013f0cSKan Liang global event_name 126*d78e20c0SIan Rogers if event_name is None: 127*d78e20c0SIan Rogers event_name = param_dict["ev_name"] 128