Files
zl_bench/_shape_inject_plugin.py
zhoulin 26b071c6e1 Stabilize first-run cudagraph timing and colorize terminal output
- _cudagraph_plugin: warm up autotune/JIT explicitly before graph capture
  (internal 5-iter warmup is too short), tag fallback markers with the
  failing phase; first-run latency no longer jitters run-to-run.
- _device_guard_plugin (new): set GEMS_VENDOR via torch probe before
  importing flag_gems, avoiding its timeout-less nvidia-smi subprocess
  probe that can hang import in fork-broken environments.
- _pretty_report_plugin (new) + _term_style (new): fold inputs identical
  across all result rows into a legend line, color status/plugin
  tags/markers on the live terminal; run.log is ANSI-stripped and keeps
  upstream SUCCESS/column wording for grep compatibility.
- run_pytest.sh: make USE_FLAGTUNE overridable, group all knobs into a
  config section with Chinese comments, add start/end banners.
- README: document the warmup semantics, new plugins/env vars, and the
  A/B rule that both sides must use the same USE_FLAGTUNE.
2026-07-19 19:21:13 +00:00

104 lines
3.6 KiB
Python

"""pytest plugin: make our shape yaml win over subclasses that override
`set_shapes()` with hardcoded shapes (~9% of upstream Benchmark subclasses).
Wraps `Benchmark.init_user_config` (runs right after `set_shapes()`): if the
op_name has a yaml entry, overwrite `self.shapes` with the yaml shapes. Ops with
no yaml entry keep their own shapes. An arity guard skips ops whose subclass
normalizes shape arity after reading yaml (e.g. BLAS (B,M,N,K)↔(M,N,K)).
"""
from __future__ import annotations
import os
import sys
import yaml as _yaml
_YAML_CACHE: dict | None = None # filled lazily from Config.shape_file
_PATCHED = False
def _load_yaml(path: str) -> dict:
if not path or not os.path.isfile(path):
return {}
try:
with open(path, "r") as f:
return _yaml.safe_load(f) or {}
except Exception as exc:
from _term_style import tag
print(f"{tag('[shape-inject-plugin]')} failed to load {path}: {exc}",
file=sys.stderr)
return {}
def _normalize_shapes(raw):
"""Mirror base.py's `[tuple(shape) for shape in self.shapes]`, defensively
handling scalar entries (`5` → `(5,)`)."""
out = []
for shape in raw:
if isinstance(shape, (list, tuple)):
out.append(tuple(shape))
else:
out.append((shape,))
return out
def _patch_init_user_config():
global _PATCHED
if _PATCHED:
return
from benchmark import base as fg_base
from benchmark.conftest import Config as fg_Config
original = fg_base.Benchmark.init_user_config
def _shape_arity(shape):
if isinstance(shape, (list, tuple)):
return len(shape)
return 1
def patched(self):
original(self)
global _YAML_CACHE
if _YAML_CACHE is None:
_YAML_CACHE = _load_yaml(getattr(fg_Config, "shape_file", "") or "")
entry = _YAML_CACHE.get(getattr(self, "op_name", None))
if not isinstance(entry, dict):
return
shapes = entry.get("shapes")
if not shapes:
return
# Skip ops whose subclass normalizes shape arity after reading yaml (e.g.
# BLAS (B,M,N,K)↔(M,N,K)): detected as both sides being homogeneous in
# arity but differing. Heterogeneous subclass shapes are safe to override.
if getattr(self, "shapes", None) and len(self.shapes) > 0:
cur_arities = {_shape_arity(s) for s in self.shapes}
yaml_arities = {_shape_arity(s) for s in shapes}
cur_homogeneous = len(cur_arities) == 1
yaml_homogeneous = len(yaml_arities) == 1
if cur_homogeneous and yaml_homogeneous and cur_arities != yaml_arities:
from _term_style import tag
print(
f"{tag('[shape-inject-plugin]')} skip override for op_name={self.op_name!r}: "
f"subclass produced homogeneous arity {next(iter(cur_arities))}, "
f"yaml has homogeneous arity {next(iter(yaml_arities))} "
f"— subclass normalization preserved",
file=sys.stderr,
)
return
self.shapes = _normalize_shapes(shapes)
if "shape_desc" in entry:
self.shape_desc = entry["shape_desc"]
fg_base.Benchmark.init_user_config = patched
_PATCHED = True
def pytest_configure(config):
from _term_style import tag
_patch_init_user_config()
print(f"{tag('[shape-inject-plugin]')} Benchmark.init_user_config patched: "
"yaml shapes now win over hardcoded subclass set_shapes()",
file=sys.stderr, flush=True)