#!/usr/bin/env python3
"""extract-speedup-from-log - Determine speedup from dfatool log files
foo
"""
import argparse
import dfatool.cli
import dfatool.utils
import logging
import numpy as np
import sys
from dfatool.loader import Logfile, CSVfile
from dfatool.model import AnalyticModel
from functools import reduce
def parse_logfile(filename):
if ".csv" in filename:
loader = CSVfile()
else:
loader = Logfile()
if filename.endswith("xz"):
import lzma
with lzma.open(filename, "rt") as f:
return loader.load(f)
with open(filename, "r") as f:
return loader.load(f)
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter, description=__doc__
)
parser.add_argument(
"--add-param",
metavar="=[ = ...]",
type=str,
help="Add additional parameter specifications to output lines",
)
parser.add_argument(
"--filter-param",
metavar="[;...]",
type=str,
help="Only consider measurements where satisfies . "
" may be with operator being < / <= / = / >= / >, "
"or ∈[,...]. "
"All other measurements (including those where it is None, that is, has not been set yet) are discarded. "
"Note that this may remove entire function calls from the model.",
)
parser.add_argument(
"--ignore-param",
metavar="[,,...]",
type=str,
help="Ignore listed parameters during model generation",
)
parser.add_argument(
"--log-level",
metavar="LEVEL",
choices=["debug", "info", "warning", "error"],
default="warning",
help="Set log level",
)
parser.add_argument(
"numerator",
type=str,
help="numerator parameters",
)
parser.add_argument(
"denominator",
type=str,
help="denominator parameters",
)
parser.add_argument(
"observation",
type=str,
help="observation (key:attribute) used for speedup calculation",
)
parser.add_argument(
"logfiles",
nargs="+",
type=str,
help="Path to benchmark output (.txt or .txt.xz)",
)
args = parser.parse_args()
if args.log_level:
numeric_level = getattr(logging, args.log_level.upper(), None)
if not isinstance(numeric_level, int):
print(f"Invalid log level: {args.log_level}", file=sys.stderr)
sys.exit(1)
logging.basicConfig(
level=numeric_level,
format="{asctime} {levelname}:{name}:{message}",
style="{",
)
observations = reduce(lambda a, b: a + b, map(parse_logfile, args.logfiles))
by_name_num, parameter_names_num = dfatool.utils.observations_to_by_name(
observations
)
by_name_denom, parameter_names_denom = dfatool.utils.observations_to_by_name(
observations
)
del observations
if args.filter_param:
args.filter_param = list(
map(
lambda entry: dfatool.cli.parse_filter_string(
entry, parameter_names=parameter_names_num
),
args.filter_param.split(";"),
)
)
else:
args.filter_param = list()
filter_num = list(
map(
lambda entry: dfatool.cli.parse_filter_string(
entry, parameter_names=parameter_names_num
),
args.numerator.split(";"),
)
)
filter_denom = list(
map(
lambda entry: dfatool.cli.parse_filter_string(
entry, parameter_names=parameter_names_denom
),
args.denominator.split(";"),
)
)
filter_num += args.filter_param
filter_denom += args.filter_param
ignore_num = list(map(lambda x: x[0], filter_num))
ignore_denom = list(map(lambda x: x[0], filter_denom))
assert ignore_num == ignore_denom
if args.ignore_param:
args.ignore_param = args.ignore_param.split(";")
ignore_num += args.ignore_param
ignore_denom += args.ignore_param
dfatool.utils.filter_aggregate_by_param(
by_name_num, parameter_names_num, filter_num
)
dfatool.utils.filter_aggregate_by_param(
by_name_denom, parameter_names_denom, filter_denom
)
dfatool.utils.ignore_param(by_name_num, parameter_names_num, ignore_num)
dfatool.utils.ignore_param(by_name_denom, parameter_names_denom, ignore_denom)
model_num = AnalyticModel(
by_name_num,
parameter_names_num,
compute_stats=False,
)
model_denom = AnalyticModel(
by_name_denom,
parameter_names_denom,
compute_stats=False,
)
for param_key in model_num.get_by_param().keys():
name, params = param_key
num_data = model_num.get_by_param().get(param_key).get(args.observation)
try:
denom_data = model_denom.get_by_param().get(param_key).get(args.observation)
except AttributeError:
logging.error(f"Cannot find numerator param {param_key} in denominator")
logging.error(f"Parameter names == {tuple(parameter_names_num)}")
logging.error("You may need to adjust --ignore-param")
sys.exit(1)
if num_data and denom_data:
param_str = " ".join(
map(
lambda i: f"{parameter_names_num[i]}={params[i]}",
range(len(params)),
)
)
if args.add_param is not None:
param_str += " " + args.add_param
for speedup in np.array(num_data) / np.array(denom_data):
print(f"[::] {name} | {param_str} | speedup={speedup}")
if __name__ == "__main__":
main()