diff --git a/imperative/src/impl/interpreter/interpreter_impl.h b/imperative/src/impl/interpreter/interpreter_impl.h index d068a0a1afcab0fb0eab5f1ff47049e0d6c83540..4ccf95c74a2f74df5d94796fb2aa715bc8169bf5 100644 --- a/imperative/src/impl/interpreter/interpreter_impl.h +++ b/imperative/src/impl/interpreter/interpreter_impl.h @@ -27,6 +27,11 @@ struct InterpreterImpl : Interpreter { std::unique_ptr create_channel() override; }; +/*! + * \brief implement Channel to execute the commands asynchronously, + * almost commands are executed by the worker threads, commands are sent + * by the interface + */ struct ChannelImpl : Interpreter::Channel, NonCopyableObj, NonMoveableObj { ChannelImpl(); ~ChannelImpl() override; @@ -304,3 +309,5 @@ private: }; } // namespace mgb::imperative::interpreter::intl + +// vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}} diff --git a/imperative/src/include/megbrain/imperative/interpreter.h b/imperative/src/include/megbrain/imperative/interpreter.h index 61f73257941ec69bf72e2e83f49829e8e498bdcc..1a99027fde7683df70f58d16bb79697c02e92eb4 100644 --- a/imperative/src/include/megbrain/imperative/interpreter.h +++ b/imperative/src/include/megbrain/imperative/interpreter.h @@ -7,6 +7,7 @@ namespace mgb::imperative::interpreter { +//! nested throw the stored exceptions struct AsyncError : std::nested_exception, std::exception { const char* what() const noexcept { try { @@ -20,9 +21,16 @@ struct AsyncError : std::nested_exception, std::exception { }; struct Interpreter { + /*! + * HandleImpl* just act as a key to represent TensorInfo + */ struct HandleImpl {}; using Handle = HandleImpl*; + /*! + * \brief the base command execution interface, Channel is similar to channel in + * golang, it executes the commands put into asynchronously. + */ struct Channel { virtual ~Channel() = default; @@ -66,3 +74,5 @@ protected: }; } // namespace mgb::imperative::interpreter + +// vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}} diff --git a/imperative/src/test/interpreter_test.cpp b/imperative/src/test/interpreter_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..72cfade8dbcf1ad6e02bbf88660a392b38364944 --- /dev/null +++ b/imperative/src/test/interpreter_test.cpp @@ -0,0 +1,81 @@ +#include "megbrain/imperative/interpreter.h" +#include "../impl/interpreter/tensor_info.h" +#include "./helper.h" +#include "megbrain/comp_node_env.h" +#include "megbrain/imperative/blob_manager.h" +#include "megbrain/imperative/ops/opr_attr.h" +#include "megbrain/imperative/physical_tensor.h" +#include "megbrain/opr/basic_arith.h" +#include "megbrain/opr/basic_arith_wrapper.h" +#include "megbrain/opr/dnn/batch_norm.h" +#include "megbrain/opr/dnn/convolution.h" +#include "megbrain/opr/tensor_manip.h" +#include "megbrain/opr/utility.h" + +using namespace mgb; +using namespace cg; +using namespace imperative; +using namespace interpreter; + +TEST(TestImperative, InterpreterPut) { + HostTensorGenerator<> gen; + auto h0 = gen({3}); + auto&& channel = Interpreter::inst().create_channel(); + auto tensor_handle = channel->put(*h0, true); + auto tensor_info = reinterpret_cast(tensor_handle); + channel->sync(); + ASSERT_TRUE(tensor_info->status == intl::TensorInfo::Produced); + //! because tensor elems is less than TensorShape::MAX_NDIM, stored it + //! directly + ASSERT_EQ(tensor_info->ptr->get_value().raw_ptr(), h0->raw_ptr()); + auto shape = channel->get_shape(tensor_handle); + ASSERT_TRUE(shape.ndim == 1); + ASSERT_TRUE(shape.total_nr_elems() == 3); + + auto h2 = gen({10}); + auto tensor_handle2 = channel->put(*h2, false); + auto tensor_handle2_once = channel->put(*h2, false); + channel->sync(); + ASSERT_NE(tensor_handle2_once, tensor_handle2); + auto finded = MultiCNConstTensorCache::inst().lookup(*h2); + ASSERT_TRUE(finded.get()); + //! Device tensor ptr is not equal host tensor ptr + ASSERT_NE(finded->raw_ptr_not_for_readwrite(), h2->raw_ptr()); + channel->del(tensor_handle); + channel->del(tensor_handle2); + channel->del(tensor_handle2_once); +} + +TEST(TestImperative, InterpreterApplyOp) { + HostTensorGenerator<> gen; + size_t add = 2, dim0 = 5, dim1 = 10; + auto h0 = gen({1}); + h0->ptr()[0] = add; + auto h1 = gen({dim0, dim1}); + for (size_t i = 0; i < dim0 * dim1; i++) { + h1->ptr()[i] = i; + } + auto&& channel = Interpreter::inst().create_channel(); + auto tensor_handle0 = channel->put(*h0, false); + auto tensor_handle1 = channel->put(*h1, false); + SmallVector inputs{tensor_handle0, tensor_handle1}; + + auto op = OprAttr::make("Elemwise"); + auto&& attr = op->cast_final_safe(); + using Param = opr::Elemwise::Param; + Param param{Param::Mode::ADD}; + attr.param.write_pod(param); + + auto outputs = channel->apply_op(op, inputs); + channel->sync(); + auto out_tensor = reinterpret_cast(outputs[0])->ptr->get_value(); + ASSERT_EQ(out_tensor.layout().ndim, 2); + ASSERT_EQ(out_tensor.shape(0), dim0); + ASSERT_EQ(out_tensor.shape(1), dim1); + float* output = out_tensor.ptr(); + for (size_t i = 0; i < dim0 * dim1; i++) { + ASSERT_EQ(output[i], i + add); + } +} + +// vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}}