lumiera_/tests/core/steam/engine/scheduler-interface-test.cpp
Ichthyostega 0b9e184fa3 Library: replace usages of rand() in the whole code base
* most usages are drop-in replacements
 * occasionally the other convenience functions can be used
 * verify call-paths from core code to identify usages
 * ensure reseeding for all tests involving some kind of randomness...

__Note__: some tests were not yet converted,
since their usage of randomness is actually not thread-safe.
This problem existed previously, since also `rand()` is not thread safe,
albeit in most cases it is possible to ignore this problem, as
''garbled internal state'' is also somehow „random“
2024-11-13 04:23:46 +01:00

205 lines
6.5 KiB
C++

/*
SchedulerInterface(Test) - verify invocation structure of the scheduler interface
Copyright (C) Lumiera.org
2013, Hermann Vosseler <Ichthyostega@web.de>
This program 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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
/** @file scheduler-interface-test.cpp
** unit test \ref SchedulerInterface_test
**
** @deprecated 6/2023 the Scheduler interface is about to be defined anew,
** and will likely be totally different than envisioned here...
*/
#include "lib/test/run.hpp"
#include "lib/util.hpp"
#include "vault/real-clock.hpp"
#include "vault/gear/scheduler-frontend.hpp"
#include "vault/gear/scheduler-diagnostics.hpp"
#include "steam/engine/mock-dispatcher.hpp"
namespace vault{
namespace gear {
namespace test {
using util::isSameObject;
using lib::time::Duration;
using lib::time::Offset;
using lib::time::FSecs;
using steam::engine::test::MockJob;
namespace { // test fixture: scheduling a dummy job operation...
Time TEST_START_TIME (vault::RealClock::now());
const Duration TEST_FRAME_DURATION(FSecs(1,2));
inline Offset
dummyFrameStart (uint frameNr)
{
return frameNr * TEST_FRAME_DURATION;
}
} //(End) test fixture
typedef SchedulerFrontend::JobTransaction JobTransaction;
/***********************************************************************//**
* @test verify and demonstrate the organisation of the high-level interface
* for defining jobs to be invoked by the scheduler.
*
* @see SchedulerFrongend
* @see DispatcherInterface_test
*/
class SchedulerInterface_test : public Test
{
virtual void
run (Arg)
{
seedRand();
SchedulerFrontend& scheduler = SchedulerFrontend::instance();
verify_simple_job_specification (scheduler);
verify_job_specification_variations (scheduler);
demonstrate_nested_job_specification (scheduler);
}
void
verify_simple_job_specification (SchedulerFrontend& scheduler)
{
SchedulerDiagnostics monitor(scheduler);
MockJob job;
Time deadline(TEST_START_TIME);
scheduler.startJobTransaction()
.addJob(deadline, job)
.commit();
CHECK ( monitor.is_scheduled_timebound (job));
CHECK (!monitor.is_scheduled_background (job));
CHECK (!monitor.is_scheduled_freewheeling (job));
}
void
verify_job_specification_variations (SchedulerFrontend& scheduler)
{
SchedulerDiagnostics monitor(scheduler);
JobTransaction tx = scheduler.startJobTransaction();
MockJob job1;
MockJob job2;
tx.addFreewheeling(job1);
tx.addBackground (job2);
CHECK (!monitor.is_scheduled_timebound (job1));
CHECK (!monitor.is_scheduled_timebound (job2));
CHECK (!monitor.is_scheduled_background (job1));
CHECK (!monitor.is_scheduled_background (job2));
CHECK (!monitor.is_scheduled_freewheeling (job1));
CHECK (!monitor.is_scheduled_freewheeling (job2));
tx.commit();
CHECK (!monitor.is_scheduled_timebound (job1));
CHECK (!monitor.is_scheduled_timebound (job2));
CHECK ( monitor.is_scheduled_background (job1));
CHECK ( monitor.is_scheduled_freewheeling (job2));
}
/** @test demonstrate how a tree of dependent render jobs
* can be handed over to the scheduler within a single "transaction"
*
* @remarks in the real usage situation, the definition of jobs will be
* driven by the exploration of a tree-like structure (the JobTicket).
* For the purpose of this interface demonstration test this recursive
* invocation structure is just emulated by a simple tail recursion.
* @deprecated 6/2023 STOP we do it quite different now, and better,
* in the Job-Planning-Pipeline
*/
void
demonstrate_nested_job_specification (SchedulerFrontend& scheduler)
{
SchedulerDiagnostics monitor(scheduler);
JobTransaction startTx = scheduler.startJobTransaction();
uint dummyLevel = 5;
specifyJobs (startTx, dummyLevel);
startTx.commit();
for (uint i=0; i <=5; ++i)
{
Time nominalTime(dummyFrameStart (i));
Time deadline(TEST_START_TIME + nominalTime);
CHECK (monitor.has_job_scheduled_at (deadline));
CHECK (nominalTime == monitor.job_at(deadline).parameter.nominalTime);
}
}
/** recursive helper function to add several levels of prerequisites
* It is crucial for this function to be recursive: this allows us to represent
* a complete tree navigation as a sequence of job definitions to be "pulled"
* out from some opaque source
*/
static void
specifyJobs (JobTransaction& currentTx, uint dummyLevel)
{
uint frameNr = dummyLevel;
Time nominalTime(dummyFrameStart(frameNr));
Time deadline(TEST_START_TIME + nominalTime);
MockJob job{nominalTime, frameNr};
currentTx.addJob (deadline, job);
if (0 < dummyLevel)
{
JobTransaction dependentTx = currentTx.startPrerequisiteTx();
specifyJobs (dependentTx, dummyLevel-1);
currentTx.attach (dependentTx);
}
}
};
/** Register this test class... */
LAUNCHER(SchedulerInterface_test, "unit engine");
}}} // namespace vault::gear::test