| Index: tools/tickprocessor.py
|
| diff --git a/tools/tickprocessor.py b/tools/tickprocessor.py
|
| index 7de022f1dde6f78b71e21ee56bf73bc943f1875b..cc5137143572caffa42184359c9b508bae5fbda1 100644
|
| --- a/tools/tickprocessor.py
|
| +++ b/tools/tickprocessor.py
|
| @@ -26,6 +26,7 @@
|
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
| import csv, splaytree, sys
|
| +from operator import itemgetter
|
|
|
|
|
| class CodeEntry(object):
|
| @@ -34,9 +35,14 @@ class CodeEntry(object):
|
| self.start_addr = start_addr
|
| self.tick_count = 0
|
| self.name = name
|
| + self.stacks = {}
|
|
|
| - def Tick(self, pc):
|
| + def Tick(self, pc, stack):
|
| self.tick_count += 1
|
| + if len(stack) > 0:
|
| + stack.insert(0, self.ToString())
|
| + stack_key = tuple(stack)
|
| + self.stacks[stack_key] = self.stacks.setdefault(stack_key, 0) + 1
|
|
|
| def RegionTicks(self):
|
| return None
|
| @@ -69,8 +75,8 @@ class JSCodeEntry(CodeEntry):
|
| self.assembler = assembler
|
| self.region_ticks = None
|
|
|
| - def Tick(self, pc):
|
| - super(JSCodeEntry, self).Tick(pc)
|
| + def Tick(self, pc, stack):
|
| + super(JSCodeEntry, self).Tick(pc, stack)
|
| if not pc is None:
|
| offset = pc - self.start_addr
|
| seen = []
|
| @@ -162,7 +168,7 @@ class TickProcessor(object):
|
| logreader = csv.reader(logfile)
|
| for row in logreader:
|
| if row[0] == 'tick':
|
| - self.ProcessTick(int(row[1], 16), int(row[2], 16), int(row[3]))
|
| + self.ProcessTick(int(row[1], 16), int(row[2], 16), int(row[3]), row[4:])
|
| elif row[0] == 'code-creation':
|
| self.ProcessCodeCreation(row[1], int(row[2], 16), int(row[3]), row[4])
|
| elif row[0] == 'code-move':
|
| @@ -237,25 +243,41 @@ class TickProcessor(object):
|
| def IncludeTick(self, pc, sp, state):
|
| return (self.included_state is None) or (self.included_state == state)
|
|
|
| - def ProcessTick(self, pc, sp, state):
|
| - if not self.IncludeTick(pc, sp, state):
|
| - self.excluded_number_of_ticks += 1;
|
| - return
|
| - self.total_number_of_ticks += 1
|
| + def FindEntry(self, pc):
|
| page = pc >> 12
|
| if page in self.vm_extent:
|
| - entry = self.cpp_entries.FindGreatestsLessThan(pc).value
|
| - if entry.IsSharedLibraryEntry():
|
| - self.number_of_library_ticks += 1
|
| - entry.Tick(None)
|
| - return
|
| + entry = self.cpp_entries.FindGreatestsLessThan(pc)
|
| + if entry != None:
|
| + return entry.value
|
| + else:
|
| + return entry
|
| max = self.js_entries.FindMax()
|
| min = self.js_entries.FindMin()
|
| if max != None and pc < max.key and pc > min.key:
|
| - code_obj = self.js_entries.FindGreatestsLessThan(pc).value
|
| - code_obj.Tick(pc)
|
| + return self.js_entries.FindGreatestsLessThan(pc).value
|
| + return None
|
| +
|
| + def ProcessStack(self, stack):
|
| + result = []
|
| + for frame in stack:
|
| + if frame.startswith('0x'):
|
| + entry = self.FindEntry(int(frame, 16))
|
| + if entry != None:
|
| + result.append(entry.ToString())
|
| + return result
|
| +
|
| + def ProcessTick(self, pc, sp, state, stack):
|
| + if not self.IncludeTick(pc, sp, state):
|
| + self.excluded_number_of_ticks += 1;
|
| return
|
| - self.unaccounted_number_of_ticks += 1
|
| + self.total_number_of_ticks += 1
|
| + entry = self.FindEntry(pc)
|
| + if entry == None:
|
| + self.unaccounted_number_of_ticks += 1
|
| + return
|
| + if entry.IsSharedLibraryEntry():
|
| + self.number_of_library_ticks += 1
|
| + entry.Tick(pc, self.ProcessStack(stack))
|
|
|
| def PrintResults(self):
|
| print('Statistical profiling result from %s, (%d ticks, %d unaccounted, %d excluded).' %
|
| @@ -276,6 +298,11 @@ class TickProcessor(object):
|
| # Print the C++ ticks.
|
| self.PrintHeader('C++')
|
| self.PrintEntries(cpp_entries, lambda e:not e.IsSharedLibraryEntry())
|
| + # Print call profile.
|
| + print('\n [Call profile]:')
|
| + print(' total call path')
|
| + js_entries.extend(cpp_entries)
|
| + self.PrintCallProfile(js_entries)
|
|
|
| def PrintHeader(self, header_title):
|
| print('\n [%s]:' % header_title)
|
| @@ -309,5 +336,21 @@ class TickProcessor(object):
|
| 'name': name
|
| })
|
|
|
| + def PrintCallProfile(self, entries):
|
| + all_stacks = {}
|
| + total_stacks = 0
|
| + for entry in entries:
|
| + all_stacks.update(entry.stacks)
|
| + for count in entry.stacks.itervalues():
|
| + total_stacks += count
|
| + all_stacks_items = all_stacks.items();
|
| + all_stacks_items.sort(key = itemgetter(1), reverse=True)
|
| + for stack, count in all_stacks_items:
|
| + total_percentage = count * 100.0 / total_stacks
|
| + print(' %(total)5.1f%% %(call_path)s' % {
|
| + 'total' : total_percentage,
|
| + 'call_path' : stack[0] + ' <- ' + stack[1]
|
| + })
|
| +
|
| if __name__ == '__main__':
|
| sys.exit('You probably want to run windows-tick-processor.py or linux-tick-processor.py.')
|
|
|