source: benchmark/plot.py @ e5e2334

pthread-emulation
Last change on this file since e5e2334 was e5e2334, checked in by Thierry Delisle <tdelisle@…>, 4 months 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.