You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

opr_io_dump.cpp 7.4 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /**
  2. * \file src/plugin/test/opr_io_dump.cpp
  3. * MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
  4. *
  5. * Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
  6. *
  7. * Unless required by applicable law or agreed to in writing,
  8. * software distributed under the License is distributed on an
  9. * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. */
  11. #include "./opr_io_dump_text_out.h"
  12. #include "megbrain/test/helper.h"
  13. #include "megbrain/opr/basic_arith_wrapper.h"
  14. #include "megbrain/opr/io.h"
  15. #include "megbrain/opr/tensor_manip.h"
  16. #include "megbrain/plugin/opr_io_dump.h"
  17. #include "megbrain/utils/debug.h"
  18. #include <fstream>
  19. #include <sstream>
  20. using namespace mgb;
  21. namespace {
  22. using PluginMaker =
  23. thin_function<std::unique_ptr<OprIODumpBase>(ComputingGraph*, int level)>;
  24. using ResultChecker = thin_function<void()>;
  25. void run_test(CompNode cn, const PluginMaker& plugin_maker) {
  26. // use a predefiend seed because we have hard-coded the expected outputs
  27. HostTensorGenerator<> gen{0.f, 1.f, /*seed*/ 23};
  28. std::shared_ptr<HostTensorND> host_x;
  29. auto make_expect = [&host_x]() {
  30. HostTensorND ret{host_x->comp_node(), host_x->dtype()};
  31. auto x = host_x->ptr<float>(), p = ret.resize(host_x->shape()).ptr<float>();
  32. auto shp1 = host_x->shape(1);
  33. for (size_t i = 0, it = host_x->shape().total_nr_elems(); i < it; ++i) {
  34. p[i] = (x[i] >= 0.f ? x[i] : 0.f) * (x[i % shp1] + 2.f);
  35. }
  36. return ret;
  37. };
  38. for (size_t record : {0, 1, 2}) {
  39. host_x = gen({2, 3}, cn);
  40. auto graph = ComputingGraph::make();
  41. graph->options().var_sanity_check_first_run = false;
  42. graph->options().comp_node_seq_record_level = record;
  43. graph->options().graph_opt_level = 0;
  44. auto sync = (record != 1);
  45. auto plug = plugin_maker(graph.get(), record);
  46. // make a non-contiguous value, also introduce some shape dependencies
  47. auto sub_brd = [](SymbolVar x) {
  48. using S = opr::Subtensor;
  49. auto zero = x.make_scalar(0), one = x.make_scalar(1), xshp = x.symshape();
  50. return S::make(x, {S::AxisIndexer::make_interval(0, zero, one, None)})
  51. .broadcast(xshp);
  52. };
  53. // write in primitive oprs to ensure stable opr ordering across
  54. // compilers
  55. auto x = opr::Host2DeviceCopy::make_no_fwd(*graph, host_x),
  56. two = x.make_scalar_dt(2), sub = sub_brd(x) + two, xrelu = opr::relu(x),
  57. y = xrelu * sub;
  58. // set stable names so the test can be used when opr naming is disabled
  59. auto cb_rename = [](cg::OperatorNodeBase* opr) {
  60. opr->name(ssprintf("opr%zu", opr->id()));
  61. for (auto i : opr->output()) {
  62. i->name(ssprintf("var%zu", i->id()));
  63. }
  64. };
  65. cg::DepOprIter{cb_rename}.add(y);
  66. HostTensorND host_y;
  67. auto func = graph->compile({make_callback_copy(y, host_y, sync)});
  68. if (record == 2) {
  69. ComputingGraph::assert_destroy(graph);
  70. }
  71. func->execute();
  72. if (!sync) {
  73. func->wait();
  74. }
  75. plug->flush_lazy();
  76. MGB_ASSERT_TENSOR_EQ(make_expect(), host_y);
  77. if (record == 2) {
  78. host_x->copy_from(*gen(host_x->shape(), cn));
  79. } else {
  80. // change ptr
  81. *host_x = *gen(host_x->shape(), cn);
  82. }
  83. func->execute();
  84. if (!sync) {
  85. func->wait();
  86. }
  87. MGB_ASSERT_TENSOR_EQ(make_expect(), host_y);
  88. for (int i = 0; i < 2; ++i) {
  89. host_x->copy_from(*gen(host_x->shape(), cn));
  90. func->execute();
  91. if (!sync) {
  92. func->wait();
  93. }
  94. MGB_ASSERT_TENSOR_EQ(make_expect(), host_y);
  95. }
  96. if (record != 2) {
  97. // change shape
  98. *host_x = *gen({5, 4}, cn);
  99. if (record == 1) {
  100. ASSERT_THROW(func->execute(), MegBrainError);
  101. } else {
  102. func->execute();
  103. MGB_ASSERT_TENSOR_EQ(make_expect(), host_y);
  104. }
  105. }
  106. }
  107. }
  108. void run_test(const PluginMaker& plugin_maker, const ResultChecker& result_checker) {
  109. for (size_t i = 1; i < CompNode::NR_DEVICE_TYPE; ++i) {
  110. auto type = static_cast<CompNode::DeviceType>(i);
  111. if (!check_device_type_avaiable(type))
  112. continue;
  113. if (CompNode::get_device_count(type)) {
  114. auto cn = CompNode::load({type, -1, 0});
  115. if (cn.contain_flag(CompNode::Flag::SUPPORT_RECORDER)) {
  116. run_test(cn, plugin_maker);
  117. ASSERT_FALSE(::testing::Test::HasFailure())
  118. << "failed for comp node " << cn.to_string();
  119. result_checker();
  120. ASSERT_FALSE(::testing::Test::HasFailure())
  121. << "failed for comp node " << cn.to_string();
  122. }
  123. }
  124. }
  125. }
  126. std::vector<std::string> getlines(std::istream& inp, size_t skip_head = 0) {
  127. std::vector<std::string> ret;
  128. for (std::string line; std::getline(inp, line);) {
  129. if (skip_head) {
  130. --skip_head;
  131. } else {
  132. ret.emplace_back(std::move(line));
  133. }
  134. }
  135. return ret;
  136. }
  137. } // anonymous namespace
  138. #if MGB_VERBOSE_TYPEINFO_NAME
  139. TEST(TestOprIODump, Text) {
  140. auto fname_base = output_file("test_opr_iodump");
  141. std::array<std::string, 3> fnames;
  142. auto make_plugin = [&](ComputingGraph* graph, int level) {
  143. fnames.at(level) = ssprintf("%s-%d.txt", fname_base.c_str(), level);
  144. auto ret = std::make_unique<TextOprIODump>(graph, fnames[level].c_str());
  145. ret->print_addr(false);
  146. return ret;
  147. };
  148. auto check_result = [&]() {
  149. for (int level = 0; level < 3; ++level) {
  150. std::ifstream inp_get{fnames[level]};
  151. std::istringstream inp_expect{EXPECTED_TEXT_OUT_REC[level]};
  152. auto lines_get = getlines(inp_get), lines_expect = getlines(inp_expect, 1);
  153. ASSERT_EQ(lines_expect.size(), lines_get.size());
  154. for (size_t i = 0; i < lines_expect.size(); ++i) {
  155. ASSERT_EQ(lines_expect[i], lines_get[i]) << "fail on line " << i;
  156. }
  157. }
  158. for (auto&& i : fnames) {
  159. // clear the content to test if next run does not produce any output
  160. debug::write_to_file(i.c_str(), "Lorem ipsum");
  161. }
  162. };
  163. run_test(make_plugin, check_result);
  164. }
  165. #endif
  166. TEST(TestOprIODump, StdErr) {
  167. MGB_MARK_USED_VAR(EXPECTED_TEXT_OUT_REC);
  168. HostTensorGenerator<> gen;
  169. auto host_x = gen({5});
  170. auto host_y = gen({5});
  171. auto graph = ComputingGraph::make();
  172. std::shared_ptr<FILE> sp(stdout, [](FILE*) {});
  173. auto plugin = std::make_unique<TextOprIODump>(graph.get(), sp);
  174. auto x = opr::Host2DeviceCopy::make(*graph, host_x);
  175. auto y = opr::Host2DeviceCopy::make(*graph, host_y);
  176. auto z = x + y;
  177. HostTensorND host_z;
  178. auto func = graph->compile({make_callback_copy(z, host_z)});
  179. func->execute();
  180. }
  181. TEST(TestOprIODump, Binary) {
  182. auto fname = output_file("");
  183. auto make_plugin = [&](ComputingGraph* graph, int level) {
  184. return std::make_unique<BinaryOprIODump>(graph, fname);
  185. };
  186. run_test(make_plugin, []() {});
  187. }
  188. // vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}}

MegEngine 安装包中集成了使用 GPU 运行代码所需的 CUDA 环境,不用区分 CPU 和 GPU 版。 如果想要运行 GPU 程序,请确保机器本身配有 GPU 硬件设备并安装好驱动。 如果你想体验在云端 GPU 算力平台进行深度学习开发的感觉,欢迎访问 MegStudio 平台