from contextlib import nullcontext
from types import SimpleNamespace
from unittest.mock import MagicMock
import numpy as np
from ttk.core_modules.framework_api import profiling as e2e_profiling
from ttk.core_modules.framework_api.result import FrameworkApiReturnStructure
from ttk.core_modules.manual_data import (
ManualDataStore,
register_manual_data_directory_provider,
unregister_manual_data_directory_provider,
)
from ttk.core_modules.npu.op_api import comparison as aclnn_comparison
from ttk.core_modules.npu.op_api import profiling as aclnn_profiling
from ttk.core_modules.npu.op_api.profiling_structure import (
ApiComparisonResult,
ApiProfilingResult,
)
from ttk.core_modules.testcase_manager.testcase_aclnn import TestcaseAclnn
from ttk.core_modules.testcase_manager.testcase_e2e import TestcaseE2e
from ttk.utilities.classes import SWITCHES
def _process_context():
return SimpleNamespace(notify_status=lambda *_: None, change_name=lambda *_: None)
def _e2e_case(name):
case = TestcaseE2e()
case.testcase_name = name
case.api_name = "torch.add"
case.tensor_view_shapes = ((2,), (2,))
case.tensor_dtypes = ("float32", "float32")
case.tensor_formats = ("ND", "ND")
case.tensor_storage_shapes = ((2,), (2,))
case.tensor_view_offsets = (0, 0)
case.tensor_view_strides = ((1,), (1,))
case.output_tensor_indexes = (1,)
case.inplace_input_indexes = ()
case.attributes = {}
case.input_data_ranges = ((-1, 1), (-1, 1))
case.golden_api = ""
case._tensor_list_dist = (0, 0)
case._pure_output_indexes = [1]
case._param_plan_cache = object()
return case
def _aclnn_case(name):
case = TestcaseAclnn()
case.testcase_name = name
case.api_name = "aclnnAdd"
case.tensor_view_shapes = ((2,), (2,))
case.tensor_dtypes = ("float32", "float32")
case.tensor_formats = ("ND", "ND")
case.tensor_storage_shapes = ((2,), (2,))
case.tensor_view_offsets = (0, 0)
case.tensor_view_strides = ((1,), (1,))
case.output_tensor_indexes = (1,)
case.output_inplace_indexes = ()
case.inplace_input_indexes = ()
case.attributes = {}
case.input_data_ranges = ((-1, 1), (-1, 1))
case.scalar_dtypes = ("float32",)
case.scalar_data_ranges = ((0, 1),)
case._tensor_list_dist = (0, 0)
case._scalar_list_dist = (0,)
case._pure_output_indexes = [1]
case._param_plan_cache = object()
return case
def _switches(tmp_path, mode):
switches = SWITCHES()
switches.manual_data_mode = mode
switches.manual_data_dirs = (str(tmp_path),)
switches.no_memory_check = True
switches.cst_switches.enabled = False
switches.dyn_switches.enabled = False
switches.dump_config.enable_input()
switches.dump_config.enable_golden()
return switches
def test_e2e_prepare_stops_before_api_resolution_and_device_execution(monkeypatch, tmp_path):
case = _e2e_case("e2e_prepare")
switches = _switches(tmp_path, "prepare")
inputs = [np.array([1.0, 2.0], np.float32), np.zeros(2, np.float32)]
golden = [np.array([3.0, 4.0], np.float32)]
resolve_api = MagicMock(side_effect=AssertionError("main API must not be resolved"))
execute = MagicMock(side_effect=AssertionError("main API must not execute"))
def generate(testcase, *_):
testcase.np_storages = inputs
return inputs
monkeypatch.setattr(e2e_profiling, "get_process_context", _process_context)
monkeypatch.setattr(e2e_profiling, "generate_inputs", generate)
def generate_golden(*_args, **_kwargs):
inputs[0][:] = -1
return golden
monkeypatch.setattr(e2e_profiling, "_generate_golden_data", generate_golden)
monkeypatch.setattr(e2e_profiling, "resolve_api", resolve_api)
monkeypatch.setattr(e2e_profiling, "_execute_eager", execute)
monkeypatch.setattr(e2e_profiling, "_profiling_end_print", lambda *_args, **_kwargs: None)
result = FrameworkApiReturnStructure()
e2e_profiling._do_profile(
case, SimpleNamespace(alias=lambda: "npu"), {}, {}, 0, switches, result
)
assert result.precision_status == "PASS"
assert result.eager_precision == "MANUAL_DATA_PREPARED"
assert not resolve_api.called
assert not execute.called
store = ManualDataStore(tmp_path)
assert (store.case_dir(case.testcase_name) / "input_0_float32.bin").is_file()
assert not (store.case_dir(case.testcase_name) / "manifest.json").exists()
np.testing.assert_array_equal(
store.load_case(case, "e2e").inputs[0],
np.array([1.0, 2.0], np.float32),
)
def test_e2e_failed_reprepare_invalidates_previous_case(monkeypatch, tmp_path):
case = _e2e_case("e2e_failed_reprepare")
inputs = [np.ones(2, np.float32), np.zeros(2, np.float32)]
store = ManualDataStore(tmp_path)
store.write_case(case, "e2e", inputs, [np.ones(2, np.float32)])
switches = _switches(tmp_path, "prepare")
monkeypatch.setattr(e2e_profiling, "get_process_context", _process_context)
monkeypatch.setattr(
e2e_profiling, "generate_inputs", MagicMock(side_effect=RuntimeError("input failure"))
)
result = FrameworkApiReturnStructure()
e2e_profiling._do_profile(
case, SimpleNamespace(alias=lambda: "npu"), {}, {}, 0, switches, result
)
assert result.precision_status == "FAIL"
assert not store.case_dir(case.testcase_name).exists()
def test_e2e_replay_skips_input_and_golden_generation(monkeypatch, tmp_path):
case = _e2e_case("e2e_replay")
inputs = [np.array([1.0, 2.0], np.float32), np.zeros(2, np.float32)]
golden = [np.array([3.0, 4.0], np.float32)]
ManualDataStore(tmp_path).write_case(case, "e2e", inputs, golden)
switches = _switches(tmp_path, "replay")
generated = MagicMock()
evaluated = MagicMock()
def restore(testcase, _switches, _backend, _plan, stored_inputs=None):
assert stored_inputs is not None
testcase.np_storages = stored_inputs
return stored_inputs
generated.side_effect = restore
monkeypatch.setattr(e2e_profiling, "get_process_context", _process_context)
monkeypatch.setattr(e2e_profiling, "generate_inputs", generated)
monkeypatch.setattr(e2e_profiling, "_generate_golden_data",
MagicMock(side_effect=AssertionError("golden generation must be skipped")))
monkeypatch.setattr(e2e_profiling, "resolve_api", lambda *_: (lambda *_: None, False))
monkeypatch.setattr(e2e_profiling, "_execute_eager", lambda *_: (golden, None))
monkeypatch.setattr(e2e_profiling, "DeviceLock", lambda *_args, **_kwargs: nullcontext())
monkeypatch.setattr(e2e_profiling, "_profiling_print", lambda *_: None)
monkeypatch.setattr(e2e_profiling, "_dump_inputs", lambda *_: None)
monkeypatch.setattr(e2e_profiling, "_dump_goldens", lambda *_: None)
monkeypatch.setattr(e2e_profiling, "_dump_outputs", lambda *_: None)
monkeypatch.setattr(e2e_profiling, "_apply_pre_compare", lambda *_: None)
monkeypatch.setattr(e2e_profiling, "_evaluate_eager_precision", evaluated)
monkeypatch.setattr(e2e_profiling, "_profiling_end_print", lambda *_args, **_kwargs: None)
backend = SimpleNamespace(alias=lambda: "npu", use_device=lambda: False)
e2e_profiling._do_profile(
case, backend, {}, {}, 0, switches, FrameworkApiReturnStructure()
)
assert generated.call_count == 1
np.testing.assert_array_equal(evaluated.call_args.args[3][0], golden[0])
def test_e2e_replay_custom_compare_receives_restored_inputs(monkeypatch, tmp_path):
case = _e2e_case("e2e_replay_compare_context")
case.attributes = {"alpha": 1}
case.original_dict = {"remark": "replay-context"}
inputs = [np.array([1.0, 2.0], np.float32), np.zeros(2, np.float32)]
golden = [np.array([3.0, 4.0], np.float32)]
ManualDataStore(tmp_path).write_case(case, "e2e", inputs, golden)
switches = _switches(tmp_path, "replay")
switches.plugin_path = (str(tmp_path),)
captured = {}
def restore(testcase, _switches, _backend, _plan, stored_inputs=None):
testcase.np_storages = list(stored_inputs)
testcase.tensors = tuple(stored_inputs)
return list(stored_inputs)
def custom_compare(output, expected, *, compare_context):
captured["context"] = compare_context
return {
"pass": bool(np.array_equal(output, expected)),
"precision": "REPLAY_CONTEXT",
}
def spec_attr(_api_name, attribute, _plugin_path):
return custom_compare if attribute == "compare" else None
monkeypatch.setattr(e2e_profiling, "get_process_context", _process_context)
monkeypatch.setattr(e2e_profiling, "generate_inputs", restore)
monkeypatch.setattr(
e2e_profiling,
"_generate_golden_data",
MagicMock(side_effect=AssertionError("golden generation must be skipped")),
)
monkeypatch.setattr(e2e_profiling, "get_spec_attr", spec_attr)
monkeypatch.setattr(e2e_profiling, "resolve_api", lambda *_: (lambda *_: None, False))
monkeypatch.setattr(
e2e_profiling, "_execute_eager", lambda *_: ([golden[0].copy()], None)
)
monkeypatch.setattr(
e2e_profiling, "DeviceLock", lambda *_args, **_kwargs: nullcontext()
)
monkeypatch.setattr(e2e_profiling, "_profiling_print", lambda *_: None)
monkeypatch.setattr(e2e_profiling, "_dump_inputs", lambda *_: None)
monkeypatch.setattr(e2e_profiling, "_dump_goldens", lambda *_: None)
monkeypatch.setattr(e2e_profiling, "_dump_outputs", lambda *_: None)
monkeypatch.setattr(
e2e_profiling, "_profiling_end_print", lambda *_args, **_kwargs: None
)
backend = SimpleNamespace(alias=lambda: "npu", use_device=lambda: False)
result = FrameworkApiReturnStructure()
e2e_profiling._do_profile(case, backend, {}, {}, 0, switches, result)
compare_context = captured["context"]
assert result.precision_status == "PASS"
assert result.eager_precision == "REPLAY_CONTEXT"
np.testing.assert_array_equal(compare_context.input_tensors[0], inputs[0])
assert compare_context.input_scalars == ()
assert compare_context.attributes == case.attributes
assert compare_context.csv_fields == case.original_dict
def test_e2e_provider_automatically_selects_replay(monkeypatch, tmp_path):
case = _e2e_case("e2e_provider_replay")
inputs = [np.array([1.0, 2.0], np.float32), np.zeros(2, np.float32)]
golden = [np.array([3.0, 4.0], np.float32)]
ManualDataStore(tmp_path).write_case(case, "e2e", inputs, golden)
switches = _switches(tmp_path, None)
switches.manual_data_dirs = ()
restored = MagicMock()
def restore(testcase, _switches, _backend, _plan, stored_inputs=None):
restored(stored_inputs)
testcase.np_storages = stored_inputs
return stored_inputs
def provider(testcase, case_type, current_switches):
assert testcase is case
assert case_type == "e2e"
assert current_switches is switches
return tmp_path
monkeypatch.setattr(e2e_profiling, "get_process_context", _process_context)
monkeypatch.setattr(e2e_profiling, "generate_inputs", restore)
monkeypatch.setattr(e2e_profiling, "_generate_golden_data",
MagicMock(side_effect=AssertionError("golden generation must be skipped")))
monkeypatch.setattr(e2e_profiling, "resolve_api", lambda *_: (lambda *_: None, False))
monkeypatch.setattr(e2e_profiling, "_execute_eager", lambda *_: (golden, None))
monkeypatch.setattr(e2e_profiling, "DeviceLock", lambda *_args, **_kwargs: nullcontext())
monkeypatch.setattr(e2e_profiling, "_profiling_print", lambda *_: None)
monkeypatch.setattr(e2e_profiling, "_dump_inputs", lambda *_: None)
monkeypatch.setattr(e2e_profiling, "_dump_goldens", lambda *_: None)
monkeypatch.setattr(e2e_profiling, "_dump_outputs", lambda *_: None)
monkeypatch.setattr(e2e_profiling, "_apply_pre_compare", lambda *_: None)
monkeypatch.setattr(e2e_profiling, "_evaluate_eager_precision", lambda *_: None)
monkeypatch.setattr(e2e_profiling, "_profiling_end_print", lambda *_args, **_kwargs: None)
backend = SimpleNamespace(alias=lambda: "npu", use_device=lambda: False)
register_manual_data_directory_provider(provider)
try:
e2e_profiling._do_profile(
case, backend, {}, {}, 0, switches, FrameworkApiReturnStructure()
)
finally:
unregister_manual_data_directory_provider(provider)
assert restored.call_count == 1
def test_aclnn_prepare_stops_before_device_execution(monkeypatch, tmp_path):
case = _aclnn_case("aclnn_prepare")
switches = _switches(tmp_path, "prepare")
inputs = [np.array([1.0, 2.0], np.float32), np.zeros(2, np.float32)]
scalar = np.array(0.5, np.float32)
golden = [np.array([3.0, 4.0], np.float32)]
execute = MagicMock(side_effect=AssertionError("ACLNN must not execute"))
compare = MagicMock(side_effect=AssertionError("ACLNN must not compare"))
class Inputs:
def __init__(self, context):
self.context = context
def gen(self):
self.context.np_storages = inputs
self.context.tensors = inputs
self.context.scalars = (scalar,)
class Golden:
def __init__(self, context):
self.context = context
def gen(self):
self.context.np_storages[0][:] = -1
self.context.scalars[0][...] = 9
self.context.golden_tensors = golden
monkeypatch.setattr(aclnn_profiling, "get_global_storage", lambda: switches)
monkeypatch.setattr(aclnn_profiling, "get_process_context", _process_context)
monkeypatch.setattr(aclnn_profiling, "OpApiInfoKeeper",
lambda: SimpleNamespace(has_api=lambda *_: True))
monkeypatch.setattr(aclnn_profiling, "InputGenerator", Inputs)
monkeypatch.setattr(aclnn_profiling, "GoldenGenerator", Golden)
monkeypatch.setattr(aclnn_profiling, "Comparator", compare)
monkeypatch.setattr(aclnn_profiling, "do_profiling", execute)
monkeypatch.setattr(aclnn_profiling, "__profiling_end_print", lambda *_: None)
result = aclnn_profiling.profile_process(case, {}, {}, 0)
assert result.precision_status == "PASS"
assert result.precision == "MANUAL_DATA_PREPARED"
assert not execute.called
assert not compare.called
loaded = ManualDataStore(tmp_path).load_case(case, "aclnn")
np.testing.assert_array_equal(
loaded.inputs[0],
np.array([1.0, 2.0], np.float32),
)
assert loaded.scalars[0] == np.array(0.5, np.float32)
def test_aclnn_failed_reprepare_invalidates_previous_case(monkeypatch, tmp_path):
case = _aclnn_case("aclnn_failed_reprepare")
inputs = [np.ones(2, np.float32), np.zeros(2, np.float32)]
scalar = [np.array(0.5, np.float32)]
store = ManualDataStore(tmp_path)
store.write_case(
case, "aclnn", inputs, [np.ones(2, np.float32)], scalars=scalar
)
switches = _switches(tmp_path, "prepare")
class Inputs:
def __init__(self, _context):
pass
def gen(self):
raise RuntimeError("input failure")
monkeypatch.setattr(aclnn_profiling, "get_global_storage", lambda: switches)
monkeypatch.setattr(aclnn_profiling, "get_process_context", _process_context)
monkeypatch.setattr(
aclnn_profiling, "OpApiInfoKeeper",
lambda: SimpleNamespace(has_api=lambda *_: True),
)
monkeypatch.setattr(aclnn_profiling, "InputGenerator", Inputs)
result = aclnn_profiling.profile_process(case, {}, {}, 0)
assert result.precision_status == "INPUT_GEN_FAILURE"
assert not store.case_dir(case.testcase_name).exists()
def test_aclnn_replay_skips_input_and_golden_plugins(monkeypatch, tmp_path):
case = _aclnn_case("aclnn_replay")
inputs = [np.array([1.0, 2.0], np.float32), np.zeros(2, np.float32)]
scalar = [np.array(0.5, np.float32)]
golden = [np.array([3.0, 4.0], np.float32)]
ManualDataStore(tmp_path).write_case(
case, "aclnn", inputs, golden, scalars=scalar
)
switches = _switches(tmp_path, "replay")
restore = MagicMock()
class Inputs:
def __init__(self, context):
self.context = context
def gen(self, stored_inputs=None, stored_scalars=None):
restore(stored_inputs, stored_scalars)
self.context.np_storages = stored_inputs
self.context.tensors = stored_inputs
self.context.scalars = stored_scalars
class Comparator:
def __init__(self, context):
self.context = context
def compare(self):
np.testing.assert_array_equal(self.context.golden_tensors[0], golden[0])
return ApiComparisonResult(None).set("100%", "PASS")
monkeypatch.setattr(aclnn_profiling, "get_global_storage", lambda: switches)
monkeypatch.setattr(aclnn_profiling, "get_process_context", _process_context)
monkeypatch.setattr(aclnn_profiling, "OpApiInfoKeeper",
lambda: SimpleNamespace(has_api=lambda *_: True))
monkeypatch.setattr(aclnn_profiling, "InputGenerator", Inputs)
monkeypatch.setattr(aclnn_profiling, "GoldenGenerator",
MagicMock(side_effect=AssertionError("golden plugin must be skipped")))
monkeypatch.setattr(aclnn_profiling, "Comparator", Comparator)
monkeypatch.setattr(aclnn_profiling, "DeviceLock", lambda *_args, **_kwargs: nullcontext())
monkeypatch.setattr(aclnn_profiling, "__profiling_print", lambda *_: None)
monkeypatch.setattr(aclnn_profiling, "__profiling_end_print", lambda *_: None)
monkeypatch.setattr(aclnn_profiling, "__dump_input", lambda *_: None)
monkeypatch.setattr(aclnn_profiling, "__dump_golden", lambda *_: None)
monkeypatch.setattr(aclnn_profiling, "__dump_output", lambda *_: None)
monkeypatch.setattr(
aclnn_profiling,
"do_profiling",
lambda *_: ApiProfilingResult(
True, output_bytes=[np.zeros(2, np.float32).tobytes()],
output_view_shapes=[(2,)],
),
)
result = aclnn_profiling.profile_process(case, {}, {}, 0)
assert result.precision_status == "PASS"
assert restore.call_count == 1
def test_aclnn_replay_runs_current_custom_compare(monkeypatch, tmp_path):
case = _aclnn_case("aclnn_replay_custom_compare")
inputs = [np.array([1.0, 2.0], np.float32), np.zeros(2, np.float32)]
scalar = [np.array(0.5, np.float32)]
golden = [np.array([3.0, 4.0], np.float32)]
ManualDataStore(tmp_path).write_case(
case, "aclnn", inputs, golden, scalars=scalar
)
switches = _switches(tmp_path, "replay")
switches.plugin_path = (str(tmp_path),)
captured = {}
def custom_compare(output, expected, *, compare_context):
captured["context"] = compare_context
return {
"pass": bool(np.array_equal(output, expected)),
"precision": "REPLAY_CUSTOM",
}
class Inputs:
def __init__(self, context):
self.context = context
def gen(self, stored_inputs=None, stored_scalars=None):
self.context.np_storages = stored_inputs
self.context.tensors = stored_inputs
self.context.scalars = stored_scalars
def spec_attr(_api_name, attribute, _plugin_path):
return custom_compare if attribute == "compare" else None
def restore_outputs(comparator):
comparator._ctx.prof_result.output_bytes = [golden[0].copy()]
monkeypatch.setattr(aclnn_profiling, "get_global_storage", lambda: switches)
monkeypatch.setattr(aclnn_comparison, "get_global_storage", lambda: switches)
monkeypatch.setattr(aclnn_comparison, "get_spec_attr", spec_attr)
monkeypatch.setattr(
aclnn_comparison.Comparator, "_output_bytes_to_tensors", restore_outputs
)
monkeypatch.setattr(aclnn_profiling, "get_process_context", _process_context)
monkeypatch.setattr(
aclnn_profiling, "OpApiInfoKeeper",
lambda: SimpleNamespace(has_api=lambda *_: True),
)
monkeypatch.setattr(aclnn_profiling, "InputGenerator", Inputs)
monkeypatch.setattr(
aclnn_profiling, "GoldenGenerator",
MagicMock(side_effect=AssertionError("golden plugin must be skipped")),
)
monkeypatch.setattr(aclnn_profiling, "DeviceLock", lambda *_args, **_kwargs: nullcontext())
monkeypatch.setattr(aclnn_profiling, "__profiling_print", lambda *_: None)
monkeypatch.setattr(aclnn_profiling, "__profiling_end_print", lambda *_: None)
monkeypatch.setattr(aclnn_profiling, "__dump_input", lambda *_: None)
monkeypatch.setattr(aclnn_profiling, "__dump_golden", lambda *_: None)
monkeypatch.setattr(aclnn_profiling, "__dump_output", lambda *_: None)
monkeypatch.setattr(
aclnn_profiling,
"do_profiling",
lambda *_: ApiProfilingResult(
True,
output_bytes=[golden[0].tobytes()],
output_view_shapes=[golden[0].shape],
),
)
result = aclnn_profiling.profile_process(case, {}, {}, 0)
assert result.precision_status == "PASS"
assert result.precision == "REPLAY_CUSTOM"
compare_context = captured["context"]
np.testing.assert_array_equal(compare_context.input_tensors[0], inputs[0])
np.testing.assert_array_equal(compare_context.input_scalars[0], scalar[0])
def test_loaded_golden_still_uses_custom_compare(monkeypatch):
case = _e2e_case("custom_compare")
switches = SWITCHES()
output = np.array([1.0, 2.0], np.float32)
loaded_golden = np.array([1.0, 2.0], np.float32)
custom_compare = MagicMock(return_value={"pass": True, "precision": "CUSTOM_PASS"})
def spec_attr(_api_name, attribute, _plugin_path):
return custom_compare if attribute == "compare" else None
monkeypatch.setattr(e2e_profiling, "get_spec_attr", spec_attr)
result = FrameworkApiReturnStructure()
e2e_profiling._evaluate_eager_precision(
case, [], [output], [loaded_golden], switches, None, result
)
assert result.precision_status == "PASS"
assert result.eager_precision == "CUSTOM_PASS"
np.testing.assert_array_equal(custom_compare.call_args.args[1], loaded_golden)
def test_loaded_golden_still_uses_current_csv_close_tolerance(monkeypatch):
case = _e2e_case("csv_tolerance")
case.precision_tolerances = ((0.0, 0.5),)
case.absolute_precision = (0.0,)
switches = SWITCHES()
switches.compare_method = "close"
monkeypatch.setattr(e2e_profiling, "get_spec_attr", lambda *_: None)
result = FrameworkApiReturnStructure()
e2e_profiling._evaluate_eager_precision(
case,
[],
[np.array([0.0, 1.0], np.float32)],
[np.array([0.0, 0.0], np.float32)],
switches,
None,
result,
)
assert result.precision_status == "PASS"
assert result.eager_precision == "50.0%"