LUMIERA.clone/tests/basics/typed-counter-test.cpp
Ichthyostega 555af315b3 Upgrade: improve Doxygen parameters and treat some warnings
- remove obsolete configuration settings
- walk through all settings according to the documentation
  https://www.doxygen.nl/manual/config.html
- now try to use the new feature to rely on Clang for C++ parsing
- walk through the doxygen-warnings.txt and fix some obvious misspellings
  and structural problems in the documentation comments.

With Debian-Trixie, we are now using Doxygen 1.9.8 —
which produces massively better results in various fine points.

However, there are still problems with automatic cross links,
especially from implementation to the corresponding test classes.
2025-04-27 05:00:14 +02:00

199 lines
6.4 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.

/*
TypedCounter(Test) - managing a set of type based contexts
Copyright (C)
2009, 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 typed-counter-test.cpp
** Stress test to verify type-based contexts.
** Besides a simple usage (unit) test, this test performs a massively multithreaded
** test of the type-based contexts, through use of the TypedCounter. The idea behind
** this facility is to provide a context, in which type-IDs can be allocated. In the
** case of the TypedCounter, these type-IDs are used to index into a vector of counters,
** this way allowing to access a counter for a given type.
**
** This test builds several "families", each sharing a TypedCounter. Each of these
** families runs a set of member threads, which concurrently access the TypedCounter of
** this family. After waiting for all threads to finish, we compare the checksum built
** within the target objects with the checksum collected through the TypedCounters.
**
** @see thread-wrapper-test.cpp
** @see thread-wrapper-join-test.cpp
**
*/
#include "lib/test/run.hpp"
#include "lib/typed-counter.hpp"
#include "lib/test/microbenchmark.hpp"
#include "lib/random.hpp"
#include "lib/util.hpp"
#include <cstdlib>
#include <utility>
#include <array>
namespace lib {
namespace test{
using util::isnil;
using lib::rani;
namespace { // test parametrisation...
const uint MAX_INDEX = 10; ///< number of distinct types / counters
const uint NUM_THREADS = 100; ///< number of threads to run in parallel
const uint NUM_ITERATIONS = 10000; ///< number of repeated random accesses per Thread
}
/***********************************************************************************//**
* @test verify the TypedCounter, which allows to maintain a counter-per-type.
* - demonstrate behaviour
* - concurrent test
* @see TypedAllocationManager
* @see typed-counter.hpp
*/
class TypedCounter_test : public Test
{
void
run (Arg)
{
simpleUsageTest();
tortureTest();
}
void
simpleUsageTest()
{
TypedCounter myCounter;
CHECK (isnil (myCounter));
CHECK (0==myCounter.size());
CHECK (0 == myCounter.get<short>());
CHECK (0 < myCounter.size());
// probably greater than 1;
// other parts of the application allocate type-IDs as well
// now allocate a counter for a type not seen yet
struct X { };
struct U { };
CHECK (0 == myCounter.get<X>());
size_t sX = myCounter.size();
CHECK (0 == myCounter.get<U>());
CHECK (sX + 1 == myCounter.size());
CHECK (0 == myCounter.get<X>());
CHECK (sX + 1 == myCounter.size());
CHECK (-1 == myCounter.dec<X>());
CHECK (-2 == myCounter.dec<X>());
CHECK (+1 == myCounter.inc<U>());
CHECK (-2 == myCounter.get<X>());
CHECK (+1 == myCounter.get<U>());
// each new type has gotten a new "slot" (i.e. a distinct type-ID)
IxID typeID_short = TypedContext<TypedCounter>::ID<short>::get();
IxID typeID_X = TypedContext<TypedCounter>::ID<X>::get();
IxID typeID_U = TypedContext<TypedCounter>::ID<U>::get();
CHECK (0 < typeID_short);
CHECK (0 < typeID_X);
CHECK (0 < typeID_U);
CHECK (typeID_short < typeID_X);
CHECK (typeID_X < typeID_U);
// type-IDs are allocated in the order of first usage
CHECK (sX + 1 == myCounter.size());
}
/** parametrised marker type to designate a counter to be incremented */
template<size_t i>
struct Dummy { };
template<size_t i>
static void
increment (TypedCounter& counter)
{
counter.inc<Dummy<i>>();
}
/**
* Helper for #tortureTest():
* Build a table of functors, where the i-th entry invokes the function
* `increment<i>()`, which leads to incrementing the counter for `Dummy<i>`.
*/
template<size_t...I>
static auto
buildOperatorsTable(std::index_sequence<I...>)
{
using Operator = void(*)(TypedCounter&);
return std::array<Operator, MAX_INDEX>{increment<I>...};
}
template<size_t...I>
static size_t
sumAllCounters(TypedCounter& counter, std::index_sequence<I...>)
{
return (counter.get<Dummy<I>>() + ... );
}
/**
* @test verify TypedCounter concurrency safety
* - use a set of types `Dummy<i>` to access a corresponding counter
* - run a large number of threads in parallel, each incrementing
* a randomly picked counter; this is achieved by using a table
* of »increment operators«, where each one is tied to a specific
* `Dummy<i>`.
*/
void
tortureTest()
{
seedRand();
using IDX = std::make_index_sequence<MAX_INDEX>;
auto operators = buildOperatorsTable(IDX{});
TypedCounter testCounter;
auto testSubject = [&
,gen = makeRandGen()]
(size_t) mutable -> size_t
{
uint i = gen.i(MAX_INDEX);
operators[i](testCounter);
return 1;
};
threadBenchmark<NUM_THREADS> (testSubject, NUM_ITERATIONS);
size_t expectedIncrements = NUM_THREADS * NUM_ITERATIONS;
CHECK (sumAllCounters(testCounter, IDX{}) == expectedIncrements);
}
};
/** Register this test class... */
LAUNCHER (TypedCounter_test, "unit common");
}} // namespace lib::test