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

189 lines
6.2 KiB

  1. #include <memory>
  2. #include <cassert>
  3. #include <cstdio>
  4. #include <stdlib.h>
  5. #include <algorithm>
  6. #include <vector>
  7. // enable debugging code in spp_bitset.h
  8. #define SPP_TEST 1
  9. #include <sparsepp/spp_timer.h>
  10. #include <sparsepp/spp_memory.h>
  11. #include <sparsepp/spp_dlalloc.h>
  12. using namespace std;
  13. static float _to_mb(uint64_t m) { return (float)((double)m / (1024 * 1024)); }
  14. // -----------------------------------------------------------
  15. // -----------------------------------------------------------
  16. template <class T, class A>
  17. class TestAlloc
  18. {
  19. public:
  20. TestAlloc(size_t num_alloc = 8000000) :
  21. _num_alloc(num_alloc)
  22. {
  23. _allocated.resize(_num_alloc, nullptr);
  24. _sizes.resize(_num_alloc, 0);
  25. _start_mem_usage = spp::GetProcessMemoryUsed();
  26. }
  27. void run()
  28. {
  29. srand(43); // always same sequence of random numbers
  30. for (size_t i=0; i<_num_alloc; ++i)
  31. _sizes[i] = std::max(2, (rand() % 5) * 2);
  32. spp::Timer<std::milli> timer;
  33. // allocate small buffers
  34. // ----------------------
  35. for (size_t i=0; i<_num_alloc; ++i)
  36. {
  37. _allocated[i] = _allocator.allocate(_sizes[i]);
  38. _set_buf(_allocated[i], _sizes[i]);
  39. }
  40. #if 1
  41. // and grow the buffers to a max size of 24 each
  42. // ---------------------------------------------
  43. for (uint32_t j=4; j<26; j += 2)
  44. {
  45. for (size_t i=0; i<_num_alloc; ++i)
  46. {
  47. // if ( _sizes[i] < j) // windows allocator friendly!
  48. if ((rand() % 4) != 3 && _sizes[i] < j) // really messes up windows allocator
  49. {
  50. _allocated[i] = _allocator.reallocate(_allocated[i], j);
  51. _check_buf(_allocated[i], _sizes[i]);
  52. _set_buf(_allocated[i], j);
  53. _sizes[i] = j;
  54. }
  55. }
  56. }
  57. #endif
  58. #if 0
  59. // test erase (shrinking the buffers)
  60. // ---------------------------------------------
  61. for (uint32_t j=28; j>4; j -= 2)
  62. {
  63. for (size_t i=0; i<_num_alloc; ++i)
  64. {
  65. // if ( _sizes[i] < j) // windows allocator friendly!
  66. if ((rand() % 4) != 3 && _sizes[i] > j) // really messes up windows allocator
  67. {
  68. _allocated[i] = _allocator.reallocate(_allocated[i], j);
  69. _check_buf1(_allocated[i], _sizes[i]);
  70. _set_buf(_allocated[i], j);
  71. _sizes[i] = j;
  72. }
  73. }
  74. }
  75. #endif
  76. #if 0
  77. // and grow the buffers back to a max size of 24 each
  78. // --------------------------------------------------
  79. for (uint32_t j=4; j<26; j += 2)
  80. {
  81. for (size_t i=0; i<_num_alloc; ++i)
  82. {
  83. // if ( _sizes[i] < j) // windows allocator friendly!
  84. if ((rand() % 4) != 3 && _sizes[i] < j) // really messes up windows allocator
  85. {
  86. _allocated[i] = _allocator.reallocate(_allocated[i], j);
  87. _check_buf(_allocated[i], _sizes[i]);
  88. _set_buf(_allocated[i], j);
  89. _sizes[i] = j;
  90. }
  91. }
  92. }
  93. #endif
  94. size_t total_units = 0;
  95. for (size_t i=0; i<_num_alloc; ++i)
  96. total_units += _sizes[i];
  97. uint64_t mem_usage = spp::GetProcessMemoryUsed();
  98. uint64_t alloc_mem_usage = mem_usage - _start_mem_usage;
  99. uint64_t expected_mem_usage = total_units * sizeof(T);
  100. // finally free the memory
  101. // -----------------------
  102. for (size_t i=0; i<_num_alloc; ++i)
  103. {
  104. _check_buf(_allocated[i], _sizes[i]);
  105. _allocator.deallocate(_allocated[i], _sizes[i]);
  106. }
  107. uint64_t mem_usage_end = spp::GetProcessMemoryUsed();
  108. printf("allocated %zd entities of size %zd\n", total_units, sizeof(T));
  109. printf("done in %3.2f seconds, mem_usage %4.1f/%4.1f/%4.1f MB\n",
  110. timer.get_total() / 1000, _to_mb(_start_mem_usage), _to_mb(mem_usage), _to_mb(mem_usage_end));
  111. printf("expected mem usage: %4.1f\n", _to_mb(expected_mem_usage));
  112. if (expected_mem_usage <= alloc_mem_usage)
  113. printf("overhead: %4.1f%%\n",
  114. (float)((double)(alloc_mem_usage - expected_mem_usage) / expected_mem_usage) * 100);
  115. else
  116. printf("bug: alloc_mem_usage <= expected_mem_usage\n");
  117. std::vector<T *>().swap(_allocated);
  118. std::vector<uint32_t>().swap(_sizes);
  119. printf("\nmem usage after freeing vectors: %4.1f\n", _to_mb(spp::GetProcessMemoryUsed()));
  120. }
  121. private:
  122. void _set_buf(T *buff, uint32_t sz) { *buff = (T)sz; buff[sz - 1] = (T)sz; }
  123. void _check_buf1(T *buff, uint32_t sz)
  124. {
  125. assert(*buff == (T)sz);
  126. (void)(buff + sz); // silence warning
  127. }
  128. void _check_buf(T *buff, uint32_t sz)
  129. {
  130. assert(*buff == (T)sz && buff[sz - 1] == (T)sz);
  131. (void)(buff + sz); // silence warning
  132. }
  133. size_t _num_alloc;
  134. uint64_t _start_mem_usage;
  135. std::vector<T *> _allocated;
  136. std::vector<uint32_t> _sizes;
  137. A _allocator;
  138. };
  139. // -----------------------------------------------------------
  140. // -----------------------------------------------------------
  141. template <class X, class A>
  142. void run_test(const char *alloc_name)
  143. {
  144. printf("\n---------------- testing %s\n\n", alloc_name);
  145. printf("\nmem usage before the alloc test: %4.1f\n",
  146. _to_mb(spp::GetProcessMemoryUsed()));
  147. {
  148. TestAlloc< X, A > test_alloc;
  149. test_alloc.run();
  150. }
  151. printf("mem usage after the alloc test: %4.1f\n",
  152. _to_mb(spp::GetProcessMemoryUsed()));
  153. printf("\n\n");
  154. }
  155. // -----------------------------------------------------------
  156. // -----------------------------------------------------------
  157. int main()
  158. {
  159. typedef uint64_t X;
  160. run_test<X, spp::libc_allocator<X>>("libc_allocator");
  161. run_test<X, spp::spp_allocator<X>>("spp_allocator");
  162. }