koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 1 | import os.path |
| 2 | import logging |
kdanylov aka koder | 026e5f2 | 2017-05-15 01:04:39 +0300 | [diff] [blame] | 3 | from typing import cast, Any, List, Union, Tuple, Optional |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 4 | |
| 5 | import numpy |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 6 | |
kdanylov aka koder | 026e5f2 | 2017-05-15 01:04:39 +0300 | [diff] [blame] | 7 | from cephlib.units import ssize2b, b2ssize |
| 8 | from cephlib.node import IRPCNode, get_os |
| 9 | |
koder aka kdanilov | 6ab4d43 | 2015-06-22 00:26:28 +0300 | [diff] [blame] | 10 | import wally |
kdanylov aka koder | 026e5f2 | 2017-05-15 01:04:39 +0300 | [diff] [blame] | 11 | from ...utils import StopTestError |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 12 | from ..itest import ThreadedTest |
koder aka kdanilov | f90de85 | 2017-01-20 18:12:27 +0200 | [diff] [blame] | 13 | from ...result_classes import TimeSeries, DataSource |
| 14 | from ..job import JobConfig |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 15 | from .fio_task_parser import execution_time, fio_cfg_compile, FioJobConfig, FioParams, get_log_files |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 16 | from . import rpc_plugin |
kdanylov aka koder | cdfcdaf | 2017-04-29 10:03:39 +0300 | [diff] [blame] | 17 | from .fio_hist import get_lat_vals, expected_lat_bins |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 18 | |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 19 | |
| 20 | logger = logging.getLogger("wally") |
| 21 | |
| 22 | |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 23 | class FioTest(ThreadedTest): |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 24 | soft_runcycle = 5 * 60 |
Michael Semenov | 8ba6e23 | 2015-08-28 10:57:18 +0000 | [diff] [blame] | 25 | retry_time = 30 |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 26 | configs_dir = os.path.dirname(__file__) # type: str |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 27 | name = 'fio' |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 28 | job_config_cls = FioJobConfig |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 29 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 30 | def __init__(self, *args, **kwargs) -> None: |
| 31 | super().__init__(*args, **kwargs) |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 32 | |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 33 | get = self.suite.params.get |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 34 | |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 35 | self.remote_task_file = self.join_remote("task.fio") |
| 36 | self.remote_output_file = self.join_remote("fio_result.json") |
| 37 | self.use_system_fio = get('use_system_fio', False) # type: bool |
| 38 | self.use_sudo = get("use_sudo", True) # type: bool |
| 39 | self.force_prefill = get('force_prefill', False) # type: bool |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 40 | self.skip_prefill = get('skip_prefill', False) # type: bool |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 41 | self.load_profile_name = self.suite.params['load'] # type: str |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 42 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 43 | if os.path.isfile(self.load_profile_name): |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 44 | self.load_profile_path = self.load_profile_name # type: str |
koder aka kdanilov | 6ab4d43 | 2015-06-22 00:26:28 +0300 | [diff] [blame] | 45 | else: |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 46 | self.load_profile_path = os.path.join(self.configs_dir, self.load_profile_name+ '.cfg') |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 47 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 48 | self.load_profile = open(self.load_profile_path, 'rt').read() # type: str |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 49 | |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 50 | if self.use_system_fio: |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 51 | self.fio_path = "fio" # type: str |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 52 | else: |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 53 | self.fio_path = os.path.join(self.suite.remote_dir, "fio") |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 54 | |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 55 | self.load_params = self.suite.params['params'] |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 56 | self.file_name = self.load_params['FILENAME'] |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 57 | |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 58 | if 'FILESIZE' not in self.load_params: |
| 59 | logger.debug("Getting test file sizes on all nodes") |
| 60 | try: |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 61 | sizes = {node.conn.fs.file_stat(self.file_name)[b'size'] |
| 62 | for node in self.suite.nodes} |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 63 | except Exception: |
| 64 | logger.exception("FILESIZE is not set in config file and fail to detect it." + |
| 65 | "Set FILESIZE or fix error and rerun test") |
| 66 | raise StopTestError() |
koder aka kdanilov | a94dfe1 | 2015-08-19 13:04:51 +0300 | [diff] [blame] | 67 | |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 68 | if len(sizes) != 1: |
| 69 | logger.error("IO target file %r has different sizes on test nodes - %r", |
| 70 | self.file_name, sizes) |
| 71 | raise StopTestError() |
koder aka kdanilov | a94dfe1 | 2015-08-19 13:04:51 +0300 | [diff] [blame] | 72 | |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 73 | self.file_size = list(sizes)[0] |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 74 | logger.info("Detected test file size is %sB", b2ssize(self.file_size)) |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 75 | if self.file_size % (4 * 1024 ** 2) != 0: |
| 76 | tail = self.file_size % (4 * 1024 ** 2) |
| 77 | logger.warning("File size is not proportional to 4M, %sb at the end will not be used for test", |
| 78 | str(tail // 1024) + "Kb" if tail > 1024 else str(tail) + "b") |
| 79 | self.file_size -= self.file_size % (4 * 1024 ** 2) |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 80 | self.load_params['FILESIZE'] = self.file_size |
| 81 | else: |
| 82 | self.file_size = ssize2b(self.load_params['FILESIZE']) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 83 | |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 84 | self.job_configs = list(fio_cfg_compile(self.load_profile, self.load_profile_path, |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 85 | cast(FioParams, self.load_params))) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 86 | |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 87 | if len(self.job_configs) == 0: |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 88 | logger.error("Empty fio config provided") |
| 89 | raise StopTestError() |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 90 | |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 91 | self.exec_folder = self.suite.remote_dir |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 92 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 93 | def config_node(self, node: IRPCNode) -> None: |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 94 | plugin_code = open(rpc_plugin.__file__.rsplit(".", 1)[0] + ".py", "rb").read() # type: bytes |
| 95 | node.upload_plugin("fio", plugin_code) |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 96 | |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 97 | try: |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 98 | node.conn.fs.rmtree(self.suite.remote_dir) |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 99 | except Exception: |
| 100 | pass |
| 101 | |
| 102 | try: |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 103 | node.conn.fs.makedirs(self.suite.remote_dir) |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 104 | except Exception: |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 105 | msg = "Failed to recreate folder {} on remote {}.".format(self.suite.remote_dir, node) |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 106 | logger.exception(msg) |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 107 | raise StopTestError() |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 108 | |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 109 | # TODO: check this during config validation |
| 110 | if self.file_size % (4 * (1024 ** 2)) != 0: |
| 111 | logger.error("Test file size must be proportional to 4MiB") |
| 112 | raise StopTestError() |
| 113 | |
koder aka kdanilov | 3b4da8b | 2016-10-17 00:17:53 +0300 | [diff] [blame] | 114 | self.install_utils(node) |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 115 | |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 116 | if self.skip_prefill: |
| 117 | logger.info("Prefill is skipped due to 'skip_prefill' set to true") |
| 118 | else: |
| 119 | mb = int(self.file_size / 1024 ** 2) |
| 120 | logger.info("Filling test file %s on node %s with %sMiB of random data", self.file_name, node.info, mb) |
| 121 | is_prefilled, fill_bw = node.conn.fio.fill_file(self.file_name, mb, |
| 122 | force=self.force_prefill, |
| 123 | fio_path=self.fio_path) |
| 124 | if not is_prefilled: |
| 125 | logger.info("Test file on node %s is already prefilled", node.info) |
| 126 | elif fill_bw is not None: |
| 127 | logger.info("Initial fio fill bw is %s MiBps for %s", fill_bw, node.info) |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 128 | |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 129 | def install_utils(self, node: IRPCNode) -> None: |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 130 | os_info = get_os(node) |
koder aka kdanilov | 6ab4d43 | 2015-06-22 00:26:28 +0300 | [diff] [blame] | 131 | if self.use_system_fio: |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 132 | if os_info.distro != 'ubuntu': |
| 133 | logger.error("Only ubuntu supported on test VM") |
| 134 | raise StopTestError() |
| 135 | node.conn.fio.install('fio', binary='fio') |
| 136 | else: |
| 137 | node.conn.fio.install('bzip2', binary='bzip2') |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 138 | fio_dir = os.path.dirname(os.path.dirname(wally.__file__)) # type: str |
| 139 | fio_dir = os.path.join(os.getcwd(), fio_dir) |
| 140 | fio_dir = os.path.join(fio_dir, 'fio_binaries') |
| 141 | fname = 'fio_{0.release}_{0.arch}.bz2'.format(os_info) |
| 142 | fio_path = os.path.join(fio_dir, fname) # type: str |
| 143 | |
| 144 | if not os.path.exists(fio_path): |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 145 | logger.error("No prebuild fio binary available for {0}".format(os_info)) |
| 146 | raise StopTestError() |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 147 | |
| 148 | bz_dest = self.join_remote('fio.bz2') # type: str |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 149 | node.copy_file(fio_path, bz_dest, compress=False) |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 150 | node.run("bzip2 --decompress {} ; chmod a+x {}".format(bz_dest, self.join_remote("fio"))) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 151 | |
koder aka kdanilov | f90de85 | 2017-01-20 18:12:27 +0200 | [diff] [blame] | 152 | def get_expected_runtime(self, job_config: JobConfig) -> int: |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 153 | return execution_time(cast(FioJobConfig, job_config)) |
koder aka kdanilov | 7022706 | 2016-11-26 23:23:21 +0200 | [diff] [blame] | 154 | |
koder aka kdanilov | f90de85 | 2017-01-20 18:12:27 +0200 | [diff] [blame] | 155 | def prepare_iteration(self, node: IRPCNode, job: JobConfig) -> None: |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 156 | node.put_to_file(self.remote_task_file, str(job).encode("utf8")) |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 157 | |
| 158 | # TODO: get a link to substorage as a parameter |
koder aka kdanilov | f90de85 | 2017-01-20 18:12:27 +0200 | [diff] [blame] | 159 | def run_iteration(self, node: IRPCNode, job: JobConfig) -> List[TimeSeries]: |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 160 | exec_time = execution_time(cast(FioJobConfig, job)) |
| 161 | |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 162 | |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 163 | fio_cmd_templ = "cd {exec_folder}; " + \ |
| 164 | "{fio_path} --output-format=json --output={out_file} --alloc-size=262144 {job_file}" |
| 165 | |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 166 | cmd = fio_cmd_templ.format(exec_folder=self.exec_folder, |
| 167 | fio_path=self.fio_path, |
| 168 | out_file=self.remote_output_file, |
| 169 | job_file=self.remote_task_file) |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 170 | must_be_empty = node.run(cmd, timeout=exec_time + max(300, exec_time), check_timeout=1).strip() |
koder aka kdanilov | bbbe1dc | 2016-12-20 01:19:56 +0200 | [diff] [blame] | 171 | |
kdanylov aka koder | 150b219 | 2017-04-01 16:53:01 +0300 | [diff] [blame] | 172 | for line in must_be_empty.split("\n"): |
| 173 | if line.strip(): |
| 174 | if 'only root may flush block devices' in line: |
| 175 | continue |
| 176 | logger.error("Unexpected fio output: %r", must_be_empty) |
| 177 | break |
koder aka kdanilov | bc2c898 | 2015-06-13 02:50:43 +0300 | [diff] [blame] | 178 | |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 179 | # put fio output into storage |
| 180 | fio_out = node.get_file_content(self.remote_output_file) |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 181 | |
| 182 | path = DataSource(suite_id=self.suite.storage_id, |
| 183 | job_id=job.storage_id, |
| 184 | node_id=node.node_id, |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 185 | sensor='fio', |
| 186 | dev=None, |
| 187 | metric='stdout', |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 188 | tag='json') |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 189 | self.storage.put_extra(fio_out, path) |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 190 | node.conn.fs.unlink(self.remote_output_file) |
| 191 | |
| 192 | files = [name for name in node.conn.fs.listdir(self.exec_folder)] |
kdanylov aka koder | 026e5f2 | 2017-05-15 01:04:39 +0300 | [diff] [blame] | 193 | result = [] # type: List[TimeSeries] |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 194 | for name, file_path, units in get_log_files(cast(FioJobConfig, job)): |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 195 | log_files = [fname for fname in files if fname.startswith(file_path)] |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 196 | if len(log_files) != 1: |
| 197 | logger.error("Found %s files, match log pattern %s(%s) - %s", |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 198 | len(log_files), file_path, name, ",".join(log_files[10:])) |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 199 | raise StopTestError() |
| 200 | |
| 201 | fname = os.path.join(self.exec_folder, log_files[0]) |
| 202 | raw_result = node.get_file_content(fname) # type: bytes |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 203 | node.conn.fs.unlink(fname) |
| 204 | |
| 205 | try: |
| 206 | log_data = raw_result.decode("utf8").split("\n") |
| 207 | except UnicodeEncodeError: |
| 208 | logger.exception("Error during parse %s fio log file - can't decode usint UTF8", name) |
| 209 | raise StopTestError() |
| 210 | |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 211 | # TODO: fix units, need to get array type from stream |
| 212 | |
| 213 | parsed = [] # type: List[Union[List[int], int]] |
| 214 | times = [] |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 215 | |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 216 | for idx, line in enumerate(log_data): |
| 217 | line = line.strip() |
| 218 | if line: |
| 219 | try: |
| 220 | time_ms_s, val_s, _, *rest = line.split(",") |
koder aka kdanilov | f286517 | 2016-12-30 03:35:11 +0200 | [diff] [blame] | 221 | times.append(int(time_ms_s.strip())) |
koder aka kdanilov | ffaf48d | 2016-12-27 02:25:29 +0200 | [diff] [blame] | 222 | |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 223 | if name == 'lat': |
| 224 | vals = [int(i.strip()) for i in rest] |
| 225 | |
| 226 | if len(vals) != expected_lat_bins: |
kdanylov aka koder | cdfcdaf | 2017-04-29 10:03:39 +0300 | [diff] [blame] | 227 | msg = "Expect {} bins in latency histogram, but found {} at time {}" \ |
| 228 | .format(expected_lat_bins, len(vals), time_ms_s) |
| 229 | logger.error(msg) |
| 230 | raise StopTestError(msg) |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 231 | |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 232 | parsed.append(vals) |
koder aka kdanilov | 23e6bdf | 2016-12-24 02:18:54 +0200 | [diff] [blame] | 233 | else: |
| 234 | parsed.append(int(val_s.strip())) |
| 235 | except ValueError: |
| 236 | logger.exception("Error during parse %s fio log file in line %s: %r", name, idx, line) |
| 237 | raise StopTestError() |
koder aka kdanilov | ffaf48d | 2016-12-27 02:25:29 +0200 | [diff] [blame] | 238 | |
kdanylov aka koder | 026e5f2 | 2017-05-15 01:04:39 +0300 | [diff] [blame] | 239 | assert not self.suite.keep_raw_files, "keep_raw_files is not supported" |
koder aka kdanilov | a732a60 | 2017-02-01 20:29:56 +0200 | [diff] [blame] | 240 | |
kdanylov aka koder | cdfcdaf | 2017-04-29 10:03:39 +0300 | [diff] [blame] | 241 | histo_bins = None if name != 'lat' else numpy.array(get_lat_vals()) |
kdanylov aka koder | 026e5f2 | 2017-05-15 01:04:39 +0300 | [diff] [blame] | 242 | ts = TimeSeries(data=numpy.array(parsed, dtype='uint64'), |
| 243 | units=units, |
| 244 | times=numpy.array(times, dtype='uint64'), |
| 245 | time_units='ms', |
| 246 | source=path(metric=name, tag='csv'), |
| 247 | histo_bins=histo_bins) |
| 248 | result.append(ts) |
koder aka kdanilov | 108ac36 | 2017-01-19 20:17:16 +0200 | [diff] [blame] | 249 | return result |
koder aka kdanilov | 7f59d56 | 2016-12-26 01:34:23 +0200 | [diff] [blame] | 250 | |
| 251 | def format_for_console(self, data: Any) -> str: |
| 252 | raise NotImplementedError() |