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.

static_mem_alloc.cpp 7.7 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /**
  2. * \file src/core/test/static_mem_alloc.cpp
  3. * MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
  4. *
  5. * Copyright (c) 2014-2020 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 "megbrain/test/helper.h"
  12. #include "megbrain/utils/arith_helper.h"
  13. #include "megbrain/utils/timer.h"
  14. #include "../impl/graph/var_node_mem_mgr/static_mem_alloc.h"
  15. #include <random>
  16. using namespace mgb;
  17. using namespace cg;
  18. #ifdef WIN32
  19. #pragma message "static_mem_alloc disabled because it causes the program to crash at startup"
  20. #else
  21. #define ITER_ALGO(cb) \
  22. cb(INTERVAL_MOVE) \
  23. cb(BEST_FIT) \
  24. cb(PUSHDOWN)
  25. namespace {
  26. struct TestParam {
  27. using Algo = StaticMemAlloc::AllocatorAlgo;
  28. Algo algo;
  29. size_t align, padding, nr_rand_opr, rng_seed;
  30. static decltype(auto) make_values(
  31. const std::vector<size_t> &aligns,
  32. const std::vector<size_t> &paddings,
  33. const std::vector<size_t> &nr_rand_opr) {
  34. std::vector<TestParam> data;
  35. std::mt19937_64 rng(next_rand_seed());
  36. //std::mt19937_64 rng(0);
  37. for (auto nr: nr_rand_opr) {
  38. size_t seed = rng();
  39. for (auto align: aligns) {
  40. for (auto padding: paddings) {
  41. #define itcb(algo) data.push_back({Algo::algo, align, padding, nr, seed});
  42. ITER_ALGO(itcb)
  43. #undef itcb
  44. }
  45. }
  46. }
  47. return ::testing::ValuesIn(data);
  48. }
  49. };
  50. std::ostream& operator << (std::ostream &ostr, const TestParam &p) {
  51. std::string algo;
  52. #define itcb(a) \
  53. do { \
  54. if (p.algo == StaticMemAlloc::AllocatorAlgo::a) \
  55. algo = #a; \
  56. } while(0);
  57. ITER_ALGO(itcb);
  58. #undef itcb
  59. ostr << "algo=" << algo << " align=" << p.align << " padding=" << p.padding;
  60. if (p.nr_rand_opr != 1)
  61. ostr << " nr_rand_opr=" << p.nr_rand_opr << " rng_seed=" << p.rng_seed;
  62. return ostr;
  63. }
  64. class BasicCorrectness: public ::testing::TestWithParam<TestParam> {
  65. protected:
  66. std::unique_ptr<cg::StaticMemAlloc> m_allocator;
  67. size_t padding() const {
  68. return GetParam().padding;
  69. }
  70. size_t align(size_t addr) const {
  71. return get_aligned_power2(addr, GetParam().align);
  72. }
  73. public:
  74. void SetUp() override {
  75. m_allocator = StaticMemAlloc::make(GetParam().algo);
  76. m_allocator->alignment(GetParam().align);
  77. m_allocator->padding(GetParam().padding);
  78. }
  79. };
  80. class RandomOpr: public BasicCorrectness {
  81. };
  82. decltype(auto) makeuk(int v) {
  83. return reinterpret_cast<cg::StaticMemAlloc::UserKeyType>(v);
  84. }
  85. } // anonymous namespace
  86. TEST_P(BasicCorrectness, Alloc) {
  87. cg::StaticMemAlloc *allocator = this->m_allocator.get();
  88. allocator->add(0, 1, 1, makeuk(0));
  89. allocator->add(0, 1, 1, makeuk(1));
  90. allocator->add(1, 2, 2, makeuk(2));
  91. allocator->solve();
  92. ASSERT_EQ(std::max(align(2 + padding()), 2 * align(1 + padding())),
  93. allocator->tot_alloc());
  94. ASSERT_EQ(std::max(align(2 + padding()), 2 * align(1 + padding())),
  95. allocator->tot_alloc_lower_bound());
  96. }
  97. TEST_P(BasicCorrectness, Overwrite) {
  98. cg::StaticMemAlloc *allocator = this->m_allocator.get();
  99. auto id0 = allocator->add(0, 2, 3, makeuk(0));
  100. auto id1 = allocator->add(1, 3, 1, makeuk(1));
  101. auto id2 = allocator->add(2, 4, 1, makeuk(2));
  102. allocator->add_overwrite_spec(id1, id0, 1);
  103. allocator->add_overwrite_spec(id2, id1, 0);
  104. allocator->solve();
  105. ASSERT_EQ(align(3 + padding()), allocator->tot_alloc());
  106. ASSERT_EQ(align(3 + padding()), allocator->tot_alloc_lower_bound());
  107. }
  108. TEST_P(BasicCorrectness, OverwriteSameEnd) {
  109. cg::StaticMemAlloc *allocator = this->m_allocator.get();
  110. auto id1 = allocator->add(1, 2, 1, makeuk(1));
  111. auto id0 = allocator->add(0, 2, 1, makeuk(0));
  112. allocator->add_overwrite_spec(id1, id0, 0);
  113. allocator->solve();
  114. ASSERT_EQ(align(1 + padding()), allocator->tot_alloc());
  115. ASSERT_EQ(align(1 + padding()), allocator->tot_alloc_lower_bound());
  116. }
  117. INSTANTIATE_TEST_CASE_P(TestStaticMemAllocAlgo,
  118. BasicCorrectness, TestParam::make_values({1, 2}, {1, 2}, {1}));
  119. #ifdef __OPTIMIZE__
  120. constexpr size_t INTERVAL_MOVE_MAX_SIZE = 600;
  121. #else
  122. constexpr size_t INTERVAL_MOVE_MAX_SIZE = 400;
  123. #endif
  124. TEST_P(RandomOpr, Main) {
  125. cg::StaticMemAlloc *allocator = this->m_allocator.get();
  126. auto &&param = this->GetParam();
  127. std::mt19937_64 rng(param.rng_seed);
  128. if (param.algo == TestParam::Algo::INTERVAL_MOVE &&
  129. param.nr_rand_opr > INTERVAL_MOVE_MAX_SIZE)
  130. return;
  131. constexpr size_t MAX_SIZE = 4096;
  132. // [0, 1)
  133. auto uniform = [&]() {
  134. return rng() / (std::mt19937_64::max() + 1.0);
  135. };
  136. // int [lo, hi)
  137. auto uniform_i = [&](size_t lo, size_t hi = 0) -> size_t {
  138. if (!hi) {
  139. hi = lo;
  140. lo = 0;
  141. }
  142. mgb_assert(lo <= hi);
  143. return (hi - lo) * uniform() + lo;
  144. };
  145. // begin, end, size, id
  146. std::vector<std::tuple<size_t, size_t, size_t, size_t>> reqs;
  147. // indices in reqs that overwrite others
  148. std::vector<size_t> overwrite_src_idx;
  149. for (size_t i = 0; i < param.nr_rand_opr; ++ i) {
  150. bool overwrite = false;
  151. size_t begin, ov_dest, ov_offset, size;
  152. if (!reqs.empty() && uniform() <= 0.2) {
  153. size_t idx;
  154. if (!overwrite_src_idx.empty() && uniform() <= 0.5)
  155. idx = overwrite_src_idx[uniform_i(overwrite_src_idx.size())];
  156. else
  157. idx = uniform_i(0, reqs.size());
  158. begin = std::get<1>(reqs[idx]);
  159. if (begin) {
  160. -- begin;
  161. auto tot_sz = std::get<2>(reqs[idx]);
  162. if (tot_sz >= 2) {
  163. ov_dest = std::get<3>(reqs[idx]);
  164. ov_offset = uniform_i(tot_sz);
  165. size = uniform_i(1, tot_sz - ov_offset);
  166. overwrite = true;
  167. }
  168. }
  169. }
  170. if (!overwrite) {
  171. begin = uniform_i(param.nr_rand_opr);
  172. size = uniform_i(1, MAX_SIZE);
  173. }
  174. auto end = begin + uniform_i(1, param.nr_rand_opr),
  175. id = allocator->add(begin, end, size, makeuk(i));
  176. reqs.emplace_back(begin, end, size, id);
  177. if (overwrite) {
  178. allocator->add_overwrite_spec(id, ov_dest, ov_offset);
  179. overwrite_src_idx.push_back(reqs.size() - 1);
  180. }
  181. }
  182. RealTimer timer;
  183. allocator->solve();
  184. std::ostringstream ostr;
  185. ostr << param;
  186. auto sz_tot = allocator->tot_alloc(),
  187. sz_lower = allocator->tot_alloc_lower_bound();
  188. mgb_log("%s: time=%.3f size=%zu/%zu cost=%.3f", ostr.str().c_str(),
  189. timer.get_secs(), sz_tot, sz_lower, double(sz_tot) / sz_lower - 1);
  190. }
  191. INSTANTIATE_TEST_CASE_P(TestStaticMemAllocAlgo,
  192. RandomOpr, TestParam::make_values({1, 256}, {1, 32}, {
  193. 10, INTERVAL_MOVE_MAX_SIZE, 1000, 10000}));
  194. TEST(TestStaticMemAllocAlgo, PushdownChain) {
  195. auto allocator = StaticMemAlloc::make(
  196. StaticMemAlloc::AllocatorAlgo::PUSHDOWN);
  197. constexpr size_t NR = 5;
  198. for (size_t i = 0; i < NR; ++ i)
  199. allocator->add(i, i + 2, i + 1, makeuk(i));
  200. allocator->solve();
  201. ASSERT_EQ(NR + NR - 1, allocator->tot_alloc_lower_bound());
  202. ASSERT_EQ(NR + NR - 1, allocator->tot_alloc());
  203. }
  204. #endif // WIN32
  205. // vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}}

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