diff --git a/util/cpu2017/buildspec b/util/cpu2017/buildspec new file mode 100755 index 00000000..1caf900e --- /dev/null +++ b/util/cpu2017/buildspec @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +: ${SPECTUNE:=base} +set -e +runcpu "-config=$CFGFILE" "--tune=$SPECTUNE" -a scrub all +runcpu "-config=$CFGFILE" "--tune=$SPECTUNE" -a build "$@" diff --git a/util/cpu2017/cpexecresults.sh b/util/cpu2017/cpexecresults.sh new file mode 100755 index 00000000..4b128938 --- /dev/null +++ b/util/cpu2017/cpexecresults.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +grep -E '\.(csv|rsf|txt)' "$@" | # Find every .csv, .rsf, or .txt mentioned in the logs + sed -E 's/^\s*format:.*-> (.*)$/\1/g' | # Extract the filenames for that + xargs -L1 -I {} cp {} . # Take each file and copy it to the current directory diff --git a/util/cpu2017/cplogs.sh b/util/cpu2017/cplogs.sh new file mode 100755 index 00000000..5023fe6b --- /dev/null +++ b/util/cpu2017/cplogs.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +# Given a single file "$1.*.log" containing the stdout from several runs, +# extracts the generated CPU2017.*.log files and copies them to a subdirectory "$1.logs/" +set -e +mkdir -p "$1.logs/" +grep 'The log for this run is in' "$1".*.log | sed -E 's/^.*(CPU.*\.log).*$/\1/g' | xargs -I {} cp /home/cpu2017/result/{} "$1.logs/" +(cd "$1.logs"; grep ' Building' * | sed -E 's/^(\S*\.log): Building ([^ ]*).*$/\1 \2.log/' | xargs -n2 mv) +rm "$1".logs/CPU* diff --git a/util/cpu2017/extract-benchs.sh b/util/cpu2017/extract-benchs.sh new file mode 100755 index 00000000..396b84f9 --- /dev/null +++ b/util/cpu2017/extract-benchs.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +# Given a file "$1.*.log", splits it into one log file per benchmark, placed in "$1.logs/" + +set -e +mkdir -p "$1.logs/" +cd "$1.logs/" +csplit ../"$1".*.log '/^ Building/' '{*}' +grep ' Building' * | sed -E 's/^(\S*): Building ([^ ]*).*$/\1 \2.log/' | xargs -n2 mv +rm xx* diff --git a/util/cpu2017/runspec b/util/cpu2017/runspec new file mode 100755 index 00000000..c0db5841 --- /dev/null +++ b/util/cpu2017/runspec @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +: ${SPECTUNE:=base} +: ${SPECITERNUM:=3} +set -e +runcpu "-config=$CFGFILE" "--tune=$SPECTUNE" -n "$SPECITERNUM" -a scrub all +runcpu "-config=$CFGFILE" "--tune=$SPECTUNE" -n "$SPECITERNUM" -a run "$@" diff --git a/util/runners/__init__.py b/util/runners/__init__.py new file mode 100644 index 00000000..63539d5d --- /dev/null +++ b/util/runners/__init__.py @@ -0,0 +1,2 @@ +from . import multirun +from . import runwith diff --git a/util/runners/datename b/util/runners/datename new file mode 100755 index 00000000..a451d9d8 --- /dev/null +++ b/util/runners/datename @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +date +'%F.%H.%M' diff --git a/util/runners/multirun.py b/util/runners/multirun.py new file mode 100755 index 00000000..ea9911a8 --- /dev/null +++ b/util/runners/multirun.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +import argparse +import os +import shlex +import subprocess +import sys +from pathlib import Path +from typing import Dict, List, Optional, Tuple +import json +import itertools +import functools + +from runners import runwith + +# %% Setup + + +def expand_matrix(matrix: List[Dict[str, Dict[str, str]]]) -> Tuple[List[Dict[str, str]], List[str]]: + withs = [] + labels = [] + from pprint import pprint + + def merge_dict(a: dict, b: dict) -> dict: + assert not (a.keys() & b.keys()) + a = a.copy() + a.update(b) + return a + + for setting in itertools.product(*matrix): + withs_setting = functools.reduce(merge_dict, (obj[opt] for opt, obj in zip(setting, matrix))) + label = '-'.join(setting) + + withs.append(withs_setting) + labels.append(label) + + return withs, labels + + +def main(outdir: Path, optsched_cfg: Path, labels: List[str], withs: List[str], cmd: List[str], append_logs: bool = False, git_state: Optional[str] = None, validate_cmd: Optional[str] = None, analyze_cmds: List[str] = [], analyze_files: List[str] = [], matrix: List[Path] = []): + if withs is not None: + withs: List[Dict[str, str]] = [runwith.parse_withs(with_) for with_ in withs] + else: + assert matrix + assert not labels + + withs = [] + labels = [] + + for matrix_path in matrix: + matrix_json = json.loads(matrix_path.read_text()) + new_withs, new_labels = expand_matrix(matrix_json) + withs += new_withs + labels += new_labels + + assert len(labels) == len(withs) + assert not analyze_files or len(analyze_files) == len(analyze_cmds) + + outdir = outdir.resolve() + logfiles = [] + + for label, with_ in zip(labels, withs): + print(f'Running {label} with settings:', ' '.join(f'{k}={v}' for k, v in with_.items())) + logfile = runwith.main( + outdir=outdir, + optsched_cfg=optsched_cfg, + label=label, + with_=with_, + cmd=[arg.replace('{{label}}', label) for arg in cmd], + append_logs=append_logs, + git_state=git_state, + ) + logfiles.append(logfile) + + if validate_cmd: + val_cmd = shlex.split(validate_cmd, comments=True) + if not validate_cmd.endswith('#'): + val_cmd += map(str, logfiles) + subprocess.run(subprocess.list2cmdline(val_cmd), cwd=outdir, check=True, shell=True) + + if not analyze_files: + analyze_files = [None] * len(analyze_cmds) + + for analyze_cmd, outfile in zip(analyze_cmds, analyze_files): + analyze_run = shlex.split(analyze_cmd, comments=True) + if not analyze_cmd.endswith('#'): + analyze_run += map(str, logfiles) + result = subprocess.run(subprocess.list2cmdline(analyze_run), cwd=outdir, + capture_output=True, encoding='utf-8', shell=True) + if result.returncode != 0: + print( + f'Analysis command {subprocess.list2cmdline(analyze_run)} failed with error code: {result.returncode}', file=sys.stderr) + + print(result.stdout) + print(result.stderr, file=sys.stderr) + if outfile: + with open(outdir / outfile, 'w') as f: + f.write(result.stdout) + + +# %% Main +if __name__ == '__main__': + OPTSCHEDCFG = os.getenv('OPTSCHEDCFG') + RUN_CMD = os.getenv('RUN_CMD') + RUN_CMD = shlex.split(RUN_CMD) if RUN_CMD else RUN_CMD + VALIDATE_CMD = os.getenv('VALIDATE_CMD') + ANALYZE_CMD = os.getenv('ANALYZE_CMD') + RUNNER_GIT_REPO = os.getenv('RUNNER_GIT_REPO') + + parser = argparse.ArgumentParser(description='Run the commands with the sched.ini settings') + parser.add_argument('-c', '--optsched-cfg', + required=OPTSCHEDCFG is None, + default=OPTSCHEDCFG, + help='The path to the optsched config to use. Defaults to the env variable OPTSCHEDCFG if it exists, else is required. The sched.ini is expected to be there') + parser.add_argument('-o', '--outdir', required=True, help='The path to place the output files at') + parser.add_argument('-L', '--labels', default='', + help='Comma separated labels to use for these runs. Must be equal to the number of --with flags. Any parts of the run command will have the string {{label}} replaced with the label for the run.') + parser.add_argument('--with', nargs='*', action='append', metavar='KEY=VALUE', + help="The sched.ini settings to set for each run. Each run's settings should have a new --with flag.") + parser.add_argument('--matrix', type=Path, action='append', metavar='MATRIX.json', + help='A json file containing a matrix of configuration values to act as-if their product was specified via --with and --labels') + parser.add_argument( + 'cmd', nargs='+', help='The command (with args) to run. Use - to default to the environment variable RUN_CMD.') + parser.add_argument('--append', action='store_true', + help='Allow a