lumiera_documentation/tests/vault/mem/local-mem-pool-test.cpp
Ichthyostega 5fafb16807 BufferProvider: decide to use only a simple heuristics for reservation
At the begin of each Render Node `pull()`, the render job is expected
to ''announce'' a maximum expected allocation requirement to the `BufferProvider`,
which information is passed-on to the `LocalMemPool` to determine
to which degree it can be satisfied with allocations from that local pool.

Without actual empiric observation, it is impossible to determine
the relevance of this step, how it should be resolved heuristically
against the known contents of the pool, and how much effort to spend
on that step.

Thus I'll settle for the ''simplest thing that can possibly work'' —
which is to check only for close matches and rather rely on additional
allocations, forwarded asynchronously, assuming that the clean-up
heuristics will deal with excess allocations quickly.
2026-04-27 00:25:10 +02:00

181 lines
4.7 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
LocalMemPool(Test) - verify low-level handling of buffer blocks in a local pool
Copyright (C)
2026, Hermann Vosseler <Ichthyostega@web.de>
  **Lumiera** is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2 of the License, or (at your
  option) any later version. See the file COPYING for further details.
* *****************************************************************/
/** @file local-mem-pool-test.cpp
** unit test \ref LocalMemPool_test
*/
#include "test/run.hpp"
#include "test/test-helper.hpp"
//#include "vault/mem/engine-buffer-metadata.hpp"
#include "vault/mem/local-mem-pool.hpp"
#include "lib/iter-stack.hpp"
//#include "lib/depend-inject.hpp"
//#include "lib/thread.hpp"
//#include "lib/error.hpp"
#include "lib/format-util.hpp"
#include "test/diagnostic-output.hpp"
//using std::this_thread::yield;
//using lib::Thread;
using util::join;
namespace vault {
namespace mem {
namespace test {
// using LERR_(LOGIC);
// using LERR_(LIFECYCLE);
namespace { // Test helper
inline constexpr Buff*
fake_Buffer(size_t id)
{
return reinterpret_cast<Buff*> (id);
}
Buff* const MEM1 = fake_Buffer(1);
Buff* const MEM2 = fake_Buffer(2);
Buff* const MEM3 = fake_Buffer(3);
const size_t SIZ10{10};
const size_t SIZ20{20};
const size_t SIZ30{30};
}
/**********************************************************************//**
* @test verify handling of prospective buffer allocations in a local pool.
*/
class LocalMemPool_test : public Test
{
virtual void
run (Arg)
{
seedRand();
simpleUse();
verify_matchAlloc();
verify_selectAlloc();
verify_pruneAlloc();
}
/** @test show how to place an allocation into the pool */
void
simpleUse()
{
LocalMemPool pool;
pool.add (MEM1, SIZ20);
CHECK (pool.canServe(SIZ20));
CHECK (pool.canServe(SIZ10));
auto [mem,siz] = pool.retrieve (SIZ10);
CHECK (MEM1 == mem);
CHECK (SIZ20 == siz);
CHECK (not pool.canServe(SIZ10));
pool.reAdd (MEM1);
CHECK (pool.canServe(SIZ20));
}
/** @test allocations are accounted by size
*/
void
verify_matchAlloc()
{
LocalMemPool pool;
CHECK (watch(pool).isEmpty());
pool.add (MEM1, SIZ10);
CHECK (watch(pool).cnt(SIZ10) == 0); // new allotment not ingested yet,....
CHECK (not watch(pool).isEmpty()); // however, there is an entry in the in-queue
CHECK (pool.canServe(SIZ10)); // query causes a scan and retrieval from the in-queu
CHECK (watch(pool).cnt(SIZ10) == 1);
CHECK (not watch(pool).isEmpty());
pool.add (MEM2, SIZ20);
pool.add (MEM3, SIZ30);
CHECK (pool.canServe(SIZ20));
CHECK (pool.canServe(SIZ10));
CHECK (watch(pool).size() == 3);
CHECK (watch(pool).cnt(SIZ10) == 1);
CHECK (watch(pool).cnt(SIZ20) == 1);
CHECK (watch(pool).cnt(SIZ30) == 1);
CHECK (watch(pool).cntFree() == 3);
auto [m1,s1] = pool.retrieve (SIZ20 -2);
CHECK (SIZ20 == s1);
CHECK (MEM2 == m1);
CHECK (watch(pool).cntFree() == 2);
auto [m2,s2] = pool.retrieve (SIZ10);
CHECK (SIZ10 == s2);
CHECK (MEM1 == m2);
CHECK (watch(pool).size() == 3);
CHECK (watch(pool).cntFree() == 1);
CHECK (pool.canServe(SIZ10));
CHECK (pool.canServe(SIZ20));
CHECK (pool.canServe(SIZ30));
pool.reAdd (m2);
pool.reAdd (m1);
CHECK (watch(pool).cntFree() == 3);
lib::IterQueue<size_t> returned;
uint cnt = pool.cleanup(0.5
,[&](auto, size_t siz){ returned.feed (siz);});
CHECK (cnt == 1);
CHECK (join(returned) == "30"_expect);
CHECK (watch(pool).cntFree() == 2);
CHECK (watch(pool).size() == 2);
}
/** @test
*/
void
verify_selectAlloc()
{
}
/** @test
*/
void
verify_pruneAlloc()
{
}
};
/** Register this test class... */
LAUNCHER (LocalMemPool_test, "unit engine");
}}} // namespace vault::mem::test