Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/bin/perf-annotate-jit.py
4545 views
1
#!/usr/bin/env python
2
#
3
# Copyright 2012 VMware Inc
4
# Copyright 2008-2009 Jose Fonseca
5
#
6
# Permission is hereby granted, free of charge, to any person obtaining a copy
7
# of this software and associated documentation files (the "Software"), to deal
8
# in the Software without restriction, including without limitation the rights
9
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
# copies of the Software, and to permit persons to whom the Software is
11
# furnished to do so, subject to the following conditions:
12
#
13
# The above copyright notice and this permission notice shall be included in
14
# all copies or substantial portions of the Software.
15
#
16
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
# THE SOFTWARE.
23
#
24
25
"""Perf annotate for JIT code.
26
27
Linux `perf annotate` does not work with JIT code. This script takes the data
28
produced by `perf script` command, plus the diassemblies outputed by gallivm
29
into /tmp/perf-XXXXX.map.asm and produces output similar to `perf annotate`.
30
31
See docs/llvmpipe.rst for usage instructions.
32
33
The `perf script` output parser was derived from the gprof2dot.py script.
34
"""
35
36
37
import sys
38
import os.path
39
import re
40
import optparse
41
import subprocess
42
43
44
class Parser:
45
"""Parser interface."""
46
47
def __init__(self):
48
pass
49
50
def parse(self):
51
raise NotImplementedError
52
53
54
class LineParser(Parser):
55
"""Base class for parsers that read line-based formats."""
56
57
def __init__(self, file):
58
Parser.__init__(self)
59
self._file = file
60
self.__line = None
61
self.__eof = False
62
self.line_no = 0
63
64
def readline(self):
65
line = self._file.readline()
66
if not line:
67
self.__line = ''
68
self.__eof = True
69
else:
70
self.line_no += 1
71
self.__line = line.rstrip('\r\n')
72
73
def lookahead(self):
74
assert self.__line is not None
75
return self.__line
76
77
def consume(self):
78
assert self.__line is not None
79
line = self.__line
80
self.readline()
81
return line
82
83
def eof(self):
84
assert self.__line is not None
85
return self.__eof
86
87
88
mapFile = None
89
90
def lookupMap(filename, matchSymbol):
91
global mapFile
92
mapFile = filename
93
stream = open(filename, 'rt')
94
for line in stream:
95
start, length, symbol = line.split()
96
97
start = int(start, 16)
98
length = int(length,16)
99
100
if symbol == matchSymbol:
101
return start
102
103
return None
104
105
def lookupAsm(filename, desiredFunction):
106
stream = open(filename + '.asm', 'rt')
107
while stream.readline() != desiredFunction + ':\n':
108
pass
109
110
asm = []
111
line = stream.readline().strip()
112
while line:
113
addr, instr = line.split(':', 1)
114
addr = int(addr)
115
asm.append((addr, instr))
116
line = stream.readline().strip()
117
118
return asm
119
120
121
122
samples = {}
123
124
125
class PerfParser(LineParser):
126
"""Parser for linux perf callgraph output.
127
128
It expects output generated with
129
130
perf record -g
131
perf script
132
"""
133
134
def __init__(self, infile, symbol):
135
LineParser.__init__(self, infile)
136
self.symbol = symbol
137
138
def readline(self):
139
# Override LineParser.readline to ignore comment lines
140
while True:
141
LineParser.readline(self)
142
if self.eof() or not self.lookahead().startswith('#'):
143
break
144
145
def parse(self):
146
# read lookahead
147
self.readline()
148
149
while not self.eof():
150
self.parse_event()
151
152
asm = lookupAsm(mapFile, self.symbol)
153
154
addresses = samples.keys()
155
addresses.sort()
156
total_samples = 0
157
158
sys.stdout.write('%s:\n' % self.symbol)
159
for address, instr in asm:
160
try:
161
sample = samples.pop(address)
162
except KeyError:
163
sys.stdout.write(6*' ')
164
else:
165
sys.stdout.write('%6u' % (sample))
166
total_samples += sample
167
sys.stdout.write('%6u: %s\n' % (address, instr))
168
print 'total:', total_samples
169
assert len(samples) == 0
170
171
sys.exit(0)
172
173
def parse_event(self):
174
if self.eof():
175
return
176
177
line = self.consume()
178
assert line
179
180
callchain = self.parse_callchain()
181
if not callchain:
182
return
183
184
def parse_callchain(self):
185
callchain = []
186
while self.lookahead():
187
function = self.parse_call(len(callchain) == 0)
188
if function is None:
189
break
190
callchain.append(function)
191
if self.lookahead() == '':
192
self.consume()
193
return callchain
194
195
call_re = re.compile(r'^\s+(?P<address>[0-9a-fA-F]+)\s+(?P<symbol>.*)\s+\((?P<module>[^)]*)\)$')
196
197
def parse_call(self, first):
198
line = self.consume()
199
mo = self.call_re.match(line)
200
assert mo
201
if not mo:
202
return None
203
204
if not first:
205
return None
206
207
function_name = mo.group('symbol')
208
if not function_name:
209
function_name = mo.group('address')
210
211
module = mo.group('module')
212
213
function_id = function_name + ':' + module
214
215
address = mo.group('address')
216
address = int(address, 16)
217
218
if function_name != self.symbol:
219
return None
220
221
start_address = lookupMap(module, function_name)
222
address -= start_address
223
224
#print function_name, module, address
225
226
samples[address] = samples.get(address, 0) + 1
227
228
return True
229
230
231
def main():
232
"""Main program."""
233
234
optparser = optparse.OptionParser(
235
usage="\n\t%prog [options] symbol_name")
236
(options, args) = optparser.parse_args(sys.argv[1:])
237
if len(args) != 1:
238
optparser.error('wrong number of arguments')
239
240
symbol = args[0]
241
242
p = subprocess.Popen(['perf', 'script'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
243
parser = PerfParser(p.stdout, symbol)
244
parser.parse()
245
246
247
if __name__ == '__main__':
248
main()
249
250
251
# vim: set sw=4 et:
252
253