123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- /*
- * Copyright (C) 2015 Pavel Kirienko <pavel.kirienko@gmail.com>
- */
- #include <gtest/gtest.h>
- #include <uavcan/helpers/heap_based_pool_allocator.hpp>
- #include <malloc.h>
- TEST(HeapBasedPoolAllocator, Basic)
- {
- std::cout << ">>> HEAP BEFORE:" << std::endl;
- malloc_stats();
- uavcan::HeapBasedPoolAllocator<uavcan::MemPoolBlockSize> al(0xEEEE);
- ASSERT_EQ(0, al.getNumReservedBlocks());
- ASSERT_EQ(0, al.getNumAllocatedBlocks());
- ASSERT_EQ(0xEEEE, al.getBlockCapacity());
- ASSERT_EQ(0xFFFF, al.getBlockCapacityHardLimit());
- void* a = al.allocate(10);
- void* b = al.allocate(10);
- void* c = al.allocate(10);
- void* d = al.allocate(10);
- ASSERT_EQ(4, al.getNumReservedBlocks());
- ASSERT_EQ(4, al.getNumAllocatedBlocks());
- al.deallocate(a);
- ASSERT_EQ(4, al.getNumReservedBlocks());
- ASSERT_EQ(3, al.getNumAllocatedBlocks());
- al.deallocate(b);
- ASSERT_EQ(4, al.getNumReservedBlocks());
- ASSERT_EQ(2, al.getNumAllocatedBlocks());
- al.deallocate(c);
- ASSERT_EQ(4, al.getNumReservedBlocks());
- ASSERT_EQ(1, al.getNumAllocatedBlocks());
- a = al.allocate(10);
- ASSERT_EQ(4, al.getNumReservedBlocks());
- ASSERT_EQ(2, al.getNumAllocatedBlocks());
- ASSERT_EQ(c, a);
- al.deallocate(a);
- ASSERT_EQ(4, al.getNumReservedBlocks());
- ASSERT_EQ(1, al.getNumAllocatedBlocks());
- al.shrink();
- ASSERT_EQ(1, al.getNumReservedBlocks());
- ASSERT_EQ(1, al.getNumAllocatedBlocks());
- al.deallocate(d);
- ASSERT_EQ(1, al.getNumReservedBlocks());
- ASSERT_EQ(0, al.getNumAllocatedBlocks());
- al.shrink();
- ASSERT_EQ(0, al.getNumReservedBlocks());
- ASSERT_EQ(0, al.getNumAllocatedBlocks());
- std::cout << ">>> HEAP AFTER:" << std::endl;
- malloc_stats();
- }
- TEST(HeapBasedPoolAllocator, Limits)
- {
- uavcan::HeapBasedPoolAllocator<uavcan::MemPoolBlockSize> al(2);
- ASSERT_EQ(2, al.getBlockCapacity());
- ASSERT_EQ(4, al.getBlockCapacityHardLimit());
- ASSERT_EQ(0, al.getNumReservedBlocks());
- ASSERT_EQ(0, al.getNumAllocatedBlocks());
- void* a = al.allocate(10);
- void* b = al.allocate(10);
- void* c = al.allocate(10);
- void* d = al.allocate(10);
- ASSERT_TRUE(a);
- ASSERT_TRUE(b);
- ASSERT_TRUE(c);
- ASSERT_TRUE(d);
- ASSERT_FALSE(al.allocate(10));
- ASSERT_EQ(4, al.getNumReservedBlocks());
- ASSERT_EQ(4, al.getNumAllocatedBlocks());
- al.deallocate(a);
- al.deallocate(b);
- al.deallocate(c);
- al.deallocate(d);
- ASSERT_EQ(4, al.getNumReservedBlocks());
- ASSERT_EQ(0, al.getNumAllocatedBlocks());
- }
- #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
- #include <thread>
- #include <mutex>
- struct RaiiSynchronizer
- {
- static std::mutex mutex;
- std::lock_guard<std::mutex> guard{mutex};
- };
- std::mutex RaiiSynchronizer::mutex;
- TEST(HeapBasedPoolAllocator, Concurrency)
- {
- std::cout << ">>> HEAP BEFORE:" << std::endl;
- malloc_stats();
- uavcan::HeapBasedPoolAllocator<uavcan::MemPoolBlockSize, RaiiSynchronizer> al(1000);
- ASSERT_EQ(1000, al.getBlockCapacity());
- ASSERT_EQ(2000, al.getBlockCapacityHardLimit());
- volatile bool terminate = false;
- /*
- * Starting the testing threads
- */
- std::thread threads[3];
- for (auto& x : threads)
- {
- x = std::thread([&al, &terminate]()
- {
- while (!terminate)
- {
- auto a = al.allocate(1);
- auto b = al.allocate(1);
- auto c = al.allocate(1);
- al.deallocate(al.allocate(1));
- al.deallocate(a);
- al.deallocate(b);
- al.deallocate(c);
- }
- });
- }
- /*
- * Running the threads for some time, then terminating
- */
- std::this_thread::sleep_for(std::chrono::seconds(1));
- terminate = true;
- std::cout << "Terminating workers..." << std::endl;
- for (auto& x : threads)
- {
- x.join();
- }
- std::cout << "All workers joined" << std::endl;
- /*
- * Now, there must not be any leaked memory, because the worker threads deallocate everything before completion.
- */
- std::cout << "Allocated: " << al.getNumAllocatedBlocks() << std::endl;
- std::cout << "Reserved: " << al.getNumReservedBlocks() << std::endl;
- std::cout << ">>> HEAP BEFORE SHRINK:" << std::endl;
- malloc_stats();
- al.shrink();
- std::cout << ">>> HEAP AFTER SHRINK:" << std::endl;
- malloc_stats();
- }
- #endif
|