From 5b6ff9f5fca668907038511b17ab4666bd06435a Mon Sep 17 00:00:00 2001 From: Luis Vega Date: Thu, 14 Jan 2021 20:26:17 +0000 Subject: [PATCH 1/6] add files --- cmake/config.cmake | 4 +- cmake/modules/contrib/Verilator.cmake | 8 +-- .../backend/contrib/verilator/codegen.cc | 30 +++++++- .../contrib/verilator/verilator_runtime.cc | 70 ++++++++++++++++--- .../contrib/test_verilator/infrastructure.py | 39 ++++++++++- .../test_verilator/test_verilator_codegen.py | 2 + 6 files changed, 132 insertions(+), 21 deletions(-) diff --git a/cmake/config.cmake b/cmake/config.cmake index cd0f4b8e75e9..872feb918a4f 100644 --- a/cmake/config.cmake +++ b/cmake/config.cmake @@ -232,8 +232,8 @@ set(USE_TENSORRT_RUNTIME OFF) # Whether use VITIS-AI codegen set(USE_VITIS_AI OFF) -# Build Verilator codegen and runtime, example located in 3rdparty/vta-hw/apps/verilator -set(USE_VERILATOR_HW OFF) +# Build Verilator codegen and runtime +set(USE_VERILATOR OFF) # Build ANTLR parser for Relay text format # Possible values: diff --git a/cmake/modules/contrib/Verilator.cmake b/cmake/modules/contrib/Verilator.cmake index d3c1a7161182..4947d44064a0 100644 --- a/cmake/modules/contrib/Verilator.cmake +++ b/cmake/modules/contrib/Verilator.cmake @@ -15,14 +15,10 @@ # specific language governing permissions and limitations # under the License. -if(USE_VERILATOR_HW STREQUAL "ON") - execute_process(COMMAND make --directory ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/vta-hw/apps/verilator) +if(USE_VERILATOR STREQUAL "ON") file(GLOB VERILATOR_RELAY_CONTRIB_SRC src/relay/backend/contrib/verilator/codegen.cc) - list(APPEND COMPILER_SRCS ${VERILATOR_RELAY_CONTRIB_SRC}) - list(APPEND COMPILER_SRCS ${JSON_RELAY_CONTRIB_SRC}) - find_library(EXTERN_LIBRARY_VERILATOR NAMES verilator PATHS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/vta-hw/apps/verilator) - list(APPEND TVM_RUNTIME_LINKER_LIBS ${EXTERN_LIBRARY_VERILATOR}) file(GLOB VERILATOR_CONTRIB_SRC src/runtime/contrib/verilator/verilator_runtime.cc) + list(APPEND COMPILER_SRCS ${VERILATOR_RELAY_CONTRIB_SRC}) list(APPEND RUNTIME_SRCS ${VERILATOR_CONTRIB_SRC}) endif() diff --git a/src/relay/backend/contrib/verilator/codegen.cc b/src/relay/backend/contrib/verilator/codegen.cc index 4124fa2459d6..f1c7f785330e 100644 --- a/src/relay/backend/contrib/verilator/codegen.cc +++ b/src/relay/backend/contrib/verilator/codegen.cc @@ -43,6 +43,7 @@ namespace contrib { using namespace backend; +/*! \brief Verilator JSON serializer */ class VerilatorJSONSerializer : public backend::contrib::JSONSerializer { using JSONGraphNode = tvm::runtime::json::JSONGraphNode; using JSONGraphNodeEntry = tvm::runtime::json::JSONGraphNodeEntry; @@ -74,6 +75,24 @@ class VerilatorJSONSerializer : public backend::contrib::JSONSerializer { } }; +/*! \brief Attributes to store the compiler options for Verilator */ +struct VerilatorCompilerConfigNode : public tvm::AttrsNode { + String lib; + + TVM_DECLARE_ATTRS(VerilatorCompilerConfigNode, "ext.attrs.VerilatorCompilerConfigNode") { + TVM_ATTR_FIELD(lib).set_default("libverilator.so"); + } +}; + +class VerilatorCompilerConfig : public Attrs { + public: + TVM_DEFINE_NOTNULLABLE_OBJECT_REF_METHODS(VerilatorCompilerConfig, Attrs, + VerilatorCompilerConfigNode); +}; + +TVM_REGISTER_NODE_TYPE(VerilatorCompilerConfigNode); +TVM_REGISTER_PASS_CONFIG_OPTION("relay.ext.verilator.options", VerilatorCompilerConfig); + /*! * \brief The external compiler/codegen tool. It takes a Relay expression/module and * compile it into a runtime module. @@ -87,9 +106,18 @@ runtime::Module VerilatorCompiler(const ObjectRef& ref) { std::string graph_json = serializer.GetJSON(); auto params = serializer.GetParams(); + // Get Verilator compiler options + auto ctx = transform::PassContext::Current(); + auto cfg = ctx->GetConfig("relay.ext.verilator.options"); + if (!cfg.defined()) { + cfg = AttrsWithDefaultValues(); + } + + auto lib_name = cfg.value()->lib; + const auto* pf = runtime::Registry::Get("runtime.VerilatorJSONRuntimeCreate"); CHECK(pf != nullptr) << "Cannot find JSON runtime module to create"; - auto mod = (*pf)(func_name, graph_json, params); + auto mod = (*pf)(lib_name, func_name, graph_json, params); return mod; } diff --git a/src/runtime/contrib/verilator/verilator_runtime.cc b/src/runtime/contrib/verilator/verilator_runtime.cc index a44faf6d3274..4b9f6147b9dc 100644 --- a/src/runtime/contrib/verilator/verilator_runtime.cc +++ b/src/runtime/contrib/verilator/verilator_runtime.cc @@ -29,6 +29,9 @@ #include #include +#include + +#include "../../library_module.h" #include "../json/json_node.h" #include "../json/json_runtime.h" #include "verilator_device.h" @@ -38,9 +41,40 @@ namespace tvm { namespace runtime { namespace contrib { +typedef VerilatorHandle (*VerilatorAllocFunc)(); +typedef void (*VerilatorResetFunc)(VerilatorHandle, int); +typedef void (*VerilatorAddFunc)(VerilatorHandle, int*, int*, int*, int, int); + using namespace tvm::runtime; using namespace tvm::runtime::json; +class VerilatorLibrary : public Library { + public: + ~VerilatorLibrary() { + if (lib_handle_) Unload(); + } + void Init(const std::string& name) { Load(name); } + + void* GetSymbol(const char* name) final { return GetSymbol_(name); } + + private: + // Library handle + void* lib_handle_{nullptr}; + // load the library + void Load(const std::string& name) { + lib_handle_ = dlopen(name.c_str(), RTLD_LAZY | RTLD_LOCAL); + ICHECK(lib_handle_ != nullptr) + << "Failed to load dynamic shared library " << name << " " << dlerror(); + } + + void* GetSymbol_(const char* name) { return dlsym(lib_handle_, name); } + + void Unload() { + dlclose(lib_handle_); + lib_handle_ = nullptr; + } +}; + class VerilatorJSONRuntime : public JSONRuntimeBase { public: VerilatorJSONRuntime(const std::string& symbol_name, const std::string& graph_json, @@ -49,8 +83,25 @@ class VerilatorJSONRuntime : public JSONRuntimeBase { const char* type_key() const { return "verilator_json"; } + void LoadLibrary(const std::string& lib_name) { + lib_ = new VerilatorLibrary(); + lib_->Init(lib_name); + } + void Init(const Array& consts) override { - BuildEngine(); + // get symbols + auto alloc_func = reinterpret_cast(lib_->GetSymbol("VerilatorAlloc")); + ICHECK(alloc_func != nullptr); + auto reset_func = reinterpret_cast(lib_->GetSymbol("VerilatorReset")); + ICHECK(reset_func != nullptr); + vadd_func_ = reinterpret_cast(lib_->GetSymbol("verilator_add")); + ICHECK(vadd_func_ != nullptr); + + // alloc device + device_ = (*alloc_func)(); + + // reset for 10 cycles + (*reset_func)(device_, 10); CHECK_EQ(consts.size(), const_idx_.size()) << "The number of input constants must match the number of required."; @@ -80,7 +131,7 @@ class VerilatorJSONRuntime : public JSONRuntimeBase { if ("add" == op_name) { auto entry = node.GetInputs()[0]; auto shape = nodes_[entry.id_].GetOpShape()[entry.index_]; - verilator_add(device_, in_ptr[0], in_ptr[1], out_ptr[0], shape[0], shape[1]); + (*vadd_func_)(device_, in_ptr[0], in_ptr[1], out_ptr[0], shape[0], shape[1]); } else { LOG(FATAL) << "Unsupported op: " << op_name; } @@ -89,19 +140,18 @@ class VerilatorJSONRuntime : public JSONRuntimeBase { } private: - void BuildEngine() { - device_ = VerilatorAlloc(); - // reset for 10 cycles - VerilatorReset(device_, 10); - } - - /* The verilator handle. */ + /* The verilator device handle. */ VerilatorHandle device_{nullptr}; + /* The verilator library handle. */ + VerilatorLibrary* lib_{nullptr}; + /* The verilator add function handle */ + VerilatorAddFunc vadd_func_{nullptr}; }; -runtime::Module VerilatorJSONRuntimeCreate(String symbol_name, String graph_json, +runtime::Module VerilatorJSONRuntimeCreate(String lib_name, String symbol_name, String graph_json, const Array& const_names) { auto n = make_object(symbol_name, graph_json, const_names); + n->LoadLibrary(lib_name); return runtime::Module(n); } diff --git a/tests/python/contrib/test_verilator/infrastructure.py b/tests/python/contrib/test_verilator/infrastructure.py index 1333f484aec9..e8fd943aa8a0 100644 --- a/tests/python/contrib/test_verilator/infrastructure.py +++ b/tests/python/contrib/test_verilator/infrastructure.py @@ -16,7 +16,9 @@ # under the License. """Verilator utility functions""" +import os import sys +import subprocess as sp import tvm from tvm import relay @@ -66,10 +68,43 @@ def offload(mod): return mod +def verilator_app_path(): + """Find verilator hardware app path""" + + cur_dir = os.path.dirname(os.path.realpath(__file__)) + return os.path.join( + cur_dir, + "..", + "..", + "..", + "..", + "3rdparty", + "vta-hw", + "apps", + "verilator", + ) + + +def compile_hardware(): + """Compile hardware into shared library""" + + cmd = [] + cmd.append("make") + cmd.append("--directory") + cmd.append(verilator_app_path()) + sp.run(cmd, check=True) + + def compile_module(mod): - """Compile Relay module""" + """Compile Relay module and hardware library""" + + lib = os.path.join(verilator_app_path(), "libverilator.so") + if not os.path.isfile(lib): + compile_hardware() - with relay.build_config(opt_level=3): + with tvm.transform.PassContext( + opt_level=3, config={"relay.ext.verilator.options": {"lib": lib}} + ): exe = relay.vm.compile(mod, target="llvm", params=None) code, lib = exe.save() return runtime.vm.Executable.load_exec(code, lib) diff --git a/tests/python/contrib/test_verilator/test_verilator_codegen.py b/tests/python/contrib/test_verilator/test_verilator_codegen.py index 664e254041b2..87e47b2ee55f 100644 --- a/tests/python/contrib/test_verilator/test_verilator_codegen.py +++ b/tests/python/contrib/test_verilator/test_verilator_codegen.py @@ -16,6 +16,7 @@ # under the License. """Verilator codegen tests""" +import os import numpy as np import tvm @@ -24,6 +25,7 @@ from test_verilator.infrastructure import ( _register_verilator_op, skip_test, + compile_hardware, compile_module, run_module, offload, From ebc9e90e6006246eea1a7240962cd1799812f7ca Mon Sep 17 00:00:00 2001 From: Luis Vega Date: Thu, 14 Jan 2021 20:31:07 +0000 Subject: [PATCH 2/6] remove import --- tests/python/contrib/test_verilator/test_verilator_codegen.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/python/contrib/test_verilator/test_verilator_codegen.py b/tests/python/contrib/test_verilator/test_verilator_codegen.py index 87e47b2ee55f..b65d6b8f5559 100644 --- a/tests/python/contrib/test_verilator/test_verilator_codegen.py +++ b/tests/python/contrib/test_verilator/test_verilator_codegen.py @@ -25,7 +25,6 @@ from test_verilator.infrastructure import ( _register_verilator_op, skip_test, - compile_hardware, compile_module, run_module, offload, From 2b1e31e4219c75ed9f525c2e046af8fddd72f763 Mon Sep 17 00:00:00 2001 From: Luis Vega Date: Thu, 14 Jan 2021 20:34:35 +0000 Subject: [PATCH 3/6] remove os import --- tests/python/contrib/test_verilator/test_verilator_codegen.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/python/contrib/test_verilator/test_verilator_codegen.py b/tests/python/contrib/test_verilator/test_verilator_codegen.py index b65d6b8f5559..664e254041b2 100644 --- a/tests/python/contrib/test_verilator/test_verilator_codegen.py +++ b/tests/python/contrib/test_verilator/test_verilator_codegen.py @@ -16,7 +16,6 @@ # under the License. """Verilator codegen tests""" -import os import numpy as np import tvm From 8f8ca22079b179c20733ed514951acdce7c68656 Mon Sep 17 00:00:00 2001 From: Luis Vega Date: Fri, 15 Jan 2021 23:52:36 +0000 Subject: [PATCH 4/6] reorder header --- src/runtime/contrib/verilator/verilator_runtime.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/runtime/contrib/verilator/verilator_runtime.cc b/src/runtime/contrib/verilator/verilator_runtime.cc index 4b9f6147b9dc..697d3c04d55d 100644 --- a/src/runtime/contrib/verilator/verilator_runtime.cc +++ b/src/runtime/contrib/verilator/verilator_runtime.cc @@ -25,18 +25,18 @@ #include #include -#include -#include -#include - -#include - #include "../../library_module.h" #include "../json/json_node.h" #include "../json/json_runtime.h" #include "verilator_device.h" #include "verilator_kernel.h" +#include +#include +#include + +#include + namespace tvm { namespace runtime { namespace contrib { From 3e695cd999207856d7ff8376f29e64355042d2d9 Mon Sep 17 00:00:00 2001 From: Luis Vega Date: Sat, 16 Jan 2021 00:29:04 +0000 Subject: [PATCH 5/6] fix header order cpplint --- src/runtime/contrib/verilator/verilator_runtime.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/runtime/contrib/verilator/verilator_runtime.cc b/src/runtime/contrib/verilator/verilator_runtime.cc index 697d3c04d55d..5477d8f3320a 100644 --- a/src/runtime/contrib/verilator/verilator_runtime.cc +++ b/src/runtime/contrib/verilator/verilator_runtime.cc @@ -21,22 +21,21 @@ * \file src/runtime/contrib/verilator/verilator_runtime.cc * \brief A simple JSON runtime for Verilator. */ +#include #include #include +#include +#include +#include + #include "../../library_module.h" #include "../json/json_node.h" #include "../json/json_runtime.h" #include "verilator_device.h" #include "verilator_kernel.h" -#include -#include -#include - -#include - namespace tvm { namespace runtime { namespace contrib { From 2f6c939fa93be00cfb1d07c0c8d3391391c4268e Mon Sep 17 00:00:00 2001 From: Luis Vega Date: Sat, 16 Jan 2021 02:03:04 +0000 Subject: [PATCH 6/6] lint fix --- src/runtime/contrib/verilator/verilator_runtime.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/contrib/verilator/verilator_runtime.cc b/src/runtime/contrib/verilator/verilator_runtime.cc index 5477d8f3320a..ae52d9e1e08d 100644 --- a/src/runtime/contrib/verilator/verilator_runtime.cc +++ b/src/runtime/contrib/verilator/verilator_runtime.cc @@ -21,8 +21,8 @@ * \file src/runtime/contrib/verilator/verilator_runtime.cc * \brief A simple JSON runtime for Verilator. */ -#include +#include #include #include