source: benchmark/plot.py@ 3f1059e

ADT ast-experimental pthread-emulation
Last change on this file since 3f1059e was e5e2334, checked in by Thierry Delisle <tdelisle@…>, 3 years ago

Updated makefile and data plotting

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