1#!/usr/bin/env python3 2 3# Copyright Hans Dembinski 2018 - 2019. 4# Distributed under the Boost Software License, Version 1.0. 5# (See accompanying file LICENSE_1_0.txt or copy at 6# https://www.boost.org/LICENSE_1_0.txt) 7 8import os 9import numpy as np 10import glob 11import re 12import json 13import sys 14from collections import defaultdict, OrderedDict 15from matplotlib.patches import Rectangle 16from matplotlib.lines import Line2D 17from matplotlib.text import Text 18from matplotlib.font_manager import FontProperties 19import matplotlib.pyplot as plt 20import matplotlib as mpl 21 22mpl.rcParams.update(mpl.rcParamsDefault) 23 24cpu_frequency = 0 25 26data = defaultdict(lambda: []) 27hostname = None 28for fn in sys.argv[1:]: 29 d = json.load(open(fn)) 30 cpu_frequency = d["context"]["mhz_per_cpu"] 31 # make sure we don't compare benchmarks from different computers 32 if hostname is None: 33 hostname = d["context"]["host_name"] 34 else: 35 assert hostname == d["context"]["host_name"] 36 for bench in d["benchmarks"]: 37 name = bench["name"] 38 time = min(bench["cpu_time"], bench["real_time"]) 39 m = re.match("fill_(n_)?([0-9])d<([^>]+)>", name) 40 if m.group(1): 41 time /= 1 << 15 42 tags = m.group(3).split(", ") 43 dim = int(m.group(2)) 44 label = re.search( 45 "fill_([a-z]+)", os.path.splitext(os.path.split(fn)[1])[0] 46 ).group(1) 47 dist = tags[0] 48 if len(tags) > 1 and tags[1] in ("dynamic_tag", "static_tag"): 49 if len(tags) == 3 and "DStore" in tags[2]: 50 continue 51 label += "-" + {"dynamic_tag": "dyn", "static_tag": "sta"}[tags[1]] 52 label += "-fill" if m.group(1) else "-call" 53 data[dim].append((label, dist, time / dim)) 54 55time_per_cycle_in_ns = 1.0 / (cpu_frequency * 1e6) / 1e-9 56 57plt.figure(figsize=(7, 6)) 58i = 0 59for dim in sorted(data): 60 v = data[dim] 61 labels = OrderedDict() 62 for label, dist, time in v: 63 if label in labels: 64 labels[label][dist] = time / time_per_cycle_in_ns 65 else: 66 labels[label] = {dist: time / time_per_cycle_in_ns} 67 j = 0 68 for label, d in labels.items(): 69 t1 = d["uniform"] 70 t2 = d["normal"] 71 i -= 1 72 z = float(j) / len(labels) 73 col = (1.0 - z) * np.array((1.0, 0.0, 0.0)) + z * np.array((1.0, 1.0, 0.0)) 74 if label == "root": 75 col = "k" 76 label = "ROOT 6" 77 if "numpy" in label: 78 col = "0.6" 79 if "gsl" in label: 80 col = "0.3" 81 label = "GSL" 82 tmin = min(t1, t2) 83 tmax = max(t1, t2) 84 r1 = Rectangle((0, i), tmax, 1, facecolor=col) 85 r2 = Rectangle( 86 (tmin, i), tmax - tmin, 1, facecolor="none", edgecolor="w", hatch="//////" 87 ) 88 plt.gca().add_artist(r1) 89 plt.gca().add_artist(r2) 90 font = FontProperties(size=9) 91 tx = Text( 92 -0.5, 93 i + 0.5, 94 "%s" % label, 95 fontproperties=font, 96 va="center", 97 ha="right", 98 clip_on=False, 99 ) 100 plt.gca().add_artist(tx) 101 j += 1 102 i -= 1 103 font = FontProperties() 104 font.set_weight("bold") 105 tx = Text( 106 -0.5, 107 i + 0.6, 108 "%iD" % dim, 109 fontproperties=font, 110 va="center", 111 ha="right", 112 clip_on=False, 113 ) 114 plt.gca().add_artist(tx) 115plt.ylim(0, i) 116plt.xlim(0, 80) 117from matplotlib.ticker import MultipleLocator 118 119plt.gca().xaxis.set_major_locator(MultipleLocator(5)) 120 121plt.tick_params("y", left=False, labelleft=False) 122plt.xlabel("average CPU cycles per random input value (smaller is better)") 123 124plt.tight_layout() 125 126plt.savefig("fill_performance.svg") 127plt.show() 128