Lumiera  0.pre.03
»edit your freedom«
job-planning-test.cpp
Go to the documentation of this file.
1 /*
2  JobPlanning(Test) - data evaluation for frame job creation
3 
4  Copyright (C)
5  2023, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 * *****************************************************************/
13 
19 #include "lib/test/run.hpp"
21 #include "steam/play/timings.hpp"
22 #include "lib/time/timevalue.hpp"
23 #include "lib/format-cout.hpp"
24 #include "lib/util.hpp"
25 
26 #include <utility>
27 
28 using test::Test;
29 using std::move;
30 using util::isSameObject;
31 
32 
33 namespace steam {
34 namespace engine{
35 namespace test {
36 
38  using lib::time::Offset;
39  using lib::time::Time;
40  using play::Timings;
41 
42 
43 
44 
45 
46  /***************************************************************/
50  class JobPlanning_test : public Test
51  {
52 
53  virtual void
54  run (Arg)
55  {
56  seedRand();
57 
58  simpleUsage();
61  }
62 
63 
66  void
68  {
69  MockDispatcher dispatcher;
70  play::Timings timings (FrameRate::PAL);
71  auto [port,sink] = dispatcher.getDummyConnection(1);
72 
73  FrameCnt frameNr{5};
74  TimeVar nominalTime{Time{200,0}};
75  size_t portIDX = dispatcher.resolveModelPort (port);
76  JobTicket& ticket = dispatcher.getJobTicketFor(portIDX, nominalTime);
77 
78  JobPlanning plan{ticket,nominalTime,frameNr};
79  Job job = plan.buildJob();
80 
81  CHECK (dispatcher.verify (job, port, sink));
82  }
83 
84 
85 
89  void
91  {
92  MockDispatcher dispatcher;
93  play::Timings timings (FrameRate::PAL, Time{0,0,5});
94  auto [port,sink] = dispatcher.getDummyConnection(1);
95 
96  FrameCnt frameNr{5};
97  Time nominalTime{200,0};
98  size_t portIDX = dispatcher.resolveModelPort (port);
99  JobTicket& ticket = dispatcher.getJobTicketFor(portIDX, nominalTime);
100 
101  JobPlanning plan{ticket,nominalTime,frameNr};
102 
103  // the following calculations are expected to happen....
104  Duration latency = ticket.getExpectedRuntime()
105  + timings.engineLatency
106  + timings.outputLatency;
107 
108  Offset nominalOffset (timings.getFrameStartAt(0), timings.getFrameStartAt(frameNr));
109  Time expectedDeadline{timings.scheduledDelivery + nominalOffset - latency};
110 
111  cout << util::_Fmt{"Frame #%d @ %s\n"
112  "real-time-origin : %s\n"
113  "total latency : %s\n"
114  "deadline : %s"}
115  % frameNr % nominalOffset
116  % timings.scheduledDelivery
117  % latency
118  % plan.determineDeadline(timings)
119  << endl;
120  CHECK (plan.determineDeadline(timings) == expectedDeadline);
121  CHECK (timings.scheduledDelivery == Time(0,0,5) );
122  CHECK (timings.playbackUrgency == play::TIMEBOUND);
123 
124  // But when switching form "timebound" to "best effort"...
125  timings.playbackUrgency = play::ASAP;
126  CHECK (Time::ANYTIME == plan.determineDeadline (timings));
127  // ... no deadline is calculated at all
128  }
129 
130 
131 
135  void
137  {
138  MockDispatcher dispatcher{MakeRec() // »master job« for each frame
139  .attrib("runtime", Duration{Time{30,0}})
140  .scope(MakeRec() // a »prerequisite job« on which the »master job« depends
141  .attrib("runtime", Duration{Time{50,0}})
142  .genNode())
143  .genNode()};
144 
145  play::Timings timings (FrameRate::PAL, Time{0,0,5});
146  auto [port,sink] = dispatcher.getDummyConnection(1);
147 
148  FrameCnt frameNr{5};
149  Time nominalTime{200,0};
150  size_t portIDX = dispatcher.resolveModelPort (port);
151  JobTicket& ticket = dispatcher.getJobTicketFor(portIDX, nominalTime);
152  JobTicket& prereq = *(ticket.getPrerequisites()); // pick up the (only) prerequisite
153 
154  JobPlanning masterPlan{ticket,nominalTime,frameNr}; // the job plan for the master frame calculation
155  JobPlanning prereqPlan{move(*(masterPlan.buildDependencyPlanning() ))}; // build a plan for calculating the prerequisite
156 
157  CHECK (isSameObject(ticket, masterPlan.ticket()));
158  CHECK (isSameObject(prereq, prereqPlan.ticket()));
159  CHECK ( masterPlan.isTopLevel());
160  CHECK (not prereqPlan.isTopLevel());
161 
162  Time masterDeadline = masterPlan.determineDeadline (timings);
163  Time prereqDeadline = prereqPlan.determineDeadline (timings);
164 
165  // the following relations are expected to hold for the prerequisite....
166  Duration latency = prereq.getExpectedRuntime()
167  + timings.engineLatency; // Note: here only the engine, not the output latency
168 
169  Time expectedDeadline{masterDeadline - latency};
170 
171  cout << util::_Fmt{"Prerequisite......\n"
172  "master deadline : %s\n"
173  "latency : %s\n"
174  "prereq deadline : %s"}
175  % masterDeadline
176  % latency
177  % prereqDeadline
178  << endl;
179  CHECK (prereqDeadline == expectedDeadline);
180 
181  // However, no deadline established for "best effort" rendering...
182  timings.playbackUrgency = play::ASAP;
183  CHECK (Time::ANYTIME == masterPlan.determineDeadline (timings));
184  CHECK (Time::ANYTIME == prereqPlan.determineDeadline (timings));
185  }
186  };
187 
188 
190  LAUNCHER (JobPlanning_test, "unit engine");
191 
192 
193 
194 }}} // namespace steam::engine::test
static const Time ANYTIME
border condition marker value. ANYTIME <= any time value
Definition: timevalue.hpp:313
a mutable time value, behaving like a plain number, allowing copy and re-accessing ...
Definition: timevalue.hpp:232
size_t resolveModelPort(ModelPort modelPort) override
translate a generic ModelPort spec into the specific index number applicable at the Timeline referred...
Mock data structures to support implementation testing of render job planning and frame dispatch...
Automatically use custom string conversion in C++ stream output.
JobTicket & getJobTicketFor(size_t portIDX, TimeValue nominalTime) override
Core Dispatcher operation: locate the appropriate Segment and retrieve/derive a »blueprint« for rende...
Definition: run.hpp:40
Framerate specified as frames per second.
Definition: timevalue.hpp:655
Generic frame timing specification.
Definition: timings.hpp:86
A mocked frame Dispatcher setup without any backing model.
play::test::DummyOutputLink getDummyConnection(uint index)
The faked builder/playback setup provides some preconfigured ModelPort and corresponding DataSink han...
Steam-Layer implementation namespace root.
A front-end for using printf-style formatting.
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:299
Abstract Base Class for all testcases.
Definition: run.hpp:53
bool verify(Job const &job, ModelPort const &port, play::DataSink const &sink)
Test support: verify the given Job is consistent with this Dispatcher.
Simplistic test class runner.
void seedRand()
draw a new random seed from a common nucleus, and re-seed the default-Gen.
Definition: suite.cpp:211
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Offset measures a distance in time.
Definition: timevalue.hpp:358
How to define a timing specification or constraint.
View on the execution planning for a single calculation step.
Duration is the internal Lumiera time metric.
Definition: timevalue.hpp:468
Individual frame rendering task, forwarding to a closure.
Definition: job.h:268
a family of time value like entities and their relationships.
auto getPrerequisites()
Core operation: iterate over the prerequisites, required to carry out a render operation based on thi...
Definition: job-ticket.hpp:155
static const FrameRate PAL
predefined constant for PAL framerate
Definition: timevalue.hpp:671
execution plan for pulling a specific exit node.
Definition: job-ticket.hpp:78
Duration getExpectedRuntime()
Core operation: guess expected runtime for rendering.
Definition: job-ticket.cpp:94
bool isSameObject(A const &a, B const &b)
compare plain object identity, based directly on the referee&#39;s memory identities. ...
Definition: util.hpp:421