libuav original

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers heap_based_pool_allocator.cpp Source File

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