Index: tools/tickprocessor.py |
diff --git a/tools/tickprocessor.py b/tools/tickprocessor.py |
index d5bca06db5f98f5a840a408fc2e6c7d8b83bd423..95e6e50f9ceaed8af6d10455fc59eba67983bdf9 100644 |
--- a/tools/tickprocessor.py |
+++ b/tools/tickprocessor.py |
@@ -147,6 +147,27 @@ class Assembler(object): |
self.regions = [] |
+class FunctionEnumerator(object): |
+ |
+ def __init__(self): |
+ self.known_funcs = {} |
+ self.next_func_id = 0 |
+ |
+ def GetFunctionId(self, name): |
+ if not self.known_funcs.has_key(name): |
+ self.known_funcs[name] = self.next_func_id |
+ self.next_func_id += 1 |
+ return self.known_funcs[name] |
+ |
+ def GetKnownFunctions(self): |
+ known_funcs_items = self.known_funcs.items(); |
+ known_funcs_items.sort(key = itemgetter(1)) |
+ result = [] |
+ for func, id_not_used in known_funcs_items: |
+ result.append(func) |
+ return result |
+ |
+ |
VMStates = { 'JS': 0, 'GC': 1, 'COMPILER': 2, 'OTHER': 3, 'EXTERNAL' : 4 } |
@@ -170,37 +191,46 @@ class TickProcessor(object): |
self.number_of_gc_ticks = 0 |
# Flag indicating whether to ignore unaccounted ticks in the report |
self.ignore_unknown = False |
+ self.func_enum = FunctionEnumerator() |
+ self.packed_stacks = [] |
- def ProcessLogfile(self, filename, included_state = None, ignore_unknown = False, separate_ic = False): |
+ def ProcessLogfile(self, filename, included_state = None, ignore_unknown = False, separate_ic = False, call_graph_json = False): |
self.log_file = filename |
self.included_state = included_state |
self.ignore_unknown = ignore_unknown |
self.separate_ic = separate_ic |
+ self.call_graph_json = call_graph_json |
try: |
logfile = open(filename, 'rb') |
except IOError: |
sys.exit("Could not open logfile: " + filename) |
try: |
- 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.PreprocessStack(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': |
- self.ProcessCodeMove(int(row[1], 16), int(row[2], 16)) |
- elif row[0] == 'code-delete': |
- self.ProcessCodeDelete(int(row[1], 16)) |
- elif row[0] == 'shared-library': |
- self.AddSharedLibraryEntry(row[1], int(row[2], 16), int(row[3], 16)) |
- self.ParseVMSymbols(row[1], int(row[2], 16), int(row[3], 16)) |
- elif row[0] == 'begin-code-region': |
- self.ProcessBeginCodeRegion(int(row[1], 16), int(row[2], 16), int(row[3], 16), row[4]) |
- elif row[0] == 'end-code-region': |
- self.ProcessEndCodeRegion(int(row[1], 16), int(row[2], 16), int(row[3], 16)) |
- elif row[0] == 'code-allocate': |
- self.ProcessCodeAllocate(int(row[1], 16), int(row[2], 16)) |
+ try: |
+ logreader = csv.reader(logfile) |
+ row_num = 1 |
+ for row in logreader: |
+ row_num += 1 |
+ if row[0] == 'tick': |
+ self.ProcessTick(int(row[1], 16), int(row[2], 16), int(row[3]), self.PreprocessStack(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': |
+ self.ProcessCodeMove(int(row[1], 16), int(row[2], 16)) |
+ elif row[0] == 'code-delete': |
+ self.ProcessCodeDelete(int(row[1], 16)) |
+ elif row[0] == 'shared-library': |
+ self.AddSharedLibraryEntry(row[1], int(row[2], 16), int(row[3], 16)) |
+ self.ParseVMSymbols(row[1], int(row[2], 16), int(row[3], 16)) |
+ elif row[0] == 'begin-code-region': |
+ self.ProcessBeginCodeRegion(int(row[1], 16), int(row[2], 16), int(row[3], 16), row[4]) |
+ elif row[0] == 'end-code-region': |
+ self.ProcessEndCodeRegion(int(row[1], 16), int(row[2], 16), int(row[3], 16)) |
+ elif row[0] == 'code-allocate': |
+ self.ProcessCodeAllocate(int(row[1], 16), int(row[2], 16)) |
+ except csv.Error: |
+ print("parse error in line " + str(row_num)) |
+ raise |
finally: |
logfile.close() |
@@ -312,8 +342,25 @@ class TickProcessor(object): |
self.unaccounted_number_of_ticks += 1 |
else: |
entry.Tick(pc, self.ProcessStack(stack)) |
+ if self.call_graph_json: |
+ self.AddToPackedStacks(pc, stack) |
+ |
+ def AddToPackedStacks(self, pc, stack): |
+ full_stack = stack |
+ full_stack.insert(0, pc) |
+ func_names = self.ProcessStack(full_stack) |
+ func_ids = [] |
+ for func in func_names: |
+ func_ids.append(self.func_enum.GetFunctionId(func)) |
+ self.packed_stacks.append(func_ids) |
def PrintResults(self): |
+ if not self.call_graph_json: |
+ self.PrintStatistics() |
+ else: |
+ self.PrintCallGraphJSON() |
+ |
+ def PrintStatistics(self): |
print('Statistical profiling result from %s, (%d ticks, %d unaccounted, %d excluded).' % |
(self.log_file, |
self.total_number_of_ticks, |
@@ -412,6 +459,16 @@ class TickProcessor(object): |
'call_path' : stack[0] + ' <- ' + stack[1] |
}) |
+ def PrintCallGraphJSON(self): |
+ print('\nvar __profile_funcs = ["' + |
+ '",\n"'.join(self.func_enum.GetKnownFunctions()) + |
+ '"];') |
+ print('var __profile_ticks = [') |
+ str_packed_stacks = [] |
+ for stack in self.packed_stacks: |
+ str_packed_stacks.append('[' + ','.join(map(str, stack)) + ']') |
+ print(',\n'.join(str_packed_stacks)) |
+ print('];') |
class CmdLineProcessor(object): |
@@ -422,12 +479,14 @@ class CmdLineProcessor(object): |
"other", |
"external", |
"ignore-unknown", |
- "separate-ic"] |
+ "separate-ic", |
+ "call-graph-json"] |
# default values |
self.state = None |
self.ignore_unknown = False |
self.log_file = None |
self.separate_ic = False |
+ self.call_graph_json = False |
def ProcessArguments(self): |
try: |
@@ -449,6 +508,8 @@ class CmdLineProcessor(object): |
self.ignore_unknown = True |
if key in ("--separate-ic"): |
self.separate_ic = True |
+ if key in ("--call-graph-json"): |
+ self.call_graph_json = True |
self.ProcessRequiredArgs(args) |
def ProcessRequiredArgs(self, args): |
@@ -466,7 +527,8 @@ class CmdLineProcessor(object): |
sys.exit(2) |
def RunLogfileProcessing(self, tick_processor): |
- tick_processor.ProcessLogfile(self.log_file, self.state, self.ignore_unknown, self.separate_ic) |
+ tick_processor.ProcessLogfile(self.log_file, self.state, self.ignore_unknown, |
+ self.separate_ic, self.call_graph_json) |
if __name__ == '__main__': |