blob: 04577a90dbd0b965fb948ec48b6d64544ba6b85d [file] [log] [blame]
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +03001import os
koder aka kdanilov4a510ee2015-04-21 18:50:42 +03002import bisect
koder aka kdanilova047e1b2015-04-21 23:16:59 +03003import logging
koder aka kdanilov416b87a2015-05-12 00:26:04 +03004import collections
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +03005from cStringIO import StringIO
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +03006
koder aka kdanilovbe8f89f2015-04-28 14:51:51 +03007try:
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +03008 import numpy
9 import scipy
koder aka kdanilovbe8f89f2015-04-28 14:51:51 +030010 import matplotlib.pyplot as plt
11except ImportError:
12 plt = None
13
koder aka kdanilov4a510ee2015-04-21 18:50:42 +030014import wally
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030015from wally.utils import ssize2b
16from wally.statistic import round_3_digit, data_property
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030017from wally.suits.io.fio_task_parser import get_test_sync_mode
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +030018
koder aka kdanilov4a510ee2015-04-21 18:50:42 +030019
koder aka kdanilova047e1b2015-04-21 23:16:59 +030020logger = logging.getLogger("wally.report")
21
22
koder aka kdanilov209e85d2015-04-27 23:11:05 +030023class DiskInfo(object):
24 def __init__(self):
25 self.direct_iops_r_max = 0
26 self.direct_iops_w_max = 0
27 self.rws4k_10ms = 0
28 self.rws4k_30ms = 0
29 self.rws4k_100ms = 0
30 self.bw_write_max = 0
31 self.bw_read_max = 0
32
33
koder aka kdanilovbe8f89f2015-04-28 14:51:51 +030034report_funcs = []
35
36
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030037class Attrmapper(object):
38 def __init__(self, dct):
39 self.__dct = dct
40
41 def __getattr__(self, name):
42 try:
43 return self.__dct[name]
44 except KeyError:
45 raise AttributeError(name)
46
47
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030048class PerfInfo(object):
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030049 def __init__(self, name, summary, intervals, params, testnodes_count):
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030050 self.name = name
51 self.bw = None
52 self.iops = None
53 self.lat = None
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030054
55 self.raw_bw = []
56 self.raw_iops = []
57 self.raw_lat = []
58
koder aka kdanilov416b87a2015-05-12 00:26:04 +030059 self.params = params
60 self.intervals = intervals
61 self.testnodes_count = testnodes_count
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030062 self.summary = summary
63 self.p = Attrmapper(self.params.vals)
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030064
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030065 self.sync_mode = get_test_sync_mode(self.params)
66 self.concurence = self.params.vals.get('numjobs', 1)
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030067
68
koder aka kdanilov416b87a2015-05-12 00:26:04 +030069def group_by_name(test_data):
70 name_map = collections.defaultdict(lambda: [])
71
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030072 for data in test_data:
73 name_map[(data.config.name, data.summary())].append(data)
koder aka kdanilov416b87a2015-05-12 00:26:04 +030074
75 return name_map
76
77
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030078def process_disk_info(test_data):
koder aka kdanilov416b87a2015-05-12 00:26:04 +030079 name_map = group_by_name(test_data)
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030080 data = {}
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030081 for (name, summary), results in name_map.items():
82 testnodes_count_set = set(dt.vm_count for dt in results)
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030083
koder aka kdanilov416b87a2015-05-12 00:26:04 +030084 assert len(testnodes_count_set) == 1
85 testnodes_count, = testnodes_count_set
86 assert len(results) % testnodes_count == 0
koder aka kdanilovf86d7af2015-05-06 04:01:54 +030087
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030088 intervals = [result.run_interval for result in results]
89 p = results[0].config
90 pinfo = PerfInfo(p.name, result.summary(), intervals,
91 p, testnodes_count)
koder aka kdanilov416b87a2015-05-12 00:26:04 +030092
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030093 pinfo.raw_bw = [result.results['bw'] for result in results]
94 pinfo.raw_iops = [result.results['iops'] for result in results]
95 pinfo.raw_lat = [result.results['lat'] for result in results]
koder aka kdanilov416b87a2015-05-12 00:26:04 +030096
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +030097 pinfo.bw = data_property(map(sum, zip(*pinfo.raw_bw)))
98 pinfo.iops = data_property(map(sum, zip(*pinfo.raw_iops)))
99 pinfo.lat = data_property(sum(pinfo.raw_lat, []))
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300100
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300101 data[(p.name, summary)] = pinfo
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300102 return data
103
104
koder aka kdanilovbe8f89f2015-04-28 14:51:51 +0300105def report(name, required_fields):
106 def closure(func):
107 report_funcs.append((required_fields.split(","), name, func))
108 return func
109 return closure
110
111
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300112def get_test_lcheck_params(pinfo):
113 res = [{
114 's': 'sync',
115 'd': 'direct',
116 'a': 'async',
117 'x': 'sync direct'
118 }[pinfo.sync_mode]]
koder aka kdanilovbe8f89f2015-04-28 14:51:51 +0300119
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300120 res.append(pinfo.p.rw)
koder aka kdanilovbe8f89f2015-04-28 14:51:51 +0300121
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300122 return " ".join(res)
koder aka kdanilov63e9c5a2015-04-28 23:06:07 +0300123
124
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300125def get_emb_data_svg(plt):
126 sio = StringIO()
127 plt.savefig(sio, format='svg')
128 img_start = "<!-- Created with matplotlib (http://matplotlib.org/) -->"
129 return sio.getvalue().split(img_start, 1)[1]
koder aka kdanilovbe8f89f2015-04-28 14:51:51 +0300130
131
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300132def get_template(templ_name):
koder aka kdanilov4a510ee2015-04-21 18:50:42 +0300133 very_root_dir = os.path.dirname(os.path.dirname(wally.__file__))
134 templ_dir = os.path.join(very_root_dir, 'report_templates')
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300135 templ_file = os.path.join(templ_dir, templ_name)
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300136 return open(templ_file, 'r').read()
koder aka kdanilov209e85d2015-04-27 23:11:05 +0300137
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300138
139@report('linearity', 'linearity_test')
140def linearity_report(processed_results, path, lab_info):
141 labels_and_data = []
142
143 vls = processed_results.values()[0].params.vals.copy()
144 del vls['blocksize']
145
146 for res in processed_results.values():
147 if res.name.startswith('linearity_test'):
148 iotimes = [1000. / val for val in res.iops.raw]
149 labels_and_data.append([res.p.blocksize, res.iops.raw, iotimes])
150 cvls = res.params.vals.copy()
151 del cvls['blocksize']
152 assert cvls == vls
153
154 labels_and_data.sort(key=lambda x: ssize2b(x[0]))
155 _, ax1 = plt.subplots()
156
157 labels, data, iotimes = zip(*labels_and_data)
158 plt.boxplot(iotimes)
159
160 if len(labels_and_data) > 2 and ssize2b(labels_and_data[-2][0]) >= 4096:
161 xt = range(1, len(labels) + 1)
162
163 def io_time(sz, bw, initial_lat):
164 return sz / bw + initial_lat
165
166 x = numpy.array(map(ssize2b, labels))
167 y = numpy.array([sum(dt) / len(dt) for dt in iotimes])
168 popt, _ = scipy.optimize.curve_fit(io_time, x, y, p0=(100., 1.))
169
170 y1 = io_time(x, *popt)
171 plt.plot(xt, y1, linestyle='--', label='LS linear approxomation')
172
173 for idx, (sz, _, _) in enumerate(labels_and_data):
174 if ssize2b(sz) >= 4096:
175 break
176
177 bw = (x[-1] - x[idx]) / (y[-1] - y[idx])
178 lat = y[-1] - x[-1] / bw
179 y2 = io_time(x, bw, lat)
180
181 plt.plot(xt, y2, linestyle='--',
182 label='(4k & max) linear approxomation')
183
184 plt.setp(ax1, xticklabels=labels)
185
186 plt.xlabel("Block size")
187 plt.ylabel("IO time, ms")
188
189 plt.legend(loc=0)
190 plt.grid()
191 iotime_plot = get_emb_data_svg(plt)
192
193 _, ax1 = plt.subplots()
194 plt.boxplot(data)
195 plt.setp(ax1, xticklabels=labels)
196
197 plt.xlabel("Block size")
198 plt.ylabel("IOPS")
199 plt.grid()
200
201 iops_plot = get_emb_data_svg(plt)
202
203 res1 = processed_results.values()[0]
204 descr = {
205 'vm_count': res1.testnodes_count,
206 'concurence': res1.concurence,
207 'oper_descr': get_test_lcheck_params(res1).capitalize()
208 }
209
210 params_map = {'iotime_vs_size': iotime_plot,
211 'iops_vs_size': iops_plot,
212 'descr': descr}
213
214 with open(path, 'w') as fd:
215 fd.write(get_template('report_linearity.html').format(**params_map))
216
217
218@report('lat_vs_iops', 'lat_vs_iops')
219def lat_vs_iops(processed_results, path, lab_info):
220 lat_iops = collections.defaultdict(lambda: [])
221 for res in processed_results.values():
222 if res.name.startswith('lat_vs_iops'):
223 lat_iops[res.concurence].append((res.lat.average / 1000.0,
224 res.lat.deviation / 1000.0,
225 res.iops.average,
226 res.iops.deviation))
227
228 colors = ['red', 'green', 'blue', 'orange', 'magenta', "teal"][::-1]
229 for conc, lat_iops in sorted(lat_iops.items()):
230 lat, dev, iops, iops_dev = zip(*lat_iops)
231 plt.errorbar(iops, lat, xerr=iops_dev, yerr=dev, fmt='ro',
232 label=str(conc) + " threads",
233 color=colors.pop())
234
235 plt.xlabel("IOPS")
236 plt.ylabel("Latency, ms")
237 plt.grid()
238 plt.legend(loc=0)
239 plt.show()
240 exit(1)
241
242
243def render_all_html(dest, info, lab_description, images, templ_name):
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300244 data = info.__dict__.copy()
245 for name, val in data.items():
koder aka kdanilov209e85d2015-04-27 23:11:05 +0300246 if not name.startswith('__'):
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300247 if val is None:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300248 data[name] = '-'
249 elif isinstance(val, (int, float, long)):
250 data[name] = round_3_digit(val)
koder aka kdanilov209e85d2015-04-27 23:11:05 +0300251
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300252 data['bw_read_max'] = (data['bw_read_max'][0] // 1024,
253 data['bw_read_max'][1])
254 data['bw_write_max'] = (data['bw_write_max'][0] // 1024,
255 data['bw_write_max'][1])
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +0300256
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300257 images.update(data)
258 report = get_template(templ_name).format(lab_info=lab_description,
259 **images)
koder aka kdanilov63ad2062015-04-27 13:11:40 +0300260
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300261 with open(dest, 'w') as fd:
262 fd.write(report)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300263
264
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300265def io_chart(title, concurence,
266 latv, latv_min, latv_max,
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300267 iops_or_bw, iops_or_bw_err,
268 legend, log=False,
269 boxplots=False):
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300270 points = " MiBps" if legend == 'BW' else ""
271 lc = len(concurence)
272 width = 0.35
273 xt = range(1, lc + 1)
274
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300275 op_per_vm = [v / (vm * th) for v, (vm, th) in zip(iops_or_bw, concurence)]
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300276 fig, p1 = plt.subplots()
277 xpos = [i - width / 2 for i in xt]
278
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300279 p1.bar(xpos, iops_or_bw,
280 width=width,
281 yerr=iops_or_bw_err,
282 ecolor='m',
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300283 color='y',
284 label=legend)
285
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300286 p1.grid(True)
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300287 p1.plot(xt, op_per_vm, '--', label=legend + "/thread", color='black')
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300288 handles1, labels1 = p1.get_legend_handles_labels()
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300289
290 p2 = p1.twinx()
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300291 p2.plot(xt, latv_max, label="lat max")
292 p2.plot(xt, latv, label="lat avg")
293 p2.plot(xt, latv_min, label="lat min")
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300294
295 plt.xlim(0.5, lc + 0.5)
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300296 plt.xticks(xt, ["{0} * {1}".format(vm, th) for (vm, th) in concurence])
297 p1.set_xlabel("VM Count * Thread per VM")
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300298 p1.set_ylabel(legend + points)
299 p2.set_ylabel("Latency ms")
300 plt.title(title)
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300301 handles2, labels2 = p2.get_legend_handles_labels()
302
303 plt.legend(handles1 + handles2, labels1 + labels2,
304 loc='center left', bbox_to_anchor=(1.1, 0.81))
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300305
306 if log:
307 p1.set_yscale('log')
308 p2.set_yscale('log')
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300309 plt.subplots_adjust(right=0.68)
310
311 return get_emb_data_svg(plt)
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300312
313
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300314def make_plots(processed_results, plots):
315 files = {}
koder aka kdanilov63ad2062015-04-27 13:11:40 +0300316 for name_pref, fname, desc in plots:
koder aka kdanilov4a510ee2015-04-21 18:50:42 +0300317 chart_data = []
koder aka kdanilov63ad2062015-04-27 13:11:40 +0300318
koder aka kdanilov4a510ee2015-04-21 18:50:42 +0300319 for res in processed_results.values():
320 if res.name.startswith(name_pref):
321 chart_data.append(res)
322
koder aka kdanilov63ad2062015-04-27 13:11:40 +0300323 if len(chart_data) == 0:
324 raise ValueError("Can't found any date for " + name_pref)
325
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300326 use_bw = ssize2b(chart_data[0].p.blocksize) > 16 * 1024
koder aka kdanilov63ad2062015-04-27 13:11:40 +0300327
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300328 chart_data.sort(key=lambda x: x.concurence)
koder aka kdanilov4a510ee2015-04-21 18:50:42 +0300329
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300330 # if x.lat.average < max_lat]
331 lat = [x.lat.average / 1000 for x in chart_data]
koder aka kdanilovd5ed4da2015-05-07 23:33:23 +0300332 lat_min = [x.lat.min / 1000 for x in chart_data]
333 lat_max = [x.lat.max / 1000 for x in chart_data]
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300334
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300335 testnodes_count = x.testnodes_count
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300336 concurence = [(testnodes_count, x.concurence)
koder aka kdanilov416b87a2015-05-12 00:26:04 +0300337 for x in chart_data]
koder aka kdanilov4a510ee2015-04-21 18:50:42 +0300338
koder aka kdanilov63ad2062015-04-27 13:11:40 +0300339 if use_bw:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300340 data = [x.bw.average / 1000 for x in chart_data]
341 data_dev = [x.bw.confidence / 1000 for x in chart_data]
koder aka kdanilov63ad2062015-04-27 13:11:40 +0300342 name = "BW"
343 else:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300344 data = [x.iops.average for x in chart_data]
345 data_dev = [x.iops.confidence for x in chart_data]
koder aka kdanilov63ad2062015-04-27 13:11:40 +0300346 name = "IOPS"
347
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300348 fc = io_chart(title=desc,
349 concurence=concurence,
350 latv=lat, latv_min=lat_min, latv_max=lat_max,
351 iops_or_bw=data,
352 iops_or_bw_err=data_dev,
353 legend=name)
354 files[fname] = fc
355
356 return files
koder aka kdanilov4a510ee2015-04-21 18:50:42 +0300357
358
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +0300359def find_max_where(processed_results, sync_mode, blocksize, rw, iops=True):
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300360 result = None
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +0300361 attr = 'iops' if iops else 'bw'
362 for measurement in processed_results.values():
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300363 ok = measurement.sync_mode == sync_mode
364 ok = ok and (measurement.p.blocksize == blocksize)
365 ok = ok and (measurement.p.rw == rw)
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +0300366
367 if ok:
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300368 field = getattr(measurement, attr)
369
370 if result is None:
371 result = field
372 elif field.average > result.average:
373 result = field
374
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +0300375 return result
376
377
koder aka kdanilov4a510ee2015-04-21 18:50:42 +0300378def get_disk_info(processed_results):
379 di = DiskInfo()
380 rws4k_iops_lat_th = []
381
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +0300382 di.direct_iops_w_max = find_max_where(processed_results,
383 'd', '4k', 'randwrite')
384 di.direct_iops_r_max = find_max_where(processed_results,
385 'd', '4k', 'randread')
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300386
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +0300387 di.bw_write_max = find_max_where(processed_results,
388 'd', '16m', 'randwrite', False)
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300389 if di.bw_write_max is None:
390 di.bw_write_max = find_max_where(processed_results,
391 'd', '1m', 'write', False)
392
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +0300393 di.bw_read_max = find_max_where(processed_results,
394 'd', '16m', 'randread', False)
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300395 if di.bw_read_max is None:
396 di.bw_read_max = find_max_where(processed_results,
397 'd', '1m', 'read', False)
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +0300398
koder aka kdanilov4a510ee2015-04-21 18:50:42 +0300399 for res in processed_results.values():
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300400 if res.sync_mode == 's' and res.p.blocksize == '4k':
401 if res.p.rw != 'randwrite':
koder aka kdanilov4a510ee2015-04-21 18:50:42 +0300402 continue
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300403 rws4k_iops_lat_th.append((res.iops.average,
404 res.lat.average,
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300405 res.concurence))
koder aka kdanilov4a510ee2015-04-21 18:50:42 +0300406
koder aka kdanilov4a510ee2015-04-21 18:50:42 +0300407 rws4k_iops_lat_th.sort(key=lambda (_1, _2, conc): conc)
408
409 latv = [lat for _, lat, _ in rws4k_iops_lat_th]
410
411 for tlatv_ms in [10, 30, 100]:
412 tlat = tlatv_ms * 1000
413 pos = bisect.bisect_left(latv, tlat)
414 if 0 == pos:
415 iops3 = 0
416 elif pos == len(latv):
417 iops3 = latv[-1]
418 else:
419 lat1 = latv[pos - 1]
420 lat2 = latv[pos]
421
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300422 iops1, _, th1 = rws4k_iops_lat_th[pos - 1]
423 iops2, _, th2 = rws4k_iops_lat_th[pos]
koder aka kdanilov4a510ee2015-04-21 18:50:42 +0300424
425 th_lat_coef = (th2 - th1) / (lat2 - lat1)
426 th3 = th_lat_coef * (tlat - lat1) + th1
427
428 th_iops_coef = (iops2 - iops1) / (th2 - th1)
429 iops3 = th_iops_coef * (th3 - th1) + iops1
430 setattr(di, 'rws4k_{}ms'.format(tlatv_ms), int(iops3))
431
432 hdi = DiskInfo()
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +0300433
434 def pp(x):
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300435 med, conf = x.rounded_average_conf()
436 conf_perc = int(float(conf) / med * 100)
437 return (med, conf_perc)
koder aka kdanilov7e0f7cf2015-05-01 17:24:35 +0300438
439 hdi.direct_iops_r_max = pp(di.direct_iops_r_max)
440 hdi.direct_iops_w_max = pp(di.direct_iops_w_max)
441 hdi.bw_write_max = pp(di.bw_write_max)
442 hdi.bw_read_max = pp(di.bw_read_max)
443
koder aka kdanilovc368eb62015-04-28 18:22:01 +0300444 hdi.rws4k_10ms = di.rws4k_10ms if 0 != di.rws4k_10ms else None
445 hdi.rws4k_30ms = di.rws4k_30ms if 0 != di.rws4k_30ms else None
446 hdi.rws4k_100ms = di.rws4k_100ms if 0 != di.rws4k_100ms else None
koder aka kdanilov4a510ee2015-04-21 18:50:42 +0300447 return hdi
448
449
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300450@report('HDD', 'hdd_test')
451def make_hdd_report(processed_results, path, lab_info):
452 plots = [
453 ('hdd_test_rrd4k', 'rand_read_4k', 'Random read 4k direct IOPS'),
454 ('hdd_test_rws4k', 'rand_write_4k', 'Random write 4k sync IOPS')
455 ]
456 images = make_plots(processed_results, plots)
koder aka kdanilova4a570f2015-04-23 22:11:40 +0300457 di = get_disk_info(processed_results)
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300458 render_all_html(path, di, lab_info, images, "report_hdd.html")
koder aka kdanilov63ad2062015-04-27 13:11:40 +0300459
460
461@report('Ceph', 'ceph_test')
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300462def make_ceph_report(processed_results, path, lab_info):
463 plots = [
464 ('ceph_test_rrd4k', 'rand_read_4k', 'Random read 4k direct IOPS'),
465 ('ceph_test_rws4k', 'rand_write_4k', 'Random write 4k sync IOPS'),
466 ('ceph_test_rrd16m', 'rand_read_16m', 'Random read 16m direct MiBps'),
467 ('ceph_test_rwd16m', 'rand_write_16m',
468 'Random write 16m direct MiBps'),
469 ]
470
471 images = make_plots(processed_results, plots)
koder aka kdanilov63ad2062015-04-27 13:11:40 +0300472 di = get_disk_info(processed_results)
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300473 render_all_html(path, di, lab_info, images, "report_ceph.html")
koder aka kdanilova4a570f2015-04-23 22:11:40 +0300474
475
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300476def make_io_report(dinfo, results, path, lab_info=None):
koder aka kdanilovf86d7af2015-05-06 04:01:54 +0300477 lab_info = {
478 "total_disk": "None",
479 "total_memory": "None",
480 "nodes_count": "None",
481 "processor_count": "None"
482 }
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300483
koder aka kdanilova047e1b2015-04-21 23:16:59 +0300484 try:
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300485 res_fields = sorted(v.name for v in dinfo.values())
486
koder aka kdanilov57ce4db2015-04-25 21:25:51 +0300487 for fields, name, func in report_funcs:
koder aka kdanilovafd98742015-04-24 01:27:22 +0300488 for field in fields:
koder aka kdanilov57ce4db2015-04-25 21:25:51 +0300489 pos = bisect.bisect_left(res_fields, field)
490
491 if pos == len(res_fields):
koder aka kdanilov63ad2062015-04-27 13:11:40 +0300492 break
koder aka kdanilov57ce4db2015-04-25 21:25:51 +0300493
koder aka kdanilovbe8f89f2015-04-28 14:51:51 +0300494 if not res_fields[pos].startswith(field):
koder aka kdanilovafd98742015-04-24 01:27:22 +0300495 break
496 else:
koder aka kdanilov57ce4db2015-04-25 21:25:51 +0300497 hpath = path.format(name)
koder aka kdanilov63ad2062015-04-27 13:11:40 +0300498 logger.debug("Generatins report " + name + " into " + hpath)
koder aka kdanilov4af1c1d2015-05-18 15:48:58 +0300499 func(dinfo, hpath, lab_info)
koder aka kdanilovafd98742015-04-24 01:27:22 +0300500 break
koder aka kdanilova4a570f2015-04-23 22:11:40 +0300501 else:
502 logger.warning("No report generator found for this load")
koder aka kdanilovafd98742015-04-24 01:27:22 +0300503
koder aka kdanilova047e1b2015-04-21 23:16:59 +0300504 except Exception as exc:
koder aka kdanilov57ce4db2015-04-25 21:25:51 +0300505 import traceback
506 traceback.print_exc()
koder aka kdanilovec1b9732015-04-23 20:43:29 +0300507 logger.error("Failed to generate html report:" + str(exc))