blob: 0b7bf1ce0babd4d9579aa76d4668155d16d28ae2 [file] [log] [blame]
koder aka kdanilov94e3a2c2015-03-27 11:36:34 +02001import sys
2import math
3import itertools
4
5from colorama import Fore, Style
6
7
8def med_dev(vals):
9 med = sum(vals) / len(vals)
10 dev = ((sum(abs(med - i) ** 2 for i in vals) / len(vals)) ** 0.5)
11 return int(med), int(dev)
12
13
14def round_deviation(med_dev):
15 med, dev = med_dev
16
17 if dev < 1E-7:
18 return med_dev
19
20 dev_div = 10.0 ** (math.floor(math.log10(dev)) - 1)
21 dev = int(dev / dev_div) * dev_div
22 med = int(med / dev_div) * dev_div
23 return (type(med_dev[0])(med),
24 type(med_dev[1])(dev))
25
26
27def groupby_globally(data, key_func):
28 grouped = {}
29 grouped_iter = itertools.groupby(data, key_func)
30
Ved-vampir0d0740c2015-04-06 15:39:33 +030031 for (bs, cache_tp, act), curr_data_it in grouped_iter:
32 key = (bs, cache_tp, act)
koder aka kdanilov94e3a2c2015-03-27 11:36:34 +020033 grouped.setdefault(key, []).extend(curr_data_it)
34
35 return grouped
36
37
38class Data(object):
39 def __init__(self, name):
40 self.name = name
41 self.series = {}
42 self.processed_series = {}
43
44
45def process_inplace(data):
46 processed = {}
47 for key, values in data.series.items():
48 processed[key] = round_deviation(med_dev(values))
49 data.processed_series = processed
50
51
52def diff_table(*datas):
53 res_table = {}
54
55 for key in datas[0].processed_series:
56 baseline = datas[0].processed_series[key]
57 base_max = baseline[0] + baseline[1]
58 base_min = baseline[0] - baseline[1]
59
60 res_line = [baseline]
61
62 for data in datas[1:]:
63 val, dev = data.processed_series[key]
64 val_min = val - dev
65 val_max = val + dev
66
67 diff_1 = int(float(val_min - base_max) / base_max * 100)
68 diff_2 = int(float(val_max - base_min) / base_max * 100)
69
70 diff_max = max(diff_1, diff_2)
71 diff_min = min(diff_1, diff_2)
72
73 res_line.append((diff_max, diff_min))
74 res_table[key] = res_line
75
76 return [data.name for data in datas], res_table
77
78
79def print_table(headers, table):
80 lines = []
81 items = sorted(table.items())
82 lines.append([(len(i), i) for i in [""] + headers])
83 item_frmt = "{0}{1:>4}{2} ~ {3}{4:>4}{5}"
84
85 for key, vals in items:
86 ln1 = "{0:>4} {1} {2:>9} {3}".format(*map(str, key))
87 ln2 = "{0:>4} ~ {1:>3}".format(*vals[0])
88
89 line = [(len(ln1), ln1), (len(ln2), ln2)]
90
91 for idx, val in enumerate(vals[1:], 2):
92 cval = []
93 for vl in val:
94 if vl < -10:
95 cval.extend([Fore.RED, vl, Style.RESET_ALL])
96 elif vl > 10:
97 cval.extend([Fore.GREEN, vl, Style.RESET_ALL])
98 else:
99 cval.extend(["", vl, ""])
100
101 ln = len(item_frmt.format("", cval[1], "", "", cval[4], ""))
102 line.append((ln, item_frmt.format(*cval)))
103
104 lines.append(line)
105
106 max_columns_with = []
107 for idx in range(len(lines[0])):
108 max_columns_with.append(
109 max(line[idx][0] for line in lines))
110
111 sep = '-' * (4 + sum(max_columns_with) + 3 * (len(lines[0]) - 1))
112
113 print sep
114 for idx, line in enumerate(lines):
115 cline = []
116 for (curr_len, txt), exp_ln in zip(line, max_columns_with):
117 cline.append(" " * (exp_ln - curr_len) + txt)
118 print "| " + " | ".join(cline) + " |"
119 if 0 == idx:
120 print sep
121 print sep
122
123
124def key_func(x):
125 return (x['__meta__']['blocksize'],
Ved-vampir0d0740c2015-04-06 15:39:33 +0300126 'd' if 'direct' in x['__meta__'] else 's',
127 x['__meta__']['name'])
koder aka kdanilov94e3a2c2015-03-27 11:36:34 +0200128
129
130template = "{bs:>4} {action:>12} {cache_tp:>3} {conc:>4}"
131template += " | {iops[0]:>6} ~ {iops[1]:>5} | {bw[0]:>7} ~ {bw[1]:>6}"
132template += " | {lat[0]:>6} ~ {lat[1]:>5} |"
133
134headers = dict(bs="BS",
135 action="operation",
136 cache_tp="S/D",
137 conc="CONC",
138 iops=("IOPS", "dev"),
139 bw=("BW kBps", "dev"),
140 lat=("LAT ms", "dev"))
141
142
143def load_io_py_file(fname):
144 with open(fname) as fc:
145 block = None
146 for line in fc:
Ved-vampir0d0740c2015-04-06 15:39:33 +0300147 if line.startswith("{"):
koder aka kdanilov94e3a2c2015-03-27 11:36:34 +0200148 block = line
149 elif block is not None:
150 block += line
151
152 if block is not None and block.count('}') == block.count('{'):
Ved-vampir0d0740c2015-04-06 15:39:33 +0300153 cut = block.rfind('}')
154 block = block[0:cut+1]
koder aka kdanilov94e3a2c2015-03-27 11:36:34 +0200155 yield eval(block)
156 block = None
157
158 if block is not None and block.count('}') == block.count('{'):
159 yield eval(block)
160
161
162def main(argv):
163 items = []
164 CONC_POS = 3
165 for hdr_fname in argv[1:]:
166 hdr, fname = hdr_fname.split("=", 1)
167 data = list(load_io_py_file(fname))
168 item = Data(hdr)
169 for key, vals in groupby_globally(data, key_func).items():
170 item.series[key] = [val['iops'] * key[CONC_POS] for val in vals]
171 process_inplace(item)
172 items.append(item)
173
174 print_table(*diff_table(*items))
175
176 # print template.format(**headers)
177
178 # for (bs, cache_tp, act, conc), curr_data in sorted(grouped.items()):
179 # iops = med_dev([i['iops'] * int(conc) for i in curr_data])
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300180 # bw = med_dev([i['bw'] * int(conc) for i in curr_data])
koder aka kdanilov94e3a2c2015-03-27 11:36:34 +0200181 # lat = med_dev([i['lat'] / 1000 for i in curr_data])
182
183 # iops = round_deviation(iops)
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300184 # bw = round_deviation(bw)
koder aka kdanilov94e3a2c2015-03-27 11:36:34 +0200185 # lat = round_deviation(lat)
186
187 # params = dict(
188 # bs=bs,
189 # action=act,
190 # cache_tp=cache_tp,
191 # iops=iops,
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300192 # bw=bw,
koder aka kdanilov94e3a2c2015-03-27 11:36:34 +0200193 # lat=lat,
194 # conc=conc
195 # )
196
197 # print template.format(**params)
198
199
200if __name__ == "__main__":
201 exit(main(sys.argv))
202
203 # vals = [(123, 23), (125678, 5678), (123.546756, 23.77),
204 # (123.546756, 102.77), (0.1234, 0.0224),
205 # (0.001234, 0.000224), (0.001234, 0.0000224)]
206 # for val in :
207 # print val, "=>", round_deviation(val)