127 lines · 4.1 KB · Python
RawDownload
# mem-phys-addr.py: Resolve physical address samples# SPDX-License-Identifier: GPL-2.0## Copyright (c) 2018, Intel Corporation. import osimport sysimport reimport bisectimport collectionsfrom dataclasses import dataclassfrom typing import (Dict, Optional) sys.path.append(os.environ['PERF_EXEC_PATH'] + \    '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') @dataclass(frozen=True)class IomemEntry:    """Read from a line in /proc/iomem"""    begin: int    end: int    indent: int    label: str # Physical memory layout from /proc/iomem. Key is the indent and then# a list of ranges.iomem: Dict[int, list[IomemEntry]] = collections.defaultdict(list)# Child nodes from the iomem parent.children: Dict[IomemEntry, set[IomemEntry]] = collections.defaultdict(set)# Maximum indent seen before an entry in the iomem file.max_indent: int = 0# Count for each range of memory.load_mem_type_cnt: Dict[IomemEntry, int] = collections.Counter()# Perf event name set from the first sample in the data.event_name: Optional[str] = None def parse_iomem():    """Populate iomem from /proc/iomem file"""    global iomem    global max_indent    global children    with open('/proc/iomem', 'r', encoding='ascii') as f:        for line in f:            indent = 0            while line[indent] == ' ':                indent += 1            if indent > max_indent:                max_indent = indent            m = re.split('-|:', line, 2)            begin = int(m[0], 16)            end = int(m[1], 16)            label = m[2].strip()            entry = IomemEntry(begin, end, indent, label)            # Before adding entry, search for a parent node using its begin.            if indent > 0:                parent = find_memory_type(begin)                assert parent, f"Given indent expected a parent for {label}"                children[parent].add(entry)            iomem[indent].append(entry) def find_memory_type(phys_addr) -> Optional[IomemEntry]:    """Search iomem for the range containing phys_addr with the maximum indent"""    for i in range(max_indent, -1, -1):        if i not in iomem:            continue        position = bisect.bisect_right(iomem[i], phys_addr,                                       key=lambda entry: entry.begin)        if position is None:            continue        iomem_entry = iomem[i][position-1]        if  iomem_entry.begin <= phys_addr <= iomem_entry.end:            return iomem_entry    print(f"Didn't find {phys_addr}")    return None def print_memory_type():    print(f"Event: {event_name}")    print(f"{'Memory type':<40}  {'count':>10}  {'percentage':>10}")    print(f"{'-' * 40:<40}  {'-' * 10:>10}  {'-' * 10:>10}")    total = sum(load_mem_type_cnt.values())    # Add count from children into the parent.    for i in range(max_indent, -1, -1):        if i not in iomem:            continue        for entry in iomem[i]:            global children            for child in children[entry]:                if load_mem_type_cnt[child] > 0:                    load_mem_type_cnt[entry] += load_mem_type_cnt[child]     def print_entries(entries):        """Print counts from parents down to their children"""        global children        for entry in sorted(entries,                            key = lambda entry: load_mem_type_cnt[entry],                            reverse = True):            count = load_mem_type_cnt[entry]            if count > 0:                mem_type = ' ' * entry.indent + f"{entry.begin:x}-{entry.end:x} : {entry.label}"                percent = 100 * count / total                print(f"{mem_type:<40}  {count:>10}  {percent:>10.1f}")                print_entries(children[entry])     print_entries(iomem[0]) def trace_begin():    parse_iomem() def trace_end():    print_memory_type() def process_event(param_dict):    if "sample" not in param_dict:        return     sample = param_dict["sample"]    if "phys_addr" not in sample:        return     phys_addr  = sample["phys_addr"]    entry = find_memory_type(phys_addr)    if entry:        load_mem_type_cnt[entry] += 1     global event_name    if event_name is None:        event_name  = param_dict["ev_name"]