History

perf script python: Add script to profile and resolve physical mem type

There could be different types of memory in the system. E.g normal System Memory, Persistent Memory. To understand how the workload maps to those memories, it's important to know the I/O statistics of them. Perf can collect physical addresses, but those are raw data. It still needs extra work to resolve the physical addresses. Provide a script to facilitate the physical addresses resolving and I/O statistics. Profile with MEM_INST_RETIRED.ALL_LOADS or MEM_UOPS_RETIRED.ALL_LOADS event if any of them is available. Look up the /proc/iomem and resolve the physical address. Provide memory type summary. Here is an example output: # perf script report mem-phys-addr Event: mem_inst_retired.all_loads:P Memory type count percentage ---------------------------------------- ----------- ----------- System RAM 74 53.2% Persistent Memory 55 39.6% N/A --- Changes since V2: - Apply the new license rules. - Add comments for globals Changes since V1: - Do not mix DLA and Load Latency. Do not compare the loads and stores. Only profile the loads. - Use event name to replace the RAW event

Kan Liang committed 8 years ago

Commit 41013f01 parent dd8bd534 files · +119 −0Browse files

Showing the changes to tools/perf/scripts/python (3 of 4 files). Show all

Unified · Split

3 files
  1. tools/perf/scripts/python/bin/mem-phys-addr-record +19 −0
  2. tools/perf/scripts/python/bin/mem-phys-addr-report +3 −0
  3. tools/perf/scripts/python/mem-phys-addr.py +95 −0
tools/perf/scripts/python/bin/mem-phys-addr-record+19−0
@@ -0,0 +1,19 @@
1+#!/bin/bash
2+
3+#
4+# Profiling physical memory by all retired load instructions/uops event
5+# MEM_INST_RETIRED.ALL_LOADS or MEM_UOPS_RETIRED.ALL_LOADS
6+#
7+
8+load=`perf list | grep mem_inst_retired.all_loads`
9+if [ -z "$load" ]; then
10+ load=`perf list | grep mem_uops_retired.all_loads`
11+fi
12+if [ -z "$load" ]; then
13+ echo "There is no event to count all retired load instructions/uops."
14+ exit 1
15+fi
16+
17+arg=$(echo $load | tr -d ' ')
18+arg="$arg:P"
19+perf record --phys-data -e $arg $@
tools/perf/scripts/python/bin/mem-phys-addr-report+3−0
@@ -0,0 +1,3 @@
1+#!/bin/bash
2+# description: resolve physical address samples
3+perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/mem-phys-addr.py
tools/perf/scripts/python/mem-phys-addr.py+95−0
@@ -0,0 +1,95 @@
1+# mem-phys-addr.py: Resolve physical address samples
2+# SPDX-License-Identifier: GPL-2.0
3+#
4+# Copyright (c) 2018, Intel Corporation.
5+
6+from __future__ import division
7+import os
8+import sys
9+import struct
10+import re
11+import bisect
12+import collections
13+
14+sys.path.append(os.environ['PERF_EXEC_PATH'] + \
15+ '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
16+
17+#physical address ranges for System RAM
18+system_ram = []
19+#physical address ranges for Persistent Memory
20+pmem = []
21+#file object for proc iomem
22+f = None
23+#Count for each type of memory
24+load_mem_type_cnt = collections.Counter()
25+#perf event name
26+event_name = None
27+
28+def parse_iomem():
29+ global f
30+ f = open('/proc/iomem', 'r')
31+ for i, j in enumerate(f):
32+ m = re.split('-|:',j,2)
33+ if m[2].strip() == 'System RAM':
34+ system_ram.append(long(m[0], 16))
35+ system_ram.append(long(m[1], 16))
36+ if m[2].strip() == 'Persistent Memory':
37+ pmem.append(long(m[0], 16))
38+ pmem.append(long(m[1], 16))
39+
40+def print_memory_type():
41+ print "Event: %s" % (event_name)
42+ print "%-40s %10s %10s\n" % ("Memory type", "count", "percentage"),
43+ print "%-40s %10s %10s\n" % ("----------------------------------------", \
44+ "-----------", "-----------"),
45+ total = sum(load_mem_type_cnt.values())
46+ for mem_type, count in sorted(load_mem_type_cnt.most_common(), \
47+ key = lambda(k, v): (v, k), reverse = True):
48+ print "%-40s %10d %10.1f%%\n" % (mem_type, count, 100 * count / total),
49+
50+def trace_begin():
51+ parse_iomem()
52+
53+def trace_end():
54+ print_memory_type()
55+ f.close()
56+
57+def is_system_ram(phys_addr):
58+ #/proc/iomem is sorted
59+ position = bisect.bisect(system_ram, phys_addr)
60+ if position % 2 == 0:
61+ return False
62+ return True
63+
64+def is_persistent_mem(phys_addr):
65+ position = bisect.bisect(pmem, phys_addr)
66+ if position % 2 == 0:
67+ return False
68+ return True
69+
70+def find_memory_type(phys_addr):
71+ if phys_addr == 0:
72+ return "N/A"
73+ if is_system_ram(phys_addr):
74+ return "System RAM"
75+
76+ if is_persistent_mem(phys_addr):
77+ return "Persistent Memory"
78+
79+ #slow path, search all
80+ f.seek(0, 0)
81+ for j in f:
82+ m = re.split('-|:',j,2)
83+ if long(m[0], 16) <= phys_addr <= long(m[1], 16):
84+ return m[2]
85+ return "N/A"
86+
87+def process_event(param_dict):
88+ name = param_dict["ev_name"]
89+ sample = param_dict["sample"]
90+ phys_addr = sample["phys_addr"]
91+
92+ global event_name
93+ if event_name == None:
94+ event_name = name
95+ load_mem_type_cnt[find_memory_type(phys_addr)] += 1