blob: b11f20ece188b584955a78729ca8f065bceb05fb [file] [log] [blame]
koder aka kdanilovda45e882015-04-06 02:24:42 +03001import sys
2import time
3import json
koder aka kdanilov0c598a12015-04-21 03:01:40 +03004import copy
koder aka kdanilovda45e882015-04-06 02:24:42 +03005import select
6import pprint
7import argparse
8import traceback
9import subprocess
10import itertools
11from collections import OrderedDict
12
13
14SECTION = 0
15SETTING = 1
16
17
koder aka kdanilov0c598a12015-04-21 03:01:40 +030018class FioJobSection(object):
19 def __init__(self, name):
20 self.name = name
21 self.vals = OrderedDict()
22 self.format_params = {}
23
24 def copy(self):
25 return copy.deepcopy(self)
26
27
28def to_bytes(sz):
29 sz = sz.lower()
30 try:
31 return int(sz)
32 except ValueError:
33 if sz[-1] == 'm':
34 return (1024 ** 2) * int(sz[:-1])
35 if sz[-1] == 'k':
36 return 1024 * int(sz[:-1])
37 if sz[-1] == 'g':
38 return (1024 ** 3) * int(sz[:-1])
39 raise
40
41
42def fio_config_lexer(fio_cfg):
43 for lineno, line in enumerate(fio_cfg.split("\n")):
44 try:
45 line = line.strip()
46
47 if line.startswith("#") or line.startswith(";"):
48 continue
49
50 if line == "":
51 continue
52
53 if line.startswith('['):
54 assert line.endswith(']'), "name should ends with ]"
55 yield lineno, SECTION, line[1:-1], None
56 elif '=' in line:
57 opt_name, opt_val = line.split('=', 1)
58 yield lineno, SETTING, opt_name.strip(), opt_val.strip()
59 else:
60 yield lineno, SETTING, line, None
61 except Exception as exc:
62 pref = "During parsing line number {0}\n".format(lineno)
63 raise ValueError(pref + exc.message)
64
65
66def fio_config_parse(lexer_iter, format_params):
67 orig_format_params_keys = set(format_params)
68 format_params = format_params.copy()
69 in_defaults = False
70 curr_section = None
71 defaults = OrderedDict()
72
73 for lineno, tp, name, val in lexer_iter:
74 if tp == SECTION:
75 if curr_section is not None:
76 yield curr_section
77
78 if name == 'defaults':
79 in_defaults = True
80 curr_section = None
81 else:
82 in_defaults = False
83 curr_section = FioJobSection(name)
84 curr_section.format_params = format_params.copy()
85 curr_section.vals = defaults.copy()
86 else:
87 assert tp == SETTING
88 if name == name.upper():
89 msg = "Param not in default section in line " + str(lineno)
90 assert in_defaults, msg
91 if name not in orig_format_params_keys:
92 # don't make parse_value for PARAMS
93 # they would be parsed later
94 # or this would breakes arrays
95 format_params[name] = val
96 elif in_defaults:
97 defaults[name] = parse_value(val)
98 else:
99 msg = "data outside section, line " + str(lineno)
100 assert curr_section is not None, msg
101 curr_section.vals[name] = parse_value(val)
102
103 if curr_section is not None:
104 yield curr_section
105
106
107def parse_value(val):
108 if val is None:
109 return None
110
111 try:
112 return int(val)
113 except ValueError:
114 pass
115
116 try:
117 return float(val)
118 except ValueError:
119 pass
120
121 if val.startswith('{%'):
122 assert val.endswith("%}")
123 content = val[2:-2]
124 vals = list(i.strip() for i in content.split(','))
125 return map(parse_value, vals)
126 return val
127
128
129def process_repeats(sec_iter):
130
131 for sec in sec_iter:
132 if '*' in sec.name:
133 msg = "Only one '*' allowed in section name"
134 assert sec.name.count('*') == 1, msg
135
136 name, count = sec.name.split("*")
137 sec.name = name.strip()
138 count = count.strip()
139
140 try:
141 count = int(count.strip().format(**sec.format_params))
142 except KeyError:
143 raise ValueError("No parameter {0} given".format(count[1:-1]))
144 except ValueError:
145 msg = "Parameter {0} nas non-int value {1!r}"
146 raise ValueError(msg.format(count[1:-1],
147 count.format(**sec.format_params)))
148
149 yield sec
150
151 if 'ramp_time' in sec.vals:
152 sec = sec.copy()
153 sec.vals['_ramp_time'] = sec.vals.pop('ramp_time')
154
155 for _ in range(count - 1):
156 yield sec.copy()
157 else:
158 yield sec
159
160
161def process_cycles(sec_iter):
162 # insert parametrized cycles
163 sec_iter = try_format_params_into_section(sec_iter)
164
165 for sec in sec_iter:
166
167 cycles_var_names = []
168 cycles_var_values = []
169
170 for name, val in sec.vals.items():
171 if isinstance(val, list):
172 cycles_var_names.append(name)
173 cycles_var_values.append(val)
174
175 if len(cycles_var_names) == 0:
176 yield sec
177 else:
178 for combination in itertools.product(*cycles_var_values):
179 new_sec = sec.copy()
180 new_sec.vals.update(zip(cycles_var_names, combination))
181 yield new_sec
182
183
184def try_format_params_into_section(sec_iter):
185 for sec in sec_iter:
186 params = sec.format_params
187 for name, val in sec.vals.items():
188 if isinstance(val, basestring):
189 try:
190 sec.vals[name] = parse_value(val.format(**params))
191 except:
192 pass
193
194 yield sec
195
196
197def format_params_into_section_finall(sec_iter, counter=[0]):
198 group_report_err_msg = "Group reporting should be set if numjobs != 1"
199
200 for sec in sec_iter:
201
202 num_jobs = int(sec.vals.get('numjobs', '1'))
203 if num_jobs != 1:
204 assert 'group_reporting' in sec.vals, group_report_err_msg
205
206 params = sec.format_params
207
208 fsize = to_bytes(sec.vals['size'])
209 params['PER_TH_OFFSET'] = fsize // num_jobs
210
211 for name, val in sec.vals.items():
212 if isinstance(val, basestring):
213 sec.vals[name] = parse_value(val.format(**params))
214 else:
215 assert isinstance(val, (int, float)) or val is None
216
217 params['UNIQ'] = 'UN{0}'.format(counter[0])
218 counter[0] += 1
219 params['TEST_SUMM'] = get_test_summary(sec.vals)
220 sec.name = sec.name.format(**params)
221
222 yield sec
223
224
225def fio_config_to_str(sec_iter):
226 res = ""
227
228 for pos, sec in enumerate(sec_iter):
229 if pos != 0:
230 res += "\n"
231
232 res += "[{0}]\n".format(sec.name)
233
234 for name, val in sec.vals.items():
235 if name.startswith('_'):
236 continue
237
238 if val is None:
239 res += name + "\n"
240 else:
241 res += "{0}={1}\n".format(name, val)
242
243 return res
244
245
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300246def get_test_sync_mode(config):
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300247 try:
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300248 return config['sync_mode']
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300249 except KeyError:
250 pass
251
koder aka kdanilovea22c3d2015-04-21 03:42:22 +0300252 is_sync = str(config.get("sync", "0")) == "1"
253 is_direct = str(config.get("direct", "0")) == "1"
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300254
255 if is_sync and is_direct:
256 return 'x'
257 elif is_sync:
258 return 's'
259 elif is_direct:
260 return 'd'
261 else:
262 return 'a'
263
264
koder aka kdanilovda45e882015-04-06 02:24:42 +0300265def get_test_summary(params):
266 rw = {"randread": "rr",
267 "randwrite": "rw",
268 "read": "sr",
269 "write": "sw"}[params["rw"]]
270
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300271 sync_mode = get_test_sync_mode(params)
272 th_count = params.get('numjobs')
koder aka kdanilovea22c3d2015-04-21 03:42:22 +0300273
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300274 if th_count is None:
koder aka kdanilovea22c3d2015-04-21 03:42:22 +0300275 th_count = params.get('concurence', 1)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300276
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300277 return "{0}{1}{2}th{3}".format(rw,
278 sync_mode,
279 params['blocksize'],
280 th_count)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300281
282
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300283def calculate_execution_time(sec_iter):
koder aka kdanilovda45e882015-04-06 02:24:42 +0300284 time = 0
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300285 for sec in sec_iter:
286 time += sec.vals.get('ramp_time', 0)
287 time += sec.vals.get('runtime', 0)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300288 return time
289
290
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300291def slice_config(sec_iter, runcycle=None, max_jobs=1000):
292 jcount = 0
293 runtime = 0
294 curr_slice = []
koder aka kdanilovda45e882015-04-06 02:24:42 +0300295
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300296 for pos, sec in enumerate(sec_iter):
koder aka kdanilovda45e882015-04-06 02:24:42 +0300297
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300298 jc = sec.vals.get('numjobs', 1)
299 msg = "numjobs should be integer, not {0!r}".format(jc)
300 assert isinstance(jc, int), msg
koder aka kdanilovda45e882015-04-06 02:24:42 +0300301
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300302 curr_task_time = calculate_execution_time([sec])
koder aka kdanilovda45e882015-04-06 02:24:42 +0300303
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300304 if jc > max_jobs:
305 err_templ = "Can't process job {0!r} - too large numjobs"
306 raise ValueError(err_templ.format(sec.name))
koder aka kdanilovda45e882015-04-06 02:24:42 +0300307
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300308 if runcycle is not None and len(curr_slice) != 0:
309 rc_ok = curr_task_time + runtime <= runcycle
koder aka kdanilovda45e882015-04-06 02:24:42 +0300310 else:
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300311 rc_ok = True
koder aka kdanilovda45e882015-04-06 02:24:42 +0300312
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300313 if jc + jcount <= max_jobs and rc_ok:
314 runtime += curr_task_time
315 jcount += jc
316 curr_slice.append(sec)
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300317 continue
318
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300319 assert len(curr_slice) != 0
320 yield curr_slice
koder aka kdanilovda45e882015-04-06 02:24:42 +0300321
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300322 if '_ramp_time' in sec.vals:
323 sec.vals['ramp_time'] = sec.vals.pop('_ramp_time')
324 curr_task_time = calculate_execution_time([sec])
325
326 runtime = curr_task_time
327 jcount = jc
328 curr_slice = [sec]
329
330 if curr_slice != []:
331 yield curr_slice
koder aka kdanilovda45e882015-04-06 02:24:42 +0300332
333
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300334def parse_all_in_1(source, test_params):
335 lexer_it = fio_config_lexer(source)
336 sec_it = fio_config_parse(lexer_it, test_params)
337 sec_it = process_cycles(sec_it)
338 sec_it = process_repeats(sec_it)
339 return format_params_into_section_finall(sec_it)
koder aka kdanilovb896f692015-04-07 14:57:55 +0300340
341
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300342def parse_and_slice_all_in_1(source, test_params, **slice_params):
343 sec_it = parse_all_in_1(source, test_params)
344 return slice_config(sec_it, **slice_params)
koder aka kdanilovb896f692015-04-07 14:57:55 +0300345
346
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300347def compile_all_in_1(source, test_params, **slice_params):
348 slices_it = parse_and_slice_all_in_1(source, test_params, **slice_params)
349 for slices in slices_it:
350 yield fio_config_to_str(slices)
koder aka kdanilovb896f692015-04-07 14:57:55 +0300351
352
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300353def do_run_fio(config_slice):
354 benchmark_config = fio_config_to_str(config_slice)
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300355 cmd = ["fio", "--output-format=json", "--alloc-size=262144", "-"]
koder aka kdanilove87ae652015-04-20 02:14:35 +0300356 p = subprocess.Popen(cmd,
357 stdin=subprocess.PIPE,
koder aka kdanilovda45e882015-04-06 02:24:42 +0300358 stdout=subprocess.PIPE,
koder aka kdanilove87ae652015-04-20 02:14:35 +0300359 stderr=subprocess.PIPE)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300360
361 # set timeout
koder aka kdanilove87ae652015-04-20 02:14:35 +0300362 raw_out, raw_err = p.communicate(benchmark_config)
363
koder aka kdanilov6b1341a2015-04-21 22:44:21 +0300364 # HACK
365 raw_out = "{" + raw_out.split('{', 1)[1]
366
koder aka kdanilove87ae652015-04-20 02:14:35 +0300367 if 0 != p.returncode:
368 msg = "Fio failed with code: {0}\nOutput={1}"
369 raise OSError(msg.format(p.returncode, raw_err))
koder aka kdanilovda45e882015-04-06 02:24:42 +0300370
371 try:
372 parsed_out = json.loads(raw_out)["jobs"]
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300373 except KeyError:
374 msg = "Can't parse fio output {0!r}: no 'jobs' found"
375 raw_out = raw_out[:100]
376 raise ValueError(msg.format(raw_out))
377
378 except Exception as exc:
koder aka kdanilovda45e882015-04-06 02:24:42 +0300379 msg = "Can't parse fio output: {0!r}\nError: {1}"
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300380 raw_out = raw_out[:100]
381 raise ValueError(msg.format(raw_out, exc.message))
koder aka kdanilovda45e882015-04-06 02:24:42 +0300382
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300383 return zip(parsed_out, config_slice)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300384
385
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300386def add_job_results(section, job_output, res):
koder aka kdanilovda45e882015-04-06 02:24:42 +0300387 if job_output['write']['iops'] != 0:
388 raw_result = job_output['write']
389 else:
390 raw_result = job_output['read']
391
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300392 vals = section.vals
393 if section.name not in res:
koder aka kdanilovda45e882015-04-06 02:24:42 +0300394 j_res = {}
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300395 j_res["rw"] = vals["rw"]
396 j_res["sync_mode"] = get_test_sync_mode(vals)
397 j_res["concurence"] = int(vals.get("numjobs", 1))
398 j_res["blocksize"] = vals["blocksize"]
koder aka kdanilovda45e882015-04-06 02:24:42 +0300399 j_res["jobname"] = job_output["jobname"]
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300400 j_res["timings"] = [int(vals.get("runtime", 0)),
401 int(vals.get("ramp_time", 0))]
koder aka kdanilovda45e882015-04-06 02:24:42 +0300402 else:
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300403 j_res = res[section.name]
404 assert j_res["rw"] == vals["rw"]
405 assert j_res["rw"] == vals["rw"]
406 assert j_res["sync_mode"] == get_test_sync_mode(vals)
407 assert j_res["concurence"] == int(vals.get("numjobs", 1))
408 assert j_res["blocksize"] == vals["blocksize"]
koder aka kdanilovda45e882015-04-06 02:24:42 +0300409 assert j_res["jobname"] == job_output["jobname"]
koder aka kdanilov652cd802015-04-13 12:21:07 +0300410
411 # ramp part is skipped for all tests, except first
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300412 # assert j_res["timings"] == (vals.get("runtime"),
413 # vals.get("ramp_time"))
koder aka kdanilovda45e882015-04-06 02:24:42 +0300414
415 def j_app(name, x):
416 j_res.setdefault(name, []).append(x)
417
koder aka kdanilov4e9f3ed2015-04-14 11:26:12 +0300418 j_app("bw", raw_result["bw"])
koder aka kdanilovda45e882015-04-06 02:24:42 +0300419 j_app("iops", raw_result["iops"])
420 j_app("lat", raw_result["lat"]["mean"])
421 j_app("clat", raw_result["clat"]["mean"])
422 j_app("slat", raw_result["slat"]["mean"])
423
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300424 res[section.name] = j_res
koder aka kdanilovda45e882015-04-06 02:24:42 +0300425
426
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300427def run_fio(sliced_it, raw_results_func=None):
428 sliced_list = list(sliced_it)
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300429 ok = True
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300430
koder aka kdanilovda45e882015-04-06 02:24:42 +0300431 try:
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300432 curr_test_num = 0
433 executed_tests = 0
434 result = {}
koder aka kdanilovb896f692015-04-07 14:57:55 +0300435
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300436 for i, test_slice in enumerate(sliced_list):
437 res_cfg_it = do_run_fio(test_slice)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300438 res_cfg_it = enumerate(res_cfg_it, curr_test_num)
439
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300440 for curr_test_num, (job_output, section) in res_cfg_it:
koder aka kdanilov2e928022015-04-08 13:47:15 +0300441 executed_tests += 1
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300442
koder aka kdanilovda45e882015-04-06 02:24:42 +0300443 if raw_results_func is not None:
koder aka kdanilov2e928022015-04-08 13:47:15 +0300444 raw_results_func(executed_tests,
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300445 [job_output, section])
koder aka kdanilovda45e882015-04-06 02:24:42 +0300446
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300447 msg = "{0} != {1}".format(section.name, job_output["jobname"])
448 assert section.name == job_output["jobname"], msg
koder aka kdanilovda45e882015-04-06 02:24:42 +0300449
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300450 if section.name.startswith('_'):
koder aka kdanilovda45e882015-04-06 02:24:42 +0300451 continue
452
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300453 add_job_results(section, job_output, result)
454
koder aka kdanilove87ae652015-04-20 02:14:35 +0300455 curr_test_num += 1
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300456 msg_template = "Done {0} tests from {1}. ETA: {2}"
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300457
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300458 rest = sliced_list[i:]
459 time_eta = sum(map(calculate_execution_time, rest))
460 test_left = sum(map(len, rest))
461 print msg_template.format(curr_test_num,
462 test_left,
463 sec_to_str(time_eta))
koder aka kdanilov4500a5f2015-04-17 16:55:17 +0300464
koder aka kdanilovda45e882015-04-06 02:24:42 +0300465 except (SystemExit, KeyboardInterrupt):
koder aka kdanilov652cd802015-04-13 12:21:07 +0300466 raise
koder aka kdanilovda45e882015-04-06 02:24:42 +0300467
468 except Exception:
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300469 print "=========== ERROR ============="
koder aka kdanilovda45e882015-04-06 02:24:42 +0300470 traceback.print_exc()
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300471 print "======== END OF ERROR ========="
472 ok = False
koder aka kdanilovda45e882015-04-06 02:24:42 +0300473
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300474 return result, executed_tests, ok
koder aka kdanilovda45e882015-04-06 02:24:42 +0300475
476
477def run_benchmark(binary_tp, *argv, **kwargs):
478 if 'fio' == binary_tp:
479 return run_fio(*argv, **kwargs)
480 raise ValueError("Unknown behcnmark {0}".format(binary_tp))
481
482
koder aka kdanilov652cd802015-04-13 12:21:07 +0300483def read_config(fd, timeout=10):
484 job_cfg = ""
485 etime = time.time() + timeout
486 while True:
487 wtime = etime - time.time()
488 if wtime <= 0:
489 raise IOError("No config provided")
490
491 r, w, x = select.select([fd], [], [], wtime)
492 if len(r) == 0:
493 raise IOError("No config provided")
494
495 char = fd.read(1)
496 if '' == char:
497 return job_cfg
498
499 job_cfg += char
500
501
koder aka kdanilov652cd802015-04-13 12:21:07 +0300502def sec_to_str(seconds):
503 h = seconds // 3600
504 m = (seconds % 3600) // 60
505 s = seconds % 60
506 return "{0}:{1:02d}:{2:02d}".format(h, m, s)
507
508
koder aka kdanilovda45e882015-04-06 02:24:42 +0300509def parse_args(argv):
510 parser = argparse.ArgumentParser(
511 description="Run fio' and return result")
512 parser.add_argument("--type", metavar="BINARY_TYPE",
513 choices=['fio'], default='fio',
514 help=argparse.SUPPRESS)
515 parser.add_argument("--start-at", metavar="START_AT_UTC", type=int,
516 help="Start execution at START_AT_UTC")
517 parser.add_argument("--json", action="store_true", default=False,
518 help="Json output format")
519 parser.add_argument("--output", default='-', metavar="FILE_PATH",
520 help="Store results to FILE_PATH")
521 parser.add_argument("--estimate", action="store_true", default=False,
522 help="Only estimate task execution time")
523 parser.add_argument("--compile", action="store_true", default=False,
524 help="Compile config file to fio config")
525 parser.add_argument("--num-tests", action="store_true", default=False,
526 help="Show total number of tests")
527 parser.add_argument("--runcycle", type=int, default=None,
528 metavar="MAX_CYCLE_SECONDS",
529 help="Max cycle length in seconds")
530 parser.add_argument("--show-raw-results", action='store_true',
531 default=False, help="Output raw input and results")
koder aka kdanilovda45e882015-04-06 02:24:42 +0300532 parser.add_argument("--params", nargs="*", metavar="PARAM=VAL",
533 default=[],
534 help="Provide set of pairs PARAM=VAL to" +
535 "format into job description")
536 parser.add_argument("jobfile")
537 return parser.parse_args(argv)
538
539
koder aka kdanilovda45e882015-04-06 02:24:42 +0300540def main(argv):
541 argv_obj = parse_args(argv)
542
543 if argv_obj.jobfile == '-':
544 job_cfg = read_config(sys.stdin)
545 else:
546 job_cfg = open(argv_obj.jobfile).read()
547
548 if argv_obj.output == '-':
549 out_fd = sys.stdout
550 else:
551 out_fd = open(argv_obj.output, "w")
552
553 params = {}
554 for param_val in argv_obj.params:
555 assert '=' in param_val
556 name, val = param_val.split("=", 1)
557 params[name] = val
558
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300559 slice_params = {
560 'runcycle': argv_obj.runcycle,
561 }
562
563 sliced_it = parse_and_slice_all_in_1(job_cfg, params, **slice_params)
564
koder aka kdanilov652cd802015-04-13 12:21:07 +0300565 if argv_obj.estimate:
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300566 it = map(calculate_execution_time, sliced_it)
567 print sec_to_str(sum(it))
koder aka kdanilov652cd802015-04-13 12:21:07 +0300568 return 0
569
570 if argv_obj.num_tests or argv_obj.compile:
koder aka kdanilovda45e882015-04-06 02:24:42 +0300571 if argv_obj.compile:
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300572 for test_slice in sliced_it:
573 out_fd.write(fio_config_to_str(test_slice))
574 out_fd.write("\n#" + "-" * 70 + "\n\n")
koder aka kdanilovda45e882015-04-06 02:24:42 +0300575
576 if argv_obj.num_tests:
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300577 print len(list(sliced_it))
koder aka kdanilovda45e882015-04-06 02:24:42 +0300578
koder aka kdanilovda45e882015-04-06 02:24:42 +0300579 return 0
580
581 if argv_obj.start_at is not None:
582 ctime = time.time()
583 if argv_obj.start_at >= ctime:
584 time.sleep(ctime - argv_obj.start_at)
585
586 def raw_res_func(test_num, data):
587 pref = "========= RAW_RESULTS({0}) =========\n".format(test_num)
588 out_fd.write(pref)
589 out_fd.write(json.dumps(data))
590 out_fd.write("\n========= END OF RAW_RESULTS =========\n")
591 out_fd.flush()
592
593 rrfunc = raw_res_func if argv_obj.show_raw_results else None
594
595 stime = time.time()
koder aka kdanilov0c598a12015-04-21 03:01:40 +0300596 job_res, num_tests, ok = run_benchmark(argv_obj.type, sliced_it, rrfunc)
koder aka kdanilovda45e882015-04-06 02:24:42 +0300597 etime = time.time()
598
koder aka kdanilov652cd802015-04-13 12:21:07 +0300599 res = {'__meta__': {'raw_cfg': job_cfg, 'params': params}, 'res': job_res}
koder aka kdanilovda45e882015-04-06 02:24:42 +0300600
601 oformat = 'json' if argv_obj.json else 'eval'
koder aka kdanilov652cd802015-04-13 12:21:07 +0300602 out_fd.write("\nRun {0} tests in {1} seconds\n".format(num_tests,
603 int(etime - stime)))
koder aka kdanilovda45e882015-04-06 02:24:42 +0300604 out_fd.write("========= RESULTS(format={0}) =========\n".format(oformat))
605 if argv_obj.json:
606 out_fd.write(json.dumps(res))
607 else:
608 out_fd.write(pprint.pformat(res) + "\n")
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300609 out_fd.write("\n========= END OF RESULTS =========\n")
koder aka kdanilovda45e882015-04-06 02:24:42 +0300610
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300611 return 0 if ok else 1
612
613
614def fake_main(x):
615 import yaml
616 time.sleep(60)
617 out_fd = sys.stdout
618 fname = "/tmp/perf_tests/metempirical_alisha/raw_results.yaml"
619 res = yaml.load(open(fname).read())[0][1]
620 out_fd.write("========= RESULTS(format=json) =========\n")
621 out_fd.write(json.dumps(res))
622 out_fd.write("\n========= END OF RESULTS =========\n")
koder aka kdanilovda45e882015-04-06 02:24:42 +0300623 return 0
624
625
626if __name__ == '__main__':
koder aka kdanilovcff7b2e2015-04-18 20:48:15 +0300627 # exit(fake_main(sys.argv[1:]))
koder aka kdanilovda45e882015-04-06 02:24:42 +0300628 exit(main(sys.argv[1:]))