/** * \file src/gopt/test/no_memory_copy.cpp * * Copyright (c) 2014-2021 Megvii Inc. All rights reserved. * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. */ #include #include "./network.h" #include "megbrain/comp_node_env.h" #include "megbrain/opr/basic_arith.h" #include "megbrain/test/helper.h" using namespace mgb; struct TestGraph { CompNode m_cn; HostTensorGenerator<> m_gen; std::unique_ptr m_network; SymbolVar m_out_var; std::shared_ptr input_tensor; TestGraph() { m_cn = CompNode::load("cpu0"); m_network = std::make_unique(m_cn); } void create_graph() { input_tensor = m_gen({1, 3, 32, 32}, m_cn); auto input = opr::Host2DeviceCopy::make(*m_network->graph, input_tensor, m_cn) .rename("input"); auto f = m_network->add_conv( input, 4, {3, 3}, dtype::Float32(), true, {2, 2}, {0, 0}); f = m_network->add_elemwise( {f}, dtype::Float32(), opr::Elemwise::Param::Mode::EXP); f = m_network->add_conv(f, 8, {3, 3}, dtype::Float32(), true, {1, 1}, {1, 1}); m_out_var = m_network->add_pooling(f, {2, 2}, {2, 2}); } std::unique_ptr compile_without_copy() { return m_network->graph->compile({{m_out_var, nullptr}}); } std::unique_ptr compile_with_copy(HostTensorND& host) { auto cb = [&host](const DeviceTensorND& dv) mutable { host.copy_from(dv); }; return m_network->graph->compile({{m_out_var, std::move(cb)}}); } }; TEST(TestNoCopy, BasicInputNoCopy) { auto test_graph = TestGraph(); test_graph.create_graph(); HostTensorND out, out_pre; auto func = test_graph.compile_with_copy(out); size_t times = 10; for (size_t i = 0; i < times; i++) { if (i % 2 == 0) { auto input_tensor = test_graph.input_tensor; auto layout = input_tensor->layout(); size_t length = layout.total_nr_elems(); auto storage = TensorStorage(test_graph.m_cn); storage.ensure_size(length * sizeof(float)); float* ptr = storage.ptr()->as(); for (size_t d = 0; d < length; d++) { ptr[d] = i; } input_tensor->reset(storage, layout); } func->execute(); func->wait(); if (i % 2 != 0) { MGB_ASSERT_TENSOR_EQ(out, out_pre); } out_pre.copy_from(out).sync(); } } TEST(TestNoCopy, IONoCopyPtrEQ) { auto test_graph = TestGraph(); auto compute_graph = test_graph.m_network->graph; compute_graph->options().force_output_use_user_specified_memory = true; test_graph.create_graph(); auto func = test_graph.compile_without_copy(); auto&& outvar = func->get_output_vars()[0]; DeviceTensorND dv0(test_graph.m_cn, {1, 8, 7, 7}); DeviceTensorND dv1(test_graph.m_cn, {1, 8, 7, 7}); size_t times = 10; for (size_t i = 0; i < times; i++) { auto input_tensor = test_graph.input_tensor; auto layout = input_tensor->layout(); size_t length = layout.total_nr_elems(); auto storage = TensorStorage(test_graph.m_cn); storage.ensure_size(length * sizeof(float)); float* ptr = storage.ptr()->as(); for (size_t d = 0; d < length; d++) { ptr[d] = i; } input_tensor->reset(storage, layout); if (i % 2 == 0) { outvar->init_mem_plan(&dv0); outvar->reset_dev_tensor_from_tensor(dv0); } else { outvar->init_mem_plan(&dv1); outvar->reset_dev_tensor_from_tensor(dv1); } func->execute(); func->wait(); auto out = func->get_output_vars()[0]->dev_tensor().ptr(); if (i % 2 == 0) { ASSERT_EQ(dv0.ptr(), out); } else { ASSERT_EQ(dv1.ptr(), out); } } } TEST(TestNoCopy, IONoCopyCorrect) { auto test_graph = TestGraph(); auto compute_graph = test_graph.m_network->graph; compute_graph->options().force_output_use_user_specified_memory = true; test_graph.create_graph(); HostTensorND truth; auto func = test_graph.compile_without_copy(); //! because the output tensor not assign user memory, so it will wrong ASSERT_THROW(func->execute(), MegBrainError); auto&& outvar = func->get_output_vars()[0]; size_t times = 10; for (size_t i = 0; i < times; i++) { auto input_tensor = test_graph.input_tensor; auto layout = input_tensor->layout(); size_t length = layout.total_nr_elems(); auto storage = TensorStorage(test_graph.m_cn); storage.ensure_size(length * sizeof(float)); float* ptr = storage.ptr()->as(); for (size_t d = 0; d < length; d++) { ptr[d] = i / 5 + 3; } input_tensor->reset(storage, layout); DeviceTensorND dv(test_graph.m_cn, {1, 8, 7, 7}); outvar->init_mem_plan(&dv); outvar->reset_dev_tensor_from_tensor(dv); func->execute(); func->wait(); if (i % 5 == 0) { truth.copy_from(func->get_output_vars()[0]->dev_tensor()).sync(); continue; } HostTensorND to_check; to_check.copy_from(func->get_output_vars()[0]->dev_tensor()).sync(); MGB_ASSERT_TENSOR_EQ(to_check, truth); } } TEST(TestNoCopy, InputNoCopyRecord) {} TEST(TestNoCopy, OutputNoCopyRecord) {} // vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}}