2011-12-24 03:47:50 +01:00
|
|
|
|
/*
|
2025-06-07 23:59:57 +02:00
|
|
|
|
DiagnosticContext(Test) - verify thread local stack for collecting diagnostics
|
2011-12-24 03:47:50 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
Copyright (C)
|
|
|
|
|
|
2011, Hermann Vosseler <Ichthyostega@web.de>
|
2011-12-24 03:47:50 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
**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.
|
2011-12-24 03:47:50 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
* *****************************************************************/
|
2011-12-24 03:47:50 +01:00
|
|
|
|
|
2017-02-22 01:54:20 +01:00
|
|
|
|
/** @file diagnostic-context-test.cpp
|
2017-02-22 03:17:18 +01:00
|
|
|
|
** unit test \ref DiagnosticContext_test
|
2016-11-03 18:20:10 +01:00
|
|
|
|
*/
|
|
|
|
|
|
|
2011-12-24 03:47:50 +01:00
|
|
|
|
|
|
|
|
|
|
#include "lib/test/run.hpp"
|
|
|
|
|
|
#include "lib/test/test-helper.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/diagnostic-context.hpp"
|
2023-10-13 23:46:38 +02:00
|
|
|
|
#include "lib/iter-explorer.hpp"
|
2023-10-03 23:44:12 +02:00
|
|
|
|
#include "lib/thread.hpp"
|
2011-12-24 03:47:50 +01:00
|
|
|
|
|
|
|
|
|
|
#include <vector>
|
2023-10-03 23:44:12 +02:00
|
|
|
|
#include <chrono>
|
|
|
|
|
|
#include <array>
|
|
|
|
|
|
|
|
|
|
|
|
using std::this_thread::sleep_for;
|
|
|
|
|
|
using std::chrono_literals::operator ""us;
|
|
|
|
|
|
|
2011-12-24 03:47:50 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace lib {
|
|
|
|
|
|
namespace test{
|
|
|
|
|
|
|
|
|
|
|
|
namespace error = lumiera::error;
|
|
|
|
|
|
|
|
|
|
|
|
namespace { // private test setup...
|
|
|
|
|
|
|
2012-01-07 03:27:31 +01:00
|
|
|
|
/* WARNING: memory hungry */
|
2014-10-18 05:09:18 +02:00
|
|
|
|
const uint NUM_THREADS = 75;
|
2012-01-07 03:27:31 +01:00
|
|
|
|
const uint MAX_RAND = 100*1000;
|
2011-12-24 03:47:50 +01:00
|
|
|
|
|
2023-10-03 23:44:12 +02:00
|
|
|
|
auto isOdd = [](auto val) { return bool (val % 2); };
|
2011-12-24 05:38:54 +01:00
|
|
|
|
|
2011-12-24 03:47:50 +01:00
|
|
|
|
} // (End) test setup....
|
|
|
|
|
|
|
2023-10-03 23:44:12 +02:00
|
|
|
|
using lib::ThreadJoinable;
|
2024-03-16 02:04:47 +01:00
|
|
|
|
using LERR_(LOGIC);
|
2011-12-24 03:47:50 +01:00
|
|
|
|
using std::rand;
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-10-03 23:44:12 +02:00
|
|
|
|
/**
|
2011-12-24 03:47:50 +01:00
|
|
|
|
* Subject of this test:
|
|
|
|
|
|
* a thread-local stack of int values
|
|
|
|
|
|
*/
|
|
|
|
|
|
typedef DiagnosticContext<uint> Marker;
|
|
|
|
|
|
|
2011-12-24 05:38:54 +01:00
|
|
|
|
typedef std::vector<uint> VecI;
|
2011-12-24 03:47:50 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-10-24 23:06:36 +02:00
|
|
|
|
/******************************************************************************//**
|
2011-12-24 03:47:50 +01:00
|
|
|
|
* @test verify a diagnostic facility to collect and access contextual information.
|
|
|
|
|
|
* DiagnosticContext frames are placed into automatic storage (as local
|
|
|
|
|
|
* variable within some function scope). Based on thread-local storage,
|
|
|
|
|
|
* the next reachable frame can be accessed from anywhere within
|
2023-10-03 23:44:12 +02:00
|
|
|
|
* the callstack. This feature is useful for collecting
|
2011-12-24 03:47:50 +01:00
|
|
|
|
* information regarding features cross-cutting
|
|
|
|
|
|
* the usual dependency hierarchy.
|
|
|
|
|
|
* @see lib::DiagnosticContext
|
2023-10-03 23:44:12 +02:00
|
|
|
|
* @see lib::ThreadJoinable
|
2011-12-24 03:47:50 +01:00
|
|
|
|
*/
|
2012-01-07 03:27:31 +01:00
|
|
|
|
class DiagnosticContext_test : public Test
|
2011-12-24 03:47:50 +01:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
virtual void
|
|
|
|
|
|
run (Arg)
|
|
|
|
|
|
{
|
2011-12-24 05:38:54 +01:00
|
|
|
|
verify_simpleAccess();
|
2011-12-24 03:47:50 +01:00
|
|
|
|
verify_heavilyParallelUsage();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test create nested scopes and place a
|
|
|
|
|
|
* DiagnosticContext frame into each.
|
|
|
|
|
|
* Access the next reachable frame.
|
|
|
|
|
|
*/
|
|
|
|
|
|
void
|
|
|
|
|
|
verify_simpleAccess()
|
|
|
|
|
|
{
|
2011-12-24 05:38:54 +01:00
|
|
|
|
VERIFY_ERROR (LOGIC, Marker::access());
|
|
|
|
|
|
|
|
|
|
|
|
VecI loggedValues;
|
2011-12-24 03:47:50 +01:00
|
|
|
|
|
|
|
|
|
|
Marker zero(0);
|
|
|
|
|
|
CHECK (0 == zero);
|
2011-12-24 05:38:54 +01:00
|
|
|
|
CHECK (0 == Marker::access());
|
2011-12-24 03:47:50 +01:00
|
|
|
|
|
2023-10-03 23:44:12 +02:00
|
|
|
|
{ // nested scope
|
2011-12-24 05:38:54 +01:00
|
|
|
|
CHECK (0 == Marker::access());
|
2011-12-24 03:47:50 +01:00
|
|
|
|
|
|
|
|
|
|
Marker one(1);
|
2011-12-24 05:38:54 +01:00
|
|
|
|
CHECK (1 == Marker::access());
|
2011-12-24 03:47:50 +01:00
|
|
|
|
CHECK (1 == one);
|
|
|
|
|
|
CHECK (0 == zero);
|
|
|
|
|
|
|
|
|
|
|
|
{ // nested scope
|
2011-12-24 05:38:54 +01:00
|
|
|
|
CHECK (1 == Marker::access());
|
2011-12-24 03:47:50 +01:00
|
|
|
|
|
|
|
|
|
|
Marker two(2);
|
2011-12-24 05:38:54 +01:00
|
|
|
|
CHECK (2 == Marker::access());
|
2011-12-24 03:47:50 +01:00
|
|
|
|
CHECK (2 == two);
|
|
|
|
|
|
CHECK (1 == one);
|
|
|
|
|
|
CHECK (0 == zero);
|
2011-12-24 05:38:54 +01:00
|
|
|
|
|
|
|
|
|
|
loggedValues = Marker::extractStack();
|
2011-12-24 03:47:50 +01:00
|
|
|
|
}
|
2011-12-24 05:38:54 +01:00
|
|
|
|
CHECK (1 == Marker::access());
|
2011-12-24 03:47:50 +01:00
|
|
|
|
}
|
2011-12-24 05:38:54 +01:00
|
|
|
|
CHECK (0 == Marker::access());
|
|
|
|
|
|
|
|
|
|
|
|
CHECK (3 == loggedValues.size());
|
|
|
|
|
|
CHECK (2 == loggedValues[0]);
|
|
|
|
|
|
CHECK (1 == loggedValues[1]);
|
|
|
|
|
|
CHECK (0 == loggedValues[2]);
|
2011-12-24 03:47:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test verify the thread local property of ContextStack.
|
|
|
|
|
|
* Create several threads, each of which processes a sequence
|
|
|
|
|
|
* of numbers starting from a random initial value down to one.
|
|
|
|
|
|
* Whenever a simple division by two leads to an odd value, this
|
|
|
|
|
|
* value is placed onto the ContextStack. At recursion end, we
|
|
|
|
|
|
* take a snapshot of the full ContextStack and then unwind.
|
|
|
|
|
|
* Thus the captured numbers must from a decreasing sequence
|
|
|
|
|
|
* of odd values.
|
2013-10-13 02:50:04 +02:00
|
|
|
|
* @warning this test case seems to cause memory pressure.
|
|
|
|
|
|
* When running the test suite with VSize limit 500MB,
|
|
|
|
|
|
* we frequently got aborts even with 40 threads.
|
|
|
|
|
|
* This is surprising, since all of the lists
|
|
|
|
|
|
* generated in the individual threads are
|
2023-10-03 23:44:12 +02:00
|
|
|
|
* of size below 20 elements.
|
2011-12-24 03:47:50 +01:00
|
|
|
|
*/
|
|
|
|
|
|
void
|
|
|
|
|
|
verify_heavilyParallelUsage()
|
|
|
|
|
|
{
|
2024-11-17 19:45:41 +01:00
|
|
|
|
seedRand();
|
2023-10-03 23:44:12 +02:00
|
|
|
|
auto verifyResult = [](VecI sequence)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint prev = 0;
|
|
|
|
|
|
for (uint val : sequence)
|
|
|
|
|
|
{
|
|
|
|
|
|
CHECK (isOdd(val) and val > prev);
|
|
|
|
|
|
prev = val;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2011-12-24 03:47:50 +01:00
|
|
|
|
|
2023-10-13 23:46:38 +02:00
|
|
|
|
std::array<TestThread, NUM_THREADS> testcases;
|
|
|
|
|
|
|
|
|
|
|
|
auto results = lib::explore(testcases)
|
|
|
|
|
|
.transform([](TestThread& t){ return t.join(); })
|
|
|
|
|
|
.effuse();
|
|
|
|
|
|
|
|
|
|
|
|
for (auto& res : results)
|
|
|
|
|
|
verifyResult (res);
|
2011-12-24 03:47:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-11-17 19:45:41 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* Build a call stack within separate thread and capture diagnostics.
|
|
|
|
|
|
* The actual test operation produces a descending number sequence,
|
|
|
|
|
|
* and only odd values will be captured into the diagnostic stack-
|
|
|
|
|
|
*/
|
2011-12-24 03:47:50 +01:00
|
|
|
|
struct TestThread
|
2023-10-03 23:44:12 +02:00
|
|
|
|
: ThreadJoinable<VecI>
|
2011-12-24 03:47:50 +01:00
|
|
|
|
{
|
|
|
|
|
|
TestThread()
|
2024-11-17 19:45:41 +01:00
|
|
|
|
: ThreadJoinable{"test context stack"
|
|
|
|
|
|
,[seed = 1+rani(MAX_RAND)]
|
|
|
|
|
|
{ return descend (seed); }}
|
2011-12-24 03:47:50 +01:00
|
|
|
|
{ }
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static VecI
|
|
|
|
|
|
descend (uint current)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (current < 2)
|
2011-12-24 05:38:54 +01:00
|
|
|
|
return Marker::extractStack();
|
|
|
|
|
|
|
2023-10-03 23:44:12 +02:00
|
|
|
|
sleep_for (500us);
|
|
|
|
|
|
|
2024-11-17 19:45:41 +01:00
|
|
|
|
if (isOdd (current))
|
2011-12-24 03:47:50 +01:00
|
|
|
|
{
|
|
|
|
|
|
Marker remember(current);
|
|
|
|
|
|
return descend (current+1);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
return descend (current/2);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Register this test class... */
|
2012-01-07 03:27:31 +01:00
|
|
|
|
LAUNCHER (DiagnosticContext_test, "function common");
|
2011-12-24 03:47:50 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-11-15 23:55:13 +01:00
|
|
|
|
}} // namespace vault::test
|