From f740804182d9adc6c2a79ef1b7b0eadefa94ee6f Mon Sep 17 00:00:00 2001 From: tqchen Date: Thu, 6 Mar 2025 16:42:58 -0500 Subject: [PATCH] [REFACTOR] Cleanup legacy relay runtime data structures This PR cleans up legacy relay runtime data structures ADT and closure as they can be superseded by Array and VMClosure in the relax VM. --- include/tvm/runtime/container/adt.h | 143 --------------------- include/tvm/runtime/container/closure.h | 52 -------- include/tvm/runtime/object.h | 2 - include/tvm/runtime/relax_vm/executable.h | 1 - include/tvm/runtime/relax_vm/vm.h | 8 +- python/tvm/relax/op/base.py | 10 -- python/tvm/runtime/container.py | 53 -------- python/tvm/runtime/name_transforms.py | 32 ----- python/tvm/runtime/profiler_vm.py | 91 ------------- src/node/structural_hash.cc | 27 ---- src/runtime/container.cc | 47 ------- src/runtime/relax_vm/vm.cc | 8 +- tests/cpp/container_test.cc | 14 -- tests/python/relax/test_relax_operators.py | 2 +- 14 files changed, 9 insertions(+), 481 deletions(-) delete mode 100644 include/tvm/runtime/container/adt.h delete mode 100644 include/tvm/runtime/container/closure.h delete mode 100644 python/tvm/runtime/name_transforms.py delete mode 100644 python/tvm/runtime/profiler_vm.py diff --git a/include/tvm/runtime/container/adt.h b/include/tvm/runtime/container/adt.h deleted file mode 100644 index 013a055bd003..000000000000 --- a/include/tvm/runtime/container/adt.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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. - */ - -/*! - * \file tvm/runtime/container/adt.h - * \brief Runtime ADT container types. - */ -#ifndef TVM_RUNTIME_CONTAINER_ADT_H_ -#define TVM_RUNTIME_CONTAINER_ADT_H_ - -#include -#include - -#include "./base.h" - -namespace tvm { -namespace runtime { - -/*! \brief An object representing a structure or enumeration. */ -class ADTObj : public Object, public InplaceArrayBase { - public: - /*! \brief The tag representing the constructor used. */ - int32_t tag; - /*! \brief Number of fields in the ADT object. */ - uint32_t size; - // The fields of the structure follows directly in memory. - - static constexpr const uint32_t _type_index = TypeIndex::kRuntimeADT; - static constexpr const char* _type_key = "runtime.ADT"; - TVM_DECLARE_FINAL_OBJECT_INFO(ADTObj, Object); - - private: - /*! - * \return The number of elements in the array. - */ - size_t GetSize() const { return size; } - - /*! - * \brief Initialize the elements in the array. - * - * \tparam Iterator Iterator type of the array. - * \param begin The begin iterator. - * \param end The end iterator. - */ - template - void Init(Iterator begin, Iterator end) { - size_t num_elems = std::distance(begin, end); - this->size = 0; - auto it = begin; - for (size_t i = 0; i < num_elems; ++i) { - InplaceArrayBase::EmplaceInit(i, *it++); - // Only increment size after the initialization succeeds - this->size++; - } - } - - friend class ADT; - friend InplaceArrayBase; -}; - -/*! \brief reference to algebraic data type objects. */ -class ADT : public ObjectRef { - public: - /*! - * \brief construct an ADT object reference. - * \param tag The tag of the ADT object. - * \param fields The fields of the ADT object. - */ - ADT(int32_t tag, std::vector fields) : ADT(tag, fields.begin(), fields.end()){}; - - /*! - * \brief construct an ADT object reference. - * \param tag The tag of the ADT object. - * \param begin The begin iterator to the start of the fields array. - * \param end The end iterator to the end of the fields array. - */ - template - ADT(int32_t tag, Iterator begin, Iterator end) { - size_t num_elems = std::distance(begin, end); - auto ptr = make_inplace_array_object(num_elems); - ptr->tag = tag; - ptr->Init(begin, end); - data_ = std::move(ptr); - } - - /*! - * \brief construct an ADT object reference. - * \param tag The tag of the ADT object. - * \param init The initializer list of fields. - */ - ADT(int32_t tag, std::initializer_list init) : ADT(tag, init.begin(), init.end()){}; - - /*! - * \brief Access element at index. - * - * \param idx The array index - * \return const ObjectRef - */ - const ObjectRef& operator[](size_t idx) const { return operator->()->operator[](idx); } - - /*! - * \brief Return the ADT tag. - */ - int32_t tag() const { return operator->()->tag; } - - /*! - * \brief Return the number of fields. - */ - size_t size() const { return operator->()->size; } - - /*! - * \brief Construct a tuple object. - * - * \tparam Args Type params of tuple feilds. - * \param args Tuple fields. - * \return ADT The tuple object reference. - */ - template - static ADT Tuple(Args&&... args) { - return ADT(0, std::forward(args)...); - } - - TVM_DEFINE_OBJECT_REF_METHODS(ADT, ObjectRef, ADTObj); -}; -} // namespace runtime -} // namespace tvm -#endif // TVM_RUNTIME_CONTAINER_ADT_H_ diff --git a/include/tvm/runtime/container/closure.h b/include/tvm/runtime/container/closure.h deleted file mode 100644 index a280d1ada7a9..000000000000 --- a/include/tvm/runtime/container/closure.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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. - */ - -/*! - * \file tvm/runtime/container/closure.h - * \brief Runtime Closure container types. - */ -#ifndef TVM_RUNTIME_CONTAINER_CLOSURE_H_ -#define TVM_RUNTIME_CONTAINER_CLOSURE_H_ - -#include "./base.h" - -namespace tvm { -namespace runtime { - -/*! - * \brief An object representing a closure. This object is used by both the - * Relay VM and interpreter. - */ -class ClosureObj : public Object { - public: - static constexpr const uint32_t _type_index = TypeIndex::kRuntimeClosure; - static constexpr const char* _type_key = "runtime.Closure"; - TVM_DECLARE_BASE_OBJECT_INFO(ClosureObj, Object); -}; - -/*! \brief reference to closure. */ -class Closure : public ObjectRef { - public: - TVM_DEFINE_OBJECT_REF_METHODS(Closure, ObjectRef, ClosureObj); -}; - -} // namespace runtime -} // namespace tvm - -#endif // TVM_RUNTIME_CONTAINER_CLOSURE_H_ diff --git a/include/tvm/runtime/object.h b/include/tvm/runtime/object.h index ea31fcac48e2..81dcb43c0b52 100644 --- a/include/tvm/runtime/object.h +++ b/include/tvm/runtime/object.h @@ -77,8 +77,6 @@ struct TypeIndex { /*! \brief runtime::RPCObjectRef */ kRuntimeRPCObjectRef = 9, // static assignments that may subject to change. - kRuntimeClosure, - kRuntimeADT, kStaticIndexEnd, /*! \brief Type index is allocated during runtime. */ kDynamic = kStaticIndexEnd diff --git a/include/tvm/runtime/relax_vm/executable.h b/include/tvm/runtime/relax_vm/executable.h index 845842f22ac4..e953d94eb956 100644 --- a/include/tvm/runtime/relax_vm/executable.h +++ b/include/tvm/runtime/relax_vm/executable.h @@ -23,7 +23,6 @@ #ifndef TVM_RUNTIME_RELAX_VM_EXECUTABLE_H_ #define TVM_RUNTIME_RELAX_VM_EXECUTABLE_H_ -#include #include #include #include diff --git a/include/tvm/runtime/relax_vm/vm.h b/include/tvm/runtime/relax_vm/vm.h index da833d5d6c5f..607269d812ab 100644 --- a/include/tvm/runtime/relax_vm/vm.h +++ b/include/tvm/runtime/relax_vm/vm.h @@ -60,7 +60,7 @@ enum class VMInstrumentReturnKind : int { /*! * \brief An object representing a vm closure. */ -class VMClosureObj : public ClosureObj { +class VMClosureObj : public Object { public: /*! * \brief The function name. The function could be any @@ -78,14 +78,14 @@ class VMClosureObj : public ClosureObj { static constexpr const uint32_t _type_index = TypeIndex::kDynamic; static constexpr const char* _type_key = "relax.vm.Closure"; - TVM_DECLARE_FINAL_OBJECT_INFO(VMClosureObj, ClosureObj); + TVM_DECLARE_FINAL_OBJECT_INFO(VMClosureObj, Object); }; /*! \brief reference to closure. */ -class VMClosure : public Closure { +class VMClosure : public ObjectRef { public: VMClosure(String func_name, PackedFunc impl); - TVM_DEFINE_OBJECT_REF_METHODS(VMClosure, Closure, VMClosureObj); + TVM_DEFINE_OBJECT_REF_METHODS(VMClosure, ObjectRef, VMClosureObj); /*! * \brief Create another PackedFunc with last arguments already bound to last_args. diff --git a/python/tvm/relax/op/base.py b/python/tvm/relax/op/base.py index 03e86a4633a6..b0570344e5a0 100644 --- a/python/tvm/relax/op/base.py +++ b/python/tvm/relax/op/base.py @@ -416,16 +416,6 @@ def render_object(val: tvm.Object) -> str: """ if isinstance(val, tvm.nd.NDArray): return str(val) - # no pretty-printer by default, so if we don't handle this, - # then we can't look inside tuples - if isinstance(val, tvm.runtime.container.ADT): - # the fields array of an ADT cannot be directly accessed in Python - # so we have to get the length and index into the fields separately - fields = ", ".join([render_object(val[i]) for i in range(len(val))]) - # special case: tag = 0 is a tuple - if val.tag == 0: - return f"({fields})" - return f"ADT(tag={val.tag}, fields=[{fields}])" if isinstance(val, tvm.ir.Array): fields = ", ".join([render_object(val[i]) for i in range(len(val))]) return f"({fields})" diff --git a/python/tvm/runtime/container.py b/python/tvm/runtime/container.py index f1a0706a387d..1bc8d798efa7 100644 --- a/python/tvm/runtime/container.py +++ b/python/tvm/runtime/container.py @@ -17,7 +17,6 @@ """Runtime container structures.""" import tvm._ffi from .object import Object, PyNativeObject -from .object_generic import ObjectTypes from . import _ffi_api @@ -60,58 +59,6 @@ def getitem_helper(obj, elem_getter, length, idx): return elem_getter(obj, idx) -@tvm._ffi.register_object("runtime.ADT") -class ADT(Object): - """Algebatic data type(ADT) object. - - Parameters - ---------- - tag : int - The tag of ADT. - - fields : list[Object] or tuple[Object] - The source tuple. - """ - - def __init__(self, tag, fields): - for f in fields: - assert isinstance( - f, ObjectTypes - ), f"Expect object or tvm NDArray type, but received : {type(f)}" - self.__init_handle_by_constructor__(_ffi_api.ADT, tag, *fields) - - @property - def tag(self): - return _ffi_api.GetADTTag(self) - - def __getitem__(self, idx): - return getitem_helper(self, _ffi_api.GetADTFields, len(self), idx) - - def __len__(self): - return _ffi_api.GetADTSize(self) - - -def tuple_object(fields=None): - """Create a ADT object from source tuple. - - Parameters - ---------- - fields : list[Object] or tuple[Object] - The source tuple. - - Returns - ------- - ret : ADT - The created object. - """ - fields = fields if fields else [] - for f in fields: - assert isinstance( - f, ObjectTypes - ), f"Expect object or tvm NDArray type, but received : {type(f)}" - return _ffi_api.Tuple(*fields) - - @tvm._ffi.register_object("runtime.String") class String(str, PyNativeObject): """TVM runtime.String object, represented as a python str. diff --git a/python/tvm/runtime/name_transforms.py b/python/tvm/runtime/name_transforms.py deleted file mode 100644 index 402a47f1a114..000000000000 --- a/python/tvm/runtime/name_transforms.py +++ /dev/null @@ -1,32 +0,0 @@ -# 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. -""" -Name transformation functions shared in Backend and Runtime -""" - -from . import _ffi_api - - -def sanitize_name(original_name: str): - """Sanitize name for output into compiler artifacts - - Parameters - ---------- - original_name : str - Original name to sanitize - """ - return _ffi_api.SanitizeName(original_name) diff --git a/python/tvm/runtime/profiler_vm.py b/python/tvm/runtime/profiler_vm.py deleted file mode 100644 index 4f625c0c67f1..000000000000 --- a/python/tvm/runtime/profiler_vm.py +++ /dev/null @@ -1,91 +0,0 @@ -# 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=no-else-return, unidiomatic-typecheck, undefined-variable, invalid-name, redefined-builtin -""" -The Relay Virtual Machine profiler. - -Provides extra APIs for profiling vm execution. -""" -import warnings -from tvm.runtime import _ffi_api -from tvm.rpc import base as rpc_base -from . import vm -from .profiling import Report - - -def enabled(): - """Whether vm profiler is enabled.""" - return hasattr(_ffi_api, "_VirtualMachineDebug") - - -class VirtualMachineProfiler(vm.VirtualMachine): - """Relay profile VM runtime.""" - - def __init__(self, exe, device, memory_cfg=None): - super(VirtualMachineProfiler, self).__init__(exe, device, memory_cfg) - - # Make sure the constructor of the VM module is on the proper device - # Remote devices have device_type of their actual device_type + RPC_SESS_MASK - if device.device_type >= rpc_base.RPC_SESS_MASK: - self.module = device._rpc_sess.get_function("runtime._VirtualMachineDebug")(exe) - else: - self.module = _ffi_api._VirtualMachineDebug(exe.module) - - self._init = self.module["init"] - self._invoke = self.module["invoke"] - self._profile = self.module["profile"] - self._profile_rpc = self.module["profile_rpc"] - self._set_input = self.module["set_input"] - self._setup_device(device, memory_cfg) - - def get_stat(self, sort_by_time=True): # pylint: disable=unused-argument - """Get the statistics of executed ops. - - REMOVED, use profile method instead. - """ - warnings.warn("get_stat has been removed, use profile instead") - return "" - - def profile(self, *args, func_name="main", collectors=None, **kwargs): - """Profile a function call. - - Parameters - ---------- - func_name : str - The name of the function. - - collectors : Optional[Sequence[MetricCollector]] - Extra metrics to collect. If profiling over RPC, collectors must be `None`. - - args : list[tvm.runtime.NDArray] or list[np.ndarray] - The arguments to the function. - - kwargs: dict of str to tvm.runtime.NDArray or np.ndarray - Named arguments to the function. - - Returns - ------- - timing_results : str - Overall and per-op timing results formatted in a table. - """ - if args or kwargs: - self.set_input(func_name, *args, **kwargs) - if self.module.type_key == "rpc": - # We cannot serialize MetricCollectors over RPC - assert collectors is None, "Profiling with collectors is not supported over RPC" - return Report.from_json(self._profile_rpc(func_name)) - return self._profile(func_name, collectors) diff --git a/src/node/structural_hash.cc b/src/node/structural_hash.cc index 1c2d766e0c5f..0a4d9d13354b 100644 --- a/src/node/structural_hash.cc +++ b/src/node/structural_hash.cc @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -345,32 +344,6 @@ TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable) p->stream << '"' << support::StrEscape(op->data, op->size) << '"'; }); -struct ADTObjTrait { - static constexpr const std::nullptr_t VisitAttrs = nullptr; - - static void SHashReduce(const runtime::ADTObj* key, SHashReducer hash_reduce) { - hash_reduce(key->tag); - hash_reduce(static_cast(key->size)); - for (uint32_t i = 0; i < key->size; ++i) { - hash_reduce((*key)[i]); - } - } - - static bool SEqualReduce(const runtime::ADTObj* lhs, const runtime::ADTObj* rhs, - SEqualReducer equal) { - if (lhs == rhs) return true; - if (lhs->tag != rhs->tag) return false; - if (lhs->size != rhs->size) return false; - - for (uint32_t i = 0; i < lhs->size; ++i) { - if (!equal((*lhs)[i], (*rhs)[i])) return false; - } - return true; - } -}; - -TVM_REGISTER_REFLECTION_VTABLE(runtime::ADTObj, ADTObjTrait); - struct ModuleNodeTrait { static constexpr const std::nullptr_t VisitAttrs = nullptr; static constexpr const std::nullptr_t SHashReduce = nullptr; diff --git a/src/runtime/container.cc b/src/runtime/container.cc index 7b5105a3fc94..cf1fa6c83acd 100644 --- a/src/runtime/container.cc +++ b/src/runtime/container.cc @@ -21,9 +21,7 @@ * \file src/runtime/container.cc * \brief Implementations of common containers. */ -#include #include -#include #include #include #include @@ -66,48 +64,6 @@ TVM_REGISTER_GLOBAL("runtime.ArraySize").set_body([](TVMArgs args, TVMRetValue* *ret = static_cast(static_cast(ptr)->size()); }); -// ADT - -TVM_REGISTER_OBJECT_TYPE(ADTObj); - -TVM_REGISTER_GLOBAL("runtime.GetADTTag").set_body([](TVMArgs args, TVMRetValue* rv) { - ObjectRef obj = args[0]; - const auto& adt = Downcast(obj); - *rv = static_cast(adt.tag()); -}); - -TVM_REGISTER_GLOBAL("runtime.GetADTSize").set_body([](TVMArgs args, TVMRetValue* rv) { - ObjectRef obj = args[0]; - const auto& adt = Downcast(obj); - *rv = static_cast(adt.size()); -}); - -TVM_REGISTER_GLOBAL("runtime.GetADTFields").set_body([](TVMArgs args, TVMRetValue* rv) { - ObjectRef obj = args[0]; - int idx = args[1]; - const auto& adt = Downcast(obj); - ICHECK_LT(idx, adt.size()); - *rv = adt[idx]; -}); - -TVM_REGISTER_GLOBAL("runtime.Tuple").set_body([](TVMArgs args, TVMRetValue* rv) { - std::vector fields; - for (auto i = 0; i < args.size(); ++i) { - fields.push_back(args[i]); - } - *rv = ADT::Tuple(fields); -}); - -TVM_REGISTER_GLOBAL("runtime.ADT").set_body([](TVMArgs args, TVMRetValue* rv) { - int itag = args[0]; - size_t tag = static_cast(itag); - std::vector fields; - for (int i = 1; i < args.size(); i++) { - fields.push_back(args[i]); - } - *rv = ADT(tag, fields); -}); - // String TVM_REGISTER_OBJECT_TYPE(StringObj); @@ -180,9 +136,6 @@ TVM_REGISTER_GLOBAL("runtime.MapItems").set_body([](TVMArgs args, TVMRetValue* r *ret = std::move(rkvs); }); -// Closure -TVM_REGISTER_OBJECT_TYPE(ClosureObj); - // ShapeTuple TVM_REGISTER_OBJECT_TYPE(ShapeTupleObj); diff --git a/src/runtime/relax_vm/vm.cc b/src/runtime/relax_vm/vm.cc index ebb5afb1f4ae..1442f6cd0699 100644 --- a/src/runtime/relax_vm/vm.cc +++ b/src/runtime/relax_vm/vm.cc @@ -70,12 +70,12 @@ PackedFunc VMClosure::BindLastArgs(PackedFunc func, std::vector las // Utility functions. //----------------------------------------------------------- // Use the args after `starting_arg_idx` as a series of indices into `obj`, -// indexing into nested ADTs and returning the final indexed object. +// indexing into nested Array and returning the final indexed object. ObjectRef IndexIntoNestedObject(ObjectRef obj, TVMArgs args, int starting_arg_idx) { for (int i = starting_arg_idx; i < args.size(); i++) { - // the object must be an ADT to be able to index into it + // the object must be an Array to be able to index into it if (!obj.as()) { - LOG(FATAL) << "ValueError: Attempted to index into an object that is not an ADT."; + LOG(FATAL) << "ValueError: Attempted to index into an object that is not an Array."; } int index = args[i]; auto arr = Downcast>(obj); @@ -283,7 +283,7 @@ class VirtualMachineImpl : public VirtualMachine { * \param save_name The saved name of the function. * \param include_return Whether forward the return value, set it to false allows * us to ignore forwarding return value, which can be helpful to do benchmarking - * in RPC environment when return value is complicated ADT. + * in RPC environment when return value is complicated Array. * * \param args The arguments to bound to the function. * \note This function is used by RPC server to help benchmarking. diff --git a/tests/cpp/container_test.cc b/tests/cpp/container_test.cc index 0a089eaebde3..6f0c47c0eacc 100644 --- a/tests/cpp/container_test.cc +++ b/tests/cpp/container_test.cc @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -99,19 +98,6 @@ class TestArrayObj : public Object, public InplaceArrayBase fields; - auto f1 = ADT::Tuple(fields); - auto f2 = ADT::Tuple(fields); - ADT v1{1, {f1, f2}}; - ASSERT_EQ(f1.tag(), 0); - ASSERT_EQ(f2.size(), 0); - ASSERT_EQ(v1.tag(), 1); - ASSERT_EQ(v1.size(), 2); - ASSERT_EQ(Downcast(v1[0]).tag(), 0); - ASSERT_EQ(Downcast(v1[1]).size(), 0); -} - TEST(InplaceArrayBase, BadExceptionSafety) { auto wrong_init = []() { TestErrorSwitch f1{false}; diff --git a/tests/python/relax/test_relax_operators.py b/tests/python/relax/test_relax_operators.py index a80b988d06c4..1fdded92393c 100644 --- a/tests/python/relax/test_relax_operators.py +++ b/tests/python/relax/test_relax_operators.py @@ -378,7 +378,7 @@ def inplace_tuple_add(a, b): for j in range(len(arr_a[i])): arr_a[i][j] = arr_a[i][j] + arr_b[i][j] a.copyfrom(arr_a) - return tvm.runtime.container.ADT(0, [a, c]) + return tvm.runtime.convert([a, c]) @tvm.script.ir_module class CallInplaceTuple: