Skip to content

Commit de99435

Browse files
author
Yifan Shen
committed
dump op tests in more rigorous format
1 parent a68f1ad commit de99435

1 file changed

Lines changed: 45 additions & 19 deletions

File tree

tests/utils.py

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ async def _execute_and_compare(
386386
num_calls: int,
387387
produce_torch_out: Any,
388388
compare: Any,
389+
coreai_program: Any = None,
389390
dump_path: Path | None = None,
390391
) -> None:
391392
"""The single place we invoke the Core AI runtime.
@@ -394,28 +395,17 @@ async def _execute_and_compare(
394395
two callbacks let path A (stateful, recompute per call) and path B
395396
(fixed expected output) share this loop without ad-hoc branching.
396397
"""
398+
# Stateful tests can't round-trip for now,
399+
# which has no `--input` JSON path for state — so skip the dump entirely.
400+
should_dump = dump_optests_enabled() and dump_path is not None and not state
397401
try:
398402
for call_idx in range(num_calls):
399-
io_numpy = {}
400-
if call_idx == 0 and dump_optests_enabled():
401-
assert dump_path is not None
402-
for name, arr in state.items():
403-
io_numpy[f"initial_state_{name}"] = arr.numpy()
404-
405403
torch_out = produce_torch_out(call_idx)
406404
rt_outputs = await rt_func(inputs=inputs, state=state)
407405
compare(rt_outputs, torch_out, call_idx)
408406

409-
if call_idx == 0 and dump_optests_enabled():
410-
assert dump_path is not None
411-
for name, arr in inputs.items():
412-
io_numpy[name] = arr.numpy()
413-
for name, arr in state.items():
414-
io_numpy[f"final_state_{name}"] = arr.numpy()
415-
for name, arr in rt_outputs.items():
416-
io_numpy[name] = arr.numpy()
417-
418-
np.savez(dump_path / "test_data.npz", **io_numpy)
407+
if call_idx == 0 and should_dump:
408+
_dump_optest_artifacts(coreai_program, inputs, rt_outputs, dump_path)
419409

420410
except Exception:
421411
# Wipe bytecode and reference IO if the test failed as
@@ -425,6 +415,39 @@ async def _execute_and_compare(
425415
raise
426416

427417

418+
def _add_npz_entry(io_numpy: dict[str, np.ndarray], key: str, arr: np.ndarray) -> None:
419+
"""Add an array to the npz dict, emitting a bf16 dtype override if needed.
420+
421+
NumPy has no native bf16, so surfaces it as void16 (``|V2``).
422+
"""
423+
io_numpy[key] = arr
424+
if arr.dtype.str == "|V2":
425+
io_numpy[f"_dtype_{key}"] = np.array("bf16")
426+
427+
428+
def _dump_optest_artifacts(
429+
coreai_program: Any,
430+
inputs: dict[str, NDArray],
431+
rt_outputs: dict[str, NDArray],
432+
dump_path: Path,
433+
) -> None:
434+
"""Write a `<testname>.aimodel` + `<testname>_test_data.npz` pair.
435+
436+
Format: aimodel prefix == npz prefix == dump_path
437+
leaf name; npz holds an ``op_name`` scalar plus ``input_<n>`` /
438+
``output_<n>`` keys.
439+
"""
440+
testname = dump_path.name
441+
coreai_program.save_asset(dump_path / f"{testname}.aimodel")
442+
443+
io_numpy: dict[str, np.ndarray] = {"op_name": np.array("main")}
444+
for name, arr in inputs.items():
445+
_add_npz_entry(io_numpy, f"input_{name}", arr.numpy())
446+
for name, arr in rt_outputs.items():
447+
_add_npz_entry(io_numpy, f"output_{name}", arr.numpy())
448+
np.savez(dump_path / f"{testname}_test_data.npz", **io_numpy)
449+
450+
428451
async def _run_with_model(
429452
model: torch.nn.Module,
430453
rt_func: Any,
@@ -437,6 +460,7 @@ async def _run_with_model(
437460
rtol: float,
438461
atol: float,
439462
metal_inputs: bool = False,
463+
coreai_program: Any = None,
440464
dump_path: Path | None = None,
441465
) -> None:
442466
"""Path A: stateful, multi-call, name-based matching."""
@@ -478,6 +502,7 @@ def compare(
478502
num_calls=num_calls,
479503
produce_torch_out=produce_torch_out,
480504
compare=compare,
505+
coreai_program=coreai_program,
481506
dump_path=dump_path,
482507
)
483508

@@ -490,6 +515,7 @@ async def _run_with_program(
490515
rtol: float,
491516
atol: float,
492517
metal_inputs: bool = False,
518+
coreai_program: Any = None,
493519
dump_path: Path | None = None,
494520
) -> None:
495521
"""Path B: pre-converted program, single call, sorted-key matching."""
@@ -519,6 +545,7 @@ def compare(
519545
num_calls=1,
520546
produce_torch_out=produce_torch_out,
521547
compare=compare,
548+
coreai_program=coreai_program,
522549
dump_path=dump_path,
523550
)
524551

@@ -592,9 +619,6 @@ async def validate_numerical_output(**kwargs: Any) -> None:
592619
if dump_optests_enabled():
593620
dump_path = _optest_dump_path(get_current_test_id())
594621
dump_path.mkdir(parents=True, exist_ok=True)
595-
model_path = dump_path / "main.AICode.bc"
596-
model_path.unlink(missing_ok=True)
597-
coreai_program._save_bytecode(model_path)
598622

599623
with TemporaryDirectory() as temp_directory:
600624
aimodel_path = Path(temp_directory) / "model.aimodel"
@@ -616,6 +640,7 @@ async def validate_numerical_output(**kwargs: Any) -> None:
616640
rtol=rtol,
617641
atol=atol,
618642
metal_inputs=metal_inputs,
643+
coreai_program=coreai_program,
619644
dump_path=dump_path,
620645
)
621646
else:
@@ -626,6 +651,7 @@ async def validate_numerical_output(**kwargs: Any) -> None:
626651
rtol=rtol,
627652
atol=atol,
628653
metal_inputs=metal_inputs,
654+
coreai_program=coreai_program,
629655
dump_path=dump_path,
630656
)
631657

0 commit comments

Comments
 (0)