blob: d1b6e9f7a07ac25fbb85ef095f50be8bfcbcbdd4 [file] [log] [blame]
import logging
from typing import cast, List, Union
import numpy
from cephlib.common import float2str
from cephlib.texttable import Texttable
from cephlib.statistic import calc_norm_stat_props, calc_histo_stat_props
from .stage import Stage, StepOrder
from .test_run_class import TestRun
from .result_classes import SuiteConfig
from .suits.io.fio import FioTest
from .suits.io.fio_job import FioJobParams
from .suits.io.fio_hist import get_lat_vals
from .data_selectors import get_aggregated
from .result_storage import IWallyStorage
logger = logging.getLogger("wally")
console_report_headers = ["Description", "IOPS ~ Dev", "BW, MiBps", 'Skew/Kurt', 'lat med, ms', 'lat 95, ms']
console_report_align = ['l', 'r', 'r', 'r', 'r', 'r']
def get_console_report_table(suite: SuiteConfig, rstorage: IWallyStorage) -> List[Union[List[str], Texttable.HLINE]]:
table: List[Union[List[str], Texttable.HLINE]] = []
prev_params = None
for job in sorted(rstorage.iter_job(suite), key=lambda job: job.params):
fparams = cast(FioJobParams, job.params)
fparams['qd'] = None
if prev_params is not None and fparams.char_tpl != prev_params:
table.append(Texttable.HLINE)
prev_params = fparams.char_tpl
bw_ts = get_aggregated(rstorage, suite.storage_id, job.storage_id, metric='bw',
trange=job.reliable_info_range_s)
props = calc_norm_stat_props(bw_ts)
avg_iops = props.average // job.params.params['bsize']
iops_dev = props.deviation // job.params.params['bsize']
lat_ts = get_aggregated(rstorage, suite.storage_id, job.storage_id, metric='lat',
trange=job.reliable_info_range_s)
bins_edges = numpy.array(get_lat_vals(lat_ts.data.shape[1]), dtype='float32') / 1000 # convert us to ms
lat_props = calc_histo_stat_props(lat_ts, bins_edges)
table.append([job.params.summary,
f"{float2str(avg_iops):>6s} ~ {float2str(iops_dev):>6s}",
float2str(props.average / 1024), # Ki -> Mi
f"{props.skew:>5.1f}/{props.kurt:>5.1f}",
float2str(lat_props.perc_50), float2str(lat_props.perc_95)])
return table
class ConsoleReportStage(Stage):
priority = StepOrder.REPORT
def run(self, ctx: TestRun) -> None:
for suite in ctx.rstorage.iter_suite(FioTest.name):
table = Texttable(max_width=200)
table.set_deco(Texttable.VLINES | Texttable.BORDER | Texttable.HEADER)
tbl = ctx.rstorage.get_txt_report(suite)
if tbl is None:
table.header(console_report_headers)
table.set_cols_align(console_report_align)
for line in get_console_report_table(suite, ctx.rstorage):
table.add_row(line)
tbl = table.draw()
ctx.rstorage.put_txt_report(suite, tbl)
print(tbl)