LUMIERA.clone/tests/core/steam/engine/job-planning-test.cpp
Ichthyostega 717af81986 Invocation: Identify parts relevant for a node builder
The immediate next step is to build some render nodes directly
in a test setting, without using any kind of ''node factory.''
Getting ahead with this task requires to identify the constituents
to be represented on the first code layer for the reworked code
(here ''first layer'' means any part that are ''not'' supplied
by generic, templated building blocks).

Notably we need to build a descriptor for the `FeedManifold` —
which in turn implies we have to decide on some fundamental aspects
of handling buffers in the render process.

To allow rework of the `ProcNode` connectivity, a lot of presumably obsoleted
draft code from 2011 has to be detached, to be able to keep it in-tree
for further reference (until the rework and refactoring is settled).
2024-06-25 04:54:39 +02:00

201 lines
7.4 KiB
C++

/*
JobPlanning(Test) - data evaluation for frame job creation
Copyright (C) Lumiera.org
2023, 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 job-planning-test.cpp
** unit test \ref JobPlanning_test
*/
#include "lib/test/run.hpp"
#include "steam/engine/mock-dispatcher.hpp"
#include "steam/play/timings.hpp"
#include "lib/time/timevalue.hpp"
#include "lib/format-cout.hpp"
#include "lib/util.hpp"
#include <utility>
using test::Test;
using std::move;
using util::isSameObject;
namespace steam {
namespace engine{
namespace test {
using lib::time::FrameRate;
using lib::time::Offset;
using lib::time::Time;
using play::Timings;
/***************************************************************//**
* @test document and verify the data aggregation and the calculations
* necessary to prepare render jobs for scheduling.
*/
class JobPlanning_test : public Test
{
virtual void
run (Arg)
{
simpleUsage();
calculateDeadline();
setupDependentJob();
}
/** @test demonstrate a simple usage scenario
*/
void
simpleUsage()
{
MockDispatcher dispatcher;
play::Timings timings (FrameRate::PAL);
auto [port,sink] = dispatcher.getDummyConnection(1);
FrameCnt frameNr{5};
TimeVar nominalTime{Time{200,0}};
size_t portIDX = dispatcher.resolveModelPort (port);
JobTicket& ticket = dispatcher.getJobTicketFor(portIDX, nominalTime);
JobPlanning plan{ticket,nominalTime,frameNr};
Job job = plan.buildJob();
CHECK (dispatcher.verify (job, port, sink));
}
/** @test verify the timing calculations to establish
* the scheduling deadline of a simple render job
*/
void
calculateDeadline()
{
MockDispatcher dispatcher;
play::Timings timings (FrameRate::PAL, Time{0,0,5});
auto [port,sink] = dispatcher.getDummyConnection(1);
FrameCnt frameNr{5};
Time nominalTime{200,0};
size_t portIDX = dispatcher.resolveModelPort (port);
JobTicket& ticket = dispatcher.getJobTicketFor(portIDX, nominalTime);
JobPlanning plan{ticket,nominalTime,frameNr};
// the following calculations are expected to happen....
Duration latency = ticket.getExpectedRuntime()
+ timings.engineLatency
+ timings.outputLatency;
Offset nominalOffset (timings.getFrameStartAt(0), timings.getFrameStartAt(frameNr));
Time expectedDeadline{timings.scheduledDelivery + nominalOffset - latency};
cout << util::_Fmt{"Frame #%d @ %s\n"
"real-time-origin : %s\n"
"total latency : %s\n"
"deadline : %s"}
% frameNr % nominalOffset
% timings.scheduledDelivery
% latency
% plan.determineDeadline(timings)
<< endl;
CHECK (plan.determineDeadline(timings) == expectedDeadline);
CHECK (timings.scheduledDelivery == Time(0,0,5) );
CHECK (timings.playbackUrgency == play::TIMEBOUND);
// But when switching form "timebound" to "best effort"...
timings.playbackUrgency = play::ASAP;
CHECK (Time::ANYTIME == plan.determineDeadline (timings));
// ... no deadline is calculated at all
}
/** @test verify the setup of a prerequisite job in relation
* to the master job depending on this prerequisite
*/
void
setupDependentJob()
{
MockDispatcher dispatcher{MakeRec() // »master job« for each frame
.attrib("runtime", Duration{Time{30,0}})
.scope(MakeRec() // a »prerequisite job« on which the »master job« depends
.attrib("runtime", Duration{Time{50,0}})
.genNode())
.genNode()};
play::Timings timings (FrameRate::PAL, Time{0,0,5});
auto [port,sink] = dispatcher.getDummyConnection(1);
FrameCnt frameNr{5};
Time nominalTime{200,0};
size_t portIDX = dispatcher.resolveModelPort (port);
JobTicket& ticket = dispatcher.getJobTicketFor(portIDX, nominalTime);
JobTicket& prereq = *(ticket.getPrerequisites()); // pick up the (only) prerequisite
JobPlanning masterPlan{ticket,nominalTime,frameNr}; // the job plan for the master frame calculation
JobPlanning prereqPlan{move(*(masterPlan.buildDependencyPlanning() ))}; // build a plan for calculating the prerequisite
CHECK (isSameObject(ticket, masterPlan.ticket()));
CHECK (isSameObject(prereq, prereqPlan.ticket()));
CHECK ( masterPlan.isTopLevel());
CHECK (not prereqPlan.isTopLevel());
Time masterDeadline = masterPlan.determineDeadline (timings);
Time prereqDeadline = prereqPlan.determineDeadline (timings);
// the following relations are expected to hold for the prerequisite....
Duration latency = prereq.getExpectedRuntime()
+ timings.engineLatency; // Note: here only the engine, not the output latency
Time expectedDeadline{masterDeadline - latency};
cout << util::_Fmt{"Prerequisite......\n"
"master deadline : %s\n"
"latency : %s\n"
"prereq deadline : %s"}
% masterDeadline
% latency
% prereqDeadline
<< endl;
CHECK (prereqDeadline == expectedDeadline);
// However, no deadline established for "best effort" rendering...
timings.playbackUrgency = play::ASAP;
CHECK (Time::ANYTIME == masterPlan.determineDeadline (timings));
CHECK (Time::ANYTIME == prereqPlan.determineDeadline (timings));
}
};
/** Register this test class... */
LAUNCHER (JobPlanning_test, "unit engine");
}}} // namespace steam::engine::test