You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tvm.apache.org by GitBox <gi...@apache.org> on 2020/04/06 17:26:48 UTC
[GitHub] [incubator-tvm] kparzysz-quic opened a new pull request #5252:
[RUNTIME] Initial implementation of Hexagon runtime support
kparzysz-quic opened a new pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252
This is only the TVM runtime. The FastRPC libraries, simulator driver, etc. will be provided in subsequent commits.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] FrozenGene commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
FrozenGene commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r405412981
##########
File path: src/runtime/hexagon/hexagon_module.cc
##########
@@ -0,0 +1,561 @@
+/*
+ * 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.
+ */
+
+#include "hexagon_module.h"
+
+#ifdef __ANDROID__
+#include <android/log.h>
+#endif
+#include <dmlc/logging.h>
+#include <tvm/runtime/registry.h>
+
+#include <memory>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "../file_util.h"
+#include "../meta_data.h"
+
+namespace tvm {
+namespace runtime {
+
+hexagon::Device::~Device() {}
+
+namespace hexagon {
+
+/*!
+ * \brief Function argument locations according to the Hexagon ABI.
+ *
+ * In order to invoke a function whose arguments are in TVMArgs list, at
+ * some point before branching to the function's address, these arguments
+ * need to be loaded into locations (registers or stack) specified by the
+ * corresponding ABI.
+ * When a host wants to call a function on Hexagon, the host will identify
+ * how each element of the TVMArgs list will be passed to the Hexagon
+ * function. This class is a description of which values should go into
+ * registers, and which values should be on stack. Right before the call
+ * this class will be serialized and transfereed over to the Hexagon side.
+ * The code running on Hexagon will then execute the argument placement
+ * and invoke the function.
+ */
+struct ArgLayout {
+ std::vector<uint32_t> Scalar; /*!< Values going into registers, maximum */
+ /*!< 6, including dummy values for skipped */
+ /*!< registers. */
+ std::vector<uint32_t> Stack; /*!< Values going on stack, including */
+ /*!< dummy values for padding. */
+ // There are no vector types at this time.
+
+ /*!
+ * \brief Alignment of type T on Hexagon.
+ */
+ template <typename T>
+ static constexpr unsigned align_of();
+ /*!
+ * \brief Size of type T on Hexagon.
+ */
+ template <typename T>
+ static constexpr unsigned size_of();
+
+ /*!
+ * \brief Add a value of type T to the layout.
+ */
+ template <typename T>
+ void Push(const T& v);
+
+ private:
+ /*!
+ * \brief Add raw data to the layout.
+ * \param v Pointer to the raw data as an array of 32-bit words.
+ * \param t_size Number of bytes to add.
+ * \param t_align Required alignment of the data on Hexagon.
+ */
+ void Push(uint32_t* v, unsigned t_size, unsigned t_align);
+};
+
+template <>
+constexpr unsigned ArgLayout::align_of<int32_t>() {
+ return 4;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<uint32_t>() {
+ return 4;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<float>() {
+ return 4;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<void*>() {
+ return 4;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<int64_t>() {
+ return 8;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<uint64_t>() {
+ return 8;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<double>() {
+ return 8;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<DLTensor*>() {
+ return 4;
+}
+
+template <typename T>
+constexpr unsigned ArgLayout::align_of() {
+ // The static_assertion should depend on T so that it's only checked
+ // after instantiation.
+ static_assert((sizeof(T), false), "Implement align_of for this type");
+ return 0;
+}
+
+template <typename T>
+constexpr unsigned ArgLayout::size_of() {
+ return ArgLayout::align_of<T>();
+}
+
+template <typename T>
+void ArgLayout::Push(const T& v) {
+ static_assert(std::is_scalar<T>::value, "T must be a scalar");
+ constexpr unsigned T_size = size_of<T>();
+ // The reason for this assertion is to avoid sign-extensions here:
+ // an extra bit of information would be required to determine whether
+ // a size- or a zero-extension is needed.
+ static_assert(T_size >= 4, "Type should be of size that is at least 4");
+ union {
+ uint32_t v[(T_size + 3) / 4];
+ T t;
+ } u;
+
+ u.t = v;
+ Push(u.v, T_size, align_of<T>());
+}
+
+void ArgLayout::Push(uint32_t* v, unsigned t_size, unsigned t_align) {
+ // t_size == 4 and t_size == 8 can be passed in scalar registers.
+ bool InReg = false;
+ if (t_size == 4) {
+ if (Scalar.size() < 6) {
+ Scalar.push_back(v[0]);
+ InReg = true;
+ }
+ } else if (t_size == 8) {
+ // Round the size up to the next
+ unsigned cs = Scalar.size();
+ if (cs <= 4) {
+ // There is room in the scalar registers.
+ if (cs & 1) Scalar.push_back(0u);
+ Scalar.push_back(v[0]);
+ Scalar.push_back(v[1]);
+ InReg = true;
+ }
+ }
+
+ if (!InReg) {
+ // Allocate on stack.
+ CHECK_EQ((t_align & (t_align - 1)), 0)
+ << "Alignment should be a power of 2";
+ CHECK_GE(t_align, 4) << "Alignment should be at least 4";
+ // Round t_size up to a multiple of 4.
+ unsigned s_size = Stack.size();
+ unsigned s_align = t_align / 4; // Alignment of T in words on the stack.
+ unsigned pad = ((s_size + s_align - 1) / s_align) * s_align - s_size;
+ Stack.insert(Stack.end(), pad / 4, 0u);
+ Stack.insert(Stack.end(), v, v + t_size / 4);
+ }
+}
+
+} // namespace hexagon
+
+class HexagonModuleNode final : public runtime::ModuleNode {
+ public:
+ HexagonModuleNode(std::string data, std::string fmt,
+ std::unordered_map<std::string, FunctionInfo> fmap,
+ std::string asm_str, std::string obj_str,
+ std::string ir_str, std::string bc_str,
+ const std::set<std::string>& packed_c_abi)
+ : hexagon_device_(hexagon::Device::Global()),
+ data_(data),
+ fmt_(fmt),
+ fmap_(fmap),
+ asm_(asm_str),
+ obj_(obj_str),
+ ir_(ir_str),
+ bc_(bc_str),
+ packed_c_abi_funcs_(packed_c_abi) {
+ dl_handle_ = hexagon_device_->Load(data, fmt);
+ }
+ ~HexagonModuleNode() {
+ if (dl_handle_) {
+ hexagon_device_->Unload(dl_handle_);
+ }
+ }
+
+ PackedFunc GetFunction(const std::string& name,
+ const ObjectPtr<Object>& sptr_to_self) final;
+
+ const char* type_key() const final { return "hexagon"; }
+
+ void SaveToFile(const std::string& file_name,
+ const std::string& format) final {
+ std::string fmt = runtime::GetFileFormat(file_name, format);
+ if (fmt == "so" || fmt == "dll" || fmt == "hexagon") {
+ std::string meta_file = GetMetaFilePath(file_name);
+ SaveMetaDataToFile(meta_file, fmap_);
+ std::string c = "cp " + data_ + " " + file_name;
+ CHECK(std::system(c.c_str()) == 0) << "Cannot create " + file_name;
+ } else if (fmt == "s" || fmt == "asm") {
+ CHECK(!asm_.empty()) << "Assembler source not available";
+ SaveBinaryToFile(file_name, asm_);
+ } else if (fmt == "o" || fmt == "obj") {
+ CHECK(!obj_.empty()) << "Object data not available";
+ SaveBinaryToFile(file_name, obj_);
+ } else if (fmt == "ll") {
+ CHECK(!ir_.empty()) << "LLVM IR source not available";
+ SaveBinaryToFile(file_name, ir_);
+ } else if (fmt == "bc") {
+ CHECK(!bc_.empty()) << "LLVM IR bitcode not available";
+ SaveBinaryToFile(file_name, bc_);
+ } else {
+ LOG(FATAL) << "HexagonModuleNode::SaveToFile: unhandled format `" << fmt
+ << "'";
+ }
+ }
+ void SaveToBinary(dmlc::Stream* stream) final {
+ stream->Write(fmt_);
+ stream->Write(fmap_);
+ stream->Write(data_);
+ }
+
+ private:
+ void CallRemotePackedCABI(void* func_ptr, const TVMArgs& args,
+ TVMRetValue* rv) const;
+ void CallRemoteDirect(void* func_ptr, const TVMArgs& args,
+ TVMRetValue* rv) const;
+ void RemapArgs(const TVMArgs& args,
+ std::vector<TVMValue>& values, // NOLINT(*)
+ std::vector<int>& type_codes, // NOLINT(*)
+ std::vector<void*>& remote_tensors) const; // NOLINT(*)
+ void* CreateRemoteTensor(const DLTensor* T) const;
+ hexagon::ArgLayout BuildArgLayout(const TVMArgs& Aa) const;
+
+ std::shared_ptr<hexagon::Device> hexagon_device_;
+ void* dl_handle_ = nullptr;
+ std::string data_;
+ std::string fmt_;
+ std::unordered_map<std::string, FunctionInfo> fmap_;
+ std::string asm_;
+ std::string obj_;
+ std::string ir_;
+ std::string bc_;
+ std::set<std::string> packed_c_abi_funcs_;
+};
+
+void HexagonModuleNode::CallRemotePackedCABI(void* func_ptr,
+ const TVMArgs& args,
+ TVMRetValue* rv) const {
+ // Remap all arguments, creating remote DLTensors.
+ std::vector<TVMValue> values;
+ std::vector<int> codes;
+ std::vector<void*> remote_tensors;
+
+ RemapArgs(args, values, codes, remote_tensors);
+ // The prototype of packed C function is
+ // int (TVMValue* args, int* type_codes, int num_args,
+ // TVMValue* ret_value, int* ret_code)
+ // The pointers must point to allocated space, the return information
+ // will be filled in by the callee.
+ // Allocate remote buffer to hold:
+ // 1. argument TVMValues,
+ // 2. return TVMValue,
+ // 3. argument type codes,
+ // 4. return type code.
+
+ int num_args = args.size();
+ int values_size = num_args * sizeof(TVMValue);
+ int codes_size = num_args * sizeof(int);
+ void* remote = hexagon_device_->Alloc(
+ values_size + sizeof(TVMValue) + codes_size + sizeof(int), 8);
+
+ // Copy all argument TVMValues to the remote space.
+ void* remote_values = remote;
+ void* remote_ret_value = static_cast<char*>(remote_values) + values_size;
+ void* remote_codes = static_cast<char*>(remote_ret_value) + sizeof(TVMValue);
+ void* remote_ret_code = static_cast<char*>(remote_codes) + codes_size;
+ hexagon_device_->CopyHostToDevice(remote_values, values.data(), values_size);
+ hexagon_device_->CopyHostToDevice(remote_codes, codes.data(), codes_size);
+
+ // Call the function: construct temporary values/codes and pass them through
+ // the arg layout building to preprare for the actual remote call.
+ TVMValue temp_values[5];
+ temp_values[0].v_handle = remote_values;
+ temp_values[1].v_handle = remote_codes;
+ temp_values[2].v_int64 = num_args;
+ temp_values[3].v_handle = remote_ret_value;
+ temp_values[4].v_handle = remote_ret_code;
+ int temp_codes[5] = {kTVMOpaqueHandle, kTVMOpaqueHandle, kDLInt,
+ kTVMOpaqueHandle, kTVMOpaqueHandle};
+ TVMArgs temp_args(temp_values, temp_codes, 5);
+ hexagon::ArgLayout as = BuildArgLayout(temp_args);
+ hexagon_device_->Call(func_ptr, as.Scalar.data(), as.Scalar.size(),
+ as.Stack.data(), as.Stack.size());
+
+ // TODO(kparzysz-quic): copy return value back
+ std::for_each(remote_tensors.begin(), remote_tensors.end(),
+ [this](void* t) { hexagon_device_->Free(t); });
+ hexagon_device_->Free(remote);
+}
+
+void HexagonModuleNode::CallRemoteDirect(void* func_ptr, const TVMArgs& args,
+ TVMRetValue* rv) const {
+ hexagon::ArgLayout as = BuildArgLayout(args);
+ hexagon_device_->Call(func_ptr, as.Scalar.data(), as.Scalar.size(),
+ as.Stack.data(), as.Stack.size());
+}
+
+PackedFunc HexagonModuleNode::GetFunction(
+ const std::string& name, const ObjectPtr<Object>& sptr_to_self) {
+ auto f = fmap_.find(name);
+ if (f == fmap_.end()) return PackedFunc(nullptr);
+
+ // Get function pointer from device.
+ void* pf = hexagon_device_->Resolve(name);
+ // The cast result and the original share ownership. Do the cast here
+ // so that sptr_to_self can be destroyed (i.e. "func" will only have
+ // one shared pointer to HexagonModuleNode).
+ auto sref = ObjectRef(sptr_to_self);
+
+ if (packed_c_abi_funcs_.count(name)) {
+ // Calling packed C func, follow the TVMBackendPackedCFunc prototype.
+ return PackedFunc([pf, sref](TVMArgs args, TVMRetValue* rv) {
+ const auto* hm = sref.as<HexagonModuleNode>();
+ hm->CallRemotePackedCABI(pf, args, rv);
+ });
+ } else {
+ // Direct call to a non-packed-C function.
+ return PackedFunc([pf, sref](TVMArgs args, TVMRetValue* rv) {
+ const auto* hm = sref.as<HexagonModuleNode>();
+ hm->CallRemoteDirect(pf, args, rv);
+ });
+ }
+}
+
+void HexagonModuleNode::RemapArgs(const TVMArgs& args,
+ std::vector<TVMValue>& values,
+ std::vector<int>& type_codes,
+ std::vector<void*>& remote_tensors) const {
+ for (unsigned i = 0, e = args.size(); i != e; ++i) {
+ const TVMArgValue& a = args[i];
+
+ switch (unsigned tc = a.type_code()) {
+ case kTVMNDArrayHandle:
+ case kTVMDLTensorHandle: {
+ DLTensor* t = static_cast<DLTensor*>(a);
+ assert(TVMDeviceExtType(t->ctx.device_type) == kDLHexagon);
+ TVMValue v;
+ v.v_handle = CreateRemoteTensor(t);
+ remote_tensors.push_back(v.v_handle);
+ values.push_back(v);
+ type_codes.push_back(tc);
+ break;
+ }
+
+ default:
+ values.push_back(a.value());
+ type_codes.push_back(tc);
+ break;
+ }
+ }
+}
+
+void* HexagonModuleNode::CreateRemoteTensor(const DLTensor* t) const {
+ /*
+ Layout of the DLTensor structure on Hexagon.
+
+ DLTensor: Size offset
+ data void* 4 0
+ ctx.device_type enum 1 4
+ <pad> 3 5
+ ctx.device_id int 4 8
+ ndim int 4 12
+ dtype.code uint8_t 1 16
+ dtype.bits uint8_t 1 17
+ dtype.lanes uint16_t 2 18
+ shape int64_t* 4 20
+ strides int64_t* 4 24
+ <pad> 4 28
+ byte_offset uint64_t 8 32
+ .. end ................................ 40
+ */
+ struct __attribute__((packed)) HexagonDLTensor {
+ uint32_t data;
+ uint8_t ctx_device_type;
+ uint8_t pad0[3]; // MUST BE ZERO!
+ int32_t ctx_device_id;
+ int32_t ndim;
+ uint8_t dtype_code;
+ uint8_t dtype_bits;
+ uint16_t dtype_lanes;
+ uint32_t shape;
+ uint32_t strides;
+ uint8_t pad1[4];
+ uint64_t byte_offset;
+ };
+
+ constexpr uint32_t size_ht = sizeof(HexagonDLTensor);
+ static_assert(size_ht == 40, "HexagonDLTensor should be 40 bytes");
+
+ // Shape and strides will contain ndim elements of size sizeof(uint64_t)
+ // each. Allocate them after the main structure.
+ int ndim = t->ndim;
+ uint32_t size_s = 8 * ndim; // sizeof(uint64_t)*ndim
+ uint32_t size_ss = t->strides ? 2 * size_s : size_s;
+ void* remote = hexagon_device_->Alloc(size_ht + size_ss, 8);
+ uint32_t remote_as_int = reinterpret_cast<uintptr_t>(remote);
+ void* remote_ss = reinterpret_cast<void*>(remote_as_int + size_ht);
+
+ HexagonDLTensor local = {
+ .data = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(t->data)),
+ .ctx_device_type = uint8_t(t->ctx.device_type),
+ .pad0 = {0, 0, 0},
+ .ctx_device_id = t->ctx.device_id,
+ .ndim = t->ndim,
+ .dtype_code = t->dtype.code,
+ .dtype_bits = t->dtype.bits,
+ .dtype_lanes = t->dtype.lanes,
+ .shape = remote_as_int + size_ht,
+ .strides = t->strides ? remote_as_int + size_ht + size_s : 0u,
+ .byte_offset = t->byte_offset};
+
+ std::vector<uint64_t> local_ss(size_ss / 8);
+ for (int i = 0; i != ndim; ++i) local_ss[i] = t->shape[i];
+ if (t->strides) {
+ for (int i = 0; i != ndim; ++i) local_ss[ndim + i] = t->strides[i];
+ }
+
+ hexagon_device_->CopyHostToDevice(remote, &local, sizeof local);
+ hexagon_device_->CopyHostToDevice(remote_ss, local_ss.data(), size_ss);
+ return remote;
+}
+
+hexagon::ArgLayout HexagonModuleNode::BuildArgLayout(const TVMArgs& As) const {
+ hexagon::ArgLayout Args;
+
+ for (unsigned i = 0, e = As.size(); i != e; ++i) {
+ const TVMArgValue& A = As[i];
+ unsigned TC = A.type_code();
+ switch (TC) {
+ // Treat all integers as 32-bit values.
+ case kDLInt:
+ case kDLUInt:
+ // KLUDGE: There is no distinction between 32- and 64-bit integer
+ // types, so there is no way to tell if the value being passed needs
+ // one or two registers. Assume that all integers are 32-bit, and
+ // simply abort if the actual value does not fit.
+ CHECK_EQ(static_cast<int64_t>(A), static_cast<int32_t>(A));
+ Args.Push(static_cast<int>(A));
+ break;
+ // 64-bit values
+ case kDLFloat:
+ Args.Push(static_cast<double>(A));
+ break;
+
+ case kTVMOpaqueHandle:
+ case kTVMNullptr:
+ case kTVMObjectHandle:
+ case kTVMModuleHandle:
+ case kTVMPackedFuncHandle:
+ Args.Push(static_cast<void*>(A));
+ break;
+
+ case kTVMNDArrayHandle:
+ case kTVMDLTensorHandle:
+ LOG(FATAL) << __func__ << ": cannot handle DLTensor*, code:" << TC;
+
+ default:
+ LOG(FATAL) << __func__ << ": unhandled type code" << TC;
+ break;
+ }
+ }
+
+ return Args;
+}
+
+Module HexagonModuleCreate(std::string data, std::string fmt,
+ std::unordered_map<std::string, FunctionInfo> fmap,
+ std::string asm_str, std::string obj_str,
+ std::string ir_str, std::string bc_str,
+ const std::set<std::string>& packed_c_abi) {
+ auto n = make_object<HexagonModuleNode>(data, fmt, fmap, asm_str, obj_str,
+ ir_str, bc_str, packed_c_abi);
+ return Module(n);
+}
+
+// Load module from file.
+Module HexagonModuleLoadFile(const std::string& file_name,
+ const std::string& format) {
+ std::string data = file_name;
+ std::unordered_map<std::string, FunctionInfo> fmap;
+ std::string fmt = GetFileFormat(file_name, format);
+ std::string meta_file = GetMetaFilePath(file_name);
+ LoadMetaDataFromFile(meta_file, &fmap);
+
+ std::string empty;
+ // This passes {} as the set of packed C functions. Won't work for
+ // standalone functions on target.
+ return HexagonModuleCreate(data, fmt, fmap, empty, empty, empty, empty, {});
+}
+
+namespace hexagon {
+
+std::shared_ptr<Device> Device::Global() {
+ // Declare device constructors.
+#ifdef __ANDROID__
Review comment:
If we want to support more Hexagon target in the future, we maybe have problem. For example, hexagon could run embed system of Ubuntu, which is official support of Hexagon SDK too. Then we can not use __ANDROID__ to distinguish target or simulator. One proposal is in our Hexagon.cmake, when we build for simulator, we define one macro like `-D__HEXAGON_SIM__=1` to indicate we are running on simulator or like `-D__HEXAGON_DEVICE__=1` to indicate we are running on real devices. This is one nit-pick comment, however, I wish we could consider it.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] kparzysz-quic commented on issue #5252: [RUNTIME]
Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
kparzysz-quic commented on issue #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#issuecomment-611544752
I don't think that the CI failure has anything to do with this PR, there are other PRs that failed in the same way. I rebased it op top of the current master, maybe that will help...
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] FrozenGene commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
FrozenGene commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r404523734
##########
File path: src/runtime/hexagon/target/hexagon_device_target.cc
##########
@@ -0,0 +1,525 @@
+/*
+ * 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.
+ */
+
+#ifdef __ANDROID__
+
+#include <unistd.h>
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "../hexagon_module.h"
+#include "AEEStdErr.h"
+#include "fastrpc/tvm_hexagon_remote.h"
+#include "hexagon_dsprpcapi.h"
+#include "hexagon_stubapi.h"
+#include "hexagon_target_log.h"
+#include "remote64.h"
+#include "rpcmem.h"
+
+#pragma weak remote_session_control
+
+#define RPCMEM_HEAP 25
+
+// All log messages start with "HexagonTarget::%s", where %s is replaced
+// with the function name, so create macros that add that to avoid repetition.
+// The downside is that the format string must be given as a string literal,
+// but it seems to be a minor issue.
+#define VA_EXPANDER(...) , ##__VA_ARGS__
+#define TVM_LOGD_HT(fmt, ...) \
+ TVM_LOGD("HexagonTarget::%s: " fmt, __func__ VA_EXPANDER(__VA_ARGS__))
+#define TVM_LOGE_HT(fmt, ...) \
+ TVM_LOGE("HexagonTarget::%s: " fmt, __func__ VA_EXPANDER(__VA_ARGS__))
+
+namespace tvm {
+namespace runtime {
+namespace hexagon {
+
+static constexpr int kStackSize = 128 * 1024; // 128kB stack
+
+class HexagonTarget : public tvm::runtime::hexagon::Device {
+ public:
+ HexagonTarget() {}
+ ~HexagonTarget() final {}
+ void* Alloc(unsigned size, unsigned align) final;
+ void Free(void* ptr) final;
+ void* AllocVtcm(unsigned size, unsigned align) final;
+ void FreeVtcm(void* ptr) final;
+ void CopyDeviceToDevice(void* dst, const void* src, unsigned len) final;
+ void CopyDeviceToHost(void* host_dst, const void* src, unsigned len) final;
+ void CopyHostToDevice(void* dst, const void* host_src, unsigned len) final;
+ void* Load(const std::string& data, const std::string& fmt) final;
+ void Unload(void* mod) final;
+ void* Resolve(const std::string& sym) final;
+ void Call(void* func, uint32_t* scalar, unsigned scalar_num, uint32_t* stack,
+ unsigned stack_num) final;
+
+ private:
+ std::pair<void*, size_t> AddAddrMapping(const void* dsp_addr,
+ void* apps_addr, size_t size);
+ std::pair<void*, size_t> GetAppsAddr(const void* dsp_addr, bool exact) const;
+ void RemoveAddrMapping(const void* dsp_addr);
+ int OpenDomainChannel(bool set_unsigned_pd);
+ int CloseDomainChannel();
+ void ReleaseLibrary();
+ void FreeMemoryBeforeChannelClose();
+
+ // Mapping from a DSP address to a pair <apps address, buffer size>.
+ // Using void* pointers is ok, since DSP pointers will always fit
+ // in apps's pointers, i.e. sizeof_dsp(void*) <= sizeof_apps(void*).
+ std::map<const void*, std::pair<void*, size_t>> dsp_to_apps_;
+ std::map<const void*, std::pair<void*, size_t>> vtcm_addr_;
+ remote_handle64 domain_channel_handle_ = AEE_EUNKNOWN;
+ tvm_hexagon_remote_handle_t module_pointer_ = AEE_EUNKNOWN;
+ uint64_t count_channel_open_ = 0;
+ // Global lock, used for all critical sections. This can be refined
+ // in the future.
+ mutable std::mutex crit_section_;
+};
+
+std::shared_ptr<Device> CreateHexagonTarget() {
+ return std::make_shared<HexagonTarget>();
+}
+
+std::pair<void*, size_t> HexagonTarget::AddAddrMapping(const void* dsp_addr,
+ void* apps_addr,
+ size_t size) {
+ crit_section_.lock();
+ auto p = dsp_to_apps_.insert({dsp_addr, {apps_addr, size}});
+ crit_section_.unlock();
+ if (!p.second) {
+ TVM_LOGE_HT(
+ "failed to insert address mapping: dsp:%p -> apps:%p, size:%zu",
+ dsp_addr, apps_addr, size);
+ return std::make_pair(nullptr, 0);
+ }
+ TVM_LOGD_HT("added address mapping: dsp:%p -> apps:%p, size:%zu", dsp_addr,
+ apps_addr, size);
+ return p.first->second;
+}
+
+void HexagonTarget::RemoveAddrMapping(const void* dsp_addr) {
+ crit_section_.lock();
+ auto f = dsp_to_apps_.find(dsp_addr);
+ if (f == dsp_to_apps_.end()) {
+ TVM_LOGE_HT("failed to remove address mapping for dsp:%p", dsp_addr);
+ crit_section_.unlock();
+ return;
+ }
+ dsp_to_apps_.erase(f);
+ crit_section_.unlock();
+}
+
+std::pair<void*, size_t> HexagonTarget::GetAppsAddr(const void* dsp_addr,
+ bool exact) const {
+ struct AutoUnlock {
+ explicit AutoUnlock(std::mutex& m) : m(m) {}
+ ~AutoUnlock() { m.unlock(); }
+ std::mutex& m;
+ };
+
+ crit_section_.lock();
+ AutoUnlock u(crit_section_);
+
+ // If the address is in the map, simply return the result.
+ auto f = dsp_to_apps_.find(dsp_addr);
+ if (f != dsp_to_apps_.end()) return f->second;
+ // If exact mapping is requested, then it hasn't been found.
+ if (exact) return std::make_pair(nullptr, 0);
+
+ // If the address is not in the map, maybe it points to somewhere in the
+ // interior of a mapped buffer.
+ uintptr_t dsp_v = reinterpret_cast<uintptr_t>(dsp_addr);
+ for (const auto& v : dsp_to_apps_) {
+ uintptr_t dsp_k = reinterpret_cast<uintptr_t>(v.first);
+ size_t size = v.second.second;
+ if (dsp_v >= dsp_k && dsp_v < dsp_k + size) {
+ uintptr_t apps_k = reinterpret_cast<uintptr_t>(v.second.first);
+ size_t offset = dsp_v - dsp_k;
+ uintptr_t apps_v = apps_k + offset;
+ return std::make_pair(reinterpret_cast<void*>(apps_v), size - offset);
+ }
+ }
+ TVM_LOGE_HT("failed to locate apps address for dsp:%p", dsp_addr);
+ return std::make_pair(nullptr, 0);
+}
+
+int HexagonTarget::OpenDomainChannel(bool use_unsigned_pd) {
+ if (domain_channel_handle_ != AEE_EUNKNOWN) return AEE_SUCCESS;
+
+ const DspRpcAPI* dsp_api = DspRpcAPI::Global();
+ const StubAPI* stub_api = StubAPI::Global();
+
+ stub_api->rpcmem_init_ptr()();
Review comment:
I maybe forget a little bit, because I do it last year. However, I remember `rpcmem_init_ptr` will have problem when we set `use_unsigned_pd` be false. In your code logic of this pr, you will always set `use_unsigned_pd` be true. Could you double check it? I set it be false, because I find when we set it be `true`, we can not do parallel on DSP. But I don't have device now and can not verify it sadly.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] kparzysz-quic commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
kparzysz-quic commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r404783723
##########
File path: src/runtime/hexagon/target/hexagon_device_target.cc
##########
@@ -0,0 +1,525 @@
+/*
+ * 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.
+ */
+
+#ifdef __ANDROID__
+
+#include <unistd.h>
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "../hexagon_module.h"
+#include "AEEStdErr.h"
+#include "fastrpc/tvm_hexagon_remote.h"
+#include "hexagon_dsprpcapi.h"
+#include "hexagon_stubapi.h"
+#include "hexagon_target_log.h"
+#include "remote64.h"
+#include "rpcmem.h"
+
+#pragma weak remote_session_control
+
+#define RPCMEM_HEAP 25
+
+// All log messages start with "HexagonTarget::%s", where %s is replaced
+// with the function name, so create macros that add that to avoid repetition.
+// The downside is that the format string must be given as a string literal,
+// but it seems to be a minor issue.
+#define VA_EXPANDER(...) , ##__VA_ARGS__
+#define TVM_LOGD_HT(fmt, ...) \
+ TVM_LOGD("HexagonTarget::%s: " fmt, __func__ VA_EXPANDER(__VA_ARGS__))
+#define TVM_LOGE_HT(fmt, ...) \
+ TVM_LOGE("HexagonTarget::%s: " fmt, __func__ VA_EXPANDER(__VA_ARGS__))
+
+namespace tvm {
+namespace runtime {
+namespace hexagon {
+
+static constexpr int kStackSize = 128 * 1024; // 128kB stack
+
+class HexagonTarget : public tvm::runtime::hexagon::Device {
+ public:
+ HexagonTarget() {}
+ ~HexagonTarget() final {}
+ void* Alloc(unsigned size, unsigned align) final;
+ void Free(void* ptr) final;
+ void* AllocVtcm(unsigned size, unsigned align) final;
+ void FreeVtcm(void* ptr) final;
+ void CopyDeviceToDevice(void* dst, const void* src, unsigned len) final;
+ void CopyDeviceToHost(void* host_dst, const void* src, unsigned len) final;
+ void CopyHostToDevice(void* dst, const void* host_src, unsigned len) final;
+ void* Load(const std::string& data, const std::string& fmt) final;
+ void Unload(void* mod) final;
+ void* Resolve(const std::string& sym) final;
+ void Call(void* func, uint32_t* scalar, unsigned scalar_num, uint32_t* stack,
+ unsigned stack_num) final;
+
+ private:
+ std::pair<void*, size_t> AddAddrMapping(const void* dsp_addr,
+ void* apps_addr, size_t size);
+ std::pair<void*, size_t> GetAppsAddr(const void* dsp_addr, bool exact) const;
+ void RemoveAddrMapping(const void* dsp_addr);
+ int OpenDomainChannel(bool set_unsigned_pd);
+ int CloseDomainChannel();
+ void ReleaseLibrary();
+ void FreeMemoryBeforeChannelClose();
+
+ // Mapping from a DSP address to a pair <apps address, buffer size>.
+ // Using void* pointers is ok, since DSP pointers will always fit
+ // in apps's pointers, i.e. sizeof_dsp(void*) <= sizeof_apps(void*).
+ std::map<const void*, std::pair<void*, size_t>> dsp_to_apps_;
+ std::map<const void*, std::pair<void*, size_t>> vtcm_addr_;
+ remote_handle64 domain_channel_handle_ = AEE_EUNKNOWN;
+ tvm_hexagon_remote_handle_t module_pointer_ = AEE_EUNKNOWN;
+ uint64_t count_channel_open_ = 0;
+ // Global lock, used for all critical sections. This can be refined
+ // in the future.
+ mutable std::mutex crit_section_;
+};
+
+std::shared_ptr<Device> CreateHexagonTarget() {
+ return std::make_shared<HexagonTarget>();
+}
+
+std::pair<void*, size_t> HexagonTarget::AddAddrMapping(const void* dsp_addr,
+ void* apps_addr,
+ size_t size) {
+ crit_section_.lock();
+ auto p = dsp_to_apps_.insert({dsp_addr, {apps_addr, size}});
+ crit_section_.unlock();
+ if (!p.second) {
+ TVM_LOGE_HT(
+ "failed to insert address mapping: dsp:%p -> apps:%p, size:%zu",
+ dsp_addr, apps_addr, size);
+ return std::make_pair(nullptr, 0);
+ }
+ TVM_LOGD_HT("added address mapping: dsp:%p -> apps:%p, size:%zu", dsp_addr,
+ apps_addr, size);
+ return p.first->second;
+}
+
+void HexagonTarget::RemoveAddrMapping(const void* dsp_addr) {
+ crit_section_.lock();
+ auto f = dsp_to_apps_.find(dsp_addr);
+ if (f == dsp_to_apps_.end()) {
+ TVM_LOGE_HT("failed to remove address mapping for dsp:%p", dsp_addr);
+ crit_section_.unlock();
+ return;
+ }
+ dsp_to_apps_.erase(f);
+ crit_section_.unlock();
+}
+
+std::pair<void*, size_t> HexagonTarget::GetAppsAddr(const void* dsp_addr,
+ bool exact) const {
+ struct AutoUnlock {
+ explicit AutoUnlock(std::mutex& m) : m(m) {}
+ ~AutoUnlock() { m.unlock(); }
+ std::mutex& m;
+ };
+
+ crit_section_.lock();
+ AutoUnlock u(crit_section_);
+
+ // If the address is in the map, simply return the result.
+ auto f = dsp_to_apps_.find(dsp_addr);
+ if (f != dsp_to_apps_.end()) return f->second;
+ // If exact mapping is requested, then it hasn't been found.
+ if (exact) return std::make_pair(nullptr, 0);
+
+ // If the address is not in the map, maybe it points to somewhere in the
+ // interior of a mapped buffer.
+ uintptr_t dsp_v = reinterpret_cast<uintptr_t>(dsp_addr);
+ for (const auto& v : dsp_to_apps_) {
+ uintptr_t dsp_k = reinterpret_cast<uintptr_t>(v.first);
+ size_t size = v.second.second;
+ if (dsp_v >= dsp_k && dsp_v < dsp_k + size) {
+ uintptr_t apps_k = reinterpret_cast<uintptr_t>(v.second.first);
+ size_t offset = dsp_v - dsp_k;
+ uintptr_t apps_v = apps_k + offset;
+ return std::make_pair(reinterpret_cast<void*>(apps_v), size - offset);
+ }
+ }
+ TVM_LOGE_HT("failed to locate apps address for dsp:%p", dsp_addr);
+ return std::make_pair(nullptr, 0);
+}
+
+int HexagonTarget::OpenDomainChannel(bool use_unsigned_pd) {
+ if (domain_channel_handle_ != AEE_EUNKNOWN) return AEE_SUCCESS;
+
+ const DspRpcAPI* dsp_api = DspRpcAPI::Global();
+ const StubAPI* stub_api = StubAPI::Global();
+
+ stub_api->rpcmem_init_ptr()();
Review comment:
I can set it to false, would you prefer that? I don't think there is a way to make it a parameter that the user can provide at run time.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] tqchen commented on issue #5252: [RUNTIME] Initial
implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
tqchen commented on issue #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#issuecomment-609948356
cc @kazum @tmoreau89 @kazum
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] FrozenGene commented on issue #5252: [RUNTIME]
Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
FrozenGene commented on issue #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#issuecomment-611312094
LGTM except one last comment. @kparzysz-quic Could you fix the CI?
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] FrozenGene commented on issue #5252: [RUNTIME]
Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
FrozenGene commented on issue #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#issuecomment-612036930
@kparzysz-quic Thanks for the great work. Looking forward other parts of Hexagon like IDL / codegen part and so on. Thanks @tmoreau89 for the code review!
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] kparzysz-quic commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
kparzysz-quic commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r405554731
##########
File path: src/runtime/hexagon/hexagon_module.cc
##########
@@ -0,0 +1,561 @@
+/*
+ * 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.
+ */
+
+#include "hexagon_module.h"
+
+#ifdef __ANDROID__
+#include <android/log.h>
+#endif
+#include <dmlc/logging.h>
+#include <tvm/runtime/registry.h>
+
+#include <memory>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "../file_util.h"
+#include "../meta_data.h"
+
+namespace tvm {
+namespace runtime {
+
+hexagon::Device::~Device() {}
+
+namespace hexagon {
+
+/*!
+ * \brief Function argument locations according to the Hexagon ABI.
+ *
+ * In order to invoke a function whose arguments are in TVMArgs list, at
+ * some point before branching to the function's address, these arguments
+ * need to be loaded into locations (registers or stack) specified by the
+ * corresponding ABI.
+ * When a host wants to call a function on Hexagon, the host will identify
+ * how each element of the TVMArgs list will be passed to the Hexagon
+ * function. This class is a description of which values should go into
+ * registers, and which values should be on stack. Right before the call
+ * this class will be serialized and transfereed over to the Hexagon side.
+ * The code running on Hexagon will then execute the argument placement
+ * and invoke the function.
+ */
+struct ArgLayout {
+ std::vector<uint32_t> Scalar; /*!< Values going into registers, maximum */
+ /*!< 6, including dummy values for skipped */
+ /*!< registers. */
+ std::vector<uint32_t> Stack; /*!< Values going on stack, including */
+ /*!< dummy values for padding. */
+ // There are no vector types at this time.
+
+ /*!
+ * \brief Alignment of type T on Hexagon.
+ */
+ template <typename T>
+ static constexpr unsigned align_of();
+ /*!
+ * \brief Size of type T on Hexagon.
+ */
+ template <typename T>
+ static constexpr unsigned size_of();
+
+ /*!
+ * \brief Add a value of type T to the layout.
+ */
+ template <typename T>
+ void Push(const T& v);
+
+ private:
+ /*!
+ * \brief Add raw data to the layout.
+ * \param v Pointer to the raw data as an array of 32-bit words.
+ * \param t_size Number of bytes to add.
+ * \param t_align Required alignment of the data on Hexagon.
+ */
+ void Push(uint32_t* v, unsigned t_size, unsigned t_align);
+};
+
+template <>
+constexpr unsigned ArgLayout::align_of<int32_t>() {
+ return 4;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<uint32_t>() {
+ return 4;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<float>() {
+ return 4;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<void*>() {
+ return 4;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<int64_t>() {
+ return 8;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<uint64_t>() {
+ return 8;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<double>() {
+ return 8;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<DLTensor*>() {
+ return 4;
+}
+
+template <typename T>
+constexpr unsigned ArgLayout::align_of() {
+ // The static_assertion should depend on T so that it's only checked
+ // after instantiation.
+ static_assert((sizeof(T), false), "Implement align_of for this type");
+ return 0;
+}
+
+template <typename T>
+constexpr unsigned ArgLayout::size_of() {
+ return ArgLayout::align_of<T>();
+}
+
+template <typename T>
+void ArgLayout::Push(const T& v) {
+ static_assert(std::is_scalar<T>::value, "T must be a scalar");
+ constexpr unsigned T_size = size_of<T>();
+ // The reason for this assertion is to avoid sign-extensions here:
+ // an extra bit of information would be required to determine whether
+ // a size- or a zero-extension is needed.
+ static_assert(T_size >= 4, "Type should be of size that is at least 4");
+ union {
+ uint32_t v[(T_size + 3) / 4];
+ T t;
+ } u;
+
+ u.t = v;
+ Push(u.v, T_size, align_of<T>());
+}
+
+void ArgLayout::Push(uint32_t* v, unsigned t_size, unsigned t_align) {
+ // t_size == 4 and t_size == 8 can be passed in scalar registers.
+ bool InReg = false;
+ if (t_size == 4) {
+ if (Scalar.size() < 6) {
+ Scalar.push_back(v[0]);
+ InReg = true;
+ }
+ } else if (t_size == 8) {
+ // Round the size up to the next
+ unsigned cs = Scalar.size();
+ if (cs <= 4) {
+ // There is room in the scalar registers.
+ if (cs & 1) Scalar.push_back(0u);
+ Scalar.push_back(v[0]);
+ Scalar.push_back(v[1]);
+ InReg = true;
+ }
+ }
+
+ if (!InReg) {
+ // Allocate on stack.
+ CHECK_EQ((t_align & (t_align - 1)), 0)
+ << "Alignment should be a power of 2";
+ CHECK_GE(t_align, 4) << "Alignment should be at least 4";
+ // Round t_size up to a multiple of 4.
+ unsigned s_size = Stack.size();
+ unsigned s_align = t_align / 4; // Alignment of T in words on the stack.
+ unsigned pad = ((s_size + s_align - 1) / s_align) * s_align - s_size;
+ Stack.insert(Stack.end(), pad / 4, 0u);
+ Stack.insert(Stack.end(), v, v + t_size / 4);
+ }
+}
+
+} // namespace hexagon
+
+class HexagonModuleNode final : public runtime::ModuleNode {
+ public:
+ HexagonModuleNode(std::string data, std::string fmt,
+ std::unordered_map<std::string, FunctionInfo> fmap,
+ std::string asm_str, std::string obj_str,
+ std::string ir_str, std::string bc_str,
+ const std::set<std::string>& packed_c_abi)
+ : hexagon_device_(hexagon::Device::Global()),
+ data_(data),
+ fmt_(fmt),
+ fmap_(fmap),
+ asm_(asm_str),
+ obj_(obj_str),
+ ir_(ir_str),
+ bc_(bc_str),
+ packed_c_abi_funcs_(packed_c_abi) {
+ dl_handle_ = hexagon_device_->Load(data, fmt);
+ }
+ ~HexagonModuleNode() {
+ if (dl_handle_) {
+ hexagon_device_->Unload(dl_handle_);
+ }
+ }
+
+ PackedFunc GetFunction(const std::string& name,
+ const ObjectPtr<Object>& sptr_to_self) final;
+
+ const char* type_key() const final { return "hexagon"; }
+
+ void SaveToFile(const std::string& file_name,
+ const std::string& format) final {
+ std::string fmt = runtime::GetFileFormat(file_name, format);
+ if (fmt == "so" || fmt == "dll" || fmt == "hexagon") {
+ std::string meta_file = GetMetaFilePath(file_name);
+ SaveMetaDataToFile(meta_file, fmap_);
+ std::string c = "cp " + data_ + " " + file_name;
+ CHECK(std::system(c.c_str()) == 0) << "Cannot create " + file_name;
+ } else if (fmt == "s" || fmt == "asm") {
+ CHECK(!asm_.empty()) << "Assembler source not available";
+ SaveBinaryToFile(file_name, asm_);
+ } else if (fmt == "o" || fmt == "obj") {
+ CHECK(!obj_.empty()) << "Object data not available";
+ SaveBinaryToFile(file_name, obj_);
+ } else if (fmt == "ll") {
+ CHECK(!ir_.empty()) << "LLVM IR source not available";
+ SaveBinaryToFile(file_name, ir_);
+ } else if (fmt == "bc") {
+ CHECK(!bc_.empty()) << "LLVM IR bitcode not available";
+ SaveBinaryToFile(file_name, bc_);
+ } else {
+ LOG(FATAL) << "HexagonModuleNode::SaveToFile: unhandled format `" << fmt
+ << "'";
+ }
+ }
+ void SaveToBinary(dmlc::Stream* stream) final {
+ stream->Write(fmt_);
+ stream->Write(fmap_);
+ stream->Write(data_);
+ }
+
+ private:
+ void CallRemotePackedCABI(void* func_ptr, const TVMArgs& args,
+ TVMRetValue* rv) const;
+ void CallRemoteDirect(void* func_ptr, const TVMArgs& args,
+ TVMRetValue* rv) const;
+ void RemapArgs(const TVMArgs& args,
+ std::vector<TVMValue>& values, // NOLINT(*)
+ std::vector<int>& type_codes, // NOLINT(*)
+ std::vector<void*>& remote_tensors) const; // NOLINT(*)
+ void* CreateRemoteTensor(const DLTensor* T) const;
+ hexagon::ArgLayout BuildArgLayout(const TVMArgs& Aa) const;
+
+ std::shared_ptr<hexagon::Device> hexagon_device_;
+ void* dl_handle_ = nullptr;
+ std::string data_;
+ std::string fmt_;
+ std::unordered_map<std::string, FunctionInfo> fmap_;
+ std::string asm_;
+ std::string obj_;
+ std::string ir_;
+ std::string bc_;
+ std::set<std::string> packed_c_abi_funcs_;
+};
+
+void HexagonModuleNode::CallRemotePackedCABI(void* func_ptr,
+ const TVMArgs& args,
+ TVMRetValue* rv) const {
+ // Remap all arguments, creating remote DLTensors.
+ std::vector<TVMValue> values;
+ std::vector<int> codes;
+ std::vector<void*> remote_tensors;
+
+ RemapArgs(args, values, codes, remote_tensors);
+ // The prototype of packed C function is
+ // int (TVMValue* args, int* type_codes, int num_args,
+ // TVMValue* ret_value, int* ret_code)
+ // The pointers must point to allocated space, the return information
+ // will be filled in by the callee.
+ // Allocate remote buffer to hold:
+ // 1. argument TVMValues,
+ // 2. return TVMValue,
+ // 3. argument type codes,
+ // 4. return type code.
+
+ int num_args = args.size();
+ int values_size = num_args * sizeof(TVMValue);
+ int codes_size = num_args * sizeof(int);
+ void* remote = hexagon_device_->Alloc(
+ values_size + sizeof(TVMValue) + codes_size + sizeof(int), 8);
+
+ // Copy all argument TVMValues to the remote space.
+ void* remote_values = remote;
+ void* remote_ret_value = static_cast<char*>(remote_values) + values_size;
+ void* remote_codes = static_cast<char*>(remote_ret_value) + sizeof(TVMValue);
+ void* remote_ret_code = static_cast<char*>(remote_codes) + codes_size;
+ hexagon_device_->CopyHostToDevice(remote_values, values.data(), values_size);
+ hexagon_device_->CopyHostToDevice(remote_codes, codes.data(), codes_size);
+
+ // Call the function: construct temporary values/codes and pass them through
+ // the arg layout building to preprare for the actual remote call.
+ TVMValue temp_values[5];
+ temp_values[0].v_handle = remote_values;
+ temp_values[1].v_handle = remote_codes;
+ temp_values[2].v_int64 = num_args;
+ temp_values[3].v_handle = remote_ret_value;
+ temp_values[4].v_handle = remote_ret_code;
+ int temp_codes[5] = {kTVMOpaqueHandle, kTVMOpaqueHandle, kDLInt,
+ kTVMOpaqueHandle, kTVMOpaqueHandle};
+ TVMArgs temp_args(temp_values, temp_codes, 5);
+ hexagon::ArgLayout as = BuildArgLayout(temp_args);
+ hexagon_device_->Call(func_ptr, as.Scalar.data(), as.Scalar.size(),
+ as.Stack.data(), as.Stack.size());
+
+ // TODO(kparzysz-quic): copy return value back
+ std::for_each(remote_tensors.begin(), remote_tensors.end(),
+ [this](void* t) { hexagon_device_->Free(t); });
+ hexagon_device_->Free(remote);
+}
+
+void HexagonModuleNode::CallRemoteDirect(void* func_ptr, const TVMArgs& args,
+ TVMRetValue* rv) const {
+ hexagon::ArgLayout as = BuildArgLayout(args);
+ hexagon_device_->Call(func_ptr, as.Scalar.data(), as.Scalar.size(),
+ as.Stack.data(), as.Stack.size());
+}
+
+PackedFunc HexagonModuleNode::GetFunction(
+ const std::string& name, const ObjectPtr<Object>& sptr_to_self) {
+ auto f = fmap_.find(name);
+ if (f == fmap_.end()) return PackedFunc(nullptr);
+
+ // Get function pointer from device.
+ void* pf = hexagon_device_->Resolve(name);
+ // The cast result and the original share ownership. Do the cast here
+ // so that sptr_to_self can be destroyed (i.e. "func" will only have
+ // one shared pointer to HexagonModuleNode).
+ auto sref = ObjectRef(sptr_to_self);
+
+ if (packed_c_abi_funcs_.count(name)) {
+ // Calling packed C func, follow the TVMBackendPackedCFunc prototype.
+ return PackedFunc([pf, sref](TVMArgs args, TVMRetValue* rv) {
+ const auto* hm = sref.as<HexagonModuleNode>();
+ hm->CallRemotePackedCABI(pf, args, rv);
+ });
+ } else {
+ // Direct call to a non-packed-C function.
+ return PackedFunc([pf, sref](TVMArgs args, TVMRetValue* rv) {
+ const auto* hm = sref.as<HexagonModuleNode>();
+ hm->CallRemoteDirect(pf, args, rv);
+ });
+ }
+}
+
+void HexagonModuleNode::RemapArgs(const TVMArgs& args,
+ std::vector<TVMValue>& values,
+ std::vector<int>& type_codes,
+ std::vector<void*>& remote_tensors) const {
+ for (unsigned i = 0, e = args.size(); i != e; ++i) {
+ const TVMArgValue& a = args[i];
+
+ switch (unsigned tc = a.type_code()) {
+ case kTVMNDArrayHandle:
+ case kTVMDLTensorHandle: {
+ DLTensor* t = static_cast<DLTensor*>(a);
+ assert(TVMDeviceExtType(t->ctx.device_type) == kDLHexagon);
+ TVMValue v;
+ v.v_handle = CreateRemoteTensor(t);
+ remote_tensors.push_back(v.v_handle);
+ values.push_back(v);
+ type_codes.push_back(tc);
+ break;
+ }
+
+ default:
+ values.push_back(a.value());
+ type_codes.push_back(tc);
+ break;
+ }
+ }
+}
+
+void* HexagonModuleNode::CreateRemoteTensor(const DLTensor* t) const {
+ /*
+ Layout of the DLTensor structure on Hexagon.
+
+ DLTensor: Size offset
+ data void* 4 0
+ ctx.device_type enum 1 4
+ <pad> 3 5
+ ctx.device_id int 4 8
+ ndim int 4 12
+ dtype.code uint8_t 1 16
+ dtype.bits uint8_t 1 17
+ dtype.lanes uint16_t 2 18
+ shape int64_t* 4 20
+ strides int64_t* 4 24
+ <pad> 4 28
+ byte_offset uint64_t 8 32
+ .. end ................................ 40
+ */
+ struct __attribute__((packed)) HexagonDLTensor {
+ uint32_t data;
+ uint8_t ctx_device_type;
+ uint8_t pad0[3]; // MUST BE ZERO!
+ int32_t ctx_device_id;
+ int32_t ndim;
+ uint8_t dtype_code;
+ uint8_t dtype_bits;
+ uint16_t dtype_lanes;
+ uint32_t shape;
+ uint32_t strides;
+ uint8_t pad1[4];
+ uint64_t byte_offset;
+ };
+
+ constexpr uint32_t size_ht = sizeof(HexagonDLTensor);
+ static_assert(size_ht == 40, "HexagonDLTensor should be 40 bytes");
+
+ // Shape and strides will contain ndim elements of size sizeof(uint64_t)
+ // each. Allocate them after the main structure.
+ int ndim = t->ndim;
+ uint32_t size_s = 8 * ndim; // sizeof(uint64_t)*ndim
+ uint32_t size_ss = t->strides ? 2 * size_s : size_s;
+ void* remote = hexagon_device_->Alloc(size_ht + size_ss, 8);
+ uint32_t remote_as_int = reinterpret_cast<uintptr_t>(remote);
+ void* remote_ss = reinterpret_cast<void*>(remote_as_int + size_ht);
+
+ HexagonDLTensor local = {
+ .data = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(t->data)),
+ .ctx_device_type = uint8_t(t->ctx.device_type),
+ .pad0 = {0, 0, 0},
+ .ctx_device_id = t->ctx.device_id,
+ .ndim = t->ndim,
+ .dtype_code = t->dtype.code,
+ .dtype_bits = t->dtype.bits,
+ .dtype_lanes = t->dtype.lanes,
+ .shape = remote_as_int + size_ht,
+ .strides = t->strides ? remote_as_int + size_ht + size_s : 0u,
+ .byte_offset = t->byte_offset};
+
+ std::vector<uint64_t> local_ss(size_ss / 8);
+ for (int i = 0; i != ndim; ++i) local_ss[i] = t->shape[i];
+ if (t->strides) {
+ for (int i = 0; i != ndim; ++i) local_ss[ndim + i] = t->strides[i];
+ }
+
+ hexagon_device_->CopyHostToDevice(remote, &local, sizeof local);
+ hexagon_device_->CopyHostToDevice(remote_ss, local_ss.data(), size_ss);
+ return remote;
+}
+
+hexagon::ArgLayout HexagonModuleNode::BuildArgLayout(const TVMArgs& As) const {
+ hexagon::ArgLayout Args;
+
+ for (unsigned i = 0, e = As.size(); i != e; ++i) {
+ const TVMArgValue& A = As[i];
+ unsigned TC = A.type_code();
+ switch (TC) {
+ // Treat all integers as 32-bit values.
+ case kDLInt:
+ case kDLUInt:
+ // KLUDGE: There is no distinction between 32- and 64-bit integer
+ // types, so there is no way to tell if the value being passed needs
+ // one or two registers. Assume that all integers are 32-bit, and
+ // simply abort if the actual value does not fit.
+ CHECK_EQ(static_cast<int64_t>(A), static_cast<int32_t>(A));
+ Args.Push(static_cast<int>(A));
+ break;
+ // 64-bit values
+ case kDLFloat:
+ Args.Push(static_cast<double>(A));
+ break;
+
+ case kTVMOpaqueHandle:
+ case kTVMNullptr:
+ case kTVMObjectHandle:
+ case kTVMModuleHandle:
+ case kTVMPackedFuncHandle:
+ Args.Push(static_cast<void*>(A));
+ break;
+
+ case kTVMNDArrayHandle:
+ case kTVMDLTensorHandle:
+ LOG(FATAL) << __func__ << ": cannot handle DLTensor*, code:" << TC;
+
+ default:
+ LOG(FATAL) << __func__ << ": unhandled type code" << TC;
+ break;
+ }
+ }
+
+ return Args;
+}
+
+Module HexagonModuleCreate(std::string data, std::string fmt,
+ std::unordered_map<std::string, FunctionInfo> fmap,
+ std::string asm_str, std::string obj_str,
+ std::string ir_str, std::string bc_str,
+ const std::set<std::string>& packed_c_abi) {
+ auto n = make_object<HexagonModuleNode>(data, fmt, fmap, asm_str, obj_str,
+ ir_str, bc_str, packed_c_abi);
+ return Module(n);
+}
+
+// Load module from file.
+Module HexagonModuleLoadFile(const std::string& file_name,
+ const std::string& format) {
+ std::string data = file_name;
+ std::unordered_map<std::string, FunctionInfo> fmap;
+ std::string fmt = GetFileFormat(file_name, format);
+ std::string meta_file = GetMetaFilePath(file_name);
+ LoadMetaDataFromFile(meta_file, &fmap);
+
+ std::string empty;
+ // This passes {} as the set of packed C functions. Won't work for
+ // standalone functions on target.
+ return HexagonModuleCreate(data, fmt, fmap, empty, empty, empty, empty, {});
+}
+
+namespace hexagon {
+
+std::shared_ptr<Device> Device::Global() {
+ // Declare device constructors.
+#ifdef __ANDROID__
Review comment:
We can probably do that, but I'd prefer to do it in another commit.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] kparzysz-quic commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
kparzysz-quic commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r406196234
##########
File path: src/runtime/hexagon/README.md
##########
@@ -0,0 +1,75 @@
+<!--- 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. -->
+
+# Hexagon backend runtime
+
+The Hexagon runtime is a part of the TVM runtime that facilitates communication between a host and a Hexagon device. There are two types of host/device arrangements that are supported:
+- X86/Linux host running Hexagon simulator,
+- Android/AArch64 host running on a physical device containing a Hexagon module (i.e. CSDP or ADSP).
+
+The TVM runtime that contains Hexagon runtime is the one executing on host. In either case, there will need to be a separate TVM runtime (i.e. the `libtvm_runtime.so` library) compiled for execution on Hexagon.
+
+The prerequisite is to have Hexagon SDK installed, preferably version 3.5.0 or later. The Hexagon SDK can be downloaded from https://developer.qualcomm.com/software/hexagon-dsp-sdk.
+
+### Compiling TVM runtime for x86
+
+This will use Hexagon simulator, which is provided in the Hexagon SDK.
+
+When configuring TVM (cmake), set the following variables:
+```
+USE_LLVM=llvm-config
Review comment:
Done. I'm not aware of any specific issues with older LLVMs for Hexagon, so I didn't know which version is the minimum. I used 7.0.0 as the minimum, based on your comment, but recommended using as recent version as possible.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] tqchen commented on a change in pull request #5252:
[RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
tqchen commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r404303430
##########
File path: include/tvm/runtime/device_api.h
##########
@@ -47,10 +47,10 @@ enum DeviceAttrKind : int {
};
/*! \brief Number of bytes each allocation must align to */
-constexpr int kAllocAlignment = 64;
+constexpr int kAllocAlignment = 128;
Review comment:
This should be fine
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] FrozenGene commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
FrozenGene commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r404855401
##########
File path: src/runtime/hexagon/target/hexagon_device_target.cc
##########
@@ -0,0 +1,525 @@
+/*
+ * 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.
+ */
+
+#ifdef __ANDROID__
+
+#include <unistd.h>
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "../hexagon_module.h"
+#include "AEEStdErr.h"
+#include "fastrpc/tvm_hexagon_remote.h"
+#include "hexagon_dsprpcapi.h"
+#include "hexagon_stubapi.h"
+#include "hexagon_target_log.h"
+#include "remote64.h"
+#include "rpcmem.h"
+
+#pragma weak remote_session_control
+
+#define RPCMEM_HEAP 25
+
+// All log messages start with "HexagonTarget::%s", where %s is replaced
+// with the function name, so create macros that add that to avoid repetition.
+// The downside is that the format string must be given as a string literal,
+// but it seems to be a minor issue.
+#define VA_EXPANDER(...) , ##__VA_ARGS__
+#define TVM_LOGD_HT(fmt, ...) \
+ TVM_LOGD("HexagonTarget::%s: " fmt, __func__ VA_EXPANDER(__VA_ARGS__))
+#define TVM_LOGE_HT(fmt, ...) \
+ TVM_LOGE("HexagonTarget::%s: " fmt, __func__ VA_EXPANDER(__VA_ARGS__))
+
+namespace tvm {
+namespace runtime {
+namespace hexagon {
+
+static constexpr int kStackSize = 128 * 1024; // 128kB stack
+
+class HexagonTarget : public tvm::runtime::hexagon::Device {
+ public:
+ HexagonTarget() {}
+ ~HexagonTarget() final {}
+ void* Alloc(unsigned size, unsigned align) final;
+ void Free(void* ptr) final;
+ void* AllocVtcm(unsigned size, unsigned align) final;
+ void FreeVtcm(void* ptr) final;
+ void CopyDeviceToDevice(void* dst, const void* src, unsigned len) final;
+ void CopyDeviceToHost(void* host_dst, const void* src, unsigned len) final;
+ void CopyHostToDevice(void* dst, const void* host_src, unsigned len) final;
+ void* Load(const std::string& data, const std::string& fmt) final;
+ void Unload(void* mod) final;
+ void* Resolve(const std::string& sym) final;
+ void Call(void* func, uint32_t* scalar, unsigned scalar_num, uint32_t* stack,
+ unsigned stack_num) final;
+
+ private:
+ std::pair<void*, size_t> AddAddrMapping(const void* dsp_addr,
+ void* apps_addr, size_t size);
+ std::pair<void*, size_t> GetAppsAddr(const void* dsp_addr, bool exact) const;
+ void RemoveAddrMapping(const void* dsp_addr);
+ int OpenDomainChannel(bool set_unsigned_pd);
+ int CloseDomainChannel();
+ void ReleaseLibrary();
+ void FreeMemoryBeforeChannelClose();
+
+ // Mapping from a DSP address to a pair <apps address, buffer size>.
+ // Using void* pointers is ok, since DSP pointers will always fit
+ // in apps's pointers, i.e. sizeof_dsp(void*) <= sizeof_apps(void*).
+ std::map<const void*, std::pair<void*, size_t>> dsp_to_apps_;
+ std::map<const void*, std::pair<void*, size_t>> vtcm_addr_;
+ remote_handle64 domain_channel_handle_ = AEE_EUNKNOWN;
+ tvm_hexagon_remote_handle_t module_pointer_ = AEE_EUNKNOWN;
+ uint64_t count_channel_open_ = 0;
+ // Global lock, used for all critical sections. This can be refined
+ // in the future.
+ mutable std::mutex crit_section_;
+};
+
+std::shared_ptr<Device> CreateHexagonTarget() {
+ return std::make_shared<HexagonTarget>();
+}
+
+std::pair<void*, size_t> HexagonTarget::AddAddrMapping(const void* dsp_addr,
+ void* apps_addr,
+ size_t size) {
+ crit_section_.lock();
+ auto p = dsp_to_apps_.insert({dsp_addr, {apps_addr, size}});
+ crit_section_.unlock();
+ if (!p.second) {
+ TVM_LOGE_HT(
+ "failed to insert address mapping: dsp:%p -> apps:%p, size:%zu",
+ dsp_addr, apps_addr, size);
+ return std::make_pair(nullptr, 0);
+ }
+ TVM_LOGD_HT("added address mapping: dsp:%p -> apps:%p, size:%zu", dsp_addr,
+ apps_addr, size);
+ return p.first->second;
+}
+
+void HexagonTarget::RemoveAddrMapping(const void* dsp_addr) {
+ crit_section_.lock();
+ auto f = dsp_to_apps_.find(dsp_addr);
+ if (f == dsp_to_apps_.end()) {
+ TVM_LOGE_HT("failed to remove address mapping for dsp:%p", dsp_addr);
+ crit_section_.unlock();
+ return;
+ }
+ dsp_to_apps_.erase(f);
+ crit_section_.unlock();
+}
+
+std::pair<void*, size_t> HexagonTarget::GetAppsAddr(const void* dsp_addr,
+ bool exact) const {
+ struct AutoUnlock {
+ explicit AutoUnlock(std::mutex& m) : m(m) {}
+ ~AutoUnlock() { m.unlock(); }
+ std::mutex& m;
+ };
+
+ crit_section_.lock();
+ AutoUnlock u(crit_section_);
+
+ // If the address is in the map, simply return the result.
+ auto f = dsp_to_apps_.find(dsp_addr);
+ if (f != dsp_to_apps_.end()) return f->second;
+ // If exact mapping is requested, then it hasn't been found.
+ if (exact) return std::make_pair(nullptr, 0);
+
+ // If the address is not in the map, maybe it points to somewhere in the
+ // interior of a mapped buffer.
+ uintptr_t dsp_v = reinterpret_cast<uintptr_t>(dsp_addr);
+ for (const auto& v : dsp_to_apps_) {
+ uintptr_t dsp_k = reinterpret_cast<uintptr_t>(v.first);
+ size_t size = v.second.second;
+ if (dsp_v >= dsp_k && dsp_v < dsp_k + size) {
+ uintptr_t apps_k = reinterpret_cast<uintptr_t>(v.second.first);
+ size_t offset = dsp_v - dsp_k;
+ uintptr_t apps_v = apps_k + offset;
+ return std::make_pair(reinterpret_cast<void*>(apps_v), size - offset);
+ }
+ }
+ TVM_LOGE_HT("failed to locate apps address for dsp:%p", dsp_addr);
+ return std::make_pair(nullptr, 0);
+}
+
+int HexagonTarget::OpenDomainChannel(bool use_unsigned_pd) {
+ if (domain_channel_handle_ != AEE_EUNKNOWN) return AEE_SUCCESS;
+
+ const DspRpcAPI* dsp_api = DspRpcAPI::Global();
+ const StubAPI* stub_api = StubAPI::Global();
+
+ stub_api->rpcmem_init_ptr()();
Review comment:
Yes. I prefer setting it to be false.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] kparzysz-quic commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
kparzysz-quic commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r404295175
##########
File path: src/runtime/hexagon/README.md
##########
@@ -0,0 +1,76 @@
+<!--- 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. -->
+
+# Hexagon backend runtime
+
+The Hexagon runtime is a part of the TVM runtime that facilitates communication between a host and a Hexagon device. There are two types of host/device arrangements that are supported:
+- X86/Linux host running Hexagon simulator,
+- Android/AArch64 host running on a physical device containing a Hexagon module (i.e. CSDP or ADSP).
+
+The TVM runtime that contains Hexagon runtime is the one executing on host. In either case, there will need to be a separate TVM runtime (i.e. the `libtvm_runtime.so` library) compiled for execution on Hexagon.
+
+The prerequisite is to have Hexagon SDK installed, preferably version 3.5.0.
Review comment:
Sure, I'll add the link. I'm not sure about automatic install, because there is a license that needs to be accepted during installation.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] kparzysz-quic commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
kparzysz-quic commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r404307975
##########
File path: src/runtime/hexagon/README.md
##########
@@ -0,0 +1,76 @@
+<!--- 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. -->
+
+# Hexagon backend runtime
+
+The Hexagon runtime is a part of the TVM runtime that facilitates communication between a host and a Hexagon device. There are two types of host/device arrangements that are supported:
+- X86/Linux host running Hexagon simulator,
+- Android/AArch64 host running on a physical device containing a Hexagon module (i.e. CSDP or ADSP).
+
+The TVM runtime that contains Hexagon runtime is the one executing on host. In either case, there will need to be a separate TVM runtime (i.e. the `libtvm_runtime.so` library) compiled for execution on Hexagon.
+
+The prerequisite is to have Hexagon SDK installed, preferably version 3.5.0.
Review comment:
The SDK link is https://developer.qualcomm.com/software/hexagon-dsp-sdk. I'll update the PR once the build completes (I want to see if it passes)...
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] FrozenGene commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
FrozenGene commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r404519901
##########
File path: src/runtime/hexagon/target/hexagon_device_target.cc
##########
@@ -0,0 +1,525 @@
+/*
+ * 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.
+ */
+
+#ifdef __ANDROID__
+
+#include <unistd.h>
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "../hexagon_module.h"
+#include "AEEStdErr.h"
+#include "fastrpc/tvm_hexagon_remote.h"
+#include "hexagon_dsprpcapi.h"
+#include "hexagon_stubapi.h"
+#include "hexagon_target_log.h"
+#include "remote64.h"
+#include "rpcmem.h"
+
+#pragma weak remote_session_control
+
+#define RPCMEM_HEAP 25
+
+// All log messages start with "HexagonTarget::%s", where %s is replaced
+// with the function name, so create macros that add that to avoid repetition.
+// The downside is that the format string must be given as a string literal,
+// but it seems to be a minor issue.
+#define VA_EXPANDER(...) , ##__VA_ARGS__
+#define TVM_LOGD_HT(fmt, ...) \
+ TVM_LOGD("HexagonTarget::%s: " fmt, __func__ VA_EXPANDER(__VA_ARGS__))
+#define TVM_LOGE_HT(fmt, ...) \
+ TVM_LOGE("HexagonTarget::%s: " fmt, __func__ VA_EXPANDER(__VA_ARGS__))
+
+namespace tvm {
+namespace runtime {
+namespace hexagon {
+
+static constexpr int kStackSize = 128 * 1024; // 128kB stack
+
+class HexagonTarget : public tvm::runtime::hexagon::Device {
+ public:
+ HexagonTarget() {}
+ ~HexagonTarget() final {}
+ void* Alloc(unsigned size, unsigned align) final;
+ void Free(void* ptr) final;
+ void* AllocVtcm(unsigned size, unsigned align) final;
+ void FreeVtcm(void* ptr) final;
+ void CopyDeviceToDevice(void* dst, const void* src, unsigned len) final;
+ void CopyDeviceToHost(void* host_dst, const void* src, unsigned len) final;
+ void CopyHostToDevice(void* dst, const void* host_src, unsigned len) final;
+ void* Load(const std::string& data, const std::string& fmt) final;
+ void Unload(void* mod) final;
+ void* Resolve(const std::string& sym) final;
+ void Call(void* func, uint32_t* scalar, unsigned scalar_num, uint32_t* stack,
+ unsigned stack_num) final;
+
+ private:
+ std::pair<void*, size_t> AddAddrMapping(const void* dsp_addr,
+ void* apps_addr, size_t size);
+ std::pair<void*, size_t> GetAppsAddr(const void* dsp_addr, bool exact) const;
+ void RemoveAddrMapping(const void* dsp_addr);
+ int OpenDomainChannel(bool set_unsigned_pd);
+ int CloseDomainChannel();
+ void ReleaseLibrary();
+ void FreeMemoryBeforeChannelClose();
+
+ // Mapping from a DSP address to a pair <apps address, buffer size>.
+ // Using void* pointers is ok, since DSP pointers will always fit
+ // in apps's pointers, i.e. sizeof_dsp(void*) <= sizeof_apps(void*).
+ std::map<const void*, std::pair<void*, size_t>> dsp_to_apps_;
+ std::map<const void*, std::pair<void*, size_t>> vtcm_addr_;
+ remote_handle64 domain_channel_handle_ = AEE_EUNKNOWN;
+ tvm_hexagon_remote_handle_t module_pointer_ = AEE_EUNKNOWN;
+ uint64_t count_channel_open_ = 0;
+ // Global lock, used for all critical sections. This can be refined
+ // in the future.
+ mutable std::mutex crit_section_;
+};
+
+std::shared_ptr<Device> CreateHexagonTarget() {
+ return std::make_shared<HexagonTarget>();
+}
+
+std::pair<void*, size_t> HexagonTarget::AddAddrMapping(const void* dsp_addr,
+ void* apps_addr,
+ size_t size) {
+ crit_section_.lock();
+ auto p = dsp_to_apps_.insert({dsp_addr, {apps_addr, size}});
+ crit_section_.unlock();
+ if (!p.second) {
+ TVM_LOGE_HT(
+ "failed to insert address mapping: dsp:%p -> apps:%p, size:%zu",
+ dsp_addr, apps_addr, size);
+ return std::make_pair(nullptr, 0);
+ }
+ TVM_LOGD_HT("added address mapping: dsp:%p -> apps:%p, size:%zu", dsp_addr,
+ apps_addr, size);
+ return p.first->second;
+}
+
+void HexagonTarget::RemoveAddrMapping(const void* dsp_addr) {
+ crit_section_.lock();
+ auto f = dsp_to_apps_.find(dsp_addr);
+ if (f == dsp_to_apps_.end()) {
+ TVM_LOGE_HT("failed to remove address mapping for dsp:%p", dsp_addr);
+ crit_section_.unlock();
+ return;
+ }
+ dsp_to_apps_.erase(f);
+ crit_section_.unlock();
+}
+
+std::pair<void*, size_t> HexagonTarget::GetAppsAddr(const void* dsp_addr,
+ bool exact) const {
+ struct AutoUnlock {
+ explicit AutoUnlock(std::mutex& m) : m(m) {}
+ ~AutoUnlock() { m.unlock(); }
+ std::mutex& m;
+ };
+
+ crit_section_.lock();
+ AutoUnlock u(crit_section_);
+
+ // If the address is in the map, simply return the result.
+ auto f = dsp_to_apps_.find(dsp_addr);
+ if (f != dsp_to_apps_.end()) return f->second;
+ // If exact mapping is requested, then it hasn't been found.
+ if (exact) return std::make_pair(nullptr, 0);
+
+ // If the address is not in the map, maybe it points to somewhere in the
+ // interior of a mapped buffer.
+ uintptr_t dsp_v = reinterpret_cast<uintptr_t>(dsp_addr);
+ for (const auto& v : dsp_to_apps_) {
+ uintptr_t dsp_k = reinterpret_cast<uintptr_t>(v.first);
+ size_t size = v.second.second;
+ if (dsp_v >= dsp_k && dsp_v < dsp_k + size) {
+ uintptr_t apps_k = reinterpret_cast<uintptr_t>(v.second.first);
+ size_t offset = dsp_v - dsp_k;
+ uintptr_t apps_v = apps_k + offset;
+ return std::make_pair(reinterpret_cast<void*>(apps_v), size - offset);
+ }
+ }
+ TVM_LOGE_HT("failed to locate apps address for dsp:%p", dsp_addr);
+ return std::make_pair(nullptr, 0);
+}
+
+int HexagonTarget::OpenDomainChannel(bool use_unsigned_pd) {
+ if (domain_channel_handle_ != AEE_EUNKNOWN) return AEE_SUCCESS;
+
+ const DspRpcAPI* dsp_api = DspRpcAPI::Global();
+ const StubAPI* stub_api = StubAPI::Global();
+
+ stub_api->rpcmem_init_ptr()();
+
+ if (auto* rsc_ptr = dsp_api->remote_session_control_ptr(true)) {
+ remote_rpc_thread_params th_data;
+ th_data.domain = CDSP_DOMAIN_ID;
+ th_data.stack_size = kStackSize;
+ th_data.prio = -1; // Default priority.
+ int rc = rsc_ptr(FASTRPC_THREAD_PARAMS, &th_data, sizeof(th_data));
+ if (rc != AEE_SUCCESS) {
+ TVM_LOGE_HT("remote_session_control failed rc=%08x for stack size", rc);
+ }
+ if (use_unsigned_pd) {
+ remote_rpc_control_unsigned_module data;
+ data.enable = 1;
+ data.domain = CDSP_DOMAIN_ID;
+ int rc = rsc_ptr(DSPRPC_CONTROL_UNSIGNED_MODULE, &data, sizeof(data));
+ if (rc != AEE_SUCCESS) {
+ TVM_LOGE_HT("remote_session_control failed rc=%08x for unsigned PD",
+ rc);
+ }
+ }
+ } else {
+ TVM_LOGD_HT("remote_session_control not available");
+ }
+
+ int rc = stub_api->tvm_hexagon_remote_open(
+ tvm_hexagon_remote_URI "&_dom=cdsp", &domain_channel_handle_);
+ if (rc != AEE_SUCCESS) {
+ TVM_LOGE_HT("failed to open channel rc=0x%x", rc);
+ } else {
+ count_channel_open_++;
+ TVM_LOGD_HT("channel open success and rpcmem_init done");
+ }
+ return rc;
+}
+
+int HexagonTarget::CloseDomainChannel() {
+ if (domain_channel_handle_ == AEE_EUNKNOWN) return AEE_SUCCESS;
+
+ const StubAPI* stub_api = StubAPI::Global();
+
+ int rc = stub_api->tvm_hexagon_remote_close(domain_channel_handle_);
+ if (rc == AEE_SUCCESS) {
+ domain_channel_handle_ = AEE_EUNKNOWN;
+ stub_api->rpcmem_deinit_ptr()();
+ TVM_LOGD_HT("channel close success and rpcmem_deinit done");
+ } else {
+ TVM_LOGE_HT("failed to close domain channel rc=0x%x", rc);
+ }
+ return rc;
+}
+
+void HexagonTarget::ReleaseLibrary() {
+ crit_section_.lock();
+ if (module_pointer_ != AEE_EUNKNOWN) {
+ const StubAPI* stub_api = StubAPI::Global();
+ int rc = stub_api->tvm_hexagon_remote_release_library(
+ domain_channel_handle_, module_pointer_);
+ if (rc != AEE_SUCCESS) {
+ TVM_LOGE_HT("failed to unload device library rc=0x%x", rc);
+ } else {
+ module_pointer_ = AEE_EUNKNOWN;
+ }
+ }
+ crit_section_.unlock();
+}
+
+void HexagonTarget::FreeMemoryBeforeChannelClose() {
+ while (!dsp_to_apps_.empty()) {
+ void* dsp_addr = const_cast<void*>((dsp_to_apps_.begin()->first));
+ TVM_LOGD_HT("Freeing up dsp_addr %p", dsp_addr);
+ HexagonTarget::Free(dsp_addr);
+ }
+}
+void* HexagonTarget::Alloc(unsigned size, unsigned align) {
+ const DspRpcAPI* dsp_api = DspRpcAPI::Global();
+ const StubAPI* stub_api = StubAPI::Global();
+
+ // Opening the domain channel should be done once.
+ crit_section_.lock();
+ int rc_oc = OpenDomainChannel(/*use_unsigned_pd*/ true);
+ crit_section_.unlock();
+ if (rc_oc != AEE_SUCCESS) {
+ TVM_LOGE_HT("mem alloc failed: unable to open domain channel");
+ return nullptr;
+ }
+
+ // This is a workaround. If HexagonTarget::Alloc is called from a different
+ // thread then remote_mmap64 fails. FastRPC expects one call to be made to
+ // DSP before calling remote_map64. Hence this call is needed for now untill
+ // FastRPC comes up with a fix.
+ int rc_call_mmap_64 =
+ stub_api->tvm_hexagon_remote_call_mmap64(domain_channel_handle_);
+ if (rc_call_mmap_64 != AEE_SUCCESS) {
+ TVM_LOGE_HT("mmap64 failed for domain channel %lu", domain_channel_handle_);
+ return nullptr;
+ }
+
+ void* mem =
+ stub_api->rpcmem_alloc_ptr()(RPCMEM_HEAP, RPCMEM_DEFAULT_FLAGS, size);
+ if (mem == nullptr) {
+ TVM_LOGE_HT("mem alloc failed for size=0x%x alignment=0x%x", size, align);
+ return nullptr;
+ }
+ int mem_fd = stub_api->rpcmem_to_fd_ptr()(mem);
+ uintptr_t dsp_va = 0;
+ int rc = dsp_api->remote_mmap64_ptr()(
+ mem_fd, 0, reinterpret_cast<uintptr_t>(mem), size, &dsp_va);
+ if (rc != AEE_SUCCESS) {
+ TVM_LOGE_HT(
+ "buffer mapping failed for remote_map64 fd=0x%x rc=0x%x "
+ "apps_addr=0x%lx",
+ mem_fd, rc, reinterpret_cast<uintptr_t>(mem));
+ return nullptr;
+ }
+
+ void* dsp_addr = reinterpret_cast<void*>(dsp_va);
+ AddAddrMapping(dsp_addr, mem, size);
+ return dsp_addr;
+}
+
+void HexagonTarget::Free(void* ptr) {
+ const DspRpcAPI* dsp_api = DspRpcAPI::Global();
+ const StubAPI* stub_api = StubAPI::Global();
+ auto bb = GetAppsAddr(ptr, true);
+ if (bb.first == reinterpret_cast<void*>(~0)) {
+ TVM_LOGD_HT("VTCM mapping found. dsp_addr=0x%p", ptr);
+ RemoveAddrMapping(ptr);
+ FreeVtcm(ptr);
+ return;
+ }
+
+ TVM_LOGD_HT("VTCM mapping not found. dsp_addr=0x%p", ptr);
+ auto aa = GetAppsAddr(ptr, true);
+ if (aa.first == nullptr) return;
+
+ int rc = dsp_api->remote_munmap64_ptr()(reinterpret_cast<uintptr_t>(ptr),
+ aa.second);
+ if (rc != AEE_SUCCESS) {
+ TVM_LOGE_HT("buffer unmapping failed rc=0x%x", rc);
+ }
+ RemoveAddrMapping(ptr);
+ stub_api->rpcmem_free_ptr()(aa.first);
+}
+
+void* HexagonTarget::AllocVtcm(unsigned size, unsigned align) {
+ const StubAPI* stub_api = StubAPI::Global();
+
+ unsigned int dsp_va = 0;
+ int rc = stub_api->tvm_hexagon_remote_alloc_vtcm(domain_channel_handle_,
+ size, align, &dsp_va);
+ if (rc != AEE_SUCCESS) {
+ TVM_LOGE_HT("VTCM allocation failed size=%u, align=%u", size, align);
+ return nullptr;
+ }
+ void* dsp_addr = reinterpret_cast<void*>(dsp_va);
+ TVM_LOGD_HT("Done vtcm alloc dsp:%p", dsp_addr);
+ AddAddrMapping(dsp_addr, reinterpret_cast<void*>(~0), size);
+ return dsp_addr;
+}
+
+void HexagonTarget::FreeVtcm(void* ptr) {
+ const StubAPI* stub_api = StubAPI::Global();
+
+ TVM_LOGD_HT("%s:Calling vtcm free. ptr=%p", __func__, ptr);
+ uintptr_t dsp_va = reinterpret_cast<uintptr_t>(ptr);
+ int rc =
+ stub_api->tvm_hexagon_remote_free_vtcm(domain_channel_handle_, dsp_va);
+ if (rc != AEE_SUCCESS) {
+ TVM_LOGE_HT("VTCM deallocation failed");
+ }
+ TVM_LOGD_HT("Done VTCM free from HexagonTarget::FreeVtcm");
+}
+
+void HexagonTarget::CopyDeviceToDevice(void* dst, const void* src,
Review comment:
As comment said: https://github.com/apache/incubator-tvm/pull/3163#discussion_r322701661 We should implement it. I tested on real device and find it is one must for device.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] tmoreau89 commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
tmoreau89 commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r404291517
##########
File path: src/runtime/hexagon/README.md
##########
@@ -0,0 +1,76 @@
+<!--- 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. -->
+
+# Hexagon backend runtime
+
+The Hexagon runtime is a part of the TVM runtime that facilitates communication between a host and a Hexagon device. There are two types of host/device arrangements that are supported:
+- X86/Linux host running Hexagon simulator,
+- Android/AArch64 host running on a physical device containing a Hexagon module (i.e. CSDP or ADSP).
+
+The TVM runtime that contains Hexagon runtime is the one executing on host. In either case, there will need to be a separate TVM runtime (i.e. the `libtvm_runtime.so` library) compiled for execution on Hexagon.
+
+The prerequisite is to have Hexagon SDK installed, preferably version 3.5.0.
Review comment:
In addition, is there a way to install it "automatically" to this back-end can be tested in the CI?
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] FrozenGene merged pull request #5252: [RUNTIME]
Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
FrozenGene merged pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] tqchen commented on a change in pull request #5252:
[RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
tqchen commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r404304102
##########
File path: src/runtime/hexagon/README.md
##########
@@ -0,0 +1,76 @@
+<!--- 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. -->
+
+# Hexagon backend runtime
+
+The Hexagon runtime is a part of the TVM runtime that facilitates communication between a host and a Hexagon device. There are two types of host/device arrangements that are supported:
+- X86/Linux host running Hexagon simulator,
+- Android/AArch64 host running on a physical device containing a Hexagon module (i.e. CSDP or ADSP).
+
+The TVM runtime that contains Hexagon runtime is the one executing on host. In either case, there will need to be a separate TVM runtime (i.e. the `libtvm_runtime.so` library) compiled for execution on Hexagon.
+
+The prerequisite is to have Hexagon SDK installed, preferably version 3.5.0.
Review comment:
While it might be hard to create an automatic installed version, we can look into at least do the compilation tests, to make sure that the runtime compiles
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] kparzysz-quic commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
kparzysz-quic commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r404894728
##########
File path: src/runtime/hexagon/target/hexagon_device_target.cc
##########
@@ -0,0 +1,525 @@
+/*
+ * 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.
+ */
+
+#ifdef __ANDROID__
+
+#include <unistd.h>
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "../hexagon_module.h"
+#include "AEEStdErr.h"
+#include "fastrpc/tvm_hexagon_remote.h"
+#include "hexagon_dsprpcapi.h"
+#include "hexagon_stubapi.h"
+#include "hexagon_target_log.h"
+#include "remote64.h"
+#include "rpcmem.h"
+
+#pragma weak remote_session_control
+
+#define RPCMEM_HEAP 25
+
+// All log messages start with "HexagonTarget::%s", where %s is replaced
+// with the function name, so create macros that add that to avoid repetition.
+// The downside is that the format string must be given as a string literal,
+// but it seems to be a minor issue.
+#define VA_EXPANDER(...) , ##__VA_ARGS__
+#define TVM_LOGD_HT(fmt, ...) \
+ TVM_LOGD("HexagonTarget::%s: " fmt, __func__ VA_EXPANDER(__VA_ARGS__))
+#define TVM_LOGE_HT(fmt, ...) \
+ TVM_LOGE("HexagonTarget::%s: " fmt, __func__ VA_EXPANDER(__VA_ARGS__))
+
+namespace tvm {
+namespace runtime {
+namespace hexagon {
+
+static constexpr int kStackSize = 128 * 1024; // 128kB stack
+
+class HexagonTarget : public tvm::runtime::hexagon::Device {
+ public:
+ HexagonTarget() {}
+ ~HexagonTarget() final {}
+ void* Alloc(unsigned size, unsigned align) final;
+ void Free(void* ptr) final;
+ void* AllocVtcm(unsigned size, unsigned align) final;
+ void FreeVtcm(void* ptr) final;
+ void CopyDeviceToDevice(void* dst, const void* src, unsigned len) final;
+ void CopyDeviceToHost(void* host_dst, const void* src, unsigned len) final;
+ void CopyHostToDevice(void* dst, const void* host_src, unsigned len) final;
+ void* Load(const std::string& data, const std::string& fmt) final;
+ void Unload(void* mod) final;
+ void* Resolve(const std::string& sym) final;
+ void Call(void* func, uint32_t* scalar, unsigned scalar_num, uint32_t* stack,
+ unsigned stack_num) final;
+
+ private:
+ std::pair<void*, size_t> AddAddrMapping(const void* dsp_addr,
+ void* apps_addr, size_t size);
+ std::pair<void*, size_t> GetAppsAddr(const void* dsp_addr, bool exact) const;
+ void RemoveAddrMapping(const void* dsp_addr);
+ int OpenDomainChannel(bool set_unsigned_pd);
+ int CloseDomainChannel();
+ void ReleaseLibrary();
+ void FreeMemoryBeforeChannelClose();
+
+ // Mapping from a DSP address to a pair <apps address, buffer size>.
+ // Using void* pointers is ok, since DSP pointers will always fit
+ // in apps's pointers, i.e. sizeof_dsp(void*) <= sizeof_apps(void*).
+ std::map<const void*, std::pair<void*, size_t>> dsp_to_apps_;
+ std::map<const void*, std::pair<void*, size_t>> vtcm_addr_;
+ remote_handle64 domain_channel_handle_ = AEE_EUNKNOWN;
+ tvm_hexagon_remote_handle_t module_pointer_ = AEE_EUNKNOWN;
+ uint64_t count_channel_open_ = 0;
+ // Global lock, used for all critical sections. This can be refined
+ // in the future.
+ mutable std::mutex crit_section_;
+};
+
+std::shared_ptr<Device> CreateHexagonTarget() {
+ return std::make_shared<HexagonTarget>();
+}
+
+std::pair<void*, size_t> HexagonTarget::AddAddrMapping(const void* dsp_addr,
+ void* apps_addr,
+ size_t size) {
+ crit_section_.lock();
+ auto p = dsp_to_apps_.insert({dsp_addr, {apps_addr, size}});
+ crit_section_.unlock();
+ if (!p.second) {
+ TVM_LOGE_HT(
+ "failed to insert address mapping: dsp:%p -> apps:%p, size:%zu",
+ dsp_addr, apps_addr, size);
+ return std::make_pair(nullptr, 0);
+ }
+ TVM_LOGD_HT("added address mapping: dsp:%p -> apps:%p, size:%zu", dsp_addr,
+ apps_addr, size);
+ return p.first->second;
+}
+
+void HexagonTarget::RemoveAddrMapping(const void* dsp_addr) {
+ crit_section_.lock();
+ auto f = dsp_to_apps_.find(dsp_addr);
+ if (f == dsp_to_apps_.end()) {
+ TVM_LOGE_HT("failed to remove address mapping for dsp:%p", dsp_addr);
+ crit_section_.unlock();
+ return;
+ }
+ dsp_to_apps_.erase(f);
+ crit_section_.unlock();
+}
+
+std::pair<void*, size_t> HexagonTarget::GetAppsAddr(const void* dsp_addr,
+ bool exact) const {
+ struct AutoUnlock {
+ explicit AutoUnlock(std::mutex& m) : m(m) {}
+ ~AutoUnlock() { m.unlock(); }
+ std::mutex& m;
+ };
+
+ crit_section_.lock();
+ AutoUnlock u(crit_section_);
+
+ // If the address is in the map, simply return the result.
+ auto f = dsp_to_apps_.find(dsp_addr);
+ if (f != dsp_to_apps_.end()) return f->second;
+ // If exact mapping is requested, then it hasn't been found.
+ if (exact) return std::make_pair(nullptr, 0);
+
+ // If the address is not in the map, maybe it points to somewhere in the
+ // interior of a mapped buffer.
+ uintptr_t dsp_v = reinterpret_cast<uintptr_t>(dsp_addr);
+ for (const auto& v : dsp_to_apps_) {
+ uintptr_t dsp_k = reinterpret_cast<uintptr_t>(v.first);
+ size_t size = v.second.second;
+ if (dsp_v >= dsp_k && dsp_v < dsp_k + size) {
+ uintptr_t apps_k = reinterpret_cast<uintptr_t>(v.second.first);
+ size_t offset = dsp_v - dsp_k;
+ uintptr_t apps_v = apps_k + offset;
+ return std::make_pair(reinterpret_cast<void*>(apps_v), size - offset);
+ }
+ }
+ TVM_LOGE_HT("failed to locate apps address for dsp:%p", dsp_addr);
+ return std::make_pair(nullptr, 0);
+}
+
+int HexagonTarget::OpenDomainChannel(bool use_unsigned_pd) {
+ if (domain_channel_handle_ != AEE_EUNKNOWN) return AEE_SUCCESS;
+
+ const DspRpcAPI* dsp_api = DspRpcAPI::Global();
+ const StubAPI* stub_api = StubAPI::Global();
+
+ stub_api->rpcmem_init_ptr()();
Review comment:
Done.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] FrozenGene commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
FrozenGene commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r405397816
##########
File path: src/runtime/hexagon/README.md
##########
@@ -0,0 +1,76 @@
+<!--- 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. -->
+
+# Hexagon backend runtime
+
+The Hexagon runtime is a part of the TVM runtime that facilitates communication between a host and a Hexagon device. There are two types of host/device arrangements that are supported:
+- X86/Linux host running Hexagon simulator,
+- Android/AArch64 host running on a physical device containing a Hexagon module (i.e. CSDP or ADSP).
+
+The TVM runtime that contains Hexagon runtime is the one executing on host. In either case, there will need to be a separate TVM runtime (i.e. the `libtvm_runtime.so` library) compiled for execution on Hexagon.
+
+The prerequisite is to have Hexagon SDK installed, preferably version 3.5.0 or later. The Hexagon SDK can be downloaded from https://developer.qualcomm.com/software/hexagon-dsp-sdk.
+
+### Compiling TVM runtime for x86
+
+This will use Hexagon simulator, which is provided in the Hexagon SDK.
+
+When configuring TVM (cmake), set the following variables:
+```
+USE_LLVM=llvm-config
+USE_HEXAGON_DEVICE=sim
+USE_HEXAGON_SDK=/path/to/sdk
+```
+
+Set the C/C++ compiler to `clang`, and pass `-DCMAKE_CXX_FLAGS='-stdlib=libc++'` to the cmake command.
Review comment:
Does it a must? I use g++ and libstdc++ ever and no problem.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] FrozenGene commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
FrozenGene commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r405412981
##########
File path: src/runtime/hexagon/hexagon_module.cc
##########
@@ -0,0 +1,561 @@
+/*
+ * 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.
+ */
+
+#include "hexagon_module.h"
+
+#ifdef __ANDROID__
+#include <android/log.h>
+#endif
+#include <dmlc/logging.h>
+#include <tvm/runtime/registry.h>
+
+#include <memory>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "../file_util.h"
+#include "../meta_data.h"
+
+namespace tvm {
+namespace runtime {
+
+hexagon::Device::~Device() {}
+
+namespace hexagon {
+
+/*!
+ * \brief Function argument locations according to the Hexagon ABI.
+ *
+ * In order to invoke a function whose arguments are in TVMArgs list, at
+ * some point before branching to the function's address, these arguments
+ * need to be loaded into locations (registers or stack) specified by the
+ * corresponding ABI.
+ * When a host wants to call a function on Hexagon, the host will identify
+ * how each element of the TVMArgs list will be passed to the Hexagon
+ * function. This class is a description of which values should go into
+ * registers, and which values should be on stack. Right before the call
+ * this class will be serialized and transfereed over to the Hexagon side.
+ * The code running on Hexagon will then execute the argument placement
+ * and invoke the function.
+ */
+struct ArgLayout {
+ std::vector<uint32_t> Scalar; /*!< Values going into registers, maximum */
+ /*!< 6, including dummy values for skipped */
+ /*!< registers. */
+ std::vector<uint32_t> Stack; /*!< Values going on stack, including */
+ /*!< dummy values for padding. */
+ // There are no vector types at this time.
+
+ /*!
+ * \brief Alignment of type T on Hexagon.
+ */
+ template <typename T>
+ static constexpr unsigned align_of();
+ /*!
+ * \brief Size of type T on Hexagon.
+ */
+ template <typename T>
+ static constexpr unsigned size_of();
+
+ /*!
+ * \brief Add a value of type T to the layout.
+ */
+ template <typename T>
+ void Push(const T& v);
+
+ private:
+ /*!
+ * \brief Add raw data to the layout.
+ * \param v Pointer to the raw data as an array of 32-bit words.
+ * \param t_size Number of bytes to add.
+ * \param t_align Required alignment of the data on Hexagon.
+ */
+ void Push(uint32_t* v, unsigned t_size, unsigned t_align);
+};
+
+template <>
+constexpr unsigned ArgLayout::align_of<int32_t>() {
+ return 4;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<uint32_t>() {
+ return 4;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<float>() {
+ return 4;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<void*>() {
+ return 4;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<int64_t>() {
+ return 8;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<uint64_t>() {
+ return 8;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<double>() {
+ return 8;
+}
+template <>
+constexpr unsigned ArgLayout::align_of<DLTensor*>() {
+ return 4;
+}
+
+template <typename T>
+constexpr unsigned ArgLayout::align_of() {
+ // The static_assertion should depend on T so that it's only checked
+ // after instantiation.
+ static_assert((sizeof(T), false), "Implement align_of for this type");
+ return 0;
+}
+
+template <typename T>
+constexpr unsigned ArgLayout::size_of() {
+ return ArgLayout::align_of<T>();
+}
+
+template <typename T>
+void ArgLayout::Push(const T& v) {
+ static_assert(std::is_scalar<T>::value, "T must be a scalar");
+ constexpr unsigned T_size = size_of<T>();
+ // The reason for this assertion is to avoid sign-extensions here:
+ // an extra bit of information would be required to determine whether
+ // a size- or a zero-extension is needed.
+ static_assert(T_size >= 4, "Type should be of size that is at least 4");
+ union {
+ uint32_t v[(T_size + 3) / 4];
+ T t;
+ } u;
+
+ u.t = v;
+ Push(u.v, T_size, align_of<T>());
+}
+
+void ArgLayout::Push(uint32_t* v, unsigned t_size, unsigned t_align) {
+ // t_size == 4 and t_size == 8 can be passed in scalar registers.
+ bool InReg = false;
+ if (t_size == 4) {
+ if (Scalar.size() < 6) {
+ Scalar.push_back(v[0]);
+ InReg = true;
+ }
+ } else if (t_size == 8) {
+ // Round the size up to the next
+ unsigned cs = Scalar.size();
+ if (cs <= 4) {
+ // There is room in the scalar registers.
+ if (cs & 1) Scalar.push_back(0u);
+ Scalar.push_back(v[0]);
+ Scalar.push_back(v[1]);
+ InReg = true;
+ }
+ }
+
+ if (!InReg) {
+ // Allocate on stack.
+ CHECK_EQ((t_align & (t_align - 1)), 0)
+ << "Alignment should be a power of 2";
+ CHECK_GE(t_align, 4) << "Alignment should be at least 4";
+ // Round t_size up to a multiple of 4.
+ unsigned s_size = Stack.size();
+ unsigned s_align = t_align / 4; // Alignment of T in words on the stack.
+ unsigned pad = ((s_size + s_align - 1) / s_align) * s_align - s_size;
+ Stack.insert(Stack.end(), pad / 4, 0u);
+ Stack.insert(Stack.end(), v, v + t_size / 4);
+ }
+}
+
+} // namespace hexagon
+
+class HexagonModuleNode final : public runtime::ModuleNode {
+ public:
+ HexagonModuleNode(std::string data, std::string fmt,
+ std::unordered_map<std::string, FunctionInfo> fmap,
+ std::string asm_str, std::string obj_str,
+ std::string ir_str, std::string bc_str,
+ const std::set<std::string>& packed_c_abi)
+ : hexagon_device_(hexagon::Device::Global()),
+ data_(data),
+ fmt_(fmt),
+ fmap_(fmap),
+ asm_(asm_str),
+ obj_(obj_str),
+ ir_(ir_str),
+ bc_(bc_str),
+ packed_c_abi_funcs_(packed_c_abi) {
+ dl_handle_ = hexagon_device_->Load(data, fmt);
+ }
+ ~HexagonModuleNode() {
+ if (dl_handle_) {
+ hexagon_device_->Unload(dl_handle_);
+ }
+ }
+
+ PackedFunc GetFunction(const std::string& name,
+ const ObjectPtr<Object>& sptr_to_self) final;
+
+ const char* type_key() const final { return "hexagon"; }
+
+ void SaveToFile(const std::string& file_name,
+ const std::string& format) final {
+ std::string fmt = runtime::GetFileFormat(file_name, format);
+ if (fmt == "so" || fmt == "dll" || fmt == "hexagon") {
+ std::string meta_file = GetMetaFilePath(file_name);
+ SaveMetaDataToFile(meta_file, fmap_);
+ std::string c = "cp " + data_ + " " + file_name;
+ CHECK(std::system(c.c_str()) == 0) << "Cannot create " + file_name;
+ } else if (fmt == "s" || fmt == "asm") {
+ CHECK(!asm_.empty()) << "Assembler source not available";
+ SaveBinaryToFile(file_name, asm_);
+ } else if (fmt == "o" || fmt == "obj") {
+ CHECK(!obj_.empty()) << "Object data not available";
+ SaveBinaryToFile(file_name, obj_);
+ } else if (fmt == "ll") {
+ CHECK(!ir_.empty()) << "LLVM IR source not available";
+ SaveBinaryToFile(file_name, ir_);
+ } else if (fmt == "bc") {
+ CHECK(!bc_.empty()) << "LLVM IR bitcode not available";
+ SaveBinaryToFile(file_name, bc_);
+ } else {
+ LOG(FATAL) << "HexagonModuleNode::SaveToFile: unhandled format `" << fmt
+ << "'";
+ }
+ }
+ void SaveToBinary(dmlc::Stream* stream) final {
+ stream->Write(fmt_);
+ stream->Write(fmap_);
+ stream->Write(data_);
+ }
+
+ private:
+ void CallRemotePackedCABI(void* func_ptr, const TVMArgs& args,
+ TVMRetValue* rv) const;
+ void CallRemoteDirect(void* func_ptr, const TVMArgs& args,
+ TVMRetValue* rv) const;
+ void RemapArgs(const TVMArgs& args,
+ std::vector<TVMValue>& values, // NOLINT(*)
+ std::vector<int>& type_codes, // NOLINT(*)
+ std::vector<void*>& remote_tensors) const; // NOLINT(*)
+ void* CreateRemoteTensor(const DLTensor* T) const;
+ hexagon::ArgLayout BuildArgLayout(const TVMArgs& Aa) const;
+
+ std::shared_ptr<hexagon::Device> hexagon_device_;
+ void* dl_handle_ = nullptr;
+ std::string data_;
+ std::string fmt_;
+ std::unordered_map<std::string, FunctionInfo> fmap_;
+ std::string asm_;
+ std::string obj_;
+ std::string ir_;
+ std::string bc_;
+ std::set<std::string> packed_c_abi_funcs_;
+};
+
+void HexagonModuleNode::CallRemotePackedCABI(void* func_ptr,
+ const TVMArgs& args,
+ TVMRetValue* rv) const {
+ // Remap all arguments, creating remote DLTensors.
+ std::vector<TVMValue> values;
+ std::vector<int> codes;
+ std::vector<void*> remote_tensors;
+
+ RemapArgs(args, values, codes, remote_tensors);
+ // The prototype of packed C function is
+ // int (TVMValue* args, int* type_codes, int num_args,
+ // TVMValue* ret_value, int* ret_code)
+ // The pointers must point to allocated space, the return information
+ // will be filled in by the callee.
+ // Allocate remote buffer to hold:
+ // 1. argument TVMValues,
+ // 2. return TVMValue,
+ // 3. argument type codes,
+ // 4. return type code.
+
+ int num_args = args.size();
+ int values_size = num_args * sizeof(TVMValue);
+ int codes_size = num_args * sizeof(int);
+ void* remote = hexagon_device_->Alloc(
+ values_size + sizeof(TVMValue) + codes_size + sizeof(int), 8);
+
+ // Copy all argument TVMValues to the remote space.
+ void* remote_values = remote;
+ void* remote_ret_value = static_cast<char*>(remote_values) + values_size;
+ void* remote_codes = static_cast<char*>(remote_ret_value) + sizeof(TVMValue);
+ void* remote_ret_code = static_cast<char*>(remote_codes) + codes_size;
+ hexagon_device_->CopyHostToDevice(remote_values, values.data(), values_size);
+ hexagon_device_->CopyHostToDevice(remote_codes, codes.data(), codes_size);
+
+ // Call the function: construct temporary values/codes and pass them through
+ // the arg layout building to preprare for the actual remote call.
+ TVMValue temp_values[5];
+ temp_values[0].v_handle = remote_values;
+ temp_values[1].v_handle = remote_codes;
+ temp_values[2].v_int64 = num_args;
+ temp_values[3].v_handle = remote_ret_value;
+ temp_values[4].v_handle = remote_ret_code;
+ int temp_codes[5] = {kTVMOpaqueHandle, kTVMOpaqueHandle, kDLInt,
+ kTVMOpaqueHandle, kTVMOpaqueHandle};
+ TVMArgs temp_args(temp_values, temp_codes, 5);
+ hexagon::ArgLayout as = BuildArgLayout(temp_args);
+ hexagon_device_->Call(func_ptr, as.Scalar.data(), as.Scalar.size(),
+ as.Stack.data(), as.Stack.size());
+
+ // TODO(kparzysz-quic): copy return value back
+ std::for_each(remote_tensors.begin(), remote_tensors.end(),
+ [this](void* t) { hexagon_device_->Free(t); });
+ hexagon_device_->Free(remote);
+}
+
+void HexagonModuleNode::CallRemoteDirect(void* func_ptr, const TVMArgs& args,
+ TVMRetValue* rv) const {
+ hexagon::ArgLayout as = BuildArgLayout(args);
+ hexagon_device_->Call(func_ptr, as.Scalar.data(), as.Scalar.size(),
+ as.Stack.data(), as.Stack.size());
+}
+
+PackedFunc HexagonModuleNode::GetFunction(
+ const std::string& name, const ObjectPtr<Object>& sptr_to_self) {
+ auto f = fmap_.find(name);
+ if (f == fmap_.end()) return PackedFunc(nullptr);
+
+ // Get function pointer from device.
+ void* pf = hexagon_device_->Resolve(name);
+ // The cast result and the original share ownership. Do the cast here
+ // so that sptr_to_self can be destroyed (i.e. "func" will only have
+ // one shared pointer to HexagonModuleNode).
+ auto sref = ObjectRef(sptr_to_self);
+
+ if (packed_c_abi_funcs_.count(name)) {
+ // Calling packed C func, follow the TVMBackendPackedCFunc prototype.
+ return PackedFunc([pf, sref](TVMArgs args, TVMRetValue* rv) {
+ const auto* hm = sref.as<HexagonModuleNode>();
+ hm->CallRemotePackedCABI(pf, args, rv);
+ });
+ } else {
+ // Direct call to a non-packed-C function.
+ return PackedFunc([pf, sref](TVMArgs args, TVMRetValue* rv) {
+ const auto* hm = sref.as<HexagonModuleNode>();
+ hm->CallRemoteDirect(pf, args, rv);
+ });
+ }
+}
+
+void HexagonModuleNode::RemapArgs(const TVMArgs& args,
+ std::vector<TVMValue>& values,
+ std::vector<int>& type_codes,
+ std::vector<void*>& remote_tensors) const {
+ for (unsigned i = 0, e = args.size(); i != e; ++i) {
+ const TVMArgValue& a = args[i];
+
+ switch (unsigned tc = a.type_code()) {
+ case kTVMNDArrayHandle:
+ case kTVMDLTensorHandle: {
+ DLTensor* t = static_cast<DLTensor*>(a);
+ assert(TVMDeviceExtType(t->ctx.device_type) == kDLHexagon);
+ TVMValue v;
+ v.v_handle = CreateRemoteTensor(t);
+ remote_tensors.push_back(v.v_handle);
+ values.push_back(v);
+ type_codes.push_back(tc);
+ break;
+ }
+
+ default:
+ values.push_back(a.value());
+ type_codes.push_back(tc);
+ break;
+ }
+ }
+}
+
+void* HexagonModuleNode::CreateRemoteTensor(const DLTensor* t) const {
+ /*
+ Layout of the DLTensor structure on Hexagon.
+
+ DLTensor: Size offset
+ data void* 4 0
+ ctx.device_type enum 1 4
+ <pad> 3 5
+ ctx.device_id int 4 8
+ ndim int 4 12
+ dtype.code uint8_t 1 16
+ dtype.bits uint8_t 1 17
+ dtype.lanes uint16_t 2 18
+ shape int64_t* 4 20
+ strides int64_t* 4 24
+ <pad> 4 28
+ byte_offset uint64_t 8 32
+ .. end ................................ 40
+ */
+ struct __attribute__((packed)) HexagonDLTensor {
+ uint32_t data;
+ uint8_t ctx_device_type;
+ uint8_t pad0[3]; // MUST BE ZERO!
+ int32_t ctx_device_id;
+ int32_t ndim;
+ uint8_t dtype_code;
+ uint8_t dtype_bits;
+ uint16_t dtype_lanes;
+ uint32_t shape;
+ uint32_t strides;
+ uint8_t pad1[4];
+ uint64_t byte_offset;
+ };
+
+ constexpr uint32_t size_ht = sizeof(HexagonDLTensor);
+ static_assert(size_ht == 40, "HexagonDLTensor should be 40 bytes");
+
+ // Shape and strides will contain ndim elements of size sizeof(uint64_t)
+ // each. Allocate them after the main structure.
+ int ndim = t->ndim;
+ uint32_t size_s = 8 * ndim; // sizeof(uint64_t)*ndim
+ uint32_t size_ss = t->strides ? 2 * size_s : size_s;
+ void* remote = hexagon_device_->Alloc(size_ht + size_ss, 8);
+ uint32_t remote_as_int = reinterpret_cast<uintptr_t>(remote);
+ void* remote_ss = reinterpret_cast<void*>(remote_as_int + size_ht);
+
+ HexagonDLTensor local = {
+ .data = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(t->data)),
+ .ctx_device_type = uint8_t(t->ctx.device_type),
+ .pad0 = {0, 0, 0},
+ .ctx_device_id = t->ctx.device_id,
+ .ndim = t->ndim,
+ .dtype_code = t->dtype.code,
+ .dtype_bits = t->dtype.bits,
+ .dtype_lanes = t->dtype.lanes,
+ .shape = remote_as_int + size_ht,
+ .strides = t->strides ? remote_as_int + size_ht + size_s : 0u,
+ .byte_offset = t->byte_offset};
+
+ std::vector<uint64_t> local_ss(size_ss / 8);
+ for (int i = 0; i != ndim; ++i) local_ss[i] = t->shape[i];
+ if (t->strides) {
+ for (int i = 0; i != ndim; ++i) local_ss[ndim + i] = t->strides[i];
+ }
+
+ hexagon_device_->CopyHostToDevice(remote, &local, sizeof local);
+ hexagon_device_->CopyHostToDevice(remote_ss, local_ss.data(), size_ss);
+ return remote;
+}
+
+hexagon::ArgLayout HexagonModuleNode::BuildArgLayout(const TVMArgs& As) const {
+ hexagon::ArgLayout Args;
+
+ for (unsigned i = 0, e = As.size(); i != e; ++i) {
+ const TVMArgValue& A = As[i];
+ unsigned TC = A.type_code();
+ switch (TC) {
+ // Treat all integers as 32-bit values.
+ case kDLInt:
+ case kDLUInt:
+ // KLUDGE: There is no distinction between 32- and 64-bit integer
+ // types, so there is no way to tell if the value being passed needs
+ // one or two registers. Assume that all integers are 32-bit, and
+ // simply abort if the actual value does not fit.
+ CHECK_EQ(static_cast<int64_t>(A), static_cast<int32_t>(A));
+ Args.Push(static_cast<int>(A));
+ break;
+ // 64-bit values
+ case kDLFloat:
+ Args.Push(static_cast<double>(A));
+ break;
+
+ case kTVMOpaqueHandle:
+ case kTVMNullptr:
+ case kTVMObjectHandle:
+ case kTVMModuleHandle:
+ case kTVMPackedFuncHandle:
+ Args.Push(static_cast<void*>(A));
+ break;
+
+ case kTVMNDArrayHandle:
+ case kTVMDLTensorHandle:
+ LOG(FATAL) << __func__ << ": cannot handle DLTensor*, code:" << TC;
+
+ default:
+ LOG(FATAL) << __func__ << ": unhandled type code" << TC;
+ break;
+ }
+ }
+
+ return Args;
+}
+
+Module HexagonModuleCreate(std::string data, std::string fmt,
+ std::unordered_map<std::string, FunctionInfo> fmap,
+ std::string asm_str, std::string obj_str,
+ std::string ir_str, std::string bc_str,
+ const std::set<std::string>& packed_c_abi) {
+ auto n = make_object<HexagonModuleNode>(data, fmt, fmap, asm_str, obj_str,
+ ir_str, bc_str, packed_c_abi);
+ return Module(n);
+}
+
+// Load module from file.
+Module HexagonModuleLoadFile(const std::string& file_name,
+ const std::string& format) {
+ std::string data = file_name;
+ std::unordered_map<std::string, FunctionInfo> fmap;
+ std::string fmt = GetFileFormat(file_name, format);
+ std::string meta_file = GetMetaFilePath(file_name);
+ LoadMetaDataFromFile(meta_file, &fmap);
+
+ std::string empty;
+ // This passes {} as the set of packed C functions. Won't work for
+ // standalone functions on target.
+ return HexagonModuleCreate(data, fmt, fmap, empty, empty, empty, empty, {});
+}
+
+namespace hexagon {
+
+std::shared_ptr<Device> Device::Global() {
+ // Declare device constructors.
+#ifdef __ANDROID__
Review comment:
If we want to support more Hexagon target in the future, we maybe have problem. For example, hexagon could run embed system of Ubuntu, which is official support of Hexagon SDK too. Then we can not use `__ANDROID__` to distinguish target or simulator. One proposal is in our Hexagon.cmake, when we build for simulator, we define one macro like `-D__HEXAGON_SIM__=1` to indicate we are running on simulator or like `-D__HEXAGON_DEVICE__=1` to indicate we are running on real devices. This is one nit-pick comment, however, I wish we could consider it.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] FrozenGene commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
FrozenGene commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r405939600
##########
File path: src/runtime/hexagon/README.md
##########
@@ -0,0 +1,75 @@
+<!--- 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. -->
+
+# Hexagon backend runtime
+
+The Hexagon runtime is a part of the TVM runtime that facilitates communication between a host and a Hexagon device. There are two types of host/device arrangements that are supported:
+- X86/Linux host running Hexagon simulator,
+- Android/AArch64 host running on a physical device containing a Hexagon module (i.e. CSDP or ADSP).
+
+The TVM runtime that contains Hexagon runtime is the one executing on host. In either case, there will need to be a separate TVM runtime (i.e. the `libtvm_runtime.so` library) compiled for execution on Hexagon.
+
+The prerequisite is to have Hexagon SDK installed, preferably version 3.5.0 or later. The Hexagon SDK can be downloaded from https://developer.qualcomm.com/software/hexagon-dsp-sdk.
+
+### Compiling TVM runtime for x86
+
+This will use Hexagon simulator, which is provided in the Hexagon SDK.
+
+When configuring TVM (cmake), set the following variables:
+```
+USE_LLVM=llvm-config
Review comment:
Need us to add one line of LLVM version requirement? If I remember correctly, older LLVM version (like 6.0 or before) has many bugs on Hexagon DSP.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] kparzysz-quic commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
kparzysz-quic commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r405539725
##########
File path: src/runtime/hexagon/sim/hexagon_device_sim.cc
##########
@@ -0,0 +1,1419 @@
+/*
+ * 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.
+ */
+
+#include <dmlc/logging.h>
+#include <llvm/ADT/Optional.h>
+#include <llvm/ADT/STLExtras.h>
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/FileSystem.h>
+#include <llvm/Support/Process.h>
+
+#include <algorithm>
+#include <deque>
+#include <iomanip>
+#include <locale>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "../hexagon_module.h"
+#include "HexagonWrapper.h"
+#include "hexagon_sim_proto.h"
+
+namespace tvm {
+namespace runtime {
+namespace hexagon {
+
+static_assert(sizeof(HEX_VA_t) == sizeof(uint32_t),
+ "Hexagon VA must be uint32");
+
+template <typename T>
+struct unalign {
+ using type = struct { T value; } __attribute__((aligned(1), packed));
+};
+
+template <unsigned N>
+struct uint {
+ using type = void;
+};
+
+template <>
+struct uint<8> {
+ using type = uint64_t;
+};
+template <>
+struct uint<4> {
+ using type = uint32_t;
+};
+template <>
+struct uint<2> {
+ using type = uint16_t;
+};
+template <>
+struct uint<1> {
+ using type = uint8_t;
+};
+
+using string_list = std::deque<std::string>;
+
+namespace detail {
+
+template <typename T, typename... Args>
+std::unique_ptr<T> make_unique(Args... args) {
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+template <typename T>
+std::unique_ptr<T> make_unique(size_t size) {
+ using U = typename std::remove_extent<T>::type;
+ return std::unique_ptr<T>(new U[size]());
+}
+
+// Converter class to translate vector<string> to char**. This relieves the
+// user from memory reallocation and copying.
+struct non_const_str {
+ non_const_str() {}
+ explicit non_const_str(const std::string& str)
+ : non_const_str(std::vector<std::string>{str}) {}
+ explicit non_const_str(const std::vector<std::string>& vec) {
+ for (const std::string& s : vec) {
+ auto c = detail::make_unique<char[]>(s.size() + 1);
+ std::strncpy(c.get(), s.c_str(), s.size() + 1);
+ storage_.push_back(std::move(c));
+ pointers_.push_back(storage_.back().get());
+ }
+ }
+ non_const_str(non_const_str&& ncs) { *this = std::move(ncs); }
+ non_const_str& operator=(non_const_str&& ncs) {
+ if (this != &ncs) {
+ for (auto& s : ncs.storage_) storage_.push_back(std::move(s));
+ for (auto& s : storage_) pointers_.push_back(s.get());
+ }
+ return *this;
+ }
+ size_t size() const { return pointers_.size(); }
+ operator char*() {
+ CHECK_EQ(pointers_.size(), 1);
+ return pointers_[0];
+ }
+ operator char* *() { return pointers_.data(); }
+
+ private:
+ std::vector<char*> pointers_;
+ std::vector<std::unique_ptr<char[]>> storage_;
+};
+
+using MaybeString = llvm::Optional<std::string>;
+
+MaybeString front(const string_list& deq) {
+ return !deq.empty() ? MaybeString(deq.front()) : MaybeString();
+}
+
+MaybeString pop_front(string_list& deq) { // NOLINT(*)
+ if (deq.empty()) return MaybeString();
+ std::string f = deq.front();
+ deq.pop_front();
+ return MaybeString(f);
+}
+
+llvm::Optional<int64_t> to_int(const MaybeString& str) {
+ auto none = llvm::Optional<int64_t>();
+ if (str.hasValue()) {
+ try {
+ size_t pos;
+ int64_t val = std::stoll(*str, &pos, 0);
+ return pos == str->size() ? llvm::Optional<int64_t>(val) : none;
+ } catch (std::invalid_argument) {
+ }
+ }
+ return none;
+}
+
+llvm::Optional<uint64_t> to_uint(const MaybeString& str) {
+ auto none = llvm::Optional<uint64_t>();
+ if (str.hasValue()) {
+ try {
+ size_t pos;
+ uint64_t val = std::stoull(*str, &pos, 0);
+ return pos == str->size() ? llvm::Optional<uint64_t>(val) : none;
+ } catch (std::invalid_argument) {
+ }
+ }
+ return none;
+}
+
+llvm::Optional<float> to_float(const MaybeString& str) {
+ auto none = llvm::Optional<float>();
+ if (str.hasValue()) {
+ try {
+ size_t pos;
+ float val = std::stof(*str, &pos);
+ return pos == str->size() ? llvm::Optional<float>(val) : none;
+ } catch (std::invalid_argument) {
+ }
+ }
+ return none;
+}
+
+llvm::Optional<bool> to_bool(const MaybeString& str) {
+ auto none = llvm::Optional<bool>();
+ if (auto num = to_int(str)) {
+ if (*num == 0) return false;
+ if (*num == 1) return true;
+ return none;
+ }
+ if (str) {
+ if (*str == "true" || *str == "TRUE") return true;
+ if (*str == "false" || *str == "FALSE") return false;
+ }
+ return none;
+}
+
+template <typename T>
+using MaybeRange = llvm::Optional<std::pair<T, T>>;
+
+template <typename T, llvm::Optional<T> Parse(const MaybeString&)>
+MaybeRange<T> to_range(const MaybeString& str) {
+ auto none = MaybeRange<T>();
+ if (str && !str->empty()) {
+ auto n = str->find('-', 1);
+ if (n != std::string::npos) {
+ auto begin = Parse(str->substr(0, n));
+ auto end = Parse(str->substr(n + 1, str->size() - n - 1));
+ if (begin && end) {
+ return std::make_pair(*begin, *end);
+ }
+ }
+ }
+ return none;
+}
+
+} // namespace detail
+
+class HexagonSimulator final : public tvm::runtime::hexagon::Device {
+ public:
+ explicit HexagonSimulator(bool enable_queuing);
+ ~HexagonSimulator() final {}
+ void* Alloc(unsigned size, unsigned align) final;
+ void Free(void* ptr) final;
+ void* AllocVtcm(unsigned size, unsigned align) final;
+ void FreeVtcm(void* ptr) final;
+ void CopyDeviceToDevice(void* dst, const void* src, unsigned len) final;
+ void CopyDeviceToHost(void* host_dst, const void* src, unsigned len) final;
+ void CopyHostToDevice(void* dst, const void* host_src, unsigned len) final;
+ void* Load(const std::string& data, const std::string& fmt) final;
+ void Unload(void* mod) final;
+ void* Resolve(const std::string& sym) final;
+ void Call(void* func, uint32_t* scalar, unsigned sc_num, uint32_t* stack,
+ unsigned st_num) final;
+
+ static std::string to_string(HEXAPI_Status status);
+
+ private:
+ static HEX_VA_t p2va(const void* p);
+ static void* va2p(HEX_VA_t va);
+
+ void CopyFromV(void* host_dst, HEX_VA_t src, unsigned len);
+ void CopyToV(HEX_VA_t dst, const void* host_src, unsigned len);
+
+ template <unsigned N>
+ void CopyNToV(HEX_VA_t dst, const void* host_src);
+ template <unsigned N>
+ void CopyNFromV(void* host_dst, HEX_VA_t src);
+
+ // NOLINTNEXTLINE(runtime/references)
+ void SendMsg(Message& m, const void* data, bool show_dbg);
+
+ std::string arch_;
+ std::unique_ptr<HexagonWrapper> sim_;
+ HEX_VA_t dispatch_v_, message_buffer_v_;
+ bool task_queuing_;
+
+ // Sim configuration routines.
+ bool Configure(string_list& opts); // NOLINT(*)
+
+ bool HandleAHBBusPenalty(string_list& rest); // NOLINT(*)
+ bool HandleAHBBusRatio(string_list& rest); // NOLINT(*)
+ bool HandleAHBHighAddr(string_list& rest); // NOLINT(*)
+ bool HandleAHBLowAddr(string_list& rest); // NOLINT(*)
+ bool HandleAXI2BusPenalty(string_list& rest); // NOLINT(*)
+ bool HandleAXI2BusRatio(string_list& rest); // NOLINT(*)
+ bool HandleAXI2HighAddr(string_list& rest); // NOLINT(*)
+ bool HandleAXI2LowAddr(string_list& rest); // NOLINT(*)
+ bool HandleBuildTag(string_list& rest); // NOLINT(*)
+ bool HandleBusPenalty(string_list& rest); // NOLINT(*)
+ bool HandleBusRatio(string_list& rest); // NOLINT(*)
+ bool HandleBusTrace(string_list& rest); // NOLINT(*)
+ bool HandleBypassIdle(string_list& rest); // NOLINT(*)
+ bool HandleConnectionTimeout(string_list& rest); // NOLINT(*)
+ bool HandleCoprocTrace(string_list& rest); // NOLINT(*)
+ bool HandleCoreDump(string_list& rest); // NOLINT(*)
+ bool HandleCosimFile(string_list& rest); // NOLINT(*)
+ bool HandleDCacheTrace(string_list& rest); // NOLINT(*)
+ bool HandleDSPClock(string_list& rest); // NOLINT(*)
+ bool HandleETMCFGBase(string_list& rest); // NOLINT(*)
+ bool HandleGDBServ(string_list& rest); // NOLINT(*)
+ bool HandleHVXLength(string_list& rest); // NOLINT(*)
+ bool HandleICacheTrace(string_list& rest); // NOLINT(*)
+ bool HandleL2CacheTrace(string_list& rest); // NOLINT(*)
+ bool HandleL2CFGBase(string_list& rest); // NOLINT(*)
+ bool HandleL2TCMBase(string_list& rest); // NOLINT(*)
+ bool HandleMemFillRand(string_list& rest); // NOLINT(*)
+ bool HandleMemFill(string_list& rest); // NOLINT(*)
+ bool HandleMemTrace(string_list& rest); // NOLINT(*)
+ bool HandleNullPtr(string_list& rest); // NOLINT(*)
+ bool HandlePacketAnalyze(string_list& rest); // NOLINT(*)
+ bool HandlePCFilter(string_list& rest); // NOLINT(*)
+ bool HandlePCTraceMin(string_list& rest); // NOLINT(*)
+ bool HandlePCTraceNano(string_list& rest); // NOLINT(*)
+ bool HandlePCTrace(string_list& rest); // NOLINT(*)
+ bool HandlePMUStatsFile(string_list& rest); // NOLINT(*)
+ bool HandleProfile(string_list& rest); // NOLINT(*)
+ bool HandleProfileTimeZero(string_list& rest); // NOLINT(*)
+ bool HandleQuiet(string_list& rest); // NOLINT(*)
+ bool HandleReconnect(string_list& rest); // NOLINT(*)
+ bool HandleRTOS(string_list& rest); // NOLINT(*)
+ bool HandleSimErr(string_list& rest); // NOLINT(*)
+ bool HandleSimIn(string_list& rest); // NOLINT(*)
+ bool HandleSimOut(string_list& rest); // NOLINT(*)
+ bool HandleStackStart(string_list& rest); // NOLINT(*)
+ bool HandleStallTrace(string_list& rest); // NOLINT(*)
+ bool HandleStatsFile(string_list& rest); // NOLINT(*)
+ bool HandleSubsystemBase(string_list& rest); // NOLINT(*)
+ bool HandleSymFile(string_list& rest); // NOLINT(*)
+ bool HandleTCM(string_list& rest); // NOLINT(*)
+ bool HandleTCMHighAddr(string_list& rest); // NOLINT(*)
+ bool HandleTCMLowAddr(string_list& rest); // NOLINT(*)
+ bool HandleTimeFilterNS(string_list& rest); // NOLINT(*)
+ bool HandleTiming(string_list& rest); // NOLINT(*)
+ bool HandleUArchTrace(string_list& rest); // NOLINT(*)
+ bool HandleUseFS(string_list& rest); // NOLINT(*)
+ bool HandleV2PTranslation(string_list& rest); // NOLINT(*)
+ bool HandleVerbose(string_list& rest); // NOLINT(*)
+
+ using MaybeUInt64 = llvm::Optional<uint64_t>;
+ using MaybeUIntRange = std::pair<MaybeUInt64, MaybeUInt64>;
+
+ bool should_parse_next(const string_list& rest);
+ llvm::Optional<HEXAPI_Interval> to_interval(const detail::MaybeString& str);
+ llvm::Optional<HEXAPI_TimingMode> to_timingmode(
+ const detail::MaybeString& str);
+ llvm::Optional<HEXAPI_VerboseMode> to_verbosemode(
+ const detail::MaybeString& str);
+ llvm::Optional<HEXAPI_Nullptr> to_nullptr(const detail::MaybeString& str);
+
+ MaybeUIntRange ahb_, axi2_;
+ llvm::Optional<uint32_t> debug_port_;
+ detail::non_const_str sim_dev_args_;
+
+ using OptionHandler = bool (HexagonSimulator::*)(string_list&);
+ static std::map<std::string, OptionHandler> opt_map_;
+};
+
+decltype(HexagonSimulator::opt_map_) HexagonSimulator::opt_map_ = {
+ {"--ahbbuspenalty", &HexagonSimulator::HandleAHBBusPenalty},
+ {"--ahbbusratio", &HexagonSimulator::HandleAHBBusRatio},
+ {"--ahb:highaddr", &HexagonSimulator::HandleAHBHighAddr},
+ {"--ahb:lowaddr", &HexagonSimulator::HandleAHBLowAddr},
+ {"--axi2buspenalty", &HexagonSimulator::HandleAXI2BusPenalty},
+ {"--axi2busratio", &HexagonSimulator::HandleAXI2BusRatio},
+ {"--axi2:highaddr", &HexagonSimulator::HandleAXI2HighAddr},
+ {"--axi2:lowaddr", &HexagonSimulator::HandleAXI2LowAddr},
+ {"-b", &HexagonSimulator::HandleBusTrace},
+ {"--build_tag", &HexagonSimulator::HandleBuildTag},
+ {"--buspenalty", &HexagonSimulator::HandleBusPenalty},
+ {"--busratio", &HexagonSimulator::HandleBusRatio},
+ {"--bustrace", &HexagonSimulator::HandleBusTrace},
+ {"--bypass_idle", &HexagonSimulator::HandleBypassIdle},
+ {"--connection_timeout", &HexagonSimulator::HandleConnectionTimeout},
+ {"--coproctrace", &HexagonSimulator::HandleCoprocTrace},
+ {"--coredump", &HexagonSimulator::HandleCoreDump},
+ {"--cosim_file", &HexagonSimulator::HandleCosimFile},
+ {"--dcachetrace", &HexagonSimulator::HandleDCacheTrace},
+ {"--dsp_clock", &HexagonSimulator::HandleDSPClock},
+ {"-E", &HexagonSimulator::HandleSimErr},
+ {"--etm_base", &HexagonSimulator::HandleETMCFGBase},
+ {"--etmcfg_base", &HexagonSimulator::HandleETMCFGBase},
+ {"--gdbserv", &HexagonSimulator::HandleGDBServ},
+ {"-G", &HexagonSimulator::HandleGDBServ},
+ {"--hvx_length", &HexagonSimulator::HandleHVXLength},
+ {"--icachetrace", &HexagonSimulator::HandleICacheTrace},
+ {"-I", &HexagonSimulator::HandleSimIn},
+ {"--l2cachetrace", &HexagonSimulator::HandleL2CacheTrace},
+ {"--l2cfg_base", &HexagonSimulator::HandleL2CFGBase},
+ {"--l2tcm_base", &HexagonSimulator::HandleL2TCMBase},
+ {"--memfill", &HexagonSimulator::HandleMemFill},
+ {"--memfill_rand", &HexagonSimulator::HandleMemFillRand},
+ {"--memtrace", &HexagonSimulator::HandleMemTrace},
+ {"-m", &HexagonSimulator::HandleMemTrace},
+ {"--nullptr", &HexagonSimulator::HandleNullPtr},
+ {"-O", &HexagonSimulator::HandleSimOut},
+ {"--packet_analyze", &HexagonSimulator::HandlePacketAnalyze},
+ {"--pcfilter", &HexagonSimulator::HandlePCFilter},
+ {"--pctrace", &HexagonSimulator::HandlePCTrace},
+ {"--pctrace_min", &HexagonSimulator::HandlePCTraceMin},
+ {"--pctrace_nano", &HexagonSimulator::HandlePCTraceNano},
+ {"-p", &HexagonSimulator::HandleProfile},
+ {"--pmu_statsfile", &HexagonSimulator::HandlePMUStatsFile},
+ {"--profile", &HexagonSimulator::HandleProfile},
+ {"--profile_timezero", &HexagonSimulator::HandleProfileTimeZero},
+ {"-q", &HexagonSimulator::HandleQuiet},
+ {"--quiet", &HexagonSimulator::HandleQuiet},
+ {"--reconnect", &HexagonSimulator::HandleReconnect},
+ {"--rtos", &HexagonSimulator::HandleRTOS},
+ {"-S", &HexagonSimulator::HandleStatsFile},
+ {"--sim_err", &HexagonSimulator::HandleSimErr},
+ {"--sim_in", &HexagonSimulator::HandleSimIn},
+ {"--sim_out", &HexagonSimulator::HandleSimOut},
+ {"--stackstart", &HexagonSimulator::HandleStackStart},
+ {"--stalltrace", &HexagonSimulator::HandleStallTrace},
+ {"--statsfile", &HexagonSimulator::HandleStatsFile},
+ {"--subsystem_base", &HexagonSimulator::HandleSubsystemBase},
+ {"--symfile", &HexagonSimulator::HandleSymFile},
+ {"--tcm", &HexagonSimulator::HandleTCM},
+ {"--tcm:highaddr", &HexagonSimulator::HandleTCMHighAddr},
+ {"--tcm:lowaddr", &HexagonSimulator::HandleTCMLowAddr},
+ {"-t", &HexagonSimulator::HandlePCTrace},
+ {"--timefilter_ns", &HexagonSimulator::HandleTimeFilterNS},
+ {"--timing", &HexagonSimulator::HandleTiming},
+ {"--uarchtrace", &HexagonSimulator::HandleUArchTrace},
+ {"-u", &HexagonSimulator::HandlePCTraceMin},
+ {"--usefs", &HexagonSimulator::HandleUseFS},
+ {"--v2p_translation", &HexagonSimulator::HandleV2PTranslation},
+ {"--verbose", &HexagonSimulator::HandleVerbose},
+};
+
+#define CHECKED_CALL(func, ...) \
+ do { \
+ HEXAPI_Status s = sim_->func(__VA_ARGS__); \
+ CHECK_EQ(s, HEX_STAT_SUCCESS) \
+ << "HexagonSimulator: " #func " failed with code " \
+ << HexagonSimulator::to_string(s); \
+ } while (false)
+
+inline HEX_VA_t HexagonSimulator::p2va(const void* p) {
+ uintptr_t u = reinterpret_cast<uintptr_t>(p);
+ HEX_VA_t va = static_cast<HEX_VA_t>(u);
+ CHECK_EQ(static_cast<uintptr_t>(va), u);
+ return va;
+}
+
+inline void* HexagonSimulator::va2p(HEX_VA_t va) {
+ return reinterpret_cast<void*>(static_cast<uintptr_t>(va));
+}
+
+template <unsigned N, unsigned A>
+constexpr bool is_multiple_of() {
+ return (N / A) * A == N;
+}
+
+std::shared_ptr<Device> CreateHexagonSimulator() {
+ return std::make_shared<HexagonSimulator>(/*enable_queuing=*/true);
+}
+
+template <unsigned N>
+void HexagonSimulator::CopyNToV(HEX_VA_t dst, const void* host_src) {
+ using src_uint_t = typename unalign<typename uint<N>::type>::type;
+ auto* ps = reinterpret_cast<const src_uint_t*>(host_src);
+ CHECK_EQ(sim_->WriteVirtual(dst, -1u, N, ps->value), HEX_STAT_SUCCESS);
+}
+
+template <unsigned N>
+void HexagonSimulator::CopyNFromV(void* host_dst, HEX_VA_t src) {
+ typename uint<N>::type v;
+ CHECK_EQ(sim_->ReadVirtual(src, -1u, N, &v), HEX_STAT_SUCCESS);
+
+ using dst_uint_t = typename unalign<typename uint<N>::type>::type;
+ auto* pd = reinterpret_cast<dst_uint_t*>(host_dst);
+ pd->value = v;
+}
+
+void HexagonSimulator::CopyToV(HEX_VA_t dst, const void* host_src,
+ unsigned len) {
+ const uint8_t* src = static_cast<const uint8_t*>(host_src);
+
+ while (len >= 8) {
+ CopyNToV<8>(dst, src);
+ dst += 8;
+ src += 8;
+ len -= 8;
+ }
+ if (len >= 4) {
+ CopyNToV<4>(dst, src);
+ dst += 4;
+ src += 4;
+ len -= 4;
+ }
+ if (len >= 2) {
+ CopyNToV<2>(dst, src);
+ dst += 2;
+ src += 2;
+ len -= 2;
+ }
+ if (len >= 1) {
+ CopyNToV<1>(dst, src);
+ dst++;
+ src++;
+ len--;
+ }
+ CHECK_EQ(len, 0);
+}
+
+void HexagonSimulator::CopyFromV(void* host_dst, HEX_VA_t src, unsigned len) {
+ uint8_t* dst = static_cast<uint8_t*>(host_dst);
+
+ while (len >= 8) {
+ CopyNFromV<8>(dst, src);
+ dst += 8;
+ src += 8;
+ len -= 8;
+ }
+ if (len >= 4) {
+ CopyNFromV<4>(dst, src);
+ dst += 4;
+ src += 4;
+ len -= 4;
+ }
+ if (len >= 2) {
+ CopyNFromV<2>(dst, src);
+ dst += 2;
+ src += 2;
+ len -= 2;
+ }
+ if (len >= 1) {
+ CopyNFromV<1>(dst, src);
+ dst++;
+ src++;
+ len--;
+ }
+ CHECK_EQ(len, 0);
+}
+
+void HexagonSimulator::SendMsg(Message& m, const void* data, bool show_dbg) {
+ auto run = [this](bool report_cycles) {
+ HEXAPI_CoreState core = HEX_CORE_RESET;
+ HEX_4u_t result;
+ HEX_8u_t cycles0, cycles1;
+ if (report_cycles) {
+ CHECK_EQ(sim_->GetSimulatedCycleCount(&cycles0), HEX_STAT_SUCCESS);
+ }
+
+ core = sim_->Run(&result);
+ CHECK_EQ(core, HEX_CORE_BREAKPOINT);
+ if (report_cycles) {
+ CHECK_EQ(sim_->GetSimulatedCycleCount(&cycles1), HEX_STAT_SUCCESS);
+ LOG(INFO) << "host: execution took " << (cycles1 - cycles0) << " cycles";
+ }
+ };
+
+ // Send the message request.
+ Message r = {kMsgReq, m.len, 0u};
+ CopyToV(message_buffer_v_, &r, sizeof(r));
+ run(false);
+
+ // Receive the acknowledgement with the address for the payload.
+ CopyFromV(&r, message_buffer_v_, sizeof(r));
+ CHECK_EQ(r.code, kMsgAck);
+ CHECK_GE(r.len, m.len);
+
+ // Send the actual message.
+ m.va = r.va;
+ CopyToV(message_buffer_v_, &m, sizeof(m));
+ if (m.len > 0) CopyToV(r.va, data, m.len);
+ run(show_dbg);
+
+ // Receive the return data.
+ CopyFromV(&m, message_buffer_v_, sizeof(m));
+ CHECK_EQ(m.code, kNone);
+}
+
+HexagonSimulator::HexagonSimulator(bool enable_queuing) {
+ task_queuing_ = enable_queuing;
+
+ // The simulator argument string is in the form:
+ // <cpu_ver> <optional_arguments>
+ // The optional arguments are seperated with spaces:
+ // Ex: --hvx_length 128 --memfill 0 --timing -m output.txt
+ const char* sim_args_env = std::getenv("HEXAGON_SIM_ARGS");
+ if (sim_args_env == nullptr) sim_args_env = "";
+ auto sim_args_iss = std::istringstream(std::string(sim_args_env));
+ using iterator = std::istream_iterator<std::string>;
+ auto sim_args = string_list(iterator(sim_args_iss), iterator());
+
+ std::string target_str =
+ !sim_args.empty() ? *detail::pop_front(sim_args) : std::string("v66");
+
+ arch_ = target_str;
+ sim_ =
+ detail::make_unique<HexagonWrapper>(detail::non_const_str(target_str));
+ LOG(INFO) << "HexagonSimulator: Core version: " << arch_;
+
+ // Locate the sim_dev binary in PATH, or in the current working directory.
+ llvm::StringRef sim_dev = "sim_dev";
+ detail::MaybeString path_sim_dev =
+ llvm::sys::Process::FindInEnvPath("PATH", sim_dev);
+ if (!path_sim_dev) {
+ if (!llvm::sys::fs::exists(sim_dev)) {
+ LOG(FATAL) << "Cannot find sim_dev in PATH.";
+ }
+ path_sim_dev = sim_dev.str();
+ }
+
+ CHECKED_CALL(ConfigureExecutableBinary, path_sim_dev->c_str());
+
+ std::vector<std::string> app_args = {*path_sim_dev};
+ if (char* ev = getenv("ADSP_LIBRARY_PATH")) {
+ app_args.push_back("-L");
+ app_args.push_back(ev);
+ }
+ sim_dev_args_ = detail::non_const_str(app_args);
+ CHECKED_CALL(ConfigureAppCommandLine, sim_dev_args_.size(), sim_dev_args_);
+
+ LOG(INFO) << "HexagonSimulator: ConfigureHVXLength: 128";
+ CHECKED_CALL(ConfigureHVXLength, 128);
Review comment:
This was actually only setting the default HVX length. If `--hvx_length` was specified in `sim_args, it would be processed in `Configure` below, resetting the HVX length to the new value.
I changed the processing of `sim_args` to always add `--hvx_length` that matches `hvx` (it already printed a warning if both were given and didn't match). Now, configuring the default HVX length here is not needed, so I removed it.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] FrozenGene commented on issue #5252: [RUNTIME]
Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
FrozenGene commented on issue #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#issuecomment-610163091
Could you provide the `.idl` file too? Because you have provided `tvm_hexagon_remote.h`, if we don't have `.idl` we can not generate .cc / .h for hexagon. I think it is core part of Hexagon runtime support too.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] kparzysz-quic commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
kparzysz-quic commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r404814243
##########
File path: src/runtime/hexagon/target/hexagon_device_target.cc
##########
@@ -0,0 +1,525 @@
+/*
+ * 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.
+ */
+
+#ifdef __ANDROID__
+
+#include <unistd.h>
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "../hexagon_module.h"
+#include "AEEStdErr.h"
+#include "fastrpc/tvm_hexagon_remote.h"
+#include "hexagon_dsprpcapi.h"
+#include "hexagon_stubapi.h"
+#include "hexagon_target_log.h"
+#include "remote64.h"
+#include "rpcmem.h"
+
+#pragma weak remote_session_control
+
+#define RPCMEM_HEAP 25
+
+// All log messages start with "HexagonTarget::%s", where %s is replaced
+// with the function name, so create macros that add that to avoid repetition.
+// The downside is that the format string must be given as a string literal,
+// but it seems to be a minor issue.
+#define VA_EXPANDER(...) , ##__VA_ARGS__
+#define TVM_LOGD_HT(fmt, ...) \
+ TVM_LOGD("HexagonTarget::%s: " fmt, __func__ VA_EXPANDER(__VA_ARGS__))
+#define TVM_LOGE_HT(fmt, ...) \
+ TVM_LOGE("HexagonTarget::%s: " fmt, __func__ VA_EXPANDER(__VA_ARGS__))
+
+namespace tvm {
+namespace runtime {
+namespace hexagon {
+
+static constexpr int kStackSize = 128 * 1024; // 128kB stack
+
+class HexagonTarget : public tvm::runtime::hexagon::Device {
+ public:
+ HexagonTarget() {}
+ ~HexagonTarget() final {}
+ void* Alloc(unsigned size, unsigned align) final;
+ void Free(void* ptr) final;
+ void* AllocVtcm(unsigned size, unsigned align) final;
+ void FreeVtcm(void* ptr) final;
+ void CopyDeviceToDevice(void* dst, const void* src, unsigned len) final;
+ void CopyDeviceToHost(void* host_dst, const void* src, unsigned len) final;
+ void CopyHostToDevice(void* dst, const void* host_src, unsigned len) final;
+ void* Load(const std::string& data, const std::string& fmt) final;
+ void Unload(void* mod) final;
+ void* Resolve(const std::string& sym) final;
+ void Call(void* func, uint32_t* scalar, unsigned scalar_num, uint32_t* stack,
+ unsigned stack_num) final;
+
+ private:
+ std::pair<void*, size_t> AddAddrMapping(const void* dsp_addr,
+ void* apps_addr, size_t size);
+ std::pair<void*, size_t> GetAppsAddr(const void* dsp_addr, bool exact) const;
+ void RemoveAddrMapping(const void* dsp_addr);
+ int OpenDomainChannel(bool set_unsigned_pd);
+ int CloseDomainChannel();
+ void ReleaseLibrary();
+ void FreeMemoryBeforeChannelClose();
+
+ // Mapping from a DSP address to a pair <apps address, buffer size>.
+ // Using void* pointers is ok, since DSP pointers will always fit
+ // in apps's pointers, i.e. sizeof_dsp(void*) <= sizeof_apps(void*).
+ std::map<const void*, std::pair<void*, size_t>> dsp_to_apps_;
+ std::map<const void*, std::pair<void*, size_t>> vtcm_addr_;
+ remote_handle64 domain_channel_handle_ = AEE_EUNKNOWN;
+ tvm_hexagon_remote_handle_t module_pointer_ = AEE_EUNKNOWN;
+ uint64_t count_channel_open_ = 0;
+ // Global lock, used for all critical sections. This can be refined
+ // in the future.
+ mutable std::mutex crit_section_;
+};
+
+std::shared_ptr<Device> CreateHexagonTarget() {
+ return std::make_shared<HexagonTarget>();
+}
+
+std::pair<void*, size_t> HexagonTarget::AddAddrMapping(const void* dsp_addr,
+ void* apps_addr,
+ size_t size) {
+ crit_section_.lock();
+ auto p = dsp_to_apps_.insert({dsp_addr, {apps_addr, size}});
+ crit_section_.unlock();
+ if (!p.second) {
+ TVM_LOGE_HT(
+ "failed to insert address mapping: dsp:%p -> apps:%p, size:%zu",
+ dsp_addr, apps_addr, size);
+ return std::make_pair(nullptr, 0);
+ }
+ TVM_LOGD_HT("added address mapping: dsp:%p -> apps:%p, size:%zu", dsp_addr,
+ apps_addr, size);
+ return p.first->second;
+}
+
+void HexagonTarget::RemoveAddrMapping(const void* dsp_addr) {
+ crit_section_.lock();
+ auto f = dsp_to_apps_.find(dsp_addr);
+ if (f == dsp_to_apps_.end()) {
+ TVM_LOGE_HT("failed to remove address mapping for dsp:%p", dsp_addr);
+ crit_section_.unlock();
+ return;
+ }
+ dsp_to_apps_.erase(f);
+ crit_section_.unlock();
+}
+
+std::pair<void*, size_t> HexagonTarget::GetAppsAddr(const void* dsp_addr,
+ bool exact) const {
+ struct AutoUnlock {
+ explicit AutoUnlock(std::mutex& m) : m(m) {}
+ ~AutoUnlock() { m.unlock(); }
+ std::mutex& m;
+ };
+
+ crit_section_.lock();
+ AutoUnlock u(crit_section_);
+
+ // If the address is in the map, simply return the result.
+ auto f = dsp_to_apps_.find(dsp_addr);
+ if (f != dsp_to_apps_.end()) return f->second;
+ // If exact mapping is requested, then it hasn't been found.
+ if (exact) return std::make_pair(nullptr, 0);
+
+ // If the address is not in the map, maybe it points to somewhere in the
+ // interior of a mapped buffer.
+ uintptr_t dsp_v = reinterpret_cast<uintptr_t>(dsp_addr);
+ for (const auto& v : dsp_to_apps_) {
+ uintptr_t dsp_k = reinterpret_cast<uintptr_t>(v.first);
+ size_t size = v.second.second;
+ if (dsp_v >= dsp_k && dsp_v < dsp_k + size) {
+ uintptr_t apps_k = reinterpret_cast<uintptr_t>(v.second.first);
+ size_t offset = dsp_v - dsp_k;
+ uintptr_t apps_v = apps_k + offset;
+ return std::make_pair(reinterpret_cast<void*>(apps_v), size - offset);
+ }
+ }
+ TVM_LOGE_HT("failed to locate apps address for dsp:%p", dsp_addr);
+ return std::make_pair(nullptr, 0);
+}
+
+int HexagonTarget::OpenDomainChannel(bool use_unsigned_pd) {
+ if (domain_channel_handle_ != AEE_EUNKNOWN) return AEE_SUCCESS;
+
+ const DspRpcAPI* dsp_api = DspRpcAPI::Global();
+ const StubAPI* stub_api = StubAPI::Global();
+
+ stub_api->rpcmem_init_ptr()();
+
+ if (auto* rsc_ptr = dsp_api->remote_session_control_ptr(true)) {
+ remote_rpc_thread_params th_data;
+ th_data.domain = CDSP_DOMAIN_ID;
+ th_data.stack_size = kStackSize;
+ th_data.prio = -1; // Default priority.
+ int rc = rsc_ptr(FASTRPC_THREAD_PARAMS, &th_data, sizeof(th_data));
+ if (rc != AEE_SUCCESS) {
+ TVM_LOGE_HT("remote_session_control failed rc=%08x for stack size", rc);
+ }
+ if (use_unsigned_pd) {
+ remote_rpc_control_unsigned_module data;
+ data.enable = 1;
+ data.domain = CDSP_DOMAIN_ID;
+ int rc = rsc_ptr(DSPRPC_CONTROL_UNSIGNED_MODULE, &data, sizeof(data));
+ if (rc != AEE_SUCCESS) {
+ TVM_LOGE_HT("remote_session_control failed rc=%08x for unsigned PD",
+ rc);
+ }
+ }
+ } else {
+ TVM_LOGD_HT("remote_session_control not available");
+ }
+
+ int rc = stub_api->tvm_hexagon_remote_open(
+ tvm_hexagon_remote_URI "&_dom=cdsp", &domain_channel_handle_);
+ if (rc != AEE_SUCCESS) {
+ TVM_LOGE_HT("failed to open channel rc=0x%x", rc);
+ } else {
+ count_channel_open_++;
+ TVM_LOGD_HT("channel open success and rpcmem_init done");
+ }
+ return rc;
+}
+
+int HexagonTarget::CloseDomainChannel() {
+ if (domain_channel_handle_ == AEE_EUNKNOWN) return AEE_SUCCESS;
+
+ const StubAPI* stub_api = StubAPI::Global();
+
+ int rc = stub_api->tvm_hexagon_remote_close(domain_channel_handle_);
+ if (rc == AEE_SUCCESS) {
+ domain_channel_handle_ = AEE_EUNKNOWN;
+ stub_api->rpcmem_deinit_ptr()();
+ TVM_LOGD_HT("channel close success and rpcmem_deinit done");
+ } else {
+ TVM_LOGE_HT("failed to close domain channel rc=0x%x", rc);
+ }
+ return rc;
+}
+
+void HexagonTarget::ReleaseLibrary() {
+ crit_section_.lock();
+ if (module_pointer_ != AEE_EUNKNOWN) {
+ const StubAPI* stub_api = StubAPI::Global();
+ int rc = stub_api->tvm_hexagon_remote_release_library(
+ domain_channel_handle_, module_pointer_);
+ if (rc != AEE_SUCCESS) {
+ TVM_LOGE_HT("failed to unload device library rc=0x%x", rc);
+ } else {
+ module_pointer_ = AEE_EUNKNOWN;
+ }
+ }
+ crit_section_.unlock();
+}
+
+void HexagonTarget::FreeMemoryBeforeChannelClose() {
+ while (!dsp_to_apps_.empty()) {
+ void* dsp_addr = const_cast<void*>((dsp_to_apps_.begin()->first));
+ TVM_LOGD_HT("Freeing up dsp_addr %p", dsp_addr);
+ HexagonTarget::Free(dsp_addr);
+ }
+}
+void* HexagonTarget::Alloc(unsigned size, unsigned align) {
+ const DspRpcAPI* dsp_api = DspRpcAPI::Global();
+ const StubAPI* stub_api = StubAPI::Global();
+
+ // Opening the domain channel should be done once.
+ crit_section_.lock();
+ int rc_oc = OpenDomainChannel(/*use_unsigned_pd*/ true);
+ crit_section_.unlock();
+ if (rc_oc != AEE_SUCCESS) {
+ TVM_LOGE_HT("mem alloc failed: unable to open domain channel");
+ return nullptr;
+ }
+
+ // This is a workaround. If HexagonTarget::Alloc is called from a different
+ // thread then remote_mmap64 fails. FastRPC expects one call to be made to
+ // DSP before calling remote_map64. Hence this call is needed for now untill
+ // FastRPC comes up with a fix.
+ int rc_call_mmap_64 =
+ stub_api->tvm_hexagon_remote_call_mmap64(domain_channel_handle_);
+ if (rc_call_mmap_64 != AEE_SUCCESS) {
+ TVM_LOGE_HT("mmap64 failed for domain channel %lu", domain_channel_handle_);
+ return nullptr;
+ }
+
+ void* mem =
+ stub_api->rpcmem_alloc_ptr()(RPCMEM_HEAP, RPCMEM_DEFAULT_FLAGS, size);
+ if (mem == nullptr) {
+ TVM_LOGE_HT("mem alloc failed for size=0x%x alignment=0x%x", size, align);
+ return nullptr;
+ }
+ int mem_fd = stub_api->rpcmem_to_fd_ptr()(mem);
+ uintptr_t dsp_va = 0;
+ int rc = dsp_api->remote_mmap64_ptr()(
+ mem_fd, 0, reinterpret_cast<uintptr_t>(mem), size, &dsp_va);
+ if (rc != AEE_SUCCESS) {
+ TVM_LOGE_HT(
+ "buffer mapping failed for remote_map64 fd=0x%x rc=0x%x "
+ "apps_addr=0x%lx",
+ mem_fd, rc, reinterpret_cast<uintptr_t>(mem));
+ return nullptr;
+ }
+
+ void* dsp_addr = reinterpret_cast<void*>(dsp_va);
+ AddAddrMapping(dsp_addr, mem, size);
+ return dsp_addr;
+}
+
+void HexagonTarget::Free(void* ptr) {
+ const DspRpcAPI* dsp_api = DspRpcAPI::Global();
+ const StubAPI* stub_api = StubAPI::Global();
+ auto bb = GetAppsAddr(ptr, true);
+ if (bb.first == reinterpret_cast<void*>(~0)) {
+ TVM_LOGD_HT("VTCM mapping found. dsp_addr=0x%p", ptr);
+ RemoveAddrMapping(ptr);
+ FreeVtcm(ptr);
+ return;
+ }
+
+ TVM_LOGD_HT("VTCM mapping not found. dsp_addr=0x%p", ptr);
+ auto aa = GetAppsAddr(ptr, true);
+ if (aa.first == nullptr) return;
+
+ int rc = dsp_api->remote_munmap64_ptr()(reinterpret_cast<uintptr_t>(ptr),
+ aa.second);
+ if (rc != AEE_SUCCESS) {
+ TVM_LOGE_HT("buffer unmapping failed rc=0x%x", rc);
+ }
+ RemoveAddrMapping(ptr);
+ stub_api->rpcmem_free_ptr()(aa.first);
+}
+
+void* HexagonTarget::AllocVtcm(unsigned size, unsigned align) {
+ const StubAPI* stub_api = StubAPI::Global();
+
+ unsigned int dsp_va = 0;
+ int rc = stub_api->tvm_hexagon_remote_alloc_vtcm(domain_channel_handle_,
+ size, align, &dsp_va);
+ if (rc != AEE_SUCCESS) {
+ TVM_LOGE_HT("VTCM allocation failed size=%u, align=%u", size, align);
+ return nullptr;
+ }
+ void* dsp_addr = reinterpret_cast<void*>(dsp_va);
+ TVM_LOGD_HT("Done vtcm alloc dsp:%p", dsp_addr);
+ AddAddrMapping(dsp_addr, reinterpret_cast<void*>(~0), size);
+ return dsp_addr;
+}
+
+void HexagonTarget::FreeVtcm(void* ptr) {
+ const StubAPI* stub_api = StubAPI::Global();
+
+ TVM_LOGD_HT("%s:Calling vtcm free. ptr=%p", __func__, ptr);
+ uintptr_t dsp_va = reinterpret_cast<uintptr_t>(ptr);
+ int rc =
+ stub_api->tvm_hexagon_remote_free_vtcm(domain_channel_handle_, dsp_va);
+ if (rc != AEE_SUCCESS) {
+ TVM_LOGE_HT("VTCM deallocation failed");
+ }
+ TVM_LOGD_HT("Done VTCM free from HexagonTarget::FreeVtcm");
+}
+
+void HexagonTarget::CopyDeviceToDevice(void* dst, const void* src,
Review comment:
Done.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] tmoreau89 commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
tmoreau89 commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r404289091
##########
File path: src/runtime/hexagon/README.md
##########
@@ -0,0 +1,76 @@
+<!--- 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. -->
+
+# Hexagon backend runtime
+
+The Hexagon runtime is a part of the TVM runtime that facilitates communication between a host and a Hexagon device. There are two types of host/device arrangements that are supported:
+- X86/Linux host running Hexagon simulator,
+- Android/AArch64 host running on a physical device containing a Hexagon module (i.e. CSDP or ADSP).
+
+The TVM runtime that contains Hexagon runtime is the one executing on host. In either case, there will need to be a separate TVM runtime (i.e. the `libtvm_runtime.so` library) compiled for execution on Hexagon.
+
+The prerequisite is to have Hexagon SDK installed, preferably version 3.5.0.
Review comment:
Could you add a link to installing the Hexagon SDK?
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] tmoreau89 commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
tmoreau89 commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r404326477
##########
File path: src/runtime/hexagon/README.md
##########
@@ -0,0 +1,76 @@
+<!--- 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. -->
+
+# Hexagon backend runtime
+
+The Hexagon runtime is a part of the TVM runtime that facilitates communication between a host and a Hexagon device. There are two types of host/device arrangements that are supported:
+- X86/Linux host running Hexagon simulator,
+- Android/AArch64 host running on a physical device containing a Hexagon module (i.e. CSDP or ADSP).
+
+The TVM runtime that contains Hexagon runtime is the one executing on host. In either case, there will need to be a separate TVM runtime (i.e. the `libtvm_runtime.so` library) compiled for execution on Hexagon.
+
+The prerequisite is to have Hexagon SDK installed, preferably version 3.5.0.
Review comment:
SGTM
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] kparzysz-quic commented on issue #5252: [RUNTIME]
Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
kparzysz-quic commented on issue #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#issuecomment-610391857
The IDL file and the implementation of the Hexagon-side target code will be upstreamed in an upcoming PR.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] kparzysz-quic commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
kparzysz-quic commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r405542401
##########
File path: src/runtime/hexagon/README.md
##########
@@ -0,0 +1,76 @@
+<!--- 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. -->
+
+# Hexagon backend runtime
+
+The Hexagon runtime is a part of the TVM runtime that facilitates communication between a host and a Hexagon device. There are two types of host/device arrangements that are supported:
+- X86/Linux host running Hexagon simulator,
+- Android/AArch64 host running on a physical device containing a Hexagon module (i.e. CSDP or ADSP).
+
+The TVM runtime that contains Hexagon runtime is the one executing on host. In either case, there will need to be a separate TVM runtime (i.e. the `libtvm_runtime.so` library) compiled for execution on Hexagon.
+
+The prerequisite is to have Hexagon SDK installed, preferably version 3.5.0 or later. The Hexagon SDK can be downloaded from https://developer.qualcomm.com/software/hexagon-dsp-sdk.
+
+### Compiling TVM runtime for x86
+
+This will use Hexagon simulator, which is provided in the Hexagon SDK.
+
+When configuring TVM (cmake), set the following variables:
+```
+USE_LLVM=llvm-config
+USE_HEXAGON_DEVICE=sim
+USE_HEXAGON_SDK=/path/to/sdk
+```
+
+Set the C/C++ compiler to `clang`, and pass `-DCMAKE_CXX_FLAGS='-stdlib=libc++'` to the cmake command.
Review comment:
When we started, I was seeing some problems with libstdc++, but I don't remember what they were anymore. Since it worked for you, I removed this line.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] kparzysz-quic commented on issue #5252: [RUNTIME]
Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
kparzysz-quic commented on issue #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#issuecomment-612002926
@FrozenGene If you're happy with the code, could you approve? Your review is still showing as "requested changes".
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] kparzysz-quic commented on issue #5252: [RUNTIME]
Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
kparzysz-quic commented on issue #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#issuecomment-611564175
Example of two other PRs that fail in the same place:
https://ci.tvm.ai/blue/organizations/jenkins/tvm/detail/PR-5272/8/pipeline/152
https://ci.tvm.ai/blue/organizations/jenkins/tvm/detail/PR-5276/6/pipeline/152
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] tmoreau89 commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
tmoreau89 commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r404289700
##########
File path: include/tvm/runtime/device_api.h
##########
@@ -47,10 +47,10 @@ enum DeviceAttrKind : int {
};
/*! \brief Number of bytes each allocation must align to */
-constexpr int kAllocAlignment = 64;
+constexpr int kAllocAlignment = 128;
Review comment:
Could there be any issues with increasing the alignment block across all devices @tqchen
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
[GitHub] [incubator-tvm] FrozenGene commented on a change in pull request
#5252: [RUNTIME] Initial implementation of Hexagon runtime support
Posted by GitBox <gi...@apache.org>.
FrozenGene commented on a change in pull request #5252: [RUNTIME] Initial implementation of Hexagon runtime support
URL: https://github.com/apache/incubator-tvm/pull/5252#discussion_r405407835
##########
File path: src/runtime/hexagon/sim/hexagon_device_sim.cc
##########
@@ -0,0 +1,1419 @@
+/*
+ * 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.
+ */
+
+#include <dmlc/logging.h>
+#include <llvm/ADT/Optional.h>
+#include <llvm/ADT/STLExtras.h>
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Support/FileSystem.h>
+#include <llvm/Support/Process.h>
+
+#include <algorithm>
+#include <deque>
+#include <iomanip>
+#include <locale>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "../hexagon_module.h"
+#include "HexagonWrapper.h"
+#include "hexagon_sim_proto.h"
+
+namespace tvm {
+namespace runtime {
+namespace hexagon {
+
+static_assert(sizeof(HEX_VA_t) == sizeof(uint32_t),
+ "Hexagon VA must be uint32");
+
+template <typename T>
+struct unalign {
+ using type = struct { T value; } __attribute__((aligned(1), packed));
+};
+
+template <unsigned N>
+struct uint {
+ using type = void;
+};
+
+template <>
+struct uint<8> {
+ using type = uint64_t;
+};
+template <>
+struct uint<4> {
+ using type = uint32_t;
+};
+template <>
+struct uint<2> {
+ using type = uint16_t;
+};
+template <>
+struct uint<1> {
+ using type = uint8_t;
+};
+
+using string_list = std::deque<std::string>;
+
+namespace detail {
+
+template <typename T, typename... Args>
+std::unique_ptr<T> make_unique(Args... args) {
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+template <typename T>
+std::unique_ptr<T> make_unique(size_t size) {
+ using U = typename std::remove_extent<T>::type;
+ return std::unique_ptr<T>(new U[size]());
+}
+
+// Converter class to translate vector<string> to char**. This relieves the
+// user from memory reallocation and copying.
+struct non_const_str {
+ non_const_str() {}
+ explicit non_const_str(const std::string& str)
+ : non_const_str(std::vector<std::string>{str}) {}
+ explicit non_const_str(const std::vector<std::string>& vec) {
+ for (const std::string& s : vec) {
+ auto c = detail::make_unique<char[]>(s.size() + 1);
+ std::strncpy(c.get(), s.c_str(), s.size() + 1);
+ storage_.push_back(std::move(c));
+ pointers_.push_back(storage_.back().get());
+ }
+ }
+ non_const_str(non_const_str&& ncs) { *this = std::move(ncs); }
+ non_const_str& operator=(non_const_str&& ncs) {
+ if (this != &ncs) {
+ for (auto& s : ncs.storage_) storage_.push_back(std::move(s));
+ for (auto& s : storage_) pointers_.push_back(s.get());
+ }
+ return *this;
+ }
+ size_t size() const { return pointers_.size(); }
+ operator char*() {
+ CHECK_EQ(pointers_.size(), 1);
+ return pointers_[0];
+ }
+ operator char* *() { return pointers_.data(); }
+
+ private:
+ std::vector<char*> pointers_;
+ std::vector<std::unique_ptr<char[]>> storage_;
+};
+
+using MaybeString = llvm::Optional<std::string>;
+
+MaybeString front(const string_list& deq) {
+ return !deq.empty() ? MaybeString(deq.front()) : MaybeString();
+}
+
+MaybeString pop_front(string_list& deq) { // NOLINT(*)
+ if (deq.empty()) return MaybeString();
+ std::string f = deq.front();
+ deq.pop_front();
+ return MaybeString(f);
+}
+
+llvm::Optional<int64_t> to_int(const MaybeString& str) {
+ auto none = llvm::Optional<int64_t>();
+ if (str.hasValue()) {
+ try {
+ size_t pos;
+ int64_t val = std::stoll(*str, &pos, 0);
+ return pos == str->size() ? llvm::Optional<int64_t>(val) : none;
+ } catch (std::invalid_argument) {
+ }
+ }
+ return none;
+}
+
+llvm::Optional<uint64_t> to_uint(const MaybeString& str) {
+ auto none = llvm::Optional<uint64_t>();
+ if (str.hasValue()) {
+ try {
+ size_t pos;
+ uint64_t val = std::stoull(*str, &pos, 0);
+ return pos == str->size() ? llvm::Optional<uint64_t>(val) : none;
+ } catch (std::invalid_argument) {
+ }
+ }
+ return none;
+}
+
+llvm::Optional<float> to_float(const MaybeString& str) {
+ auto none = llvm::Optional<float>();
+ if (str.hasValue()) {
+ try {
+ size_t pos;
+ float val = std::stof(*str, &pos);
+ return pos == str->size() ? llvm::Optional<float>(val) : none;
+ } catch (std::invalid_argument) {
+ }
+ }
+ return none;
+}
+
+llvm::Optional<bool> to_bool(const MaybeString& str) {
+ auto none = llvm::Optional<bool>();
+ if (auto num = to_int(str)) {
+ if (*num == 0) return false;
+ if (*num == 1) return true;
+ return none;
+ }
+ if (str) {
+ if (*str == "true" || *str == "TRUE") return true;
+ if (*str == "false" || *str == "FALSE") return false;
+ }
+ return none;
+}
+
+template <typename T>
+using MaybeRange = llvm::Optional<std::pair<T, T>>;
+
+template <typename T, llvm::Optional<T> Parse(const MaybeString&)>
+MaybeRange<T> to_range(const MaybeString& str) {
+ auto none = MaybeRange<T>();
+ if (str && !str->empty()) {
+ auto n = str->find('-', 1);
+ if (n != std::string::npos) {
+ auto begin = Parse(str->substr(0, n));
+ auto end = Parse(str->substr(n + 1, str->size() - n - 1));
+ if (begin && end) {
+ return std::make_pair(*begin, *end);
+ }
+ }
+ }
+ return none;
+}
+
+} // namespace detail
+
+class HexagonSimulator final : public tvm::runtime::hexagon::Device {
+ public:
+ explicit HexagonSimulator(bool enable_queuing);
+ ~HexagonSimulator() final {}
+ void* Alloc(unsigned size, unsigned align) final;
+ void Free(void* ptr) final;
+ void* AllocVtcm(unsigned size, unsigned align) final;
+ void FreeVtcm(void* ptr) final;
+ void CopyDeviceToDevice(void* dst, const void* src, unsigned len) final;
+ void CopyDeviceToHost(void* host_dst, const void* src, unsigned len) final;
+ void CopyHostToDevice(void* dst, const void* host_src, unsigned len) final;
+ void* Load(const std::string& data, const std::string& fmt) final;
+ void Unload(void* mod) final;
+ void* Resolve(const std::string& sym) final;
+ void Call(void* func, uint32_t* scalar, unsigned sc_num, uint32_t* stack,
+ unsigned st_num) final;
+
+ static std::string to_string(HEXAPI_Status status);
+
+ private:
+ static HEX_VA_t p2va(const void* p);
+ static void* va2p(HEX_VA_t va);
+
+ void CopyFromV(void* host_dst, HEX_VA_t src, unsigned len);
+ void CopyToV(HEX_VA_t dst, const void* host_src, unsigned len);
+
+ template <unsigned N>
+ void CopyNToV(HEX_VA_t dst, const void* host_src);
+ template <unsigned N>
+ void CopyNFromV(void* host_dst, HEX_VA_t src);
+
+ // NOLINTNEXTLINE(runtime/references)
+ void SendMsg(Message& m, const void* data, bool show_dbg);
+
+ std::string arch_;
+ std::unique_ptr<HexagonWrapper> sim_;
+ HEX_VA_t dispatch_v_, message_buffer_v_;
+ bool task_queuing_;
+
+ // Sim configuration routines.
+ bool Configure(string_list& opts); // NOLINT(*)
+
+ bool HandleAHBBusPenalty(string_list& rest); // NOLINT(*)
+ bool HandleAHBBusRatio(string_list& rest); // NOLINT(*)
+ bool HandleAHBHighAddr(string_list& rest); // NOLINT(*)
+ bool HandleAHBLowAddr(string_list& rest); // NOLINT(*)
+ bool HandleAXI2BusPenalty(string_list& rest); // NOLINT(*)
+ bool HandleAXI2BusRatio(string_list& rest); // NOLINT(*)
+ bool HandleAXI2HighAddr(string_list& rest); // NOLINT(*)
+ bool HandleAXI2LowAddr(string_list& rest); // NOLINT(*)
+ bool HandleBuildTag(string_list& rest); // NOLINT(*)
+ bool HandleBusPenalty(string_list& rest); // NOLINT(*)
+ bool HandleBusRatio(string_list& rest); // NOLINT(*)
+ bool HandleBusTrace(string_list& rest); // NOLINT(*)
+ bool HandleBypassIdle(string_list& rest); // NOLINT(*)
+ bool HandleConnectionTimeout(string_list& rest); // NOLINT(*)
+ bool HandleCoprocTrace(string_list& rest); // NOLINT(*)
+ bool HandleCoreDump(string_list& rest); // NOLINT(*)
+ bool HandleCosimFile(string_list& rest); // NOLINT(*)
+ bool HandleDCacheTrace(string_list& rest); // NOLINT(*)
+ bool HandleDSPClock(string_list& rest); // NOLINT(*)
+ bool HandleETMCFGBase(string_list& rest); // NOLINT(*)
+ bool HandleGDBServ(string_list& rest); // NOLINT(*)
+ bool HandleHVXLength(string_list& rest); // NOLINT(*)
+ bool HandleICacheTrace(string_list& rest); // NOLINT(*)
+ bool HandleL2CacheTrace(string_list& rest); // NOLINT(*)
+ bool HandleL2CFGBase(string_list& rest); // NOLINT(*)
+ bool HandleL2TCMBase(string_list& rest); // NOLINT(*)
+ bool HandleMemFillRand(string_list& rest); // NOLINT(*)
+ bool HandleMemFill(string_list& rest); // NOLINT(*)
+ bool HandleMemTrace(string_list& rest); // NOLINT(*)
+ bool HandleNullPtr(string_list& rest); // NOLINT(*)
+ bool HandlePacketAnalyze(string_list& rest); // NOLINT(*)
+ bool HandlePCFilter(string_list& rest); // NOLINT(*)
+ bool HandlePCTraceMin(string_list& rest); // NOLINT(*)
+ bool HandlePCTraceNano(string_list& rest); // NOLINT(*)
+ bool HandlePCTrace(string_list& rest); // NOLINT(*)
+ bool HandlePMUStatsFile(string_list& rest); // NOLINT(*)
+ bool HandleProfile(string_list& rest); // NOLINT(*)
+ bool HandleProfileTimeZero(string_list& rest); // NOLINT(*)
+ bool HandleQuiet(string_list& rest); // NOLINT(*)
+ bool HandleReconnect(string_list& rest); // NOLINT(*)
+ bool HandleRTOS(string_list& rest); // NOLINT(*)
+ bool HandleSimErr(string_list& rest); // NOLINT(*)
+ bool HandleSimIn(string_list& rest); // NOLINT(*)
+ bool HandleSimOut(string_list& rest); // NOLINT(*)
+ bool HandleStackStart(string_list& rest); // NOLINT(*)
+ bool HandleStallTrace(string_list& rest); // NOLINT(*)
+ bool HandleStatsFile(string_list& rest); // NOLINT(*)
+ bool HandleSubsystemBase(string_list& rest); // NOLINT(*)
+ bool HandleSymFile(string_list& rest); // NOLINT(*)
+ bool HandleTCM(string_list& rest); // NOLINT(*)
+ bool HandleTCMHighAddr(string_list& rest); // NOLINT(*)
+ bool HandleTCMLowAddr(string_list& rest); // NOLINT(*)
+ bool HandleTimeFilterNS(string_list& rest); // NOLINT(*)
+ bool HandleTiming(string_list& rest); // NOLINT(*)
+ bool HandleUArchTrace(string_list& rest); // NOLINT(*)
+ bool HandleUseFS(string_list& rest); // NOLINT(*)
+ bool HandleV2PTranslation(string_list& rest); // NOLINT(*)
+ bool HandleVerbose(string_list& rest); // NOLINT(*)
+
+ using MaybeUInt64 = llvm::Optional<uint64_t>;
+ using MaybeUIntRange = std::pair<MaybeUInt64, MaybeUInt64>;
+
+ bool should_parse_next(const string_list& rest);
+ llvm::Optional<HEXAPI_Interval> to_interval(const detail::MaybeString& str);
+ llvm::Optional<HEXAPI_TimingMode> to_timingmode(
+ const detail::MaybeString& str);
+ llvm::Optional<HEXAPI_VerboseMode> to_verbosemode(
+ const detail::MaybeString& str);
+ llvm::Optional<HEXAPI_Nullptr> to_nullptr(const detail::MaybeString& str);
+
+ MaybeUIntRange ahb_, axi2_;
+ llvm::Optional<uint32_t> debug_port_;
+ detail::non_const_str sim_dev_args_;
+
+ using OptionHandler = bool (HexagonSimulator::*)(string_list&);
+ static std::map<std::string, OptionHandler> opt_map_;
+};
+
+decltype(HexagonSimulator::opt_map_) HexagonSimulator::opt_map_ = {
+ {"--ahbbuspenalty", &HexagonSimulator::HandleAHBBusPenalty},
+ {"--ahbbusratio", &HexagonSimulator::HandleAHBBusRatio},
+ {"--ahb:highaddr", &HexagonSimulator::HandleAHBHighAddr},
+ {"--ahb:lowaddr", &HexagonSimulator::HandleAHBLowAddr},
+ {"--axi2buspenalty", &HexagonSimulator::HandleAXI2BusPenalty},
+ {"--axi2busratio", &HexagonSimulator::HandleAXI2BusRatio},
+ {"--axi2:highaddr", &HexagonSimulator::HandleAXI2HighAddr},
+ {"--axi2:lowaddr", &HexagonSimulator::HandleAXI2LowAddr},
+ {"-b", &HexagonSimulator::HandleBusTrace},
+ {"--build_tag", &HexagonSimulator::HandleBuildTag},
+ {"--buspenalty", &HexagonSimulator::HandleBusPenalty},
+ {"--busratio", &HexagonSimulator::HandleBusRatio},
+ {"--bustrace", &HexagonSimulator::HandleBusTrace},
+ {"--bypass_idle", &HexagonSimulator::HandleBypassIdle},
+ {"--connection_timeout", &HexagonSimulator::HandleConnectionTimeout},
+ {"--coproctrace", &HexagonSimulator::HandleCoprocTrace},
+ {"--coredump", &HexagonSimulator::HandleCoreDump},
+ {"--cosim_file", &HexagonSimulator::HandleCosimFile},
+ {"--dcachetrace", &HexagonSimulator::HandleDCacheTrace},
+ {"--dsp_clock", &HexagonSimulator::HandleDSPClock},
+ {"-E", &HexagonSimulator::HandleSimErr},
+ {"--etm_base", &HexagonSimulator::HandleETMCFGBase},
+ {"--etmcfg_base", &HexagonSimulator::HandleETMCFGBase},
+ {"--gdbserv", &HexagonSimulator::HandleGDBServ},
+ {"-G", &HexagonSimulator::HandleGDBServ},
+ {"--hvx_length", &HexagonSimulator::HandleHVXLength},
+ {"--icachetrace", &HexagonSimulator::HandleICacheTrace},
+ {"-I", &HexagonSimulator::HandleSimIn},
+ {"--l2cachetrace", &HexagonSimulator::HandleL2CacheTrace},
+ {"--l2cfg_base", &HexagonSimulator::HandleL2CFGBase},
+ {"--l2tcm_base", &HexagonSimulator::HandleL2TCMBase},
+ {"--memfill", &HexagonSimulator::HandleMemFill},
+ {"--memfill_rand", &HexagonSimulator::HandleMemFillRand},
+ {"--memtrace", &HexagonSimulator::HandleMemTrace},
+ {"-m", &HexagonSimulator::HandleMemTrace},
+ {"--nullptr", &HexagonSimulator::HandleNullPtr},
+ {"-O", &HexagonSimulator::HandleSimOut},
+ {"--packet_analyze", &HexagonSimulator::HandlePacketAnalyze},
+ {"--pcfilter", &HexagonSimulator::HandlePCFilter},
+ {"--pctrace", &HexagonSimulator::HandlePCTrace},
+ {"--pctrace_min", &HexagonSimulator::HandlePCTraceMin},
+ {"--pctrace_nano", &HexagonSimulator::HandlePCTraceNano},
+ {"-p", &HexagonSimulator::HandleProfile},
+ {"--pmu_statsfile", &HexagonSimulator::HandlePMUStatsFile},
+ {"--profile", &HexagonSimulator::HandleProfile},
+ {"--profile_timezero", &HexagonSimulator::HandleProfileTimeZero},
+ {"-q", &HexagonSimulator::HandleQuiet},
+ {"--quiet", &HexagonSimulator::HandleQuiet},
+ {"--reconnect", &HexagonSimulator::HandleReconnect},
+ {"--rtos", &HexagonSimulator::HandleRTOS},
+ {"-S", &HexagonSimulator::HandleStatsFile},
+ {"--sim_err", &HexagonSimulator::HandleSimErr},
+ {"--sim_in", &HexagonSimulator::HandleSimIn},
+ {"--sim_out", &HexagonSimulator::HandleSimOut},
+ {"--stackstart", &HexagonSimulator::HandleStackStart},
+ {"--stalltrace", &HexagonSimulator::HandleStallTrace},
+ {"--statsfile", &HexagonSimulator::HandleStatsFile},
+ {"--subsystem_base", &HexagonSimulator::HandleSubsystemBase},
+ {"--symfile", &HexagonSimulator::HandleSymFile},
+ {"--tcm", &HexagonSimulator::HandleTCM},
+ {"--tcm:highaddr", &HexagonSimulator::HandleTCMHighAddr},
+ {"--tcm:lowaddr", &HexagonSimulator::HandleTCMLowAddr},
+ {"-t", &HexagonSimulator::HandlePCTrace},
+ {"--timefilter_ns", &HexagonSimulator::HandleTimeFilterNS},
+ {"--timing", &HexagonSimulator::HandleTiming},
+ {"--uarchtrace", &HexagonSimulator::HandleUArchTrace},
+ {"-u", &HexagonSimulator::HandlePCTraceMin},
+ {"--usefs", &HexagonSimulator::HandleUseFS},
+ {"--v2p_translation", &HexagonSimulator::HandleV2PTranslation},
+ {"--verbose", &HexagonSimulator::HandleVerbose},
+};
+
+#define CHECKED_CALL(func, ...) \
+ do { \
+ HEXAPI_Status s = sim_->func(__VA_ARGS__); \
+ CHECK_EQ(s, HEX_STAT_SUCCESS) \
+ << "HexagonSimulator: " #func " failed with code " \
+ << HexagonSimulator::to_string(s); \
+ } while (false)
+
+inline HEX_VA_t HexagonSimulator::p2va(const void* p) {
+ uintptr_t u = reinterpret_cast<uintptr_t>(p);
+ HEX_VA_t va = static_cast<HEX_VA_t>(u);
+ CHECK_EQ(static_cast<uintptr_t>(va), u);
+ return va;
+}
+
+inline void* HexagonSimulator::va2p(HEX_VA_t va) {
+ return reinterpret_cast<void*>(static_cast<uintptr_t>(va));
+}
+
+template <unsigned N, unsigned A>
+constexpr bool is_multiple_of() {
+ return (N / A) * A == N;
+}
+
+std::shared_ptr<Device> CreateHexagonSimulator() {
+ return std::make_shared<HexagonSimulator>(/*enable_queuing=*/true);
+}
+
+template <unsigned N>
+void HexagonSimulator::CopyNToV(HEX_VA_t dst, const void* host_src) {
+ using src_uint_t = typename unalign<typename uint<N>::type>::type;
+ auto* ps = reinterpret_cast<const src_uint_t*>(host_src);
+ CHECK_EQ(sim_->WriteVirtual(dst, -1u, N, ps->value), HEX_STAT_SUCCESS);
+}
+
+template <unsigned N>
+void HexagonSimulator::CopyNFromV(void* host_dst, HEX_VA_t src) {
+ typename uint<N>::type v;
+ CHECK_EQ(sim_->ReadVirtual(src, -1u, N, &v), HEX_STAT_SUCCESS);
+
+ using dst_uint_t = typename unalign<typename uint<N>::type>::type;
+ auto* pd = reinterpret_cast<dst_uint_t*>(host_dst);
+ pd->value = v;
+}
+
+void HexagonSimulator::CopyToV(HEX_VA_t dst, const void* host_src,
+ unsigned len) {
+ const uint8_t* src = static_cast<const uint8_t*>(host_src);
+
+ while (len >= 8) {
+ CopyNToV<8>(dst, src);
+ dst += 8;
+ src += 8;
+ len -= 8;
+ }
+ if (len >= 4) {
+ CopyNToV<4>(dst, src);
+ dst += 4;
+ src += 4;
+ len -= 4;
+ }
+ if (len >= 2) {
+ CopyNToV<2>(dst, src);
+ dst += 2;
+ src += 2;
+ len -= 2;
+ }
+ if (len >= 1) {
+ CopyNToV<1>(dst, src);
+ dst++;
+ src++;
+ len--;
+ }
+ CHECK_EQ(len, 0);
+}
+
+void HexagonSimulator::CopyFromV(void* host_dst, HEX_VA_t src, unsigned len) {
+ uint8_t* dst = static_cast<uint8_t*>(host_dst);
+
+ while (len >= 8) {
+ CopyNFromV<8>(dst, src);
+ dst += 8;
+ src += 8;
+ len -= 8;
+ }
+ if (len >= 4) {
+ CopyNFromV<4>(dst, src);
+ dst += 4;
+ src += 4;
+ len -= 4;
+ }
+ if (len >= 2) {
+ CopyNFromV<2>(dst, src);
+ dst += 2;
+ src += 2;
+ len -= 2;
+ }
+ if (len >= 1) {
+ CopyNFromV<1>(dst, src);
+ dst++;
+ src++;
+ len--;
+ }
+ CHECK_EQ(len, 0);
+}
+
+void HexagonSimulator::SendMsg(Message& m, const void* data, bool show_dbg) {
+ auto run = [this](bool report_cycles) {
+ HEXAPI_CoreState core = HEX_CORE_RESET;
+ HEX_4u_t result;
+ HEX_8u_t cycles0, cycles1;
+ if (report_cycles) {
+ CHECK_EQ(sim_->GetSimulatedCycleCount(&cycles0), HEX_STAT_SUCCESS);
+ }
+
+ core = sim_->Run(&result);
+ CHECK_EQ(core, HEX_CORE_BREAKPOINT);
+ if (report_cycles) {
+ CHECK_EQ(sim_->GetSimulatedCycleCount(&cycles1), HEX_STAT_SUCCESS);
+ LOG(INFO) << "host: execution took " << (cycles1 - cycles0) << " cycles";
+ }
+ };
+
+ // Send the message request.
+ Message r = {kMsgReq, m.len, 0u};
+ CopyToV(message_buffer_v_, &r, sizeof(r));
+ run(false);
+
+ // Receive the acknowledgement with the address for the payload.
+ CopyFromV(&r, message_buffer_v_, sizeof(r));
+ CHECK_EQ(r.code, kMsgAck);
+ CHECK_GE(r.len, m.len);
+
+ // Send the actual message.
+ m.va = r.va;
+ CopyToV(message_buffer_v_, &m, sizeof(m));
+ if (m.len > 0) CopyToV(r.va, data, m.len);
+ run(show_dbg);
+
+ // Receive the return data.
+ CopyFromV(&m, message_buffer_v_, sizeof(m));
+ CHECK_EQ(m.code, kNone);
+}
+
+HexagonSimulator::HexagonSimulator(bool enable_queuing) {
+ task_queuing_ = enable_queuing;
+
+ // The simulator argument string is in the form:
+ // <cpu_ver> <optional_arguments>
+ // The optional arguments are seperated with spaces:
+ // Ex: --hvx_length 128 --memfill 0 --timing -m output.txt
+ const char* sim_args_env = std::getenv("HEXAGON_SIM_ARGS");
+ if (sim_args_env == nullptr) sim_args_env = "";
+ auto sim_args_iss = std::istringstream(std::string(sim_args_env));
+ using iterator = std::istream_iterator<std::string>;
+ auto sim_args = string_list(iterator(sim_args_iss), iterator());
+
+ std::string target_str =
+ !sim_args.empty() ? *detail::pop_front(sim_args) : std::string("v66");
+
+ arch_ = target_str;
+ sim_ =
+ detail::make_unique<HexagonWrapper>(detail::non_const_str(target_str));
+ LOG(INFO) << "HexagonSimulator: Core version: " << arch_;
+
+ // Locate the sim_dev binary in PATH, or in the current working directory.
+ llvm::StringRef sim_dev = "sim_dev";
+ detail::MaybeString path_sim_dev =
+ llvm::sys::Process::FindInEnvPath("PATH", sim_dev);
+ if (!path_sim_dev) {
+ if (!llvm::sys::fs::exists(sim_dev)) {
+ LOG(FATAL) << "Cannot find sim_dev in PATH.";
+ }
+ path_sim_dev = sim_dev.str();
+ }
+
+ CHECKED_CALL(ConfigureExecutableBinary, path_sim_dev->c_str());
+
+ std::vector<std::string> app_args = {*path_sim_dev};
+ if (char* ev = getenv("ADSP_LIBRARY_PATH")) {
+ app_args.push_back("-L");
+ app_args.push_back(ev);
+ }
+ sim_dev_args_ = detail::non_const_str(app_args);
+ CHECKED_CALL(ConfigureAppCommandLine, sim_dev_args_.size(), sim_dev_args_);
+
+ LOG(INFO) << "HexagonSimulator: ConfigureHVXLength: 128";
+ CHECKED_CALL(ConfigureHVXLength, 128);
Review comment:
I am concerning here. When we create Hexagon target and use HVX 64, but we write hard code of 128 here. We can not find the problem easily. I didn't think of good solution before too. If we don't have a better way, could we add comment in `def hexagon(cpu_ver='v66', sim_args=None, hvx=128):` to prompt users if you change the hvx length, we should change the simulator here?
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services