1#!/bin/env python3 2# 3# Copyright © 2022 Intel Corporation 4# 5# SPDX-License-Identifier: Apache-2.0 6# 7 8from colorsys import hsv_to_rgb 9from random import random 10import xml 11import json 12from sys import argv, stderr 13import xml.etree.ElementTree as ET 14 15width = 1000 16height = 200 17padding = 10 18 19if len(argv) < 3: 20 stderr.write("./ch-trace-visualiser <trace file> <output file>\n") 21 exit(1) 22 23 24def nano_time(duration): 25 return (duration["secs"] * 10 ** 9) + duration["nanos"] 26 27 28def duration_to_px_x(start): 29 return (nano_time(start) * (width - 2 * padding)) / total_time 30 31 32def duration_to_px_width(start, end): 33 return ((nano_time(end) - nano_time(start)) * (width - 2 * padding)) / total_time 34 35 36def duration_ms(start, end): 37 return (nano_time(end) - nano_time(start)) // 1000000 38 39 40f = open(argv[1]) 41report = json.load(f) 42total_time = nano_time(report["duration"]) 43 44svg = ET.Element("svg", attrib={"width": str(width), "height": str(height), 45 "xmlns": "http://www.w3.org/2000/svg", 46 "xmlns:svg": "http://www.w3.org/2000/svg" 47 }) 48 49 50def add_traced_block(thread_group, depth, traced_block): 51 g = ET.SubElement(thread_group, "g", 52 attrib={"transform": "translate(%d,%d)" % ( 53 duration_to_px_x(traced_block["timestamp"]), 54 (depth * 18))}) 55 width = str(duration_to_px_width( 56 traced_block["timestamp"], traced_block["end_timestamp"])) 57 58 clip = ET.SubElement(g, "clipPath", attrib={ 59 "id": "clip_%s" % (traced_block["event"]), 60 }) 61 ET.SubElement(clip, "rect", attrib={ 62 "width": width, 63 "height": "1.5em", 64 "x": "0", 65 "y": "0" 66 }) 67 68 (red, green, blue) = hsv_to_rgb(random(), 0.3, 0.75) 69 ET.SubElement(g, "rect", attrib={ 70 "width": width, 71 "height": "1.5em", 72 "fill": "#%x%x%x" % (int(red * 255), int(green * 255), int(blue * 255)) 73 }) 74 text = ET.SubElement(g, "text", attrib={ 75 "x": "0.2em", "y": "1em", "clip-path": "url(#clip_%s)" % (traced_block["event"])}) 76 text.text = "%s (%dms)" % (traced_block["event"], duration_ms( 77 traced_block["timestamp"], traced_block["end_timestamp"])) 78 79 80thread_size = (height - (2 * padding)) / len(report["events"]) 81thread_offset = padding 82 83for thread in report["events"]: 84 thread_events = report["events"][thread] 85 thread_events = sorted( 86 thread_events, key=lambda traced_block: nano_time(traced_block["timestamp"])) 87 thread_group = ET.SubElement( 88 svg, "g", attrib={"transform": "translate(%d,%d)" % (padding, thread_offset)}) 89 thread_text = ET.SubElement(thread_group, "text", attrib={ 90 "y": "1em"}).text = "Thread: %s" % (thread) 91 thread_children = ET.SubElement(thread_group, "g", attrib={ 92 "transform": "translate(0, 18)"}) 93 for traced_block in thread_events: 94 add_traced_block(thread_children, traced_block["depth"], traced_block) 95 thread_offset += thread_size + padding 96 97xml = ET.ElementTree(element=svg) 98xml.write(argv[2], xml_declaration=True) 99