source: benchmark/plot.py@ 3ce3fb9

ADT ast-experimental pthread-emulation stuck-waitfor-destruct
Last change on this file since 3ce3fb9 was 41a6a78, checked in by Thierry Delisle <tdelisle@…>, 3 years ago

It was brought to my attention that I forgot to commit this file

  • Property mode set to 100755
File size: 7.5 KB
RevLine 
[0bb691b1]1#!/usr/bin/python3
2"""
3Python Script to plot values obtained by the rmit.py script
4Runs a R.I.P.L.
5
6./plot.py
7-t trials
8-o option:values
9"""
10
11import argparse
12import itertools
13import json
14import math
15import numpy
[c0458be3]16import os
[0bb691b1]17import re
[57af3f3]18import statistics
[0bb691b1]19import sys
[41a6a78]20import time
[0bb691b1]21
[41a6a78]22import matplotlib
[0bb691b1]23import matplotlib.pyplot as plt
[41a6a78]24from matplotlib.ticker import EngFormatter, ScalarFormatter
25
26def fmtDur( duration ):
27 if duration :
28 hours, rem = divmod(duration, 3600)
29 minutes, rem = divmod(rem, 60)
30 seconds, millis = divmod(rem, 1)
31 return "%2d:%02d.%03d" % (minutes, seconds, millis * 1000)
32 return " n/a"
[0bb691b1]33
[44706d1]34class Field:
[c0458be3]35 def __init__(self, unit, _min, _log, _name=None, _factor=1.0):
[44706d1]36 self.unit = unit
37 self.min = _min
[e9c5db2]38 self.log = _log
[76f5e9f]39 self.name = _name
[c0458be3]40 self.factor = _factor
[44706d1]41
42field_names = {
[e9c5db2]43 "ns per ops" : Field('ns' , 0, False),
[41a6a78]44 "Number of processors" : Field('' , 1, "exact"),
[e9c5db2]45 "Ops per procs" : Field('Ops' , 0, False),
46 "Ops per threads" : Field('Ops' , 0, False),
[41a6a78]47 "ns per ops/procs" : Field('' , 0, False, _name = "ns $\\times$ (Processor $/$ Total Ops)" ),
[3b5dcfa]48 "Number of threads" : Field('' , 1, False),
[e9c5db2]49 "Total Operations(ops)" : Field('Ops' , 0, False),
50 "Ops/sec/procs" : Field('Ops' , 0, False),
51 "Total blocks" : Field('Blocks', 0, False),
[c0458be3]52 "Ops per second" : Field('' , 0, False),
[e9c5db2]53 "Cycle size (# thrds)" : Field('thrd' , 1, False),
54 "Duration (ms)" : Field('ms' , 0, False),
[3b5dcfa]55 "Target QPS" : Field('' , 0, False),
56 "Actual QPS" : Field('' , 0, False),
[e5e2334]57 "Average Read Latency" : Field('s' , 0, False, _factor = 0.000001),
[c0458be3]58 "Median Read Latency" : Field('s' , 0, True, _factor = 0.000001),
59 "Tail Read Latency" : Field('s' , 0, True, _factor = 0.000001),
60 "Average Update Latency": Field('s' , 0, True, _factor = 0.000001),
61 "Median Update Latency" : Field('s' , 0, True, _factor = 0.000001),
62 "Tail Update Latency" : Field('s' , 0, True, _factor = 0.000001),
[e5e2334]63 "Update Ratio" : Field('%' , 0, False),
[c0458be3]64 "Request Rate" : Field('req/s' , 0, False),
65 "Data Rate" : Field('b/s' , 0, False, _factor = 1000 * 1000, _name = "Response Throughput"),
[e5e2334]66 "Errors" : Field('%' , 0, False),
[44706d1]67}
[0bb691b1]68
[c0458be3]69def plot(in_data, x, y, options, prefix):
[0bb691b1]70 fig, ax = plt.subplots()
[c0458be3]71 colors = itertools.cycle(['#006cb4','#0aa000','#ff6600','#8510a1','#0095e3','#fd8f00','#e30002','#8f00d6','#4b009a','#ffff00','#69df00','#fb0300','#b13f00'])
[57af3f3]72 series = {} # scatter data for each individual data point
73 groups = {} # data points for x value
[e9c5db2]74
75 print("Preparing Data")
76
[57af3f3]77 for entry in in_data:
78 name = entry[0]
[41a6a78]79 if options.filter and not name.startswith(options.filter):
80 continue
81
[57af3f3]82 if not name in series:
83 series[name] = {'x':[], 'y':[]}
84
85 if not name in groups:
86 groups[name] = {}
[0bb691b1]87
88 if x in entry[2] and y in entry[2]:
[57af3f3]89 xval = entry[2][x]
[c0458be3]90 yval = entry[2][y] * field_names[y].factor
[57af3f3]91 series[name]['x'].append(xval)
92 series[name]['y'].append(yval)
93
94 if not xval in groups[name]:
95 groups[name][xval] = []
96
97 groups[name][xval].append(yval)
98
[e9c5db2]99 print("Preparing Lines")
100
[57af3f3]101 lines = {} # lines from groups with min, max, median, etc.
102 for name, data in groups.items():
103 if not name in lines:
104 lines[name] = { 'x': [], 'min':[], 'max':[], 'med':[], 'avg':[] }
105
106 for xkey in sorted(data):
107 ys = data[xkey]
108 lines[name]['x'] .append(xkey)
109 lines[name]['min'].append(min(ys))
110 lines[name]['max'].append(max(ys))
111 lines[name]['med'].append(statistics.median(ys))
112 lines[name]['avg'].append(statistics.mean(ys))
113
[e9c5db2]114 print("Making Plots")
115
[1f4fde5]116 for name, data in sorted(series.items()):
[57af3f3]117 _col = next(colors)
[c0458be3]118 plt.scatter(data['x'], data['y'], color=_col, label=name[len(prefix):], marker='x')
[57af3f3]119 plt.plot(lines[name]['x'], lines[name]['min'], '--', color=_col)
120 plt.plot(lines[name]['x'], lines[name]['max'], '--', color=_col)
121 plt.plot(lines[name]['x'], lines[name]['med'], '-', color=_col)
[0bb691b1]122
[e9c5db2]123 print("Calculating Extremums")
124
[0bb691b1]125 mx = max([max(s['x']) for s in series.values()])
126 my = max([max(s['y']) for s in series.values()])
127
[e9c5db2]128 print("Finishing Plots")
129
[76f5e9f]130 plt.ylabel(field_names[y].name if field_names[y].name else y)
[e9c5db2]131 # plt.xticks(range(1, math.ceil(mx) + 1))
[76f5e9f]132 plt.xlabel(field_names[x].name if field_names[x].name else x)
[0bb691b1]133 plt.grid(b = True)
[44706d1]134 ax.xaxis.set_major_formatter( EngFormatter(unit=field_names[x].unit) )
[76f5e9f]135 if options.logx:
136 ax.set_xscale('log')
137 elif field_names[x].log:
[e9c5db2]138 ax.set_xscale('log')
[41a6a78]139 if field_names[x].log == "exact":
140 xvals = set()
141 for s in series.values():
142 xvals |= set(s['x'])
143 ax.set_xticks(sorted(xvals))
144 ax.get_xaxis().set_major_formatter(ScalarFormatter())
145 plt.xticks(rotation = 45)
[e9c5db2]146 else:
147 plt.xlim(field_names[x].min, mx + 0.25)
148
[76f5e9f]149 if options.logy:
150 ax.set_yscale('log')
151 elif field_names[y].log:
[e9c5db2]152 ax.set_yscale('log')
153 else:
[76f5e9f]154 plt.ylim(field_names[y].min, options.MaxY if options.MaxY else my*1.2)
[e9c5db2]155
[c0458be3]156 ax.yaxis.set_major_formatter( EngFormatter(unit=field_names[y].unit) )
157
[44706d1]158 plt.legend(loc='upper left')
[e9c5db2]159
160 print("Results Ready")
[41a6a78]161 start = time.time()
[76f5e9f]162 if options.out:
163 plt.savefig(options.out, bbox_inches='tight')
[f34f95c]164 else:
165 plt.show()
[41a6a78]166 end = time.time()
167 print("Took {}".format(fmtDur(end - start)))
[0bb691b1]168
169
170if __name__ == "__main__":
171 # ================================================================================
172 # parse command line arguments
[e9c5db2]173 parser = argparse.ArgumentParser(description='Python Script to draw R.M.I.T. results')
174 parser.add_argument('-f', '--file', nargs='?', type=argparse.FileType('r'), default=sys.stdin, help="Input file")
175 parser.add_argument('-o', '--out', nargs='?', type=str, default=None, help="Output file")
176 parser.add_argument('-y', nargs='?', type=str, default="", help="Which field to use as the Y axis")
177 parser.add_argument('-x', nargs='?', type=str, default="", help="Which field to use as the X axis")
[76f5e9f]178 parser.add_argument('--logx', action='store_true', help="if set, makes the x-axis logscale")
179 parser.add_argument('--logy', action='store_true', help="if set, makes the y-axis logscale")
180 parser.add_argument('--MaxY', nargs='?', type=int, help="maximum value of the y-axis")
[41a6a78]181 parser.add_argument('--filter', nargs='?', type=str, default="", help="if not empty, only print series that start with specified filter")
[e9c5db2]182
183 options = parser.parse_args()
[0bb691b1]184
[41a6a78]185 # if not options.out:
186 # matplotlib.use('SVG')
187
[0bb691b1]188 # ================================================================================
189 # load data
190 try :
191 data = json.load(options.file)
192 except :
193 print('ERROR: could not read input', file=sys.stderr)
194 parser.print_help(sys.stderr)
195 sys.exit(1)
196
197 # ================================================================================
198 # identify the keys
199
200 series = set()
201 fields = set()
202
203 for entry in data:
204 series.add(entry[0])
205 for label in entry[2].keys():
206 fields.add(label)
207
[41a6a78]208 # filter out the series if needed
209 if options.filter:
210 series = set(filter(lambda elem: elem.startswith(options.filter), series))
211
212 # find the common prefix on series for removal (only if no filter)
[c0458be3]213 prefix = os.path.commonprefix(list(series))
214
[f34f95c]215 if not options.out :
216 print(series)
[e9c5db2]217 print("fields: ", ' '.join(fields))
[f34f95c]218
[e9c5db2]219 wantx = "Number of processors"
220 wanty = "ns per ops"
221
222 if options.x:
223 if options.x in field_names.keys():
224 wantx = options.x
225 else:
226 print("Could not find X key '{}', defaulting to '{}'".format(options.x, wantx))
227
228 if options.y:
229 if options.y in field_names.keys():
230 wanty = options.y
231 else:
232 print("Could not find Y key '{}', defaulting to '{}'".format(options.y, wanty))
233
234
[c0458be3]235 plot(data, wantx, wanty, options, prefix)
Note: See TracBrowser for help on using the repository browser.