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

Side by Side Diff: tools/tickprocessor.py

Issue 21403: Added the simplest call stack sampling and call profile in tick processor output. (Closed)
Patch Set: Merged after Soren's changes to logging 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 | « src/platform-win32.cc ('k') | 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
29 from operator import itemgetter
29 30
30 31
31 class CodeEntry(object): 32 class CodeEntry(object):
32 33
33 def __init__(self, start_addr, name): 34 def __init__(self, start_addr, name):
34 self.start_addr = start_addr 35 self.start_addr = start_addr
35 self.tick_count = 0 36 self.tick_count = 0
36 self.name = name 37 self.name = name
38 self.stacks = {}
37 39
38 def Tick(self, pc): 40 def Tick(self, pc, stack):
39 self.tick_count += 1 41 self.tick_count += 1
42 if len(stack) > 0:
43 stack.insert(0, self.ToString())
44 stack_key = tuple(stack)
45 self.stacks[stack_key] = self.stacks.setdefault(stack_key, 0) + 1
40 46
41 def RegionTicks(self): 47 def RegionTicks(self):
42 return None 48 return None
43 49
44 def SetStartAddress(self, start_addr): 50 def SetStartAddress(self, start_addr):
45 self.start_addr = start_addr 51 self.start_addr = start_addr
46 52
47 def ToString(self): 53 def ToString(self):
48 return self.name 54 return self.name
49 55
(...skipping 12 matching lines...) Expand all
62 68
63 class JSCodeEntry(CodeEntry): 69 class JSCodeEntry(CodeEntry):
64 70
65 def __init__(self, start_addr, name, type, size, assembler): 71 def __init__(self, start_addr, name, type, size, assembler):
66 CodeEntry.__init__(self, start_addr, name) 72 CodeEntry.__init__(self, start_addr, name)
67 self.type = type 73 self.type = type
68 self.size = size 74 self.size = size
69 self.assembler = assembler 75 self.assembler = assembler
70 self.region_ticks = None 76 self.region_ticks = None
71 77
72 def Tick(self, pc): 78 def Tick(self, pc, stack):
73 super(JSCodeEntry, self).Tick(pc) 79 super(JSCodeEntry, self).Tick(pc, stack)
74 if not pc is None: 80 if not pc is None:
75 offset = pc - self.start_addr 81 offset = pc - self.start_addr
76 seen = [] 82 seen = []
77 narrowest = None 83 narrowest = None
78 narrowest_width = None 84 narrowest_width = None
79 for region in self.Regions(): 85 for region in self.Regions():
80 if region.Contains(offset): 86 if region.Contains(offset):
81 if (not region.name in seen): 87 if (not region.name in seen):
82 seen.append(region.name) 88 seen.append(region.name)
83 if narrowest is None or region.Width() < narrowest.Width(): 89 if narrowest is None or region.Width() < narrowest.Width():
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 self.log_file = filename 161 self.log_file = filename
156 self.included_state = included_state 162 self.included_state = included_state
157 try: 163 try:
158 logfile = open(filename, 'rb') 164 logfile = open(filename, 'rb')
159 except IOError: 165 except IOError:
160 sys.exit("Could not open logfile: " + filename) 166 sys.exit("Could not open logfile: " + filename)
161 try: 167 try:
162 logreader = csv.reader(logfile) 168 logreader = csv.reader(logfile)
163 for row in logreader: 169 for row in logreader:
164 if row[0] == 'tick': 170 if row[0] == 'tick':
165 self.ProcessTick(int(row[1], 16), int(row[2], 16), int(row[3])) 171 self.ProcessTick(int(row[1], 16), int(row[2], 16), int(row[3]), row[4: ])
166 elif row[0] == 'code-creation': 172 elif row[0] == 'code-creation':
167 self.ProcessCodeCreation(row[1], int(row[2], 16), int(row[3]), row[4]) 173 self.ProcessCodeCreation(row[1], int(row[2], 16), int(row[3]), row[4])
168 elif row[0] == 'code-move': 174 elif row[0] == 'code-move':
169 self.ProcessCodeMove(int(row[1], 16), int(row[2], 16)) 175 self.ProcessCodeMove(int(row[1], 16), int(row[2], 16))
170 elif row[0] == 'code-delete': 176 elif row[0] == 'code-delete':
171 self.ProcessCodeDelete(int(row[1], 16)) 177 self.ProcessCodeDelete(int(row[1], 16))
172 elif row[0] == 'shared-library': 178 elif row[0] == 'shared-library':
173 self.AddSharedLibraryEntry(row[1], int(row[2], 16), int(row[3], 16)) 179 self.AddSharedLibraryEntry(row[1], int(row[2], 16), int(row[3], 16))
174 self.ParseVMSymbols(row[1], int(row[2], 16), int(row[3], 16)) 180 self.ParseVMSymbols(row[1], int(row[2], 16), int(row[3], 16))
175 elif row[0] == 'begin-code-region': 181 elif row[0] == 'begin-code-region':
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 236
231 def ProcessEndCodeRegion(self, id, assm, end): 237 def ProcessEndCodeRegion(self, id, assm, end):
232 assm = self.pending_assemblers[assm] 238 assm = self.pending_assemblers[assm]
233 region = assm.pending_regions.pop(id) 239 region = assm.pending_regions.pop(id)
234 region.end_offset = end 240 region.end_offset = end
235 assm.regions.append(region) 241 assm.regions.append(region)
236 242
237 def IncludeTick(self, pc, sp, state): 243 def IncludeTick(self, pc, sp, state):
238 return (self.included_state is None) or (self.included_state == state) 244 return (self.included_state is None) or (self.included_state == state)
239 245
240 def ProcessTick(self, pc, sp, state): 246 def FindEntry(self, pc):
247 page = pc >> 12
248 if page in self.vm_extent:
249 entry = self.cpp_entries.FindGreatestsLessThan(pc)
250 if entry != None:
251 return entry.value
252 else:
253 return entry
254 max = self.js_entries.FindMax()
255 min = self.js_entries.FindMin()
256 if max != None and pc < max.key and pc > min.key:
257 return self.js_entries.FindGreatestsLessThan(pc).value
258 return None
259
260 def ProcessStack(self, stack):
261 result = []
262 for frame in stack:
263 if frame.startswith('0x'):
264 entry = self.FindEntry(int(frame, 16))
265 if entry != None:
266 result.append(entry.ToString())
267 return result
268
269 def ProcessTick(self, pc, sp, state, stack):
241 if not self.IncludeTick(pc, sp, state): 270 if not self.IncludeTick(pc, sp, state):
242 self.excluded_number_of_ticks += 1; 271 self.excluded_number_of_ticks += 1;
243 return 272 return
244 self.total_number_of_ticks += 1 273 self.total_number_of_ticks += 1
245 page = pc >> 12 274 entry = self.FindEntry(pc)
246 if page in self.vm_extent: 275 if entry == None:
247 entry = self.cpp_entries.FindGreatestsLessThan(pc).value 276 self.unaccounted_number_of_ticks += 1
248 if entry.IsSharedLibraryEntry():
249 self.number_of_library_ticks += 1
250 entry.Tick(None)
251 return 277 return
252 max = self.js_entries.FindMax() 278 if entry.IsSharedLibraryEntry():
253 min = self.js_entries.FindMin() 279 self.number_of_library_ticks += 1
254 if max != None and pc < max.key and pc > min.key: 280 entry.Tick(pc, self.ProcessStack(stack))
255 code_obj = self.js_entries.FindGreatestsLessThan(pc).value
256 code_obj.Tick(pc)
257 return
258 self.unaccounted_number_of_ticks += 1
259 281
260 def PrintResults(self): 282 def PrintResults(self):
261 print('Statistical profiling result from %s, (%d ticks, %d unaccounted, %d e xcluded).' % 283 print('Statistical profiling result from %s, (%d ticks, %d unaccounted, %d e xcluded).' %
262 (self.log_file, 284 (self.log_file,
263 self.total_number_of_ticks, 285 self.total_number_of_ticks,
264 self.unaccounted_number_of_ticks, 286 self.unaccounted_number_of_ticks,
265 self.excluded_number_of_ticks)) 287 self.excluded_number_of_ticks))
266 if self.total_number_of_ticks > 0: 288 if self.total_number_of_ticks > 0:
267 js_entries = self.js_entries.ExportValueList() 289 js_entries = self.js_entries.ExportValueList()
268 js_entries.extend(self.deleted_code) 290 js_entries.extend(self.deleted_code)
269 cpp_entries = self.cpp_entries.ExportValueList() 291 cpp_entries = self.cpp_entries.ExportValueList()
270 # Print the library ticks. 292 # Print the library ticks.
271 self.PrintHeader('Shared libraries') 293 self.PrintHeader('Shared libraries')
272 self.PrintEntries(cpp_entries, lambda e:e.IsSharedLibraryEntry()) 294 self.PrintEntries(cpp_entries, lambda e:e.IsSharedLibraryEntry())
273 # Print the JavaScript ticks. 295 # Print the JavaScript ticks.
274 self.PrintHeader('JavaScript') 296 self.PrintHeader('JavaScript')
275 self.PrintEntries(js_entries, lambda e:not e.IsSharedLibraryEntry()) 297 self.PrintEntries(js_entries, lambda e:not e.IsSharedLibraryEntry())
276 # Print the C++ ticks. 298 # Print the C++ ticks.
277 self.PrintHeader('C++') 299 self.PrintHeader('C++')
278 self.PrintEntries(cpp_entries, lambda e:not e.IsSharedLibraryEntry()) 300 self.PrintEntries(cpp_entries, lambda e:not e.IsSharedLibraryEntry())
301 # Print call profile.
302 print('\n [Call profile]:')
303 print(' total call path')
304 js_entries.extend(cpp_entries)
305 self.PrintCallProfile(js_entries)
279 306
280 def PrintHeader(self, header_title): 307 def PrintHeader(self, header_title):
281 print('\n [%s]:' % header_title) 308 print('\n [%s]:' % header_title)
282 print(' total nonlib name') 309 print(' total nonlib name')
283 310
284 def PrintEntries(self, entries, condition): 311 def PrintEntries(self, entries, condition):
285 number_of_accounted_ticks = self.total_number_of_ticks - self.unaccounted_nu mber_of_ticks 312 number_of_accounted_ticks = self.total_number_of_ticks - self.unaccounted_nu mber_of_ticks
286 number_of_non_library_ticks = number_of_accounted_ticks - self.number_of_lib rary_ticks 313 number_of_non_library_ticks = number_of_accounted_ticks - self.number_of_lib rary_ticks
287 entries.sort(key=lambda e:e.tick_count, reverse=True) 314 entries.sort(key=lambda e:e.tick_count, reverse=True)
288 for entry in entries: 315 for entry in entries:
(...skipping 13 matching lines...) Expand all
302 items = region_ticks.items() 329 items = region_ticks.items()
303 items.sort(key=lambda e: e[1][1], reverse=True) 330 items.sort(key=lambda e: e[1][1], reverse=True)
304 for (name, ticks) in items: 331 for (name, ticks) in items:
305 print(' flat cum') 332 print(' flat cum')
306 print(' %(flat)5.1f%% %(accum)5.1f%% %(name)s' % { 333 print(' %(flat)5.1f%% %(accum)5.1f%% %(name)s' % {
307 'flat' : ticks[1] * 100.0 / entry.tick_count, 334 'flat' : ticks[1] * 100.0 / entry.tick_count,
308 'accum' : ticks[0] * 100.0 / entry.tick_count, 335 'accum' : ticks[0] * 100.0 / entry.tick_count,
309 'name': name 336 'name': name
310 }) 337 })
311 338
339 def PrintCallProfile(self, entries):
340 all_stacks = {}
341 total_stacks = 0
342 for entry in entries:
343 all_stacks.update(entry.stacks)
344 for count in entry.stacks.itervalues():
345 total_stacks += count
346 all_stacks_items = all_stacks.items();
347 all_stacks_items.sort(key = itemgetter(1), reverse=True)
348 for stack, count in all_stacks_items:
349 total_percentage = count * 100.0 / total_stacks
350 print(' %(total)5.1f%% %(call_path)s' % {
351 'total' : total_percentage,
352 'call_path' : stack[0] + ' <- ' + stack[1]
353 })
354
312 if __name__ == '__main__': 355 if __name__ == '__main__':
313 sys.exit('You probably want to run windows-tick-processor.py or linux-tick-pro cessor.py.') 356 sys.exit('You probably want to run windows-tick-processor.py or linux-tick-pro cessor.py.')
OLDNEW
« no previous file with comments | « src/platform-win32.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698