This is an automated email from the ASF dual-hosted git repository.
sanirudh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git
The following commit(s) were added to refs/heads/main by this push:
new a7478cc2b1 [VM][Hexagon] Implement dma_copy and dma_wait builtin for
hexagon (#16448)
a7478cc2b1 is described below
commit a7478cc2b17346bb4586629700e7047464214a87
Author: Abhikrant Sharma <[email protected]>
AuthorDate: Tue Jan 23 22:45:43 2024 +0530
[VM][Hexagon] Implement dma_copy and dma_wait builtin for hexagon (#16448)
* [VM][Hexagon] Implement dma_copy and dma_wait builtin for hexagon
- This is needed for asynchronous transfer of data.
* Fix lint errors and rename file.
---
cmake/modules/Hexagon.cmake | 3 +
src/runtime/relax_vm/hexagon/builtin.cc | 62 +++++++
.../contrib/test_hexagon/test_dma_builtin.py | 192 +++++++++++++++++++++
3 files changed, 257 insertions(+)
diff --git a/cmake/modules/Hexagon.cmake b/cmake/modules/Hexagon.cmake
index 8872118935..21a909e315 100644
--- a/cmake/modules/Hexagon.cmake
+++ b/cmake/modules/Hexagon.cmake
@@ -125,6 +125,9 @@ if(BUILD_FOR_HEXAGON)
file_glob_append(RUNTIME_HEXAGON_SRCS
"${TVMRT_SOURCE_DIR}/hexagon/*.cc"
)
+ # Add builtins to RelaxVM
+ tvm_file_glob(GLOB RELAX_VM_BUILTIN_SRC_CC src/runtime/relax_vm/hexagon/*.cc)
+ list(APPEND RUNTIME_SRCS ${RELAX_VM_BUILTIN_SRC_CC})
else()
file_glob_append(RUNTIME_HEXAGON_SRCS
"${TVMRT_SOURCE_DIR}/hexagon/hexagon_module.cc"
diff --git a/src/runtime/relax_vm/hexagon/builtin.cc
b/src/runtime/relax_vm/hexagon/builtin.cc
new file mode 100644
index 0000000000..d18c434193
--- /dev/null
+++ b/src/runtime/relax_vm/hexagon/builtin.cc
@@ -0,0 +1,62 @@
+/*
+ * 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 src/runtime/relax_vm/hexagon/builtin.cc
+ * \brief The hexagon graph related builtin functions for Relax virtual
machine.
+ */
+
+#include <tvm/runtime/packed_func.h>
+#include <tvm/runtime/registry.h>
+#include <tvm/runtime/relax_vm/vm.h>
+
+#include "../../hexagon/hexagon_device_api.h"
+namespace tvm {
+namespace runtime {
+namespace relax_vm {
+
+TVM_REGISTER_GLOBAL("vm.builtin.hexagon.dma_copy")
+ .set_body_typed([](TVMArgValue vm_ptr, NDArray src_arr, NDArray dst_arr,
int queue_id,
+ bool bypass_cache) {
+ const DLTensor* dptr = dst_arr.operator->();
+ const DLTensor* sptr = src_arr.operator->();
+ void* dst = dptr->data;
+ void* src = sptr->data;
+ uint32_t size = 1;
+ int ret = DMA_RETRY;
+ for (int i = 0; i < dptr->ndim; i++) {
+ size = size * dptr->shape[i];
+ }
+ size = size * sizeof(dptr->dtype);
+ ICHECK(size > 0);
+ do {
+ ret =
tvm::runtime::hexagon::HexagonDeviceAPI::Global()->UserDMA()->Copy(
+ queue_id, dst, src, size, bypass_cache);
+ } while (ret == DMA_RETRY);
+ CHECK(ret == DMA_SUCCESS);
+ });
+
+TVM_REGISTER_GLOBAL("vm.builtin.hexagon.dma_wait")
+ .set_body_typed([](TVMArgValue vm_ptr, int queue_id, int inflight_dma) {
+ ICHECK(inflight_dma >= 0);
+
tvm::runtime::hexagon::HexagonDeviceAPI::Global()->UserDMA()->Wait(queue_id,
inflight_dma);
+ });
+} // namespace relax_vm
+} // namespace runtime
+} // namespace tvm
diff --git a/tests/python/contrib/test_hexagon/test_dma_builtin.py
b/tests/python/contrib/test_hexagon/test_dma_builtin.py
new file mode 100644
index 0000000000..74f25acaba
--- /dev/null
+++ b/tests/python/contrib/test_hexagon/test_dma_builtin.py
@@ -0,0 +1,192 @@
+# 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.
+
+"""
+Test relax vm builtin to enable DMA copy and wait operations.
+"""
+
+import tvm
+import tvm.script
+from tvm import relax
+from tvm.script.parser import ir as I
+from tvm.script.parser import relax as R
+from tvm.script.parser import tir as T
+import tvm.contrib.hexagon
+import tvm.testing
+import numpy as np
+
+# pylint: disable=invalid-name, missing-class-docstring,
missing-function-docstring
+
+
[email protected]_module
+class Module_1D:
+ @T.prim_func
+ def compute_add_in_vtcm(a: T.handle, b: T.handle, c: T.handle) -> None:
+ m = T.int32()
+ A = T.match_buffer(a, (m,), "int32", scope="global.vtcm")
+ B = T.match_buffer(b, (m,), "int32", scope="global.vtcm")
+ C = T.match_buffer(c, (m,), "int32", scope="global.vtcm")
+ for ax0 in T.grid(m):
+ with T.block("T_add"):
+ v_ax0 = T.axis.remap("S", [ax0])
+ T.reads(A[v_ax0], B[v_ax0])
+ T.writes(C[v_ax0])
+ C[v_ax0] = A[v_ax0] + B[v_ax0]
+
+ @R.function
+ def main(
+ x: R.Tensor((12800,), "int32"),
+ y: R.Tensor((12800,), "int32"),
+ ) -> R.Tensor((12800,), "int32"):
+ cls = Module_1D
+ vtcm_obj_a: R.Object = R.vm.alloc_storage(
+ R.shape(
+ [
+ 12800,
+ ]
+ ),
+ runtime_device_index=0,
+ dtype="int32",
+ storage_scope="global.vtcm",
+ )
+ a: R.Tensor([12800,], dtype="int32") = R.vm.alloc_tensor(
+ vtcm_obj_a,
+ offset=0,
+ shape=R.shape(
+ [
+ 12800,
+ ]
+ ),
+ dtype="int32",
+ )
+ __: R.Tuple = R.call_builtin_with_ctx(
+ "vm.builtin.hexagon.dma_copy",
+ [x, a, 0, True],
+ sinfo_args=[],
+ )
+ vtcm_obj_b: R.Object = R.vm.alloc_storage(
+ R.shape(
+ [
+ 12800,
+ ]
+ ),
+ runtime_device_index=0,
+ dtype="int32",
+ storage_scope="global.vtcm",
+ )
+ b: R.Tensor([12800,], dtype="int32") = R.vm.alloc_tensor(
+ vtcm_obj_b,
+ offset=0,
+ shape=R.shape(
+ [
+ 12800,
+ ]
+ ),
+ dtype="int32",
+ )
+ __: R.Tuple = R.call_builtin_with_ctx(
+ "vm.builtin.hexagon.dma_copy",
+ [y, b, 1, True],
+ sinfo_args=[],
+ )
+ vtcm_obj_c: R.Object = R.vm.alloc_storage(
+ R.shape(
+ [
+ 12800,
+ ]
+ ),
+ runtime_device_index=0,
+ dtype="int32",
+ storage_scope="global.vtcm",
+ )
+ c: R.Tensor([12800,], dtype="int32") = R.vm.alloc_tensor(
+ vtcm_obj_c,
+ offset=0,
+ shape=R.shape(
+ [
+ 12800,
+ ]
+ ),
+ dtype="int32",
+ )
+ __: R.Tuple = R.call_builtin_with_ctx(
+ "vm.builtin.hexagon.dma_wait",
+ [0, 2],
+ sinfo_args=[],
+ )
+ __: R.Tuple = R.call_builtin_with_ctx(
+ "vm.builtin.hexagon.dma_wait",
+ [1, 1],
+ sinfo_args=[],
+ )
+ ___: R.Tuple = cls.compute_add_in_vtcm(a, b, c)
+ ret_val: R.Tensor((12800,), dtype="int32") = R.builtin.alloc_tensor(
+ R.shape(
+ [
+ 12800,
+ ]
+ ),
+ R.dtype("int32"),
+ R.prim_value(0),
+ )
+ __: R.Tuple = R.call_builtin_with_ctx(
+ "vm.builtin.hexagon.dma_copy",
+ [c, ret_val, 0, True],
+ sinfo_args=[],
+ )
+ _t3: R.Tuple = R.vm.kill_object(vtcm_obj_a)
+ _t4: R.Tuple = R.vm.kill_object(vtcm_obj_b)
+ _t6: R.Tuple = R.vm.kill_object(a)
+ _t7: R.Tuple = R.vm.kill_object(b)
+ __: R.Tuple = R.call_builtin_with_ctx(
+ "vm.builtin.hexagon.dma_wait",
+ [0, 1],
+ sinfo_args=[],
+ )
+ _t5: R.Tuple = R.vm.kill_object(vtcm_obj_c)
+ _t8: R.Tuple = R.vm.kill_object(c)
+ lv: R.Tensor((12800,), dtype="int32") = ret_val
+ return lv
+
+
+class TestDMACopyWait:
+ """Tests for Copy and wait"""
+
+ mode = tvm.testing.parameter("bytecode", "compiled")
+ module = tvm.testing.parameter(Module_1D)
+
+ @tvm.testing.requires_hexagon
+ def test_vtcm_alloc_compute(self, hexagon_launcher, mode, module):
+ target_hexagon = tvm.target.hexagon("v69")
+ target = tvm.target.Target(target_hexagon, host=target_hexagon)
+ with tvm.transform.PassContext(opt_level=3, config=[]):
+ ex = relax.build(mod=module, target=target, exec_mode=mode)
+ with hexagon_launcher.create_session() as session:
+ dev = session.device
+ input_arg0_data = np.random.randint(0, 9, size=(12800,),
dtype="int32")
+ input_arg1_data = np.random.randint(0, 9, size=(12800,),
dtype="int32")
+ output_data = np.add(input_arg0_data, input_arg1_data)
+ vm_mod = session.get_executor_from_factory(ex)
+ vm_rt = relax.VirtualMachine(
+ vm_mod, dev, "naive"
+ ) # Use naive allocator to exercise VTCM allocation in relax
+ data0 = tvm.nd.array(input_arg0_data, dev)
+ data1 = tvm.nd.array(input_arg1_data, dev)
+ vm_rt.set_input("main", data0, data1)
+ vm_rt.invoke_stateful("main")
+ hexagon_output = vm_rt.get_outputs("main").numpy()
+ tvm.testing.assert_allclose(output_data, hexagon_output)