Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(141)

Side by Side Diff: tools/tickprocessor.py

Issue 21452: Profiler tick processor now counts IC ticks on behalf of a caller. (Closed)
Patch Set: Created 11 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2008 the V8 project authors. All rights reserved. 1 # Copyright 2008 the V8 project authors. All rights reserved.
2 # Redistribution and use in source and binary forms, with or without 2 # Redistribution and use in source and binary forms, with or without
3 # modification, are permitted provided that the following conditions are 3 # modification, are permitted provided that the following conditions are
4 # met: 4 # met:
5 # 5 #
6 # * Redistributions of source code must retain the above copyright 6 # * Redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer. 7 # notice, this list of conditions and the following disclaimer.
8 # * Redistributions in binary form must reproduce the above 8 # * Redistributions in binary form must reproduce the above
9 # copyright notice, this list of conditions and the following 9 # copyright notice, this list of conditions and the following
10 # disclaimer in the documentation and/or other materials provided 10 # disclaimer in the documentation and/or other materials provided
11 # with the distribution. 11 # with the distribution.
12 # * Neither the name of Google Inc. nor the names of its 12 # * Neither the name of Google Inc. nor the names of its
13 # contributors may be used to endorse or promote products derived 13 # contributors may be used to endorse or promote products derived
14 # from this software without specific prior written permission. 14 # from this software without specific prior written permission.
15 # 15 #
16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 import csv, splaytree, sys 28 import csv, splaytree, sys, re
29 from operator import itemgetter 29 from operator import itemgetter
30 import getopt, os 30 import getopt, os, string
31 31
32 class CodeEntry(object): 32 class CodeEntry(object):
33 33
34 def __init__(self, start_addr, name): 34 def __init__(self, start_addr, name):
35 self.start_addr = start_addr 35 self.start_addr = start_addr
36 self.tick_count = 0 36 self.tick_count = 0
37 self.name = name 37 self.name = name
38 self.stacks = {} 38 self.stacks = {}
39 39
40 def Tick(self, pc, stack): 40 def Tick(self, pc, stack):
41 self.tick_count += 1 41 self.tick_count += 1
42 if len(stack) > 0: 42 if len(stack) > 0:
43 stack.insert(0, self.ToString()) 43 stack.insert(0, self.ToString())
44 stack_key = tuple(stack) 44 stack_key = tuple(stack)
45 self.stacks[stack_key] = self.stacks.setdefault(stack_key, 0) + 1 45 self.stacks[stack_key] = self.stacks.setdefault(stack_key, 0) + 1
46 46
47 def RegionTicks(self): 47 def RegionTicks(self):
48 return None 48 return None
49 49
50 def SetStartAddress(self, start_addr): 50 def SetStartAddress(self, start_addr):
51 self.start_addr = start_addr 51 self.start_addr = start_addr
52 52
53 def ToString(self): 53 def ToString(self):
54 return self.name 54 return self.name
55 55
56 def IsSharedLibraryEntry(self): 56 def IsSharedLibraryEntry(self):
57 return False 57 return False
58 58
59 def IsICEntry(self):
60 return False
61
59 62
60 class SharedLibraryEntry(CodeEntry): 63 class SharedLibraryEntry(CodeEntry):
61 64
62 def __init__(self, start_addr, name): 65 def __init__(self, start_addr, name):
63 CodeEntry.__init__(self, start_addr, name) 66 CodeEntry.__init__(self, start_addr, name)
64 67
65 def IsSharedLibraryEntry(self): 68 def IsSharedLibraryEntry(self):
66 return True 69 return True
67 70
68 71
69 class JSCodeEntry(CodeEntry): 72 class JSCodeEntry(CodeEntry):
70 73
71 def __init__(self, start_addr, name, type, size, assembler): 74 def __init__(self, start_addr, name, type, size, assembler):
72 CodeEntry.__init__(self, start_addr, name) 75 CodeEntry.__init__(self, start_addr, name)
73 self.type = type 76 self.type = type
74 self.size = size 77 self.size = size
75 self.assembler = assembler 78 self.assembler = assembler
76 self.region_ticks = None 79 self.region_ticks = None
80 self.builtin_ic_re = re.compile('^(Keyed)?(Call|Load|Store)IC_')
77 81
78 def Tick(self, pc, stack): 82 def Tick(self, pc, stack):
79 super(JSCodeEntry, self).Tick(pc, stack) 83 super(JSCodeEntry, self).Tick(pc, stack)
80 if not pc is None: 84 if not pc is None:
81 offset = pc - self.start_addr 85 offset = pc - self.start_addr
82 seen = [] 86 seen = []
83 narrowest = None 87 narrowest = None
84 narrowest_width = None 88 narrowest_width = None
85 for region in self.Regions(): 89 for region in self.Regions():
86 if region.Contains(offset): 90 if region.Contains(offset):
(...skipping 22 matching lines...) Expand all
109 return [] 113 return []
110 114
111 def ToString(self): 115 def ToString(self):
112 name = self.name 116 name = self.name
113 if name == '': 117 if name == '':
114 name = '<anonymous>' 118 name = '<anonymous>'
115 elif name.startswith(' '): 119 elif name.startswith(' '):
116 name = '<anonymous>' + name 120 name = '<anonymous>' + name
117 return self.type + ': ' + name 121 return self.type + ': ' + name
118 122
123 def IsICEntry(self):
124 return self.type in ('CallIC', 'LoadIC', 'StoreIC') or \
125 (self.type == 'Builtin' and self.builtin_ic_re.match(self.name))
126
119 127
120 class CodeRegion(object): 128 class CodeRegion(object):
121 129
122 def __init__(self, start_offset, name): 130 def __init__(self, start_offset, name):
123 self.start_offset = start_offset 131 self.start_offset = start_offset
124 self.name = name 132 self.name = name
125 self.end_offset = None 133 self.end_offset = None
126 134
127 def Contains(self, pc): 135 def Contains(self, pc):
128 return (self.start_offset <= pc) and (pc <= self.end_offset) 136 return (self.start_offset <= pc) and (pc <= self.end_offset)
(...skipping 23 matching lines...) Expand all
152 self.assemblers = {} 160 self.assemblers = {}
153 self.js_entries = splaytree.SplayTree() 161 self.js_entries = splaytree.SplayTree()
154 self.cpp_entries = splaytree.SplayTree() 162 self.cpp_entries = splaytree.SplayTree()
155 self.total_number_of_ticks = 0 163 self.total_number_of_ticks = 0
156 self.number_of_library_ticks = 0 164 self.number_of_library_ticks = 0
157 self.unaccounted_number_of_ticks = 0 165 self.unaccounted_number_of_ticks = 0
158 self.excluded_number_of_ticks = 0 166 self.excluded_number_of_ticks = 0
159 # Flag indicating whether to ignore unaccounted ticks in the report 167 # Flag indicating whether to ignore unaccounted ticks in the report
160 self.ignore_unknown = False 168 self.ignore_unknown = False
161 169
162 def ProcessLogfile(self, filename, included_state = None, ignore_unknown = Fal se): 170 def ProcessLogfile(self, filename, included_state = None, ignore_unknown = Fal se, separate_ic = False):
163 self.log_file = filename 171 self.log_file = filename
164 self.included_state = included_state 172 self.included_state = included_state
165 self.ignore_unknown = ignore_unknown 173 self.ignore_unknown = ignore_unknown
174 self.separate_ic = separate_ic
166 175
167 try: 176 try:
168 logfile = open(filename, 'rb') 177 logfile = open(filename, 'rb')
169 except IOError: 178 except IOError:
170 sys.exit("Could not open logfile: " + filename) 179 sys.exit("Could not open logfile: " + filename)
171 try: 180 try:
172 logreader = csv.reader(logfile) 181 logreader = csv.reader(logfile)
173 for row in logreader: 182 for row in logreader:
174 if row[0] == 'tick': 183 if row[0] == 'tick':
175 self.ProcessTick(int(row[1], 16), int(row[2], 16), int(row[3]), row[4: ]) 184 self.ProcessTick(int(row[1], 16), int(row[2], 16), int(row[3]), self.P reprocessStack(row[4:]))
176 elif row[0] == 'code-creation': 185 elif row[0] == 'code-creation':
177 self.ProcessCodeCreation(row[1], int(row[2], 16), int(row[3]), row[4]) 186 self.ProcessCodeCreation(row[1], int(row[2], 16), int(row[3]), row[4])
178 elif row[0] == 'code-move': 187 elif row[0] == 'code-move':
179 self.ProcessCodeMove(int(row[1], 16), int(row[2], 16)) 188 self.ProcessCodeMove(int(row[1], 16), int(row[2], 16))
180 elif row[0] == 'code-delete': 189 elif row[0] == 'code-delete':
181 self.ProcessCodeDelete(int(row[1], 16)) 190 self.ProcessCodeDelete(int(row[1], 16))
182 elif row[0] == 'shared-library': 191 elif row[0] == 'shared-library':
183 self.AddSharedLibraryEntry(row[1], int(row[2], 16), int(row[3], 16)) 192 self.AddSharedLibraryEntry(row[1], int(row[2], 16), int(row[3], 16))
184 self.ParseVMSymbols(row[1], int(row[2], 16), int(row[3], 16)) 193 self.ParseVMSymbols(row[1], int(row[2], 16), int(row[3], 16))
185 elif row[0] == 'begin-code-region': 194 elif row[0] == 'begin-code-region':
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 if entry != None: 263 if entry != None:
255 return entry.value 264 return entry.value
256 else: 265 else:
257 return entry 266 return entry
258 max = self.js_entries.FindMax() 267 max = self.js_entries.FindMax()
259 min = self.js_entries.FindMin() 268 min = self.js_entries.FindMin()
260 if max != None and pc < (max.key + max.value.size) and pc > min.key: 269 if max != None and pc < (max.key + max.value.size) and pc > min.key:
261 return self.js_entries.FindGreatestsLessThan(pc).value 270 return self.js_entries.FindGreatestsLessThan(pc).value
262 return None 271 return None
263 272
273 def PreprocessStack(self, stack):
274 # remove all non-addresses (e.g. 'overflow') and convert to int
275 result = []
276 for frame in stack:
277 if frame.startswith('0x'):
278 result.append(int(frame, 16))
279 return result
280
264 def ProcessStack(self, stack): 281 def ProcessStack(self, stack):
265 result = [] 282 result = []
266 for frame in stack: 283 for frame in stack:
267 if frame.startswith('0x'): 284 entry = self.FindEntry(frame)
268 entry = self.FindEntry(int(frame, 16)) 285 if entry != None:
269 if entry != None: 286 result.append(entry.ToString())
270 result.append(entry.ToString())
271 return result 287 return result
272 288
273 def ProcessTick(self, pc, sp, state, stack): 289 def ProcessTick(self, pc, sp, state, stack):
274 if not self.IncludeTick(pc, sp, state): 290 if not self.IncludeTick(pc, sp, state):
275 self.excluded_number_of_ticks += 1; 291 self.excluded_number_of_ticks += 1;
276 return 292 return
277 self.total_number_of_ticks += 1 293 self.total_number_of_ticks += 1
278 entry = self.FindEntry(pc) 294 entry = self.FindEntry(pc)
279 if entry == None: 295 if entry == None:
280 self.unaccounted_number_of_ticks += 1 296 self.unaccounted_number_of_ticks += 1
281 return 297 return
282 if entry.IsSharedLibraryEntry(): 298 if entry.IsSharedLibraryEntry():
283 self.number_of_library_ticks += 1 299 self.number_of_library_ticks += 1
284 entry.Tick(pc, self.ProcessStack(stack)) 300 if entry.IsICEntry() and not self.separate_ic:
301 if len(stack) > 0:
302 caller_pc = stack.pop(0)
303 self.total_number_of_ticks -= 1
304 self.ProcessTick(caller_pc, sp, state, stack)
305 else:
306 self.unaccounted_number_of_ticks += 1
307 else:
308 entry.Tick(pc, self.ProcessStack(stack))
285 309
286 def PrintResults(self): 310 def PrintResults(self):
287 print('Statistical profiling result from %s, (%d ticks, %d unaccounted, %d e xcluded).' % 311 print('Statistical profiling result from %s, (%d ticks, %d unaccounted, %d e xcluded).' %
288 (self.log_file, 312 (self.log_file,
289 self.total_number_of_ticks, 313 self.total_number_of_ticks,
290 self.unaccounted_number_of_ticks, 314 self.unaccounted_number_of_ticks,
291 self.excluded_number_of_ticks)) 315 self.excluded_number_of_ticks))
292 if self.total_number_of_ticks > 0: 316 if self.total_number_of_ticks > 0:
293 js_entries = self.js_entries.ExportValueList() 317 js_entries = self.js_entries.ExportValueList()
294 js_entries.extend(self.deleted_code) 318 js_entries.extend(self.deleted_code)
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
365 total_percentage = count * 100.0 / total_stacks 389 total_percentage = count * 100.0 / total_stacks
366 print(' %(total)5.1f%% %(call_path)s' % { 390 print(' %(total)5.1f%% %(call_path)s' % {
367 'total' : total_percentage, 391 'total' : total_percentage,
368 'call_path' : stack[0] + ' <- ' + stack[1] 392 'call_path' : stack[0] + ' <- ' + stack[1]
369 }) 393 })
370 394
371 395
372 class CmdLineProcessor(object): 396 class CmdLineProcessor(object):
373 397
374 def __init__(self): 398 def __init__(self):
399 self.options = ["js", "gc", "compiler", "other", "ignore-unknown", "separate -ic"]
375 # default values 400 # default values
376 self.state = None 401 self.state = None
377 self.ignore_unknown = False 402 self.ignore_unknown = False
378 self.log_file = None 403 self.log_file = None
404 self.separate_ic = False
379 405
380 def ProcessArguments(self): 406 def ProcessArguments(self):
381 try: 407 try:
382 opts, args = getopt.getopt(sys.argv[1:], "jgco", ["js", "gc", "compiler", "other", "ignore-unknown"]) 408 opts, args = getopt.getopt(sys.argv[1:], "jgco", self.options)
383 except getopt.GetoptError: 409 except getopt.GetoptError:
384 self.PrintUsageAndExit() 410 self.PrintUsageAndExit()
385 for key, value in opts: 411 for key, value in opts:
386 if key in ("-j", "--js"): 412 if key in ("-j", "--js"):
387 self.state = 0 413 self.state = 0
388 if key in ("-g", "--gc"): 414 if key in ("-g", "--gc"):
389 self.state = 1 415 self.state = 1
390 if key in ("-c", "--compiler"): 416 if key in ("-c", "--compiler"):
391 self.state = 2 417 self.state = 2
392 if key in ("-o", "--other"): 418 if key in ("-o", "--other"):
393 self.state = 3 419 self.state = 3
394 if key in ("--ignore-unknown"): 420 if key in ("--ignore-unknown"):
395 self.ignore_unknown = True 421 self.ignore_unknown = True
422 if key in ("--separate-ic"):
423 self.separate_ic = True
396 self.ProcessRequiredArgs(args) 424 self.ProcessRequiredArgs(args)
397 425
398 def ProcessRequiredArgs(self, args): 426 def ProcessRequiredArgs(self, args):
399 return 427 return
400 428
401 def GetRequiredArgsNames(self): 429 def GetRequiredArgsNames(self):
402 return 430 return
403 431
404 def PrintUsageAndExit(self): 432 def PrintUsageAndExit(self):
405 print('Usage: %(script_name)s --{js,gc,compiler,other} %(req_opts)s' % { 433 print('Usage: %(script_name)s --{%(opts)s} %(req_opts)s' % {
406 'script_name': os.path.basename(sys.argv[0]), 434 'script_name': os.path.basename(sys.argv[0]),
435 'opts': string.join(self.options, ','),
407 'req_opts': self.GetRequiredArgsNames() 436 'req_opts': self.GetRequiredArgsNames()
408 }) 437 })
409 sys.exit(2) 438 sys.exit(2)
410 439
411 def RunLogfileProcessing(self, tick_processor): 440 def RunLogfileProcessing(self, tick_processor):
412 tick_processor.ProcessLogfile(self.log_file, self.state, self.ignore_unknown ) 441 tick_processor.ProcessLogfile(self.log_file, self.state, self.ignore_unknown , self.separate_ic)
413 442
414 443
415 if __name__ == '__main__': 444 if __name__ == '__main__':
416 sys.exit('You probably want to run windows-tick-processor.py or linux-tick-pro cessor.py.') 445 sys.exit('You probably want to run windows-tick-processor.py or linux-tick-pro cessor.py.')
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698