heap_based_pool_allocator.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * Copyright (C) 2015 Pavel Kirienko <pavel.kirienko@gmail.com>
  3. */
  4. #include <gtest/gtest.h>
  5. #include <uavcan/helpers/heap_based_pool_allocator.hpp>
  6. #include <malloc.h>
  7. TEST(HeapBasedPoolAllocator, Basic)
  8. {
  9. std::cout << ">>> HEAP BEFORE:" << std::endl;
  10. malloc_stats();
  11. uavcan::HeapBasedPoolAllocator<uavcan::MemPoolBlockSize> al(0xEEEE);
  12. ASSERT_EQ(0, al.getNumReservedBlocks());
  13. ASSERT_EQ(0, al.getNumAllocatedBlocks());
  14. ASSERT_EQ(0xEEEE, al.getBlockCapacity());
  15. ASSERT_EQ(0xFFFF, al.getBlockCapacityHardLimit());
  16. void* a = al.allocate(10);
  17. void* b = al.allocate(10);
  18. void* c = al.allocate(10);
  19. void* d = al.allocate(10);
  20. ASSERT_EQ(4, al.getNumReservedBlocks());
  21. ASSERT_EQ(4, al.getNumAllocatedBlocks());
  22. al.deallocate(a);
  23. ASSERT_EQ(4, al.getNumReservedBlocks());
  24. ASSERT_EQ(3, al.getNumAllocatedBlocks());
  25. al.deallocate(b);
  26. ASSERT_EQ(4, al.getNumReservedBlocks());
  27. ASSERT_EQ(2, al.getNumAllocatedBlocks());
  28. al.deallocate(c);
  29. ASSERT_EQ(4, al.getNumReservedBlocks());
  30. ASSERT_EQ(1, al.getNumAllocatedBlocks());
  31. a = al.allocate(10);
  32. ASSERT_EQ(4, al.getNumReservedBlocks());
  33. ASSERT_EQ(2, al.getNumAllocatedBlocks());
  34. ASSERT_EQ(c, a);
  35. al.deallocate(a);
  36. ASSERT_EQ(4, al.getNumReservedBlocks());
  37. ASSERT_EQ(1, al.getNumAllocatedBlocks());
  38. al.shrink();
  39. ASSERT_EQ(1, al.getNumReservedBlocks());
  40. ASSERT_EQ(1, al.getNumAllocatedBlocks());
  41. al.deallocate(d);
  42. ASSERT_EQ(1, al.getNumReservedBlocks());
  43. ASSERT_EQ(0, al.getNumAllocatedBlocks());
  44. al.shrink();
  45. ASSERT_EQ(0, al.getNumReservedBlocks());
  46. ASSERT_EQ(0, al.getNumAllocatedBlocks());
  47. std::cout << ">>> HEAP AFTER:" << std::endl;
  48. malloc_stats();
  49. }
  50. TEST(HeapBasedPoolAllocator, Limits)
  51. {
  52. uavcan::HeapBasedPoolAllocator<uavcan::MemPoolBlockSize> al(2);
  53. ASSERT_EQ(2, al.getBlockCapacity());
  54. ASSERT_EQ(4, al.getBlockCapacityHardLimit());
  55. ASSERT_EQ(0, al.getNumReservedBlocks());
  56. ASSERT_EQ(0, al.getNumAllocatedBlocks());
  57. void* a = al.allocate(10);
  58. void* b = al.allocate(10);
  59. void* c = al.allocate(10);
  60. void* d = al.allocate(10);
  61. ASSERT_TRUE(a);
  62. ASSERT_TRUE(b);
  63. ASSERT_TRUE(c);
  64. ASSERT_TRUE(d);
  65. ASSERT_FALSE(al.allocate(10));
  66. ASSERT_EQ(4, al.getNumReservedBlocks());
  67. ASSERT_EQ(4, al.getNumAllocatedBlocks());
  68. al.deallocate(a);
  69. al.deallocate(b);
  70. al.deallocate(c);
  71. al.deallocate(d);
  72. ASSERT_EQ(4, al.getNumReservedBlocks());
  73. ASSERT_EQ(0, al.getNumAllocatedBlocks());
  74. }
  75. #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
  76. #include <thread>
  77. #include <mutex>
  78. struct RaiiSynchronizer
  79. {
  80. static std::mutex mutex;
  81. std::lock_guard<std::mutex> guard{mutex};
  82. };
  83. std::mutex RaiiSynchronizer::mutex;
  84. TEST(HeapBasedPoolAllocator, Concurrency)
  85. {
  86. std::cout << ">>> HEAP BEFORE:" << std::endl;
  87. malloc_stats();
  88. uavcan::HeapBasedPoolAllocator<uavcan::MemPoolBlockSize, RaiiSynchronizer> al(1000);
  89. ASSERT_EQ(1000, al.getBlockCapacity());
  90. ASSERT_EQ(2000, al.getBlockCapacityHardLimit());
  91. volatile bool terminate = false;
  92. /*
  93. * Starting the testing threads
  94. */
  95. std::thread threads[3];
  96. for (auto& x : threads)
  97. {
  98. x = std::thread([&al, &terminate]()
  99. {
  100. while (!terminate)
  101. {
  102. auto a = al.allocate(1);
  103. auto b = al.allocate(1);
  104. auto c = al.allocate(1);
  105. al.deallocate(al.allocate(1));
  106. al.deallocate(a);
  107. al.deallocate(b);
  108. al.deallocate(c);
  109. }
  110. });
  111. }
  112. /*
  113. * Running the threads for some time, then terminating
  114. */
  115. std::this_thread::sleep_for(std::chrono::seconds(1));
  116. terminate = true;
  117. std::cout << "Terminating workers..." << std::endl;
  118. for (auto& x : threads)
  119. {
  120. x.join();
  121. }
  122. std::cout << "All workers joined" << std::endl;
  123. /*
  124. * Now, there must not be any leaked memory, because the worker threads deallocate everything before completion.
  125. */
  126. std::cout << "Allocated: " << al.getNumAllocatedBlocks() << std::endl;
  127. std::cout << "Reserved: " << al.getNumReservedBlocks() << std::endl;
  128. std::cout << ">>> HEAP BEFORE SHRINK:" << std::endl;
  129. malloc_stats();
  130. al.shrink();
  131. std::cout << ">>> HEAP AFTER SHRINK:" << std::endl;
  132. malloc_stats();
  133. }
  134. #endif