"""Parse the fio logs. Extracts the bandwidth for I/O, from various fio benchmarks. Example log file (extracting read and write bandwidth): ... Run status group 0 (all jobs): READ: bw=5311KiB/s (5438kB/s), 5311KiB/s-5311KiB/s (5438kB/s-5438kB/s), io=311MiB (327MB), run=60058-60058msec WRITE: bw=2289KiB/s (2343kB/s), 2289KiB/s-2289KiB/s (2343kB/s-2343kB/s), io=134MiB (141MB), run=60058-60058msec ... """ import os import re from pathlib import Path from typing import Dict # get different mixes of read/write IO as subtests subtests = { 'fio_root_async_R70W30': 'fio_async_randR70W30.out', 'fio_root_async_R100W0': 'fio_async_randR100W0.out', 'fio_root_async_R0W100': 'fio_async_randR0W100.out', } def evaluate(tests: Dict[str, str]) -> Dict[str, Dict[str, float]]: """Read the results of the fio tests. Return a result dictionary. """ result = {} for t in tests: base_path = os.path.join(tests[t], 'dp_fio') row = {} for subtest in subtests: try: log_path = next(Path(base_path).rglob(subtests[subtest])) except StopIteration: raise Exception( "Error: No iperfclient.out found for network test {subtest} in {base_path}".format( subtest=subtest, base_path=base_path) ) with open(log_path) as f: fio = f.readlines() if not fio: raise Exception( "Empty fio log {subtest}?".format(subtest=subtest)) for line in fio: if "READ" in line: speed = get_io_bw_from_line(line) row[subtest + '_R'] = speed elif "WRITE" in line: speed = get_io_bw_from_line(line) row[subtest + '_W'] = speed result[t] = row return result # Dictionary for conversion to MiB units = { 'KiB': 1/1024, 'MiB': 1, 'GiB': 1024, } def get_io_bw_from_line(line) -> float: """Get the IO bandwidth from line and convert to MiB/s. Return the IO bandwidth in MiB/s """ # READ: bw=32.5MiB/s (34.1MB/s), 32.5MiB/s-32.5MiB/s (34.1MB/s-34.1MB/s), io=1954MiB (2048MB), run=60022-60022msec match = re.search(r'bw=(\d+\.?\d+)(MiB|KiB|GiB)', line) if not match: raise Exception("Could not extract bw from fio line.") num = float(match.group(1)) # return in MiB/s with 2 decimal digits num = num * units[match.group(2)] num = round(num, 2) return num