Source code for torch_lattice_bench.run

from __future__ import annotations

import argparse
import random
from collections.abc import Sequence
from datetime import datetime
from pathlib import Path

import torch

import torch_lattice
from torch_lattice_bench.catalog import GROUPS, MODES, PRESETS
from torch_lattice_bench.cases import all_cases
from torch_lattice_bench.console import make_console
from torch_lattice_bench.report import write_json, write_summary

_RESULTS_DIR = Path("benchmarks/results")


[docs] def main() -> None: args = _parser().parse_args() if args.smoke: args.preset = "smoke" if not torch.cuda.is_available() or not str(args.device).startswith("cuda"): raise RuntimeError("torch-lattice benchmark requires a CUDA device.") _configure_backend(args) device = torch.device(args.device) groups = tuple(args.group) if args.group else GROUPS modes = tuple(args.mode) if args.mode else _default_modes(groups) n_values = tuple(args.n_values) if args.n_values else None channels = tuple(args.channels) if args.channels else None layouts = tuple(args.layout) if args.layout else None console = make_console(args.color, quiet=args.quiet) cases = all_cases( args.preset, groups=groups, n_values=n_values, channels=channels, layouts=layouts, dtype=args.dtype, device=device, ) if args.list: for case in cases: print(f"{case.group}/{case.name}") return total = _count_runs(cases, modes, args.case_filter) console.set_total(total) json_path, summary_path = _report_paths(args) from torch_lattice_bench.harness import run_cases console.heading(f"device {args.device}") results = run_cases( cases, modes=modes, device=args.device, warmup=args.warmup, repeats=args.repeats, include=args.case_filter, keep_going=not args.fail_fast, on_start=console.start, on_result=console.done, on_skip=console.skipped, on_error=console.failed, ) write_json(json_path, results=results) write_summary(summary_path, results=results) console.report(json_path, summary_path)
def _parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( description="Benchmark torch-lattice CUDA sparse operator and module surfaces.", ) parser.add_argument("--preset", choices=PRESETS, default="smoke") parser.add_argument("--device", default="cuda") parser.add_argument("--mode", action="append", choices=MODES) parser.add_argument( "--group", "--groups", dest="group", action="append", choices=GROUPS ) parser.add_argument("--case-filter") parser.add_argument("--warmup", type=int, default=5) parser.add_argument("--repeats", "--iters", dest="repeats", type=int, default=20) parser.add_argument( "--size", "--points", dest="n_values", action="append", type=_positive_int ) parser.add_argument("--channels", action="append", type=_positive_int) parser.add_argument( "--layout", "--pattern", "--patterns", dest="layout", action="append", choices=( "isolated", "line", "plane", "grid", "block2", "block3", "block4", "block8", ), ) parser.add_argument("--dtype", choices=("fp16", "fp32"), default="fp16") parser.add_argument("--output") parser.add_argument("--color", choices=("auto", "always", "never"), default="auto") parser.add_argument("--quiet", action="store_true") parser.add_argument("--list", action="store_true") parser.add_argument( "--smoke", action="store_true", help="Alias for --preset smoke." ) parser.add_argument("--seed", type=int, default=0) parser.add_argument( "--allow-tf32", dest="allow_tf32", action="store_true", default=True ) parser.add_argument("--no-allow-tf32", dest="allow_tf32", action="store_false") parser.add_argument( "--allow-fp16", dest="allow_fp16", action="store_true", default=True ) parser.add_argument("--no-allow-fp16", dest="allow_fp16", action="store_false") parser.add_argument("--hash-rsv-ratio", type=int, default=64) parser.add_argument("--fail-fast", action="store_true") return parser def _configure_backend(args: argparse.Namespace) -> None: random.seed(args.seed) torch.manual_seed(args.seed) torch.cuda.manual_seed_all(args.seed) torch.backends.cuda.matmul.allow_tf32 = args.allow_tf32 torch_lattice.backends.allow_tf32 = args.allow_tf32 torch_lattice.backends.allow_fp16 = args.allow_fp16 torch_lattice.backends.hash_rsv_ratio = max( args.hash_rsv_ratio, torch_lattice.backends.hash_rsv_ratio ) torch_lattice.backends.benchmark = True def _default_modes(groups: Sequence[str]) -> tuple[str, ...]: if tuple(groups) == ("train",): return ("backward",) return ("cold_op", "hot_op") def _count_runs(cases, modes: Sequence[str], include: str | None) -> int: total = 0 for case in cases: if include is not None and include not in case.name: continue for _params in case.params: total += sum(1 for mode in modes if case.supports(mode)) return total def _report_paths(args: argparse.Namespace) -> tuple[Path, Path]: if args.output: json_path = Path(args.output) if not json_path.is_absolute() and json_path.parent == Path("."): json_path = _RESULTS_DIR / json_path if json_path.suffix != ".json": json_path = json_path.with_suffix(".json") else: stamp = datetime.now().strftime("%Y%m%d-%H%M%S") json_path = _RESULTS_DIR / f"torch-lattice-bench-{args.preset}-{stamp}.json" return json_path, json_path.with_suffix(".summary.txt") def _positive_int(value: str) -> int: parsed = int(value) if parsed <= 0: raise argparse.ArgumentTypeError("value must be positive") return parsed if __name__ == "__main__": main()