# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # pylint: disable=dangerous-default-value """Testing utilities for the TensorIR schedule API""" from collections.abc import Sequence from typing import Any import tvm from tvm.ir import IRModule, assert_structural_equal from tvm.s_tir.schedule import Schedule, Trace from tvm.tirx import PrimFunc def assert_structural_equal_ignore_global_symbol( func1: PrimFunc, func2: PrimFunc, *args: Any, **kwargs: Any, ) -> None: """ Asserts that PrimFuncs func1 and func2 are structurally equal, setting both their global symbol attributes to main so that the global symbol will not be a point of comparison. """ assert_structural_equal( func1.with_attr("global_symbol", "main"), func2.with_attr("global_symbol", "main"), *args, **kwargs, ) def verify_trace_roundtrip( sch: Schedule, mod: PrimFunc | IRModule, *, debug_mask: str | int = "all", text_format: str | Sequence[str] = ["python", "json"], ) -> Schedule: """Serialize a traced schedule to JSON, then replay the JSON trace by applying to a fresh new schedule, verifying the reproducibility of scheduling. Parameters ---------- sch : s_tir.Schedule The traced TensorIR schedule to be verified mod : Union[PrimFunc, IRModule] The IRModule or PrimFunc to construct the fresh new schedule debug_mask : Union[str, int] Do extra correctness checking after the class creation and each time after calling the Replace method. Possible choices of `debug_mask`: 1) "all" - Turn on all the checks 2) "none" - Turn off all the checks 3) An integer - Turn on checks according to the bitmasks provided in ScheduleDebugMask text_format: Union[str, Sequence[str]] The text format or formats whose round-trip behavior should be validated. If a single string, validate round-trips through """ from tvm.script import tirx as T # pylint: disable=import-outside-toplevel if not isinstance(text_format, str): for opt in text_format: new_sch = verify_trace_roundtrip(sch, mod, debug_mask=debug_mask, text_format=opt) return new_sch trace = sch.trace assert trace is not None # Step 1. Perform a round-trip through the text-format new_sch = Schedule(mod=mod, debug_mask=debug_mask) if text_format == "json": json_obj = trace.as_json() Trace.apply_json_to_schedule(json_obj=json_obj, sch=new_sch) elif text_format == "python": py_trace = "\n".join(trace.as_python()) vars_dict = {"T": T} vars_dict.update(tvm.tirx.__dict__) exec(py_trace, vars_dict, {"sch": new_sch}) # pylint: disable=exec-used else: assert text_format in ("json", "python"), f"Unknown text format: {text_format}" # Step 2. Verify that the round-trip produced the same scheduling assert_structural_equal(new_sch.mod, sch.mod) # Step 3. Check the consistency of the text format between the old and new traces py_repr = "\n".join(trace.as_python()) new_py_repr = "\n".join(new_sch.trace.as_python()) assert py_repr == new_py_repr # Step 4. Return the new schedule in case it could be useful return new_sch