source: benchmark/plot.py@ 10c1770

Last change on this file since 10c1770 was 8fca132, checked in by Thierry Delisle <tdelisle@…>, 3 years ago

Changed plots to use different markers and dotted lines for minimum

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