| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 1 | import sys | 
 | 2 | import time | 
 | 3 | import json | 
| koder aka kdanilov | b896f69 | 2015-04-07 14:57:55 +0300 | [diff] [blame] | 4 | import random | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 5 | import select | 
 | 6 | import pprint | 
 | 7 | import argparse | 
 | 8 | import traceback | 
 | 9 | import subprocess | 
 | 10 | import itertools | 
 | 11 | from collections import OrderedDict | 
 | 12 |  | 
 | 13 |  | 
 | 14 | SECTION = 0 | 
 | 15 | SETTING = 1 | 
 | 16 |  | 
 | 17 |  | 
| koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 18 | def get_test_sync_mode(config): | 
| koder aka kdanilov | 4e9f3ed | 2015-04-14 11:26:12 +0300 | [diff] [blame] | 19 |     try: | 
| koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 20 |         return config['sync_mode'] | 
| koder aka kdanilov | 4e9f3ed | 2015-04-14 11:26:12 +0300 | [diff] [blame] | 21 |     except KeyError: | 
 | 22 |         pass | 
 | 23 |  | 
| koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 24 |     is_sync = config.get("sync", "0") == "1" | 
 | 25 |     is_direct = config.get("direct", "0") == "1" | 
| koder aka kdanilov | 4e9f3ed | 2015-04-14 11:26:12 +0300 | [diff] [blame] | 26 |  | 
 | 27 |     if is_sync and is_direct: | 
 | 28 |         return 'x' | 
 | 29 |     elif is_sync: | 
 | 30 |         return 's' | 
 | 31 |     elif is_direct: | 
 | 32 |         return 'd' | 
 | 33 |     else: | 
 | 34 |         return 'a' | 
 | 35 |  | 
 | 36 |  | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 37 | def get_test_summary(params): | 
 | 38 |     rw = {"randread": "rr", | 
 | 39 |           "randwrite": "rw", | 
 | 40 |           "read": "sr", | 
 | 41 |           "write": "sw"}[params["rw"]] | 
 | 42 |  | 
| koder aka kdanilov | 4e9f3ed | 2015-04-14 11:26:12 +0300 | [diff] [blame] | 43 |     sync_mode = get_test_sync_mode(params) | 
 | 44 |     th_count = params.get('numjobs') | 
 | 45 |     if th_count is None: | 
 | 46 |         th_count = params.get('concurence', '1') | 
 | 47 |     th_count = int(th_count) | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 48 |  | 
| koder aka kdanilov | 4e9f3ed | 2015-04-14 11:26:12 +0300 | [diff] [blame] | 49 |     return "{0}{1}{2}th{3}".format(rw, | 
 | 50 |                                    sync_mode, | 
 | 51 |                                    params['blocksize'], | 
 | 52 |                                    th_count) | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 53 |  | 
 | 54 |  | 
 | 55 | counter = [0] | 
 | 56 |  | 
 | 57 |  | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 58 | def extract_iterables(vals): | 
 | 59 |     iterable_names = [] | 
 | 60 |     iterable_values = [] | 
 | 61 |     rest = {} | 
 | 62 |  | 
 | 63 |     for val_name, val in vals.items(): | 
 | 64 |         if val is None or not val.startswith('{%'): | 
 | 65 |             rest[val_name] = val | 
 | 66 |         else: | 
 | 67 |             assert val.endswith("%}") | 
 | 68 |             content = val[2:-2] | 
 | 69 |             iterable_names.append(val_name) | 
 | 70 |             iterable_values.append(list(i.strip() for i in content.split(','))) | 
 | 71 |  | 
 | 72 |     return iterable_names, iterable_values, rest | 
 | 73 |  | 
 | 74 |  | 
 | 75 | def format_params_into_section(sec, params, final=True): | 
 | 76 |     processed_vals = {} | 
 | 77 |  | 
 | 78 |     for val_name, val in sec.items(): | 
 | 79 |         if val is None: | 
 | 80 |             processed_vals[val_name] = val | 
 | 81 |         else: | 
 | 82 |             try: | 
 | 83 |                 processed_vals[val_name] = val.format(**params) | 
 | 84 |             except KeyError: | 
 | 85 |                 if final: | 
 | 86 |                     raise | 
 | 87 |                 processed_vals[val_name] = val | 
 | 88 |  | 
 | 89 |     return processed_vals | 
 | 90 |  | 
 | 91 |  | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 92 | def process_section(name, vals, defaults, format_params): | 
 | 93 |     vals = vals.copy() | 
 | 94 |     params = format_params.copy() | 
 | 95 |  | 
 | 96 |     if '*' in name: | 
 | 97 |         name, repeat = name.split('*') | 
 | 98 |         name = name.strip() | 
 | 99 |         repeat = int(repeat.format(**params)) | 
 | 100 |     else: | 
 | 101 |         repeat = 1 | 
 | 102 |  | 
 | 103 |     # this code can be optimized | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 104 |     iterable_names, iterable_values, processed_vals = extract_iterables(vals) | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 105 |  | 
| koder aka kdanilov | 2e92802 | 2015-04-08 13:47:15 +0300 | [diff] [blame] | 106 |     group_report_err_msg = "Group reporting should be set if numjobs != 1" | 
 | 107 |  | 
| koder aka kdanilov | b896f69 | 2015-04-07 14:57:55 +0300 | [diff] [blame] | 108 |     if iterable_values == []: | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 109 |         processed_vals = format_params_into_section(processed_vals, params, | 
 | 110 |                                                     final=False) | 
| koder aka kdanilov | b896f69 | 2015-04-07 14:57:55 +0300 | [diff] [blame] | 111 |         params['UNIQ'] = 'UN{0}'.format(counter[0]) | 
 | 112 |         counter[0] += 1 | 
 | 113 |         params['TEST_SUMM'] = get_test_summary(processed_vals) | 
| koder aka kdanilov | 2e92802 | 2015-04-08 13:47:15 +0300 | [diff] [blame] | 114 |  | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 115 |         num_jobs = int(processed_vals.get('numjobs', '1')) | 
 | 116 |         fsize = to_bytes(processed_vals['size']) | 
 | 117 |         params['PER_TH_OFFSET'] = fsize // num_jobs | 
 | 118 |  | 
 | 119 |         processed_vals = format_params_into_section(processed_vals, params, | 
 | 120 |                                                     final=True) | 
 | 121 |  | 
 | 122 |         if num_jobs != 1: | 
| koder aka kdanilov | 2e92802 | 2015-04-08 13:47:15 +0300 | [diff] [blame] | 123 |             assert 'group_reporting' in processed_vals, group_report_err_msg | 
 | 124 |  | 
| koder aka kdanilov | 652cd80 | 2015-04-13 12:21:07 +0300 | [diff] [blame] | 125 |         ramp_time = processed_vals.get('ramp_time') | 
| koder aka kdanilov | b896f69 | 2015-04-07 14:57:55 +0300 | [diff] [blame] | 126 |         for i in range(repeat): | 
| koder aka kdanilov | 2e92802 | 2015-04-08 13:47:15 +0300 | [diff] [blame] | 127 |             yield name.format(**params), processed_vals.copy() | 
| koder aka kdanilov | 652cd80 | 2015-04-13 12:21:07 +0300 | [diff] [blame] | 128 |  | 
 | 129 |             if 'ramp_time' in processed_vals: | 
 | 130 |                 del processed_vals['ramp_time'] | 
 | 131 |  | 
 | 132 |         if ramp_time is not None: | 
 | 133 |             processed_vals['ramp_time'] = ramp_time | 
| koder aka kdanilov | b896f69 | 2015-04-07 14:57:55 +0300 | [diff] [blame] | 134 |     else: | 
 | 135 |         for it_vals in itertools.product(*iterable_values): | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 136 |             processed_vals = format_params_into_section(processed_vals, params, | 
 | 137 |                                                         final=False) | 
 | 138 |  | 
| koder aka kdanilov | b896f69 | 2015-04-07 14:57:55 +0300 | [diff] [blame] | 139 |             processed_vals.update(dict(zip(iterable_names, it_vals))) | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 140 |             params['UNIQ'] = 'UN{0}'.format(counter[0]) | 
 | 141 |             counter[0] += 1 | 
 | 142 |             params['TEST_SUMM'] = get_test_summary(processed_vals) | 
| koder aka kdanilov | 2e92802 | 2015-04-08 13:47:15 +0300 | [diff] [blame] | 143 |  | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 144 |             num_jobs = int(processed_vals.get('numjobs', '1')) | 
 | 145 |             fsize = to_bytes(processed_vals['size']) | 
 | 146 |             params['PER_TH_OFFSET'] = fsize // num_jobs | 
 | 147 |  | 
 | 148 |             processed_vals = format_params_into_section(processed_vals, params, | 
 | 149 |                                                         final=True) | 
 | 150 |  | 
| koder aka kdanilov | 2e92802 | 2015-04-08 13:47:15 +0300 | [diff] [blame] | 151 |             if processed_vals.get('numjobs', '1') != '1': | 
 | 152 |                 assert 'group_reporting' in processed_vals,\ | 
 | 153 |                     group_report_err_msg | 
 | 154 |  | 
| koder aka kdanilov | 66839a9 | 2015-04-11 13:22:31 +0300 | [diff] [blame] | 155 |             ramp_time = processed_vals.get('ramp_time') | 
 | 156 |  | 
| koder aka kdanilov | b896f69 | 2015-04-07 14:57:55 +0300 | [diff] [blame] | 157 |             for i in range(repeat): | 
 | 158 |                 yield name.format(**params), processed_vals.copy() | 
| koder aka kdanilov | 66839a9 | 2015-04-11 13:22:31 +0300 | [diff] [blame] | 159 |                 if 'ramp_time' in processed_vals: | 
| koder aka kdanilov | 4500a5f | 2015-04-17 16:55:17 +0300 | [diff] [blame] | 160 |                     processed_vals['_ramp_time'] = ramp_time | 
 | 161 |                     processed_vals.pop('ramp_time') | 
| koder aka kdanilov | 66839a9 | 2015-04-11 13:22:31 +0300 | [diff] [blame] | 162 |  | 
 | 163 |             if ramp_time is not None: | 
 | 164 |                 processed_vals['ramp_time'] = ramp_time | 
| koder aka kdanilov | 4500a5f | 2015-04-17 16:55:17 +0300 | [diff] [blame] | 165 |                 processed_vals.pop('_ramp_time') | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 166 |  | 
 | 167 |  | 
 | 168 | def calculate_execution_time(combinations): | 
 | 169 |     time = 0 | 
 | 170 |     for _, params in combinations: | 
 | 171 |         time += int(params.get('ramp_time', 0)) | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 172 |         time += int(params.get('_ramp_time', 0)) | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 173 |         time += int(params.get('runtime', 0)) | 
 | 174 |     return time | 
 | 175 |  | 
 | 176 |  | 
 | 177 | def parse_fio_config_full(fio_cfg, params=None): | 
 | 178 |     defaults = {} | 
 | 179 |     format_params = {} | 
 | 180 |  | 
 | 181 |     if params is None: | 
 | 182 |         ext_params = {} | 
 | 183 |     else: | 
 | 184 |         ext_params = params.copy() | 
 | 185 |  | 
 | 186 |     curr_section = None | 
 | 187 |     curr_section_name = None | 
 | 188 |  | 
 | 189 |     for tp, name, val in parse_fio_config_iter(fio_cfg): | 
 | 190 |         if tp == SECTION: | 
 | 191 |             non_def = curr_section_name != 'defaults' | 
 | 192 |             if curr_section_name is not None and non_def: | 
 | 193 |                 format_params.update(ext_params) | 
 | 194 |                 for sec in process_section(curr_section_name, | 
 | 195 |                                            curr_section, | 
 | 196 |                                            defaults, | 
 | 197 |                                            format_params): | 
 | 198 |                     yield sec | 
 | 199 |  | 
 | 200 |             if name == 'defaults': | 
 | 201 |                 curr_section = defaults | 
 | 202 |             else: | 
 | 203 |                 curr_section = OrderedDict() | 
 | 204 |                 curr_section.update(defaults) | 
 | 205 |             curr_section_name = name | 
 | 206 |  | 
 | 207 |         else: | 
 | 208 |             assert tp == SETTING | 
 | 209 |             assert curr_section_name is not None, "no section name" | 
 | 210 |             if name == name.upper(): | 
 | 211 |                 assert curr_section_name == 'defaults' | 
 | 212 |                 format_params[name] = val | 
 | 213 |             else: | 
 | 214 |                 curr_section[name] = val | 
 | 215 |  | 
 | 216 |     if curr_section_name is not None and curr_section_name != 'defaults': | 
 | 217 |         format_params.update(ext_params) | 
 | 218 |         for sec in process_section(curr_section_name, | 
 | 219 |                                    curr_section, | 
 | 220 |                                    defaults, | 
 | 221 |                                    format_params): | 
 | 222 |             yield sec | 
 | 223 |  | 
 | 224 |  | 
 | 225 | def parse_fio_config_iter(fio_cfg): | 
 | 226 |     for lineno, line in enumerate(fio_cfg.split("\n")): | 
 | 227 |         try: | 
 | 228 |             line = line.strip() | 
 | 229 |  | 
 | 230 |             if line.startswith("#") or line.startswith(";"): | 
 | 231 |                 continue | 
 | 232 |  | 
 | 233 |             if line == "": | 
 | 234 |                 continue | 
 | 235 |  | 
 | 236 |             if line.startswith('['): | 
 | 237 |                 assert line.endswith(']'), "name should ends with ]" | 
 | 238 |                 yield SECTION, line[1:-1], None | 
 | 239 |             elif '=' in line: | 
 | 240 |                 opt_name, opt_val = line.split('=', 1) | 
 | 241 |                 yield SETTING, opt_name.strip(), opt_val.strip() | 
 | 242 |             else: | 
 | 243 |                 yield SETTING, line, None | 
 | 244 |         except Exception as exc: | 
 | 245 |             pref = "During parsing line number {0}\n".format(lineno) | 
 | 246 |             raise ValueError(pref + exc.message) | 
 | 247 |  | 
 | 248 |  | 
 | 249 | def format_fio_config(fio_cfg): | 
 | 250 |     res = "" | 
 | 251 |     for pos, (name, section) in enumerate(fio_cfg): | 
| koder aka kdanilov | 4500a5f | 2015-04-17 16:55:17 +0300 | [diff] [blame] | 252 |         if name.startswith('_'): | 
 | 253 |             continue | 
 | 254 |  | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 255 |         if pos != 0: | 
 | 256 |             res += "\n" | 
 | 257 |  | 
 | 258 |         res += "[{0}]\n".format(name) | 
 | 259 |         for opt_name, opt_val in section.items(): | 
 | 260 |             if opt_val is None: | 
 | 261 |                 res += opt_name + "\n" | 
 | 262 |             else: | 
 | 263 |                 res += "{0}={1}\n".format(opt_name, opt_val) | 
 | 264 |     return res | 
 | 265 |  | 
 | 266 |  | 
| koder aka kdanilov | b896f69 | 2015-04-07 14:57:55 +0300 | [diff] [blame] | 267 | count = 0 | 
 | 268 |  | 
 | 269 |  | 
 | 270 | def to_bytes(sz): | 
 | 271 |     sz = sz.lower() | 
 | 272 |     try: | 
 | 273 |         return int(sz) | 
 | 274 |     except ValueError: | 
 | 275 |         if sz[-1] == 'm': | 
 | 276 |             return (1024 ** 2) * int(sz[:-1]) | 
 | 277 |         if sz[-1] == 'k': | 
 | 278 |             return 1024 * int(sz[:-1]) | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 279 |         if sz[-1] == 'g': | 
 | 280 |             return (1024 ** 3) * int(sz[:-1]) | 
| koder aka kdanilov | b896f69 | 2015-04-07 14:57:55 +0300 | [diff] [blame] | 281 |         raise | 
 | 282 |  | 
 | 283 |  | 
| koder aka kdanilov | b896f69 | 2015-04-07 14:57:55 +0300 | [diff] [blame] | 284 | def do_run_fio_fake(bconf): | 
| koder aka kdanilov | 66839a9 | 2015-04-11 13:22:31 +0300 | [diff] [blame] | 285 |     def estimate_iops(sz, bw, lat): | 
 | 286 |         return 1 / (lat + float(sz) / bw) | 
| koder aka kdanilov | b896f69 | 2015-04-07 14:57:55 +0300 | [diff] [blame] | 287 |     global count | 
 | 288 |     count += 1 | 
 | 289 |     parsed_out = [] | 
 | 290 |  | 
 | 291 |     BW = 120.0 * (1024 ** 2) | 
 | 292 |     LAT = 0.003 | 
 | 293 |  | 
 | 294 |     for name, cfg in bconf: | 
 | 295 |         sz = to_bytes(cfg['blocksize']) | 
 | 296 |         curr_lat = LAT * ((random.random() - 0.5) * 0.1 + 1) | 
 | 297 |         curr_ulat = curr_lat * 1000000 | 
 | 298 |         curr_bw = BW * ((random.random() - 0.5) * 0.1 + 1) | 
 | 299 |         iops = estimate_iops(sz, curr_bw, curr_lat) | 
 | 300 |         bw = iops * sz | 
 | 301 |  | 
 | 302 |         res = {'ctx': 10683, | 
 | 303 |                'error': 0, | 
 | 304 |                'groupid': 0, | 
 | 305 |                'jobname': name, | 
 | 306 |                'majf': 0, | 
 | 307 |                'minf': 30, | 
 | 308 |                'read': {'bw': 0, | 
 | 309 |                         'bw_agg': 0.0, | 
 | 310 |                         'bw_dev': 0.0, | 
 | 311 |                         'bw_max': 0, | 
 | 312 |                         'bw_mean': 0.0, | 
 | 313 |                         'bw_min': 0, | 
 | 314 |                         'clat': {'max': 0, | 
 | 315 |                                  'mean': 0.0, | 
 | 316 |                                  'min': 0, | 
 | 317 |                                  'stddev': 0.0}, | 
 | 318 |                         'io_bytes': 0, | 
 | 319 |                         'iops': 0, | 
 | 320 |                         'lat': {'max': 0, 'mean': 0.0, | 
 | 321 |                                 'min': 0, 'stddev': 0.0}, | 
 | 322 |                         'runtime': 0, | 
 | 323 |                         'slat': {'max': 0, 'mean': 0.0, | 
 | 324 |                                  'min': 0, 'stddev': 0.0} | 
 | 325 |                         }, | 
 | 326 |                'sys_cpu': 0.64, | 
 | 327 |                'trim': {'bw': 0, | 
 | 328 |                         'bw_agg': 0.0, | 
 | 329 |                         'bw_dev': 0.0, | 
 | 330 |                         'bw_max': 0, | 
 | 331 |                         'bw_mean': 0.0, | 
 | 332 |                         'bw_min': 0, | 
 | 333 |                         'clat': {'max': 0, | 
 | 334 |                                  'mean': 0.0, | 
 | 335 |                                  'min': 0, | 
 | 336 |                                  'stddev': 0.0}, | 
 | 337 |                         'io_bytes': 0, | 
 | 338 |                         'iops': 0, | 
 | 339 |                         'lat': {'max': 0, 'mean': 0.0, | 
 | 340 |                                 'min': 0, 'stddev': 0.0}, | 
 | 341 |                         'runtime': 0, | 
 | 342 |                         'slat': {'max': 0, 'mean': 0.0, | 
 | 343 |                                  'min': 0, 'stddev': 0.0} | 
 | 344 |                         }, | 
 | 345 |                'usr_cpu': 0.23, | 
 | 346 |                'write': {'bw': 0, | 
 | 347 |                          'bw_agg': 0, | 
 | 348 |                          'bw_dev': 0, | 
 | 349 |                          'bw_max': 0, | 
 | 350 |                          'bw_mean': 0, | 
 | 351 |                          'bw_min': 0, | 
 | 352 |                          'clat': {'max': 0, 'mean': 0, | 
 | 353 |                                   'min': 0, 'stddev': 0}, | 
 | 354 |                          'io_bytes': 0, | 
 | 355 |                          'iops': 0, | 
 | 356 |                          'lat': {'max': 0, 'mean': 0, | 
 | 357 |                                  'min': 0, 'stddev': 0}, | 
 | 358 |                          'runtime': 0, | 
 | 359 |                          'slat': {'max': 0, 'mean': 0.0, | 
 | 360 |                                   'min': 0, 'stddev': 0.0} | 
 | 361 |                          } | 
 | 362 |                } | 
 | 363 |  | 
 | 364 |         if cfg['rw'] in ('read', 'randread'): | 
 | 365 |             key = 'read' | 
 | 366 |         elif cfg['rw'] in ('write', 'randwrite'): | 
 | 367 |             key = 'write' | 
 | 368 |         else: | 
 | 369 |             raise ValueError("Uknown op type {0}".format(key)) | 
 | 370 |  | 
 | 371 |         res[key]['bw'] = bw | 
 | 372 |         res[key]['iops'] = iops | 
 | 373 |         res[key]['runtime'] = 30 | 
 | 374 |         res[key]['io_bytes'] = res[key]['runtime'] * bw | 
 | 375 |         res[key]['bw_agg'] = bw | 
 | 376 |         res[key]['bw_dev'] = bw / 30 | 
 | 377 |         res[key]['bw_max'] = bw * 1.5 | 
 | 378 |         res[key]['bw_min'] = bw / 1.5 | 
 | 379 |         res[key]['bw_mean'] = bw | 
 | 380 |         res[key]['clat'] = {'max': curr_ulat * 10, 'mean': curr_ulat, | 
 | 381 |                             'min': curr_ulat / 2, 'stddev': curr_ulat} | 
 | 382 |         res[key]['lat'] = res[key]['clat'].copy() | 
 | 383 |         res[key]['slat'] = res[key]['clat'].copy() | 
 | 384 |  | 
 | 385 |         parsed_out.append(res) | 
 | 386 |  | 
 | 387 |     return zip(parsed_out, bconf) | 
 | 388 |  | 
 | 389 |  | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 390 | def do_run_fio(bconf): | 
 | 391 |     benchmark_config = format_fio_config(bconf) | 
| koder aka kdanilov | 4500a5f | 2015-04-17 16:55:17 +0300 | [diff] [blame] | 392 |     cmd = ["fio", "--output-format=json", "--alloc-size=262144", "-"] | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 393 |     p = subprocess.Popen(cmd, | 
 | 394 |                          stdin=subprocess.PIPE, | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 395 |                          stdout=subprocess.PIPE, | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 396 |                          stderr=subprocess.PIPE) | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 397 |  | 
 | 398 |     # set timeout | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 399 |     raw_out, raw_err = p.communicate(benchmark_config) | 
 | 400 |  | 
 | 401 |     if 0 != p.returncode: | 
 | 402 |         msg = "Fio failed with code: {0}\nOutput={1}" | 
 | 403 |         raise OSError(msg.format(p.returncode, raw_err)) | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 404 |  | 
 | 405 |     try: | 
 | 406 |         parsed_out = json.loads(raw_out)["jobs"] | 
| koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 407 |     except KeyError: | 
 | 408 |         msg = "Can't parse fio output {0!r}: no 'jobs' found" | 
 | 409 |         raw_out = raw_out[:100] | 
 | 410 |         raise ValueError(msg.format(raw_out)) | 
 | 411 |  | 
 | 412 |     except Exception as exc: | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 413 |         msg = "Can't parse fio output: {0!r}\nError: {1}" | 
| koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 414 |         raw_out = raw_out[:100] | 
 | 415 |         raise ValueError(msg.format(raw_out, exc.message)) | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 416 |  | 
 | 417 |     return zip(parsed_out, bconf) | 
 | 418 |  | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 419 | # limited by fio | 
 | 420 | MAX_JOBS = 1000 | 
 | 421 |  | 
 | 422 |  | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 423 | def next_test_portion(whole_conf, runcycle, cluster=False): | 
 | 424 |     if cluster: | 
 | 425 |         for name, sec in whole_conf: | 
 | 426 |             if '_ramp_time' in sec: | 
 | 427 |                 sec['ramp_time'] = sec.pop('_ramp_time') | 
 | 428 |             yield [(name, sec)] | 
 | 429 |         return | 
 | 430 |  | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 431 |     jcount = 0 | 
 | 432 |     runtime = 0 | 
 | 433 |     bconf = [] | 
 | 434 |  | 
 | 435 |     for pos, (name, sec) in enumerate(whole_conf): | 
 | 436 |         jc = int(sec.get('numjobs', '1')) | 
 | 437 |  | 
 | 438 |         if runcycle is not None: | 
 | 439 |             curr_task_time = calculate_execution_time([(name, sec)]) | 
 | 440 |         else: | 
 | 441 |             curr_task_time = 0 | 
 | 442 |  | 
 | 443 |         if jc > MAX_JOBS: | 
 | 444 |             err_templ = "Can't process job {0!r} - too large numjobs" | 
 | 445 |             raise ValueError(err_templ.format(name)) | 
 | 446 |  | 
 | 447 |         if runcycle is not None and len(bconf) != 0: | 
 | 448 |             rc_ok = curr_task_time + runtime <= runcycle | 
 | 449 |         else: | 
 | 450 |             rc_ok = True | 
 | 451 |  | 
 | 452 |         if jc + jcount <= MAX_JOBS and rc_ok: | 
 | 453 |             runtime += curr_task_time | 
 | 454 |             jcount += jc | 
 | 455 |             bconf.append((name, sec)) | 
| koder aka kdanilov | 4500a5f | 2015-04-17 16:55:17 +0300 | [diff] [blame] | 456 |             if '_ramp_time' in sec: | 
 | 457 |                 del sec['_ramp_time'] | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 458 |             continue | 
 | 459 |  | 
 | 460 |         assert len(bconf) != 0 | 
 | 461 |         yield bconf | 
 | 462 |  | 
| koder aka kdanilov | 4500a5f | 2015-04-17 16:55:17 +0300 | [diff] [blame] | 463 |         if '_ramp_time' in sec: | 
 | 464 |             sec['ramp_time'] = sec.pop('_ramp_time') | 
 | 465 |             curr_task_time = calculate_execution_time([(name, sec)]) | 
 | 466 |  | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 467 |         runtime = curr_task_time | 
 | 468 |         jcount = jc | 
 | 469 |         bconf = [(name, sec)] | 
 | 470 |  | 
 | 471 |     if bconf != []: | 
 | 472 |         yield bconf | 
 | 473 |  | 
 | 474 |  | 
 | 475 | def add_job_results(jname, job_output, jconfig, res): | 
 | 476 |     if job_output['write']['iops'] != 0: | 
 | 477 |         raw_result = job_output['write'] | 
 | 478 |     else: | 
 | 479 |         raw_result = job_output['read'] | 
 | 480 |  | 
 | 481 |     if jname not in res: | 
 | 482 |         j_res = {} | 
| koder aka kdanilov | 4e9f3ed | 2015-04-14 11:26:12 +0300 | [diff] [blame] | 483 |         j_res["rw"] = jconfig["rw"] | 
| koder aka kdanilov | 652cd80 | 2015-04-13 12:21:07 +0300 | [diff] [blame] | 484 |         j_res["sync_mode"] = get_test_sync_mode(jconfig) | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 485 |         j_res["concurence"] = int(jconfig.get("numjobs", 1)) | 
| koder aka kdanilov | 2e92802 | 2015-04-08 13:47:15 +0300 | [diff] [blame] | 486 |         j_res["blocksize"] = jconfig["blocksize"] | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 487 |         j_res["jobname"] = job_output["jobname"] | 
| koder aka kdanilov | 66839a9 | 2015-04-11 13:22:31 +0300 | [diff] [blame] | 488 |         j_res["timings"] = [int(jconfig.get("runtime", 0)), | 
 | 489 |                             int(jconfig.get("ramp_time", 0))] | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 490 |     else: | 
 | 491 |         j_res = res[jname] | 
| koder aka kdanilov | 4e9f3ed | 2015-04-14 11:26:12 +0300 | [diff] [blame] | 492 |         assert j_res["rw"] == jconfig["rw"] | 
 | 493 |         assert j_res["rw"] == jconfig["rw"] | 
| koder aka kdanilov | 652cd80 | 2015-04-13 12:21:07 +0300 | [diff] [blame] | 494 |         assert j_res["sync_mode"] == get_test_sync_mode(jconfig) | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 495 |         assert j_res["concurence"] == int(jconfig.get("numjobs", 1)) | 
| koder aka kdanilov | 2e92802 | 2015-04-08 13:47:15 +0300 | [diff] [blame] | 496 |         assert j_res["blocksize"] == jconfig["blocksize"] | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 497 |         assert j_res["jobname"] == job_output["jobname"] | 
| koder aka kdanilov | 652cd80 | 2015-04-13 12:21:07 +0300 | [diff] [blame] | 498 |  | 
 | 499 |         # ramp part is skipped for all tests, except first | 
 | 500 |         # assert j_res["timings"] == (jconfig.get("runtime"), | 
 | 501 |         #                             jconfig.get("ramp_time")) | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 502 |  | 
 | 503 |     def j_app(name, x): | 
 | 504 |         j_res.setdefault(name, []).append(x) | 
 | 505 |  | 
| koder aka kdanilov | 4e9f3ed | 2015-04-14 11:26:12 +0300 | [diff] [blame] | 506 |     j_app("bw", raw_result["bw"]) | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 507 |     j_app("iops", raw_result["iops"]) | 
 | 508 |     j_app("lat", raw_result["lat"]["mean"]) | 
 | 509 |     j_app("clat", raw_result["clat"]["mean"]) | 
 | 510 |     j_app("slat", raw_result["slat"]["mean"]) | 
 | 511 |  | 
 | 512 |     res[jname] = j_res | 
 | 513 |  | 
 | 514 |  | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 515 | def compile(benchmark_config, params, skip=0, runcycle=None, cluster=False): | 
| koder aka kdanilov | 4500a5f | 2015-04-17 16:55:17 +0300 | [diff] [blame] | 516 |     whole_conf = list(parse_fio_config_full(benchmark_config, params)) | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 517 |     whole_conf = whole_conf[skip:] | 
| koder aka kdanilov | 4500a5f | 2015-04-17 16:55:17 +0300 | [diff] [blame] | 518 |     res = "" | 
 | 519 |  | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 520 |     for bconf in next_test_portion(whole_conf, runcycle, cluster=cluster): | 
| koder aka kdanilov | 4500a5f | 2015-04-17 16:55:17 +0300 | [diff] [blame] | 521 |         res += format_fio_config(bconf) | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 522 |         res += "\n#" + "-" * 50 + "\n\n" | 
| koder aka kdanilov | 4500a5f | 2015-04-17 16:55:17 +0300 | [diff] [blame] | 523 |  | 
 | 524 |     return res | 
 | 525 |  | 
 | 526 |  | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 527 | def run_fio(benchmark_config, | 
 | 528 |             params, | 
 | 529 |             runcycle=None, | 
 | 530 |             raw_results_func=None, | 
| koder aka kdanilov | b896f69 | 2015-04-07 14:57:55 +0300 | [diff] [blame] | 531 |             skip_tests=0, | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 532 |             fake_fio=False, | 
 | 533 |             cluster=False): | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 534 |  | 
 | 535 |     whole_conf = list(parse_fio_config_full(benchmark_config, params)) | 
 | 536 |     whole_conf = whole_conf[skip_tests:] | 
 | 537 |     res = {} | 
 | 538 |     curr_test_num = skip_tests | 
| koder aka kdanilov | 2e92802 | 2015-04-08 13:47:15 +0300 | [diff] [blame] | 539 |     executed_tests = 0 | 
| koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 540 |     ok = True | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 541 |     try: | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 542 |         for bconf in next_test_portion(whole_conf, runcycle, cluster=cluster): | 
| koder aka kdanilov | b896f69 | 2015-04-07 14:57:55 +0300 | [diff] [blame] | 543 |  | 
 | 544 |             if fake_fio: | 
 | 545 |                 res_cfg_it = do_run_fio_fake(bconf) | 
 | 546 |             else: | 
 | 547 |                 res_cfg_it = do_run_fio(bconf) | 
 | 548 |  | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 549 |             res_cfg_it = enumerate(res_cfg_it, curr_test_num) | 
 | 550 |  | 
 | 551 |             for curr_test_num, (job_output, (jname, jconfig)) in res_cfg_it: | 
| koder aka kdanilov | 2e92802 | 2015-04-08 13:47:15 +0300 | [diff] [blame] | 552 |                 executed_tests += 1 | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 553 |                 if raw_results_func is not None: | 
| koder aka kdanilov | 2e92802 | 2015-04-08 13:47:15 +0300 | [diff] [blame] | 554 |                     raw_results_func(executed_tests, | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 555 |                                      [job_output, jname, jconfig]) | 
 | 556 |  | 
| koder aka kdanilov | b896f69 | 2015-04-07 14:57:55 +0300 | [diff] [blame] | 557 |                 assert jname == job_output["jobname"], \ | 
 | 558 |                     "{0} != {1}".format(jname, job_output["jobname"]) | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 559 |  | 
 | 560 |                 if jname.startswith('_'): | 
 | 561 |                     continue | 
 | 562 |  | 
 | 563 |                 add_job_results(jname, job_output, jconfig, res) | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 564 |             curr_test_num += 1 | 
| koder aka kdanilov | 4500a5f | 2015-04-17 16:55:17 +0300 | [diff] [blame] | 565 |             msg_template = "Done {0} tests from {1}. ETA: {2}" | 
 | 566 |             exec_time = estimate_cfg(benchmark_config, params, curr_test_num) | 
 | 567 |  | 
 | 568 |             print msg_template.format(curr_test_num - skip_tests, | 
 | 569 |                                       len(whole_conf), | 
 | 570 |                                       sec_to_str(exec_time)) | 
 | 571 |  | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 572 |     except (SystemExit, KeyboardInterrupt): | 
| koder aka kdanilov | 652cd80 | 2015-04-13 12:21:07 +0300 | [diff] [blame] | 573 |         raise | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 574 |  | 
 | 575 |     except Exception: | 
| koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 576 |         print "=========== ERROR =============" | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 577 |         traceback.print_exc() | 
| koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 578 |         print "======== END OF ERROR =========" | 
 | 579 |         ok = False | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 580 |  | 
| koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 581 |     return res, executed_tests, ok | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 582 |  | 
 | 583 |  | 
 | 584 | def run_benchmark(binary_tp, *argv, **kwargs): | 
 | 585 |     if 'fio' == binary_tp: | 
 | 586 |         return run_fio(*argv, **kwargs) | 
 | 587 |     raise ValueError("Unknown behcnmark {0}".format(binary_tp)) | 
 | 588 |  | 
 | 589 |  | 
| koder aka kdanilov | 652cd80 | 2015-04-13 12:21:07 +0300 | [diff] [blame] | 590 | def read_config(fd, timeout=10): | 
 | 591 |     job_cfg = "" | 
 | 592 |     etime = time.time() + timeout | 
 | 593 |     while True: | 
 | 594 |         wtime = etime - time.time() | 
 | 595 |         if wtime <= 0: | 
 | 596 |             raise IOError("No config provided") | 
 | 597 |  | 
 | 598 |         r, w, x = select.select([fd], [], [], wtime) | 
 | 599 |         if len(r) == 0: | 
 | 600 |             raise IOError("No config provided") | 
 | 601 |  | 
 | 602 |         char = fd.read(1) | 
 | 603 |         if '' == char: | 
 | 604 |             return job_cfg | 
 | 605 |  | 
 | 606 |         job_cfg += char | 
 | 607 |  | 
 | 608 |  | 
| koder aka kdanilov | 4500a5f | 2015-04-17 16:55:17 +0300 | [diff] [blame] | 609 | def estimate_cfg(job_cfg, params, skip_tests=0): | 
 | 610 |     bconf = list(parse_fio_config_full(job_cfg, params))[skip_tests:] | 
| koder aka kdanilov | 652cd80 | 2015-04-13 12:21:07 +0300 | [diff] [blame] | 611 |     return calculate_execution_time(bconf) | 
 | 612 |  | 
 | 613 |  | 
 | 614 | def sec_to_str(seconds): | 
 | 615 |     h = seconds // 3600 | 
 | 616 |     m = (seconds % 3600) // 60 | 
 | 617 |     s = seconds % 60 | 
 | 618 |     return "{0}:{1:02d}:{2:02d}".format(h, m, s) | 
 | 619 |  | 
 | 620 |  | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 621 | def parse_args(argv): | 
 | 622 |     parser = argparse.ArgumentParser( | 
 | 623 |         description="Run fio' and return result") | 
 | 624 |     parser.add_argument("--type", metavar="BINARY_TYPE", | 
 | 625 |                         choices=['fio'], default='fio', | 
 | 626 |                         help=argparse.SUPPRESS) | 
 | 627 |     parser.add_argument("--start-at", metavar="START_AT_UTC", type=int, | 
 | 628 |                         help="Start execution at START_AT_UTC") | 
 | 629 |     parser.add_argument("--json", action="store_true", default=False, | 
 | 630 |                         help="Json output format") | 
 | 631 |     parser.add_argument("--output", default='-', metavar="FILE_PATH", | 
 | 632 |                         help="Store results to FILE_PATH") | 
 | 633 |     parser.add_argument("--estimate", action="store_true", default=False, | 
 | 634 |                         help="Only estimate task execution time") | 
 | 635 |     parser.add_argument("--compile", action="store_true", default=False, | 
 | 636 |                         help="Compile config file to fio config") | 
 | 637 |     parser.add_argument("--num-tests", action="store_true", default=False, | 
 | 638 |                         help="Show total number of tests") | 
 | 639 |     parser.add_argument("--runcycle", type=int, default=None, | 
 | 640 |                         metavar="MAX_CYCLE_SECONDS", | 
 | 641 |                         help="Max cycle length in seconds") | 
 | 642 |     parser.add_argument("--show-raw-results", action='store_true', | 
 | 643 |                         default=False, help="Output raw input and results") | 
 | 644 |     parser.add_argument("--skip-tests", type=int, default=0, metavar="NUM", | 
 | 645 |                         help="Skip NUM tests") | 
| koder aka kdanilov | b896f69 | 2015-04-07 14:57:55 +0300 | [diff] [blame] | 646 |     parser.add_argument("--faked-fio", action='store_true', | 
 | 647 |                         default=False, help="Emulate fio with 0 test time") | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 648 |     parser.add_argument("--cluster", action='store_true', | 
 | 649 |                         default=False, help="Apply cluster-test settings") | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 650 |     parser.add_argument("--params", nargs="*", metavar="PARAM=VAL", | 
 | 651 |                         default=[], | 
 | 652 |                         help="Provide set of pairs PARAM=VAL to" + | 
 | 653 |                              "format into job description") | 
 | 654 |     parser.add_argument("jobfile") | 
 | 655 |     return parser.parse_args(argv) | 
 | 656 |  | 
 | 657 |  | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 658 | def main(argv): | 
 | 659 |     argv_obj = parse_args(argv) | 
 | 660 |  | 
 | 661 |     if argv_obj.jobfile == '-': | 
 | 662 |         job_cfg = read_config(sys.stdin) | 
 | 663 |     else: | 
 | 664 |         job_cfg = open(argv_obj.jobfile).read() | 
 | 665 |  | 
 | 666 |     if argv_obj.output == '-': | 
 | 667 |         out_fd = sys.stdout | 
 | 668 |     else: | 
 | 669 |         out_fd = open(argv_obj.output, "w") | 
 | 670 |  | 
 | 671 |     params = {} | 
 | 672 |     for param_val in argv_obj.params: | 
 | 673 |         assert '=' in param_val | 
 | 674 |         name, val = param_val.split("=", 1) | 
 | 675 |         params[name] = val | 
 | 676 |  | 
| koder aka kdanilov | 652cd80 | 2015-04-13 12:21:07 +0300 | [diff] [blame] | 677 |     if argv_obj.estimate: | 
 | 678 |         print sec_to_str(estimate_cfg(job_cfg, params)) | 
 | 679 |         return 0 | 
 | 680 |  | 
 | 681 |     if argv_obj.num_tests or argv_obj.compile: | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 682 |         if argv_obj.compile: | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 683 |             data = compile(job_cfg, params, argv_obj.skip_tests, | 
 | 684 |                            cluster=argv_obj.cluster) | 
 | 685 |             out_fd.write(data) | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 686 |             out_fd.write("\n") | 
 | 687 |  | 
 | 688 |         if argv_obj.num_tests: | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 689 |             bconf = list(parse_fio_config_full(job_cfg, params, | 
 | 690 |                                                argv_obj.cluster)) | 
 | 691 |             bconf = bconf[argv_obj.skip_tests:] | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 692 |             print len(bconf) | 
 | 693 |  | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 694 |         return 0 | 
 | 695 |  | 
 | 696 |     if argv_obj.start_at is not None: | 
 | 697 |         ctime = time.time() | 
 | 698 |         if argv_obj.start_at >= ctime: | 
 | 699 |             time.sleep(ctime - argv_obj.start_at) | 
 | 700 |  | 
 | 701 |     def raw_res_func(test_num, data): | 
 | 702 |         pref = "========= RAW_RESULTS({0}) =========\n".format(test_num) | 
 | 703 |         out_fd.write(pref) | 
 | 704 |         out_fd.write(json.dumps(data)) | 
 | 705 |         out_fd.write("\n========= END OF RAW_RESULTS =========\n") | 
 | 706 |         out_fd.flush() | 
 | 707 |  | 
 | 708 |     rrfunc = raw_res_func if argv_obj.show_raw_results else None | 
 | 709 |  | 
 | 710 |     stime = time.time() | 
| koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 711 |     job_res, num_tests, ok = run_benchmark(argv_obj.type, | 
 | 712 |                                            job_cfg, | 
 | 713 |                                            params, | 
 | 714 |                                            argv_obj.runcycle, | 
 | 715 |                                            rrfunc, | 
 | 716 |                                            argv_obj.skip_tests, | 
| koder aka kdanilov | e87ae65 | 2015-04-20 02:14:35 +0300 | [diff] [blame^] | 717 |                                            argv_obj.faked_fio, | 
 | 718 |                                            cluster=argv_obj.cluster) | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 719 |     etime = time.time() | 
 | 720 |  | 
| koder aka kdanilov | 652cd80 | 2015-04-13 12:21:07 +0300 | [diff] [blame] | 721 |     res = {'__meta__': {'raw_cfg': job_cfg, 'params': params}, 'res': job_res} | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 722 |  | 
 | 723 |     oformat = 'json' if argv_obj.json else 'eval' | 
| koder aka kdanilov | 652cd80 | 2015-04-13 12:21:07 +0300 | [diff] [blame] | 724 |     out_fd.write("\nRun {0} tests in {1} seconds\n".format(num_tests, | 
 | 725 |                                                            int(etime - stime))) | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 726 |     out_fd.write("========= RESULTS(format={0}) =========\n".format(oformat)) | 
 | 727 |     if argv_obj.json: | 
 | 728 |         out_fd.write(json.dumps(res)) | 
 | 729 |     else: | 
 | 730 |         out_fd.write(pprint.pformat(res) + "\n") | 
| koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 731 |     out_fd.write("\n========= END OF RESULTS =========\n") | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 732 |  | 
| koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 733 |     return 0 if ok else 1 | 
 | 734 |  | 
 | 735 |  | 
 | 736 | def fake_main(x): | 
 | 737 |     import yaml | 
 | 738 |     time.sleep(60) | 
 | 739 |     out_fd = sys.stdout | 
 | 740 |     fname = "/tmp/perf_tests/metempirical_alisha/raw_results.yaml" | 
 | 741 |     res = yaml.load(open(fname).read())[0][1] | 
 | 742 |     out_fd.write("========= RESULTS(format=json) =========\n") | 
 | 743 |     out_fd.write(json.dumps(res)) | 
 | 744 |     out_fd.write("\n========= END OF RESULTS =========\n") | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 745 |     return 0 | 
 | 746 |  | 
 | 747 |  | 
 | 748 | if __name__ == '__main__': | 
| koder aka kdanilov | cff7b2e | 2015-04-18 20:48:15 +0300 | [diff] [blame] | 749 |     # exit(fake_main(sys.argv[1:])) | 
| koder aka kdanilov | da45e88 | 2015-04-06 02:24:42 +0300 | [diff] [blame] | 750 |     exit(main(sys.argv[1:])) |