def finish(self): GraphCombiner.finish(self) cluster_index = 0 clusters = {} for domain, data in self.per_domain.items(): cluster = clusters.setdefault(cluster_index, []) cluster.append('subgraph cluster_%d {\nlabel = "%s";' % (cluster_index, domain)) # counters for counter_name, counter_data in data['counters'].items(): id = self.make_id(domain, counter_name) self._write( '%s [label="{COUNTER: %s|min=%s|max=%s|avg=%s}"];\n' % (id, html.escape(counter_name), format_time( min(counter_data)), format_time(max(counter_data)), format_time(sum(counter_data) / len(counter_data)))) cluster.append("%s;" % (id)) # tasks for task_name, task_data in data['tasks'].items(): id = self.make_id(domain, task_name) time = task_data['time'] self._write( '%s [label="{TASK: %s|min=%s|max=%s|avg=%s|count=%d%s}"];\n' % (id, html.escape(task_name), format_time( min(time)), format_time(max(time)), format_time(sum(time) / len(time)), len(time), (("|%s" % task_data['src'].replace('\\', '/')) if 'src' in task_data else ""))) cluster.append("%s;" % id) #: {}, 'objects':{}, 'frames': {}, 'markers': {} cluster_index += 1 # threads thread_names = self.tree['threads'] for tid in self.threads: tid_str, tid_hex = str(tid), (to_hex(tid) if tid is not None else "None") id = self.make_id("threads", tid_str) thread_name = thread_names[ tid_str] if tid_str in thread_names else "" self._write( '%s [label="{THREAD: %s|%s}" color=gray fontcolor=gray];\n' % (id, tid_hex, html.escape(thread_name))) # clusters for _, cluster in clusters.items(): for line in cluster: self._write(line + "\n") self._write("}\n") # relations for relation in self.relations.values(): if 'color' not in relation: relation['color'] = 'black' self._write( 'edge [label="{label}" color={color} fontcolor={color}];\n{from}->{to};\n' .format(**relation)) self._write("}\n") self.file.close()
def complete_task(self, type, begin, end): if 'tid' not in begin: return start_time = round(begin['time'] / 1000) # sad but it's limiter to milliseconds only end_time = round(end['time'] / 1000) dur = end_time - start_time if dur < self.args.min_dur: return name = get_name(begin) details = (type + ":") if type != 'task' else "" if begin.has_key('parent'): details += to_hex(begin['parent']) + "->" details += name if type == 'counter' or type == 'marker': kind = 'Painting' elif type == 'frame' or 'object_' in type: kind = 'Creating' else: kind = 'Javascript' record = (begin['__file__'].replace("\\", "/") if begin.has_key('__file__') else "", begin['__line__'] if begin.has_key('__line__') else "0", kind, "%s | %s" % (details, begin['domain']), name) record = tuple([cgi.escape(item) for item in record]) if self.event_map.has_key(record): index = self.event_map[record] else: index = len(self.events) self.events.append(record) self.event_map[record] = index tag = '<range startTime="%d" duration="%d" eventIndex="%d"/>\n' % ( start_time, dur, index) args = {} if type == "counter": if 'delta' in begin: args['value'] = begin['delta'] else: # TODO: add multi-value support return if begin.has_key('args'): args = begin['args'] if end.has_key('args'): args.update(end['args']) if args: self.notes.append((start_time, dur, index, args)) self.set_times(start_time, end_time) self.file.write(tag)
def complete_task(self, type, begin, end): if 'tid' not in begin: return start_time = round(begin['time'] / 1000) # sad but it's limiter to milliseconds only end_time = round(end['time'] / 1000) dur = end_time - start_time if dur < self.args.min_dur: return name = get_name(begin) details = (type + ":") if type != 'task' else "" if begin.has_key('parent'): details += to_hex(begin['parent']) + "->" details += name if type == 'counter' or type == 'marker': kind = 'Painting' elif type == 'frame' or 'object_' in type: kind = 'Creating' else: kind = 'Javascript' record = ( begin['__file__'].replace("\\", "/") if begin.has_key('__file__') else "", begin['__line__'] if begin.has_key('__line__') else "0", kind, "%s | %s" % (details, begin['domain']), name ) record = tuple([cgi.escape(item) for item in record]) if self.event_map.has_key(record): index = self.event_map[record] else: index = len(self.events) self.events.append(record) self.event_map[record] = index tag = '<range startTime="%d" duration="%d" eventIndex="%d"/>\n' % (start_time, dur, index) args = {} if type == "counter": args['value'] = begin['delta'] if begin.has_key('args'): args = begin['args'] if end.has_key('args'): args.update(end['args']) if args: self.notes.append((start_time, dur, index, args)) self.set_times(start_time, end_time) self.file.write(tag)
def finish(self): self.file.write('<Nodes>\n') for domain, data in self.per_domain.iteritems(): # counters for counter_name, counter_data in data['counters'].iteritems(): id = self.make_id(domain, counter_name) self.file.write('<Node Id="%s" Label="%s" Min="%g" Max="%g" Avg="%g" Category="CodeSchema_Type"/>\n' % (id, cgi.escape(counter_name), min(counter_data), max(counter_data), sum(counter_data) / len(counter_data))) # tasks for task_name, task_data in data['tasks'].iteritems(): id = self.make_id(domain, task_name) time = task_data['time'] self.file.write('<Node Id="%s" Category="CodeSchema_Method" Label="%s" Min="%s" Max="%s" Avg="%s" Count="%d" Src="%s"/>\n' % ( id, cgi.escape(task_name), format_time(min(time)), format_time(max(time)), format_time(sum(time) / len(time)), len(time), task_data['src'].replace('\\', '/') if task_data.has_key('src') else "" ) ) self.file.write('<Node Id="%s" Label="%s" Category="CodeSchema_Namespace" Group="Expanded"/>\n' % (self.make_id("domain", domain), cgi.escape(domain))) # threads thread_names = self.tree['threads'] for tid in self.threads: tid_str, tid_hex = str(tid), (to_hex(tid) if tid is not None else "None") id = self.make_id("threads", tid_str) thread_name = thread_names[tid_str] if thread_names.has_key(tid_str) else "" self.file.write('<Node Id="%s" Label="%s(%s)"/>\n' % (id, cgi.escape(thread_name), tid_hex)) self.file.write('</Nodes>\n') self.file.write('<Links>\n') # relations for relation in self.relations.itervalues(): if not relation.has_key('color'): relation['color'] = 'black' self.file.write('<Link Source="{from}" Target="{to}" Category="CodeSchema_Calls"/>\n'.format(**relation)) for domain, data in self.per_domain.iteritems(): # counters for counter_name, counter_data in data['counters'].iteritems(): self.file.write('<Link Source="%s" Target="%s" Category="Contains"/>\n' % (self.make_id("domain", domain), self.make_id(domain, counter_name))) # tasks for task_name, task_data in data['tasks'].iteritems(): self.file.write('<Link Source="%s" Target="%s" Category="Contains"/>\n' % (self.make_id("domain", domain), self.make_id(domain, task_name))) self.file.write('</Links>\n') self.file.write("</DirectedGraph>\n") self.file.close()
def finish(self): self.file.write('<Nodes>\n') for domain, data in self.per_domain.iteritems(): # counters for counter_name, counter_data in data['counters'].iteritems(): id = self.make_id(domain, counter_name) self.file.write('<Node Id="%s" Label="%s" Min="%g" Max="%g" Avg="%g" Category="CodeSchema_Type"/>\n' % (id, cgi.escape(counter_name), min(counter_data), max(counter_data), sum(counter_data) / len(counter_data))) # tasks for task_name, task_data in data['tasks'].iteritems(): id = self.make_id(domain, task_name) time = task_data['time'] self.file.write('<Node Id="%s" Category="CodeSchema_Method" Label="%s" Min="%s" Max="%s" Avg="%s" Count="%d" Src="%s"/>\n' % ( id, cgi.escape(task_name), format_time(min(time)), format_time(max(time)), format_time(sum(time) / len(time)), len(time), task_data['src'].replace('\\', '/') if task_data.has_key('src') else "" ) ) self.file.write('<Node Id="%s" Label="%s" Category="CodeSchema_Namespace" Group="Expanded"/>\n' % (self.make_id("domain", domain), cgi.escape(domain))) # threads thread_names = self.tree['threads'] for tid in self.threads: tid_str, tid_hex = str(tid), to_hex(tid) id = self.make_id("threads", tid_str) thread_name = thread_names[tid_str] if thread_names.has_key(tid_str) else "" self.file.write('<Node Id="%s" Label="%s(%s)"/>\n' % (id, cgi.escape(thread_name), tid_hex)) self.file.write('</Nodes>\n') self.file.write('<Links>\n') # relations for relation in self.relations.itervalues(): if not relation.has_key('color'): relation['color'] = 'black' self.file.write('<Link Source="{from}" Target="{to}" Category="CodeSchema_Calls"/>\n'.format(**relation)) for domain, data in self.per_domain.iteritems(): # counters for counter_name, counter_data in data['counters'].iteritems(): self.file.write('<Link Source="%s" Target="%s" Category="Contains"/>\n' % (self.make_id("domain", domain), self.make_id(domain, counter_name))) # tasks for task_name, task_data in data['tasks'].iteritems(): self.file.write('<Link Source="%s" Target="%s" Category="Contains"/>\n' % (self.make_id("domain", domain), self.make_id(domain, task_name))) self.file.write('</Links>\n') self.file.write("</DirectedGraph>\n") self.file.close()
def finish(self): cluster_index = 0 clusters = {} for domain, data in self.per_domain.iteritems(): cluster = clusters.setdefault(cluster_index, []) cluster.append('subgraph cluster_%d {\nlabel = "%s";' % (cluster_index, domain)) # counters for counter_name, counter_data in data['counters'].iteritems(): id = self.make_id(domain, counter_name) self.file.write('%s [label="{COUNTER: %s|min=%g|max=%g|avg=%g}"];\n' % (id, cgi.escape(counter_name), min(counter_data), max(counter_data), sum(counter_data) / len(counter_data))) cluster.append("%s;" % (id)) # tasks for task_name, task_data in data['tasks'].iteritems(): id = self.make_id(domain, task_name) time = task_data['time'] self.file.write( '%s [label="{TASK: %s|min=%s|max=%s|avg=%s|count=%d%s}"];\n' % ( id, cgi.escape(task_name), format_time(min(time)), format_time(max(time)), format_time(sum(time) / len(time)), len(time), (("|%s" % task_data['src'].replace('\\', '/')) if task_data.has_key('src') else "") ) ) cluster.append("%s;" % id) #: {}, 'objects':{}, 'frames': {}, 'markers': {} cluster_index += 1 # threads thread_names = self.tree['threads'] for tid in self.threads: tid_str, tid_hex = str(tid), (to_hex(tid) if tid is not None else "None") id = self.make_id("threads", tid_str) thread_name = thread_names[tid_str] if thread_names.has_key(tid_str) else "" self.file.write('%s [label="{THREAD: %s|%s}" color=gray fontcolor=gray];\n' % (id, tid_hex, cgi.escape(thread_name))) # clusters for _, cluster in clusters.iteritems(): for line in cluster: self.file.write(line + "\n") self.file.write("}\n") # relations for relation in self.relations.itervalues(): if not relation.has_key('color'): relation['color'] = 'black' self.file.write('edge [label="{label}" color={color} fontcolor={color}];\n{from}->{to};\n'.format(**relation)) self.file.write("}\n") self.file.close()
def format_task(self, phase, type, begin, end): res = [] res.append('{"ph":"%s"' % phase) res.append(', "pid":%(pid)d' % begin) if begin.has_key('tid'): res.append(', "tid":%(tid)d' % begin) if GT_FLOAT_TIME: res.append(', "ts":%.3f' % (self.convert_time(begin['time']))) else: res.append(', "ts":%d' % (self.convert_time(begin['time']))) if "counter" == type: # workaround of chrome issue with forgetting the last counter value self.counters.setdefault(begin['domain'], {})[begin['str']] = begin # remember the last counter value if "marker" == type: name = begin['str'] res.append(', "s":"%s"' % (GoogleTrace.Markers[begin['data']])) elif "object_" in type: if 'str' in begin: name = begin['str'] else: name = "" elif "frame" == type: if 'str' in begin: name = begin['str'] else: name = begin['domain'] else: if type not in ["counter", "task", "overlapped"]: name = type + ":" else: name = "" if 'parent' in begin: name += to_hex(begin['parent']) + "->" if 'str' in begin: name += begin['str'] + ":" if 'pointer' in begin: name += "func<" + to_hex(begin['pointer']) + ">:" else: name = name.rstrip(":") assert (name or "object_" in type) res.append(', "name":"%s"' % name) res.append(', "cat":"%s"' % (begin['domain'])) if 'id' in begin: res.append(', "id":"%s"' % str(begin['id'])) if type in ['task']: dur = self.convert_time(end['time']) - self.convert_time(begin['time']) if dur < self.args.min_dur: return [] if GT_FLOAT_TIME: res.append(', "dur":%.3f' % dur) else: res.append(', "dur":%d' % dur) args = {} if 'args' in begin: args = begin['args'].copy() if 'args' in end: args.update(end['args']) if '__file__' in begin: args["__file__"] = begin["__file__"] args["__line__"] = begin["__line__"] if 'counter' == type: if 'delta' in begin: # multi-counter is passed as named sub-counters dict args[name] = begin['delta'] if 'memory' in begin: total = 0 breakdown = {} children = 0 for size, values in begin['memory'].iteritems(): if size is None: # special case for children attribution children = values else: all = sum(values) total += size * all if all: breakdown[size] = all breakdown['TOTAL'] = total breakdown['CHILDREN'] = children args['CRT:Memory(size,count)'] = breakdown if args: res.append(', "args":') res.append(self.format_value(args)) res.append('}') return res
def format_task(self, phase, type, begin, end): res = [] res.append('{"ph":"%s"' % (phase)) res.append(', "pid":%(pid)d' % begin) if begin.has_key('tid'): res.append(', "tid":%(tid)d' % begin) if GT_FLOAT_TIME: res.append(', "ts":%.3f' % (self.convert_time(begin['time']))) else: res.append(', "ts":%d' % (self.convert_time(begin['time']))) if "counter" == type: # workaround of chrome issue with forgetting the last counter value self.counters.setdefault(begin['domain'], {})[begin['str']] = begin # remember the last counter value if "marker" == type: name = begin['str'] res.append(', "s":"%s"' % (GoogleTrace.Markers[begin['data']])) elif "object_" in type: if begin.has_key('str'): name = begin['str'] else: name = "" elif "frame" == type: if begin.has_key('str'): name = begin['str'] else: name = begin['domain'] else: if type not in ["counter", "task", "overlapped"]: name = type + ":" else: name = "" if begin.has_key('parent'): name += to_hex(begin['parent']) + "->" if begin.has_key('str'): name += begin['str'] + ":" if begin.has_key('pointer'): name += "func<" + to_hex(begin['pointer']) + ">:" if begin.has_key('id') and type != "overlapped": name += "(" + to_hex(begin['id']) + ")" else: name = name.rstrip(":") assert (name or "object_" in type) res.append(', "name":"%s"' % (name)) res.append(', "cat":"%s"' % (begin['domain'])) if begin.has_key('id'): res.append(', "id":%s' % (begin['id'])) if type in ['task']: dur = self.convert_time(end['time']) - self.convert_time(begin['time']) if GT_FLOAT_TIME: res.append(', "dur":%.3f' % (dur)) else: if dur < self.args.min_dur: return [] # google misbehaves on tasks of 0 length res.append(', "dur":%d' % (dur)) args = {} if begin.has_key('args'): args = begin['args'].copy() if end.has_key('args'): args.update(end['args']) if begin.has_key('__file__'): args["__file__"] = begin["__file__"] args["__line__"] = begin["__line__"] if 'counter' == type: args[name] = begin['delta'] if begin.has_key('memory'): total = 0 breakdown = {} children = 0 for size, values in begin['memory'].iteritems(): if size is None: # special case for children attribution children = values else: all = sum(values) total += size * all if all: breakdown[size] = all breakdown['TOTAL'] = total breakdown['CHILDREN'] = children args['CRT:Memory(size,count)'] = breakdown if args: res.append(', "args":') res.append(self.format_value(args)) res.append('}'); return res