libuav original
Dependents: UAVCAN UAVCAN_Subscriber
heap_based_pool_allocator.cpp
00001 /* 00002 * Copyright (C) 2015 Pavel Kirienko <pavel.kirienko@gmail.com> 00003 */ 00004 00005 #include <gtest/gtest.h> 00006 #include <uavcan/helpers/heap_based_pool_allocator.hpp> 00007 #include <malloc.h> 00008 00009 00010 TEST(HeapBasedPoolAllocator, Basic) 00011 { 00012 std::cout << ">>> HEAP BEFORE:" << std::endl; 00013 malloc_stats(); 00014 00015 uavcan::HeapBasedPoolAllocator<uavcan::MemPoolBlockSize> al(0xEEEE); 00016 00017 ASSERT_EQ(0, al.getNumReservedBlocks()); 00018 ASSERT_EQ(0, al.getNumAllocatedBlocks()); 00019 00020 ASSERT_EQ(0xEEEE, al.getBlockCapacity()); 00021 ASSERT_EQ(0xFFFF, al.getBlockCapacityHardLimit()); 00022 00023 void* a = al.allocate(10); 00024 void* b = al.allocate(10); 00025 void* c = al.allocate(10); 00026 void* d = al.allocate(10); 00027 00028 ASSERT_EQ(4, al.getNumReservedBlocks()); 00029 ASSERT_EQ(4, al.getNumAllocatedBlocks()); 00030 00031 al.deallocate(a); 00032 ASSERT_EQ(4, al.getNumReservedBlocks()); 00033 ASSERT_EQ(3, al.getNumAllocatedBlocks()); 00034 00035 al.deallocate(b); 00036 ASSERT_EQ(4, al.getNumReservedBlocks()); 00037 ASSERT_EQ(2, al.getNumAllocatedBlocks()); 00038 00039 al.deallocate(c); 00040 ASSERT_EQ(4, al.getNumReservedBlocks()); 00041 ASSERT_EQ(1, al.getNumAllocatedBlocks()); 00042 00043 a = al.allocate(10); 00044 ASSERT_EQ(4, al.getNumReservedBlocks()); 00045 ASSERT_EQ(2, al.getNumAllocatedBlocks()); 00046 ASSERT_EQ(c, a); 00047 00048 al.deallocate(a); 00049 ASSERT_EQ(4, al.getNumReservedBlocks()); 00050 ASSERT_EQ(1, al.getNumAllocatedBlocks()); 00051 00052 al.shrink(); 00053 ASSERT_EQ(1, al.getNumReservedBlocks()); 00054 ASSERT_EQ(1, al.getNumAllocatedBlocks()); 00055 00056 al.deallocate(d); 00057 ASSERT_EQ(1, al.getNumReservedBlocks()); 00058 ASSERT_EQ(0, al.getNumAllocatedBlocks()); 00059 00060 al.shrink(); 00061 ASSERT_EQ(0, al.getNumReservedBlocks()); 00062 ASSERT_EQ(0, al.getNumAllocatedBlocks()); 00063 00064 std::cout << ">>> HEAP AFTER:" << std::endl; 00065 malloc_stats(); 00066 } 00067 00068 00069 TEST(HeapBasedPoolAllocator, Limits) 00070 { 00071 uavcan::HeapBasedPoolAllocator<uavcan::MemPoolBlockSize> al(2); 00072 00073 ASSERT_EQ(2, al.getBlockCapacity()); 00074 ASSERT_EQ(4, al.getBlockCapacityHardLimit()); 00075 00076 ASSERT_EQ(0, al.getNumReservedBlocks()); 00077 ASSERT_EQ(0, al.getNumAllocatedBlocks()); 00078 00079 void* a = al.allocate(10); 00080 void* b = al.allocate(10); 00081 void* c = al.allocate(10); 00082 void* d = al.allocate(10); 00083 00084 ASSERT_TRUE(a); 00085 ASSERT_TRUE(b); 00086 ASSERT_TRUE(c); 00087 ASSERT_TRUE(d); 00088 00089 ASSERT_FALSE(al.allocate(10)); 00090 00091 ASSERT_EQ(4, al.getNumReservedBlocks()); 00092 ASSERT_EQ(4, al.getNumAllocatedBlocks()); 00093 00094 al.deallocate(a); 00095 al.deallocate(b); 00096 al.deallocate(c); 00097 al.deallocate(d); 00098 00099 ASSERT_EQ(4, al.getNumReservedBlocks()); 00100 ASSERT_EQ(0, al.getNumAllocatedBlocks()); 00101 } 00102 00103 #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11 00104 00105 #include <thread> 00106 #include <mutex> 00107 00108 struct RaiiSynchronizer 00109 { 00110 static std::mutex mutex; 00111 std::lock_guard<std::mutex> guard{mutex}; 00112 }; 00113 00114 std::mutex RaiiSynchronizer::mutex; 00115 00116 TEST(HeapBasedPoolAllocator, Concurrency) 00117 { 00118 std::cout << ">>> HEAP BEFORE:" << std::endl; 00119 malloc_stats(); 00120 00121 uavcan::HeapBasedPoolAllocator<uavcan::MemPoolBlockSize, RaiiSynchronizer> al(1000); 00122 00123 ASSERT_EQ(1000, al.getBlockCapacity()); 00124 ASSERT_EQ(2000, al.getBlockCapacityHardLimit()); 00125 00126 volatile bool terminate = false; 00127 00128 /* 00129 * Starting the testing threads 00130 */ 00131 std::thread threads[3]; 00132 00133 for (auto& x : threads) 00134 { 00135 x = std::thread([&al, &terminate]() 00136 { 00137 while (!terminate) 00138 { 00139 auto a = al.allocate(1); 00140 auto b = al.allocate(1); 00141 auto c = al.allocate(1); 00142 al.deallocate(al.allocate(1)); 00143 al.deallocate(a); 00144 al.deallocate(b); 00145 al.deallocate(c); 00146 } 00147 }); 00148 } 00149 00150 /* 00151 * Running the threads for some time, then terminating 00152 */ 00153 std::this_thread::sleep_for(std::chrono::seconds(1)); 00154 00155 terminate = true; 00156 std::cout << "Terminating workers..." << std::endl; 00157 00158 for (auto& x : threads) 00159 { 00160 x.join(); 00161 } 00162 std::cout << "All workers joined" << std::endl; 00163 00164 /* 00165 * Now, there must not be any leaked memory, because the worker threads deallocate everything before completion. 00166 */ 00167 std::cout << "Allocated: " << al.getNumAllocatedBlocks() << std::endl; 00168 std::cout << "Reserved: " << al.getNumReservedBlocks() << std::endl; 00169 00170 std::cout << ">>> HEAP BEFORE SHRINK:" << std::endl; 00171 malloc_stats(); 00172 00173 al.shrink(); 00174 00175 std::cout << ">>> HEAP AFTER SHRINK:" << std::endl; 00176 malloc_stats(); 00177 } 00178 00179 #endif
Generated on Tue Jul 12 2022 17:17:32 by 1.7.2