mem-phys-addr.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. # mem-phys-addr.py: Resolve physical address samples
  2. # SPDX-License-Identifier: GPL-2.0
  3. #
  4. # Copyright (c) 2018, Intel Corporation.
  5. import os
  6. import sys
  7. import re
  8. import bisect
  9. import collections
  10. from dataclasses import dataclass
  11. from typing import (Dict, Optional)
  12. sys.path.append(os.environ['PERF_EXEC_PATH'] + \
  13. '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
  14. @dataclass(frozen=True)
  15. class IomemEntry:
  16. """Read from a line in /proc/iomem"""
  17. begin: int
  18. end: int
  19. indent: int
  20. label: str
  21. # Physical memory layout from /proc/iomem. Key is the indent and then
  22. # a list of ranges.
  23. iomem: Dict[int, list[IomemEntry]] = collections.defaultdict(list)
  24. # Child nodes from the iomem parent.
  25. children: Dict[IomemEntry, set[IomemEntry]] = collections.defaultdict(set)
  26. # Maximum indent seen before an entry in the iomem file.
  27. max_indent: int = 0
  28. # Count for each range of memory.
  29. load_mem_type_cnt: Dict[IomemEntry, int] = collections.Counter()
  30. # Perf event name set from the first sample in the data.
  31. event_name: Optional[str] = None
  32. def parse_iomem():
  33. """Populate iomem from /proc/iomem file"""
  34. global iomem
  35. global max_indent
  36. global children
  37. with open('/proc/iomem', 'r', encoding='ascii') as f:
  38. for line in f:
  39. indent = 0
  40. while line[indent] == ' ':
  41. indent += 1
  42. if indent > max_indent:
  43. max_indent = indent
  44. m = re.split('-|:', line, 2)
  45. begin = int(m[0], 16)
  46. end = int(m[1], 16)
  47. label = m[2].strip()
  48. entry = IomemEntry(begin, end, indent, label)
  49. # Before adding entry, search for a parent node using its begin.
  50. if indent > 0:
  51. parent = find_memory_type(begin)
  52. assert parent, f"Given indent expected a parent for {label}"
  53. children[parent].add(entry)
  54. iomem[indent].append(entry)
  55. def find_memory_type(phys_addr) -> Optional[IomemEntry]:
  56. """Search iomem for the range containing phys_addr with the maximum indent"""
  57. for i in range(max_indent, -1, -1):
  58. if i not in iomem:
  59. continue
  60. position = bisect.bisect_right(iomem[i], phys_addr,
  61. key=lambda entry: entry.begin)
  62. if position is None:
  63. continue
  64. iomem_entry = iomem[i][position-1]
  65. if iomem_entry.begin <= phys_addr <= iomem_entry.end:
  66. return iomem_entry
  67. print(f"Didn't find {phys_addr}")
  68. return None
  69. def print_memory_type():
  70. print(f"Event: {event_name}")
  71. print(f"{'Memory type':<40} {'count':>10} {'percentage':>10}")
  72. print(f"{'-' * 40:<40} {'-' * 10:>10} {'-' * 10:>10}")
  73. total = sum(load_mem_type_cnt.values())
  74. # Add count from children into the parent.
  75. for i in range(max_indent, -1, -1):
  76. if i not in iomem:
  77. continue
  78. for entry in iomem[i]:
  79. global children
  80. for child in children[entry]:
  81. if load_mem_type_cnt[child] > 0:
  82. load_mem_type_cnt[entry] += load_mem_type_cnt[child]
  83. def print_entries(entries):
  84. """Print counts from parents down to their children"""
  85. global children
  86. for entry in sorted(entries,
  87. key = lambda entry: load_mem_type_cnt[entry],
  88. reverse = True):
  89. count = load_mem_type_cnt[entry]
  90. if count > 0:
  91. mem_type = ' ' * entry.indent + f"{entry.begin:x}-{entry.end:x} : {entry.label}"
  92. percent = 100 * count / total
  93. print(f"{mem_type:<40} {count:>10} {percent:>10.1f}")
  94. print_entries(children[entry])
  95. print_entries(iomem[0])
  96. def trace_begin():
  97. parse_iomem()
  98. def trace_end():
  99. print_memory_type()
  100. def process_event(param_dict):
  101. if "sample" not in param_dict:
  102. return
  103. sample = param_dict["sample"]
  104. if "phys_addr" not in sample:
  105. return
  106. phys_addr = sample["phys_addr"]
  107. entry = find_memory_type(phys_addr)
  108. if entry:
  109. load_mem_type_cnt[entry] += 1
  110. global event_name
  111. if event_name is None:
  112. event_name = param_dict["ev_name"]