]>
Commit | Line | Data |
---|---|---|
7b72d14a AK |
1 | #!/usr/bin/python |
2 | # Generate Intel taken branches Linux perf event script for autofdo profiling. | |
3 | ||
4 | # Copyright (C) 2016 Free Software Foundation, Inc. | |
5 | # | |
6 | # GCC is free software; you can redistribute it and/or modify it under | |
7 | # the terms of the GNU General Public License as published by the Free | |
8 | # Software Foundation; either version 3, or (at your option) any later | |
9 | # version. | |
10 | # | |
11 | # GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
12 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | # for more details. | |
15 | # | |
16 | # You should have received a copy of the GNU General Public License | |
17 | # along with GCC; see the file COPYING3. If not see | |
18 | # <http://www.gnu.org/licenses/>. */ | |
19 | ||
20 | # Run it with perf record -b -e EVENT program ... | |
21 | # The Linux Kernel needs to support the PMU of the current CPU, and | |
22 | # It will likely not work in VMs. | |
23 | # Add --all to print for all cpus, otherwise for current cpu. | |
24 | # Add --script to generate shell script to run correct event. | |
25 | # | |
26 | # Requires internet (https) access. This may require setting up a proxy | |
27 | # with export https_proxy=... | |
28 | # | |
29 | import urllib2 | |
30 | import sys | |
31 | import json | |
32 | import argparse | |
33 | import collections | |
34 | ||
35 | baseurl = "https://download.01.org/perfmon" | |
36 | ||
37 | target_events = (u'BR_INST_RETIRED.NEAR_TAKEN', | |
38 | u'BR_INST_EXEC.TAKEN', | |
39 | u'BR_INST_RETIRED.TAKEN_JCC', | |
40 | u'BR_INST_TYPE_RETIRED.COND_TAKEN') | |
41 | ||
42 | ap = argparse.ArgumentParser() | |
43 | ap.add_argument('--all', '-a', help='Print for all CPUs', action='store_true') | |
44 | ap.add_argument('--script', help='Generate shell script', action='store_true') | |
45 | args = ap.parse_args() | |
46 | ||
47 | eventmap = collections.defaultdict(list) | |
48 | ||
49 | def get_cpu_str(): | |
50 | with open('/proc/cpuinfo', 'r') as c: | |
51 | vendor, fam, model = None, None, None | |
52 | for j in c: | |
53 | n = j.split() | |
54 | if n[0] == 'vendor_id': | |
55 | vendor = n[2] | |
56 | elif n[0] == 'model' and n[1] == ':': | |
57 | model = int(n[2]) | |
58 | elif n[0] == 'cpu' and n[1] == 'family': | |
59 | fam = int(n[3]) | |
60 | if vendor and fam and model: | |
61 | return "%s-%d-%X" % (vendor, fam, model), model | |
62 | return None, None | |
63 | ||
64 | def find_event(eventurl, model): | |
65 | print >>sys.stderr, "Downloading", eventurl | |
66 | u = urllib2.urlopen(eventurl) | |
67 | events = json.loads(u.read()) | |
68 | u.close() | |
69 | ||
70 | found = 0 | |
71 | for j in events: | |
72 | if j[u'EventName'] in target_events: | |
73 | event = "cpu/event=%s,umask=%s/" % (j[u'EventCode'], j[u'UMask']) | |
74 | if u'PEBS' in j and j[u'PEBS'] > 0: | |
75 | event += "p" | |
76 | if args.script: | |
77 | eventmap[event].append(model) | |
78 | else: | |
79 | print j[u'EventName'], "event for model", model, "is", event | |
80 | found += 1 | |
81 | return found | |
82 | ||
83 | if not args.all: | |
84 | cpu, model = get_cpu_str() | |
85 | if not cpu: | |
86 | sys.exit("Unknown CPU type") | |
87 | ||
88 | url = baseurl + "/mapfile.csv" | |
89 | print >>sys.stderr, "Downloading", url | |
90 | u = urllib2.urlopen(url) | |
91 | found = 0 | |
92 | cpufound = 0 | |
93 | for j in u: | |
94 | n = j.rstrip().split(',') | |
95 | if len(n) >= 4 and (args.all or n[0] == cpu) and n[3] == "core": | |
96 | if args.all: | |
97 | vendor, fam, model = n[0].split("-") | |
98 | model = int(model, 16) | |
99 | cpufound += 1 | |
100 | found += find_event(baseurl + n[2], model) | |
101 | u.close() | |
102 | ||
103 | if args.script: | |
104 | print '''#!/bin/sh | |
105 | # Profile workload for gcc profile feedback (autofdo) using Linux perf. | |
106 | # Auto generated. To regenerate for new CPUs run | |
9f06c15a | 107 | # contrib/gen_autofdo_event.py --script --all in gcc source |
7b72d14a AK |
108 | |
109 | # usages: | |
110 | # gcc-auto-profile program (profile program and children) | |
111 | # gcc-auto-profile -a sleep X (profile all for X secs, may need root) | |
112 | # gcc-auto-profile -p PID sleep X (profile PID) | |
113 | # gcc-auto-profile --kernel -a sleep X (profile kernel) | |
114 | # gcc-auto-profile --all -a sleep X (profile kernel and user space) | |
115 | ||
116 | # Identify branches taken event for CPU. | |
117 | # | |
118 | ||
119 | FLAGS=u | |
120 | ||
121 | if [ "$1" = "--kernel" ] ; then | |
122 | FLAGS=k | |
123 | shift | |
124 | fi | |
125 | if [ "$1" = "--all" ] ; then | |
126 | FLAGS=uk | |
127 | shift | |
128 | fi | |
129 | ||
130 | if ! grep -q Intel /proc/cpuinfo ; then | |
131 | echo >&2 "Only Intel CPUs supported" | |
132 | exit 1 | |
133 | fi | |
134 | ||
135 | if grep -q hypervisor /proc/cpuinfo ; then | |
136 | echo >&2 "Warning: branch profiling may not be functional in VMs" | |
137 | fi | |
138 | ||
139 | case `egrep -q "^cpu family\s*: 6" /proc/cpuinfo && | |
140 | egrep "^model\s*:" /proc/cpuinfo | head -n1` in''' | |
141 | for event, mod in eventmap.iteritems(): | |
142 | for m in mod[:-1]: | |
143 | print "model*:\ %s|\\" % m | |
144 | print 'model*:\ %s) E="%s$FLAGS" ;;' % (mod[-1], event) | |
145 | print '''*) | |
146 | echo >&2 "Unknown CPU. Run contrib/gen_autofdo_event.py --all --script to update script." | |
147 | exit 1 ;;''' | |
148 | print "esac" | |
149 | print 'exec perf record -e $E -b "$@"' | |
150 | ||
151 | if cpufound == 0 and not args.all: | |
152 | sys.exit('CPU %s not found' % cpu) | |
153 | ||
154 | if found == 0: | |
155 | sys.exit('Branch event not found') |