LCOV - code coverage report
Current view: top level - src/test - allocator_tests.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 153 153 100.0 %
Date: 2022-04-21 14:51:19 Functions: 7 7 100.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 28 28 100.0 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2012-2021 The Bitcoin Core developers
#       2                 :            : // Distributed under the MIT software license, see the accompanying
#       3                 :            : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#       4                 :            : 
#       5                 :            : #include <support/lockedpool.h>
#       6                 :            : #include <util/system.h>
#       7                 :            : 
#       8                 :            : #include <limits>
#       9                 :            : #include <memory>
#      10                 :            : #include <stdexcept>
#      11                 :            : #include <utility>
#      12                 :            : #include <vector>
#      13                 :            : 
#      14                 :            : #include <boost/test/unit_test.hpp>
#      15                 :            : 
#      16                 :            : BOOST_AUTO_TEST_SUITE(allocator_tests)
#      17                 :            : 
#      18                 :            : BOOST_AUTO_TEST_CASE(arena_tests)
#      19                 :          2 : {
#      20                 :            :     // Fake memory base address for testing
#      21                 :            :     // without actually using memory.
#      22                 :          2 :     void *synth_base = reinterpret_cast<void*>(0x08000000);
#      23                 :          2 :     const size_t synth_size = 1024*1024;
#      24                 :          2 :     Arena b(synth_base, synth_size, 16);
#      25                 :          2 :     void *chunk = b.alloc(1000);
#      26                 :            : #ifdef ARENA_DEBUG
#      27                 :            :     b.walk();
#      28                 :            : #endif
#      29                 :          2 :     BOOST_CHECK(chunk != nullptr);
#      30                 :          2 :     BOOST_CHECK(b.stats().used == 1008); // Aligned to 16
#      31                 :          2 :     BOOST_CHECK(b.stats().total == synth_size); // Nothing has disappeared?
#      32                 :          2 :     b.free(chunk);
#      33                 :            : #ifdef ARENA_DEBUG
#      34                 :            :     b.walk();
#      35                 :            : #endif
#      36                 :          2 :     BOOST_CHECK(b.stats().used == 0);
#      37                 :          2 :     BOOST_CHECK(b.stats().free == synth_size);
#      38                 :          2 :     try { // Test exception on double-free
#      39                 :          2 :         b.free(chunk);
#      40                 :          2 :         BOOST_CHECK(0);
#      41                 :          2 :     } catch(std::runtime_error &)
#      42                 :          2 :     {
#      43                 :          2 :     }
#      44                 :            : 
#      45                 :          2 :     void *a0 = b.alloc(128);
#      46                 :          2 :     void *a1 = b.alloc(256);
#      47                 :          2 :     void *a2 = b.alloc(512);
#      48                 :          2 :     BOOST_CHECK(b.stats().used == 896);
#      49                 :          2 :     BOOST_CHECK(b.stats().total == synth_size);
#      50                 :            : #ifdef ARENA_DEBUG
#      51                 :            :     b.walk();
#      52                 :            : #endif
#      53                 :          2 :     b.free(a0);
#      54                 :            : #ifdef ARENA_DEBUG
#      55                 :            :     b.walk();
#      56                 :            : #endif
#      57                 :          2 :     BOOST_CHECK(b.stats().used == 768);
#      58                 :          2 :     b.free(a1);
#      59                 :          2 :     BOOST_CHECK(b.stats().used == 512);
#      60                 :          2 :     void *a3 = b.alloc(128);
#      61                 :            : #ifdef ARENA_DEBUG
#      62                 :            :     b.walk();
#      63                 :            : #endif
#      64                 :          2 :     BOOST_CHECK(b.stats().used == 640);
#      65                 :          2 :     b.free(a2);
#      66                 :          2 :     BOOST_CHECK(b.stats().used == 128);
#      67                 :          2 :     b.free(a3);
#      68                 :          2 :     BOOST_CHECK(b.stats().used == 0);
#      69                 :          2 :     BOOST_CHECK_EQUAL(b.stats().chunks_used, 0U);
#      70                 :          2 :     BOOST_CHECK(b.stats().total == synth_size);
#      71                 :          2 :     BOOST_CHECK(b.stats().free == synth_size);
#      72                 :          2 :     BOOST_CHECK_EQUAL(b.stats().chunks_free, 1U);
#      73                 :            : 
#      74                 :          2 :     std::vector<void*> addr;
#      75                 :          2 :     BOOST_CHECK(b.alloc(0) == nullptr); // allocating 0 always returns nullptr
#      76                 :            : #ifdef ARENA_DEBUG
#      77                 :            :     b.walk();
#      78                 :            : #endif
#      79                 :            :     // Sweeping allocate all memory
#      80         [ +  + ]:       2050 :     for (int x=0; x<1024; ++x)
#      81                 :       2048 :         addr.push_back(b.alloc(1024));
#      82                 :          2 :     BOOST_CHECK(b.stats().free == 0);
#      83                 :          2 :     BOOST_CHECK(b.alloc(1024) == nullptr); // memory is full, this must return nullptr
#      84                 :          2 :     BOOST_CHECK(b.alloc(0) == nullptr);
#      85         [ +  + ]:       2050 :     for (int x=0; x<1024; ++x)
#      86                 :       2048 :         b.free(addr[x]);
#      87                 :          2 :     addr.clear();
#      88                 :          2 :     BOOST_CHECK(b.stats().total == synth_size);
#      89                 :          2 :     BOOST_CHECK(b.stats().free == synth_size);
#      90                 :            : 
#      91                 :            :     // Now in the other direction...
#      92         [ +  + ]:       2050 :     for (int x=0; x<1024; ++x)
#      93                 :       2048 :         addr.push_back(b.alloc(1024));
#      94         [ +  + ]:       2050 :     for (int x=0; x<1024; ++x)
#      95                 :       2048 :         b.free(addr[1023-x]);
#      96                 :          2 :     addr.clear();
#      97                 :            : 
#      98                 :            :     // Now allocate in smaller unequal chunks, then deallocate haphazardly
#      99                 :            :     // Not all the chunks will succeed allocating, but freeing nullptr is
#     100                 :            :     // allowed so that is no problem.
#     101         [ +  + ]:       4098 :     for (int x=0; x<2048; ++x)
#     102                 :       4096 :         addr.push_back(b.alloc(x+1));
#     103         [ +  + ]:       4098 :     for (int x=0; x<2048; ++x)
#     104                 :       4096 :         b.free(addr[((x*23)%2048)^242]);
#     105                 :          2 :     addr.clear();
#     106                 :            : 
#     107                 :            :     // Go entirely wild: free and alloc interleaved,
#     108                 :            :     // generate targets and sizes using pseudo-randomness.
#     109         [ +  + ]:       4098 :     for (int x=0; x<2048; ++x)
#     110                 :       4096 :         addr.push_back(nullptr);
#     111                 :          2 :     uint32_t s = 0x12345678;
#     112         [ +  + ]:      10002 :     for (int x=0; x<5000; ++x) {
#     113                 :      10000 :         int idx = s & (addr.size()-1);
#     114         [ +  + ]:      10000 :         if (s & 0x80000000) {
#     115                 :       4916 :             b.free(addr[idx]);
#     116                 :       4916 :             addr[idx] = nullptr;
#     117         [ +  + ]:       5084 :         } else if(!addr[idx]) {
#     118                 :       3482 :             addr[idx] = b.alloc((s >> 16) & 2047);
#     119                 :       3482 :         }
#     120                 :      10000 :         bool lsb = s & 1;
#     121                 :      10000 :         s >>= 1;
#     122         [ +  + ]:      10000 :         if (lsb)
#     123                 :       4916 :             s ^= 0xf00f00f0; // LFSR period 0xf7ffffe0
#     124                 :      10000 :     }
#     125         [ +  + ]:          2 :     for (void *ptr: addr)
#     126                 :       4096 :         b.free(ptr);
#     127                 :          2 :     addr.clear();
#     128                 :            : 
#     129                 :          2 :     BOOST_CHECK(b.stats().total == synth_size);
#     130                 :          2 :     BOOST_CHECK(b.stats().free == synth_size);
#     131                 :          2 : }
#     132                 :            : 
#     133                 :            : /** Mock LockedPageAllocator for testing */
#     134                 :            : class TestLockedPageAllocator: public LockedPageAllocator
#     135                 :            : {
#     136                 :            : public:
#     137                 :          2 :     TestLockedPageAllocator(int count_in, int lockedcount_in): count(count_in), lockedcount(lockedcount_in) {}
#     138                 :            :     void* AllocateLocked(size_t len, bool *lockingSuccess) override
#     139                 :          8 :     {
#     140                 :          8 :         *lockingSuccess = false;
#     141         [ +  + ]:          8 :         if (count > 0) {
#     142                 :          6 :             --count;
#     143                 :            : 
#     144         [ +  + ]:          6 :             if (lockedcount > 0) {
#     145                 :          2 :                 --lockedcount;
#     146                 :          2 :                 *lockingSuccess = true;
#     147                 :          2 :             }
#     148                 :            : 
#     149                 :          6 :             return reinterpret_cast<void*>(uint64_t{static_cast<uint64_t>(0x08000000) + (count << 24)}); // Fake address, do not actually use this memory
#     150                 :          6 :         }
#     151                 :          2 :         return nullptr;
#     152                 :          8 :     }
#     153                 :            :     void FreeLocked(void* addr, size_t len) override
#     154                 :          6 :     {
#     155                 :          6 :     }
#     156                 :            :     size_t GetLimit() override
#     157                 :          2 :     {
#     158                 :          2 :         return std::numeric_limits<size_t>::max();
#     159                 :          2 :     }
#     160                 :            : private:
#     161                 :            :     int count;
#     162                 :            :     int lockedcount;
#     163                 :            : };
#     164                 :            : 
#     165                 :            : BOOST_AUTO_TEST_CASE(lockedpool_tests_mock)
#     166                 :          2 : {
#     167                 :            :     // Test over three virtual arenas, of which one will succeed being locked
#     168                 :          2 :     std::unique_ptr<LockedPageAllocator> x = std::make_unique<TestLockedPageAllocator>(3, 1);
#     169                 :          2 :     LockedPool pool(std::move(x));
#     170                 :          2 :     BOOST_CHECK(pool.stats().total == 0);
#     171                 :          2 :     BOOST_CHECK(pool.stats().locked == 0);
#     172                 :            : 
#     173                 :            :     // Ensure unreasonable requests are refused without allocating anything
#     174                 :          2 :     void *invalid_toosmall = pool.alloc(0);
#     175                 :          2 :     BOOST_CHECK(invalid_toosmall == nullptr);
#     176                 :          2 :     BOOST_CHECK(pool.stats().used == 0);
#     177                 :          2 :     BOOST_CHECK(pool.stats().free == 0);
#     178                 :          2 :     void *invalid_toobig = pool.alloc(LockedPool::ARENA_SIZE+1);
#     179                 :          2 :     BOOST_CHECK(invalid_toobig == nullptr);
#     180                 :          2 :     BOOST_CHECK(pool.stats().used == 0);
#     181                 :          2 :     BOOST_CHECK(pool.stats().free == 0);
#     182                 :            : 
#     183                 :          2 :     void *a0 = pool.alloc(LockedPool::ARENA_SIZE / 2);
#     184                 :          2 :     BOOST_CHECK(a0);
#     185                 :          2 :     BOOST_CHECK(pool.stats().locked == LockedPool::ARENA_SIZE);
#     186                 :          2 :     void *a1 = pool.alloc(LockedPool::ARENA_SIZE / 2);
#     187                 :          2 :     BOOST_CHECK(a1);
#     188                 :          2 :     void *a2 = pool.alloc(LockedPool::ARENA_SIZE / 2);
#     189                 :          2 :     BOOST_CHECK(a2);
#     190                 :          2 :     void *a3 = pool.alloc(LockedPool::ARENA_SIZE / 2);
#     191                 :          2 :     BOOST_CHECK(a3);
#     192                 :          2 :     void *a4 = pool.alloc(LockedPool::ARENA_SIZE / 2);
#     193                 :          2 :     BOOST_CHECK(a4);
#     194                 :          2 :     void *a5 = pool.alloc(LockedPool::ARENA_SIZE / 2);
#     195                 :          2 :     BOOST_CHECK(a5);
#     196                 :            :     // We've passed a count of three arenas, so this allocation should fail
#     197                 :          2 :     void *a6 = pool.alloc(16);
#     198                 :          2 :     BOOST_CHECK(!a6);
#     199                 :            : 
#     200                 :          2 :     pool.free(a0);
#     201                 :          2 :     pool.free(a2);
#     202                 :          2 :     pool.free(a4);
#     203                 :          2 :     pool.free(a1);
#     204                 :          2 :     pool.free(a3);
#     205                 :          2 :     pool.free(a5);
#     206                 :          2 :     BOOST_CHECK(pool.stats().total == 3*LockedPool::ARENA_SIZE);
#     207                 :          2 :     BOOST_CHECK(pool.stats().locked == LockedPool::ARENA_SIZE);
#     208                 :          2 :     BOOST_CHECK(pool.stats().used == 0);
#     209                 :          2 : }
#     210                 :            : 
#     211                 :            : // These tests used the live LockedPoolManager object, this is also used
#     212                 :            : // by other tests so the conditions are somewhat less controllable and thus the
#     213                 :            : // tests are somewhat more error-prone.
#     214                 :            : BOOST_AUTO_TEST_CASE(lockedpool_tests_live)
#     215                 :          2 : {
#     216                 :          2 :     LockedPoolManager &pool = LockedPoolManager::Instance();
#     217                 :          2 :     LockedPool::Stats initial = pool.stats();
#     218                 :            : 
#     219                 :          2 :     void *a0 = pool.alloc(16);
#     220                 :          2 :     BOOST_CHECK(a0);
#     221                 :            :     // Test reading and writing the allocated memory
#     222                 :          2 :     *((uint32_t*)a0) = 0x1234;
#     223                 :          2 :     BOOST_CHECK(*((uint32_t*)a0) == 0x1234);
#     224                 :            : 
#     225                 :          2 :     pool.free(a0);
#     226                 :          2 :     try { // Test exception on double-free
#     227                 :          2 :         pool.free(a0);
#     228                 :          2 :         BOOST_CHECK(0);
#     229                 :          2 :     } catch(std::runtime_error &)
#     230                 :          2 :     {
#     231                 :          2 :     }
#     232                 :            :     // If more than one new arena was allocated for the above tests, something is wrong
#     233                 :          2 :     BOOST_CHECK(pool.stats().total <= (initial.total + LockedPool::ARENA_SIZE));
#     234                 :            :     // Usage must be back to where it started
#     235                 :          2 :     BOOST_CHECK(pool.stats().used == initial.used);
#     236                 :          2 : }
#     237                 :            : 
#     238                 :            : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a