Dispatcher-Pipeline: remould Segment for on-demand JobTicket generation

Use another unit-test (FixtureSegment_test) to guide and cover
the transition from the existing fake-implementation to the
actual implementation, where the JobTicket will be generated
on-demand, from a NodeGraphAttachment
This commit is contained in:
Fischlurch 2023-06-08 03:21:43 +02:00
parent 0c57a61545
commit c246c21e41
9 changed files with 264 additions and 39 deletions

View file

@ -54,9 +54,13 @@ namespace engine {
* @todo 6/2023 for the »Playback Vertical Slice« we need somehow to represent "the nodes",
* while the final solution how to hook up ProcNode and how to represent prerequisites
* remains still to be settled. So this is a placeholder to support mock testing for now.
* @warning ExitNode should ideally be NonCopyable, since it is referred by the JobTicket
* However, we need to clone-and-remould Segments (Split-Splice-Algo), and this implies
* that the render nodes can be shared among multiple Segments. If all these assessments
* are correct an only be decided when the actual memory management is settled.
*/
class ExitNode
: util::MoveOnly
: util::Cloneable
{
HashVal pipelineIdentity_; //////////////////////////////////////////////////////////TICKET #1293 : Hash-Chaining for invocation-ID... derive from ProcNode wiring
ExitNodes prerequisites_; ///////////////////////////////////////////////////////////TICKET #1306 : actual access to low-level-Model (ProcNode)

View file

@ -53,6 +53,9 @@ namespace fixture {
* For each ModelPort, we can expect to get an ExitNode (the number of ports is fixed
* for the complete Timeline). However, this ExitNode does not need to be active, since
* parts of the timeline can be empty, or partially empty for some ModelPort.
* @warning while this descriptor object is freely copyable, the referred ExitNode(s) are
* move-only, and will be referred by the JobTicket. Thus a Segment in the Fixture
* must remain fixed in memory as long as any derived render jobs are alive.
*
* @todo WIP-WIP as of 4/2023 -- starting with a fake implementation /////////////////////TICKET #1306 : create an actual link to the low-level Model
*/

View file

@ -33,10 +33,12 @@
#include "steam/common.hpp"
#include "steam/fixture/node-graph-attachment.hpp"
#include "steam/mobject/explicitplacement.hpp"
#include "steam/engine/job-ticket.hpp"
#include "lib/time/timevalue.hpp"
#include <utility>
#include <list>
@ -47,6 +49,7 @@ namespace fixture {
using lib::time::TimeSpan;
using lib::time::Time;
using std::list;
using std::move;
/**
* For the purpose of building and rendering, the fixture (for each timeline)
@ -56,7 +59,7 @@ namespace fixture {
*
* @ingroup fixture
* @todo 1/2012 Just a Placeholder. The real thing is not yet implemented.
* @todo WIP-WIP as of 4/2023 -- about to pull up the engine backbone
* @todo WIP-WIP as of 6/2023 -- about to establish the engine backbone
* @see http://lumiera.org/wiki/renderengine.html#Fixture
*/
class Segment
@ -76,15 +79,23 @@ namespace fixture {
// TODO: ownership??
///////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #725 : placeholder code
public:
/////////////////////////////////////////////////////////////////////////////////////////////////////////////OOO : Obsolet ... nur für Umbau erhalten!!
Segment (TimeSpan covered =TimeSpan::ALL
,const engine::JobTicket* ticket =nullptr)
: span_{covered}
, jobTicket_{ticket? ticket : &engine::JobTicket::NOP} //////////////////////////////////////////TICKET #1297 : ensure to provide a JobTicket for each ModelPort in initialisation
{ }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////TODO Obsolet ... nur für Umbau erhalten!!
Segment (TimeSpan covered
,NodeGraphAttachment&& modelLink)
: span_{covered}
, exitNode{move (modelLink)}
{ }
Segment (Segment const& original, TimeSpan changed)
: span_{changed}
, jobTicket_{original.jobTicket_}
, exitNode{original.exitNode} /////////////////////////////////////////////////////////////////////OOO really? cloning ExitNodes?
{ }
// default copy acceptable
@ -92,6 +103,10 @@ namespace fixture {
Time start() const { return span_.start(); }
Time after() const { return span_.end(); }
/** connection to the render nodes network */
NodeGraphAttachment exitNode;
engine::JobTicket const&
jobTicket() const /////////////////////////////////////////////////////////////////TICKET #1297 : introduce additional key per ModelPort here
{

View file

@ -72,6 +72,7 @@ namespace fixture {
* creating a second (copied) part of the encompassing old Segment.
* - in case the JobTicket is omitted, the new Segment will be marked as _passive_
* and any job created from such a Segment will then be a »NOP-job«
* @see SplitSplice_test
*/
Segment const&
Segmentation::splitSplice (OptTime start, OptTime after, const engine::JobTicket* jobTicket)

View file

@ -6,6 +6,11 @@ return: 0
END
PLANNED "A Segment in the Fixture" FixtureSegment_test <<END
return: 0
END
TEST "ModelPort registry" ModelPortRegistry_test <<END
return: 0
END
@ -16,7 +21,7 @@ return: 0
END
PLANNED "Segmentation datastructure" SegmentationDatastructure_test <<END
PLANNED "Segmentation integration test" SegmentationIntegration_test <<END
return: 0
END

View file

@ -0,0 +1,123 @@
/*
FixtureSegment(Test) - verify properties of a single segment in the fixture
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 node-graph-attachment-test.cpp
** unit test \ref NodeGraphAttachment_test
*/
#include "lib/test/run.hpp"
#include "steam/fixture/node-graph-attachment.hpp"
#include "steam/engine/mock-dispatcher.hpp"
#include "steam/engine/exit-node.hpp"
#include "lib/util.hpp"
#include <utility>
namespace steam {
namespace fixture {
namespace test {
using std::move;
using util::isnil;
using util::isSameObject;
using engine::ExitNode;
using lib::diff::MakeRec;
using engine::test::MockSegmentation;
/*****************************************************************************//**
* @test Verify properties and behaviour of a single Segment in the Segmentation
* - construction of a mocked Segment
* - TODO
* - TODO
* @see steam::fixture::Segment
* @see JobPlanningSetup_test
* @see MockSupport_test
*/
class FixtureSegment_test : public Test
{
virtual void
run (Arg)
{
fabricate_MockSegment();
retrieve_JobTicket();
}
/** @test setup a properly structured ExitNode graph using the
* specification scheme supported by MockSegmentation
* @see MockSupport_test::verify_MockSegmentation
*/
void
fabricate_MockSegment()
{
// Build a Segmentation partitioned at 10s
MockSegmentation segmentation{MakeRec()
.attrib ("start", Time{0,10}
,"mark", 101010)
.genNode()};
CHECK (2 == segmentation.size());
Segment const& seg = segmentation[Time{0,20}]; // access anywhere >= 10s
CHECK (Time(0,10) == seg.start());
CHECK (Time::NEVER == seg.after());
CHECK (101010 == seg.exitNode[0].getPipelineIdentity());
}
/** @test on-demand generate a JobTicket from an existing NodeGraphAttachment
*/
void
retrieve_JobTicket()
{
MockSegmentation segmentation{MakeRec()
.attrib("mark", 13) // top-level: marked with hash/id = 13
.scope(MakeRec() // ... defines two nested prerequisites
.attrib("mark",23) // + Prerequisite-1 hash/id = 23
.genNode()
,MakeRec()
.attrib("mark",55) // + Prerequisite-2 hash/id = 55
.genNode()
)
.genNode()};
UNIMPLEMENTED("fabricate JobTicket from ExitNode-Graph");
// // verify generated Node is assembled according to above spec...
// CHECK (13 == node.getPipelineIdentity());
// auto feed = node.getPrerequisites();
// CHECK (not isnil (feed));
// CHECK (23 == feed->getPipelineIdentity());
// ++feed;
// CHECK (55 == feed->getPipelineIdentity());
// ++feed;
// CHECK (isnil (feed));
}
};
/** Register this test class... */
LAUNCHER (FixtureSegment_test, "unit fixture");
}}} // namespace steam::fixture::test

View file

@ -26,10 +26,9 @@
#include "lib/test/run.hpp"
//#include "lib/test/test-helper.hpp"
#include "steam/fixture/node-graph-attachment.hpp"
#include "steam/engine/exit-node.hpp"
#include "steam/engine/mock-dispatcher.hpp"
#include "steam/engine/exit-node.hpp"
#include "lib/util.hpp"
#include <utility>
@ -39,35 +38,21 @@ namespace steam {
namespace fixture {
namespace test {
// using util::isSameObject;
using std::move;
using util::isnil;
//
// using asset::Pipe;
// using asset::PPipe;
// using asset::Struct;
// using asset::Timeline;
// using asset::PTimeline;
// using lumiera::Query;
using util::isSameObject;
using engine::ExitNode;
//
// typedef asset::ID<Pipe> PID;
// typedef asset::ID<Struct> TID;
//
// typedef ModelPortRegistry::ModelPortDescriptor const& MPDescriptor;
namespace { // test environment
}
/*****************************************************************************//**
* @test Verify the facade object used to connect from the Segments in the Fixture
* into the actual render nodes network
* @see mobject::builder::FixtureChangeDetector
* - construction of ExitNode
* - composition of the NodeGraphAttachment including prerequisites
* - generation of a complete setup of fake ExitNodes from a test spec.
* @see steam::fixture::Segment
* @see JobPlanningSetup_test
* @see MockSupport_test
*/
class NodeGraphAttachment_test : public Test
{
@ -75,7 +60,7 @@ namespace test {
virtual void
run (Arg)
{
access_ExitNode();
access_ExitNodeTree();
fabricate_MockExitNode();
}
@ -89,7 +74,7 @@ namespace test {
* - access existing and non-existing index positions
*/
void
access_ExitNode()
access_ExitNodeTree()
{
CHECK (0 == ExitNode::NIL.getPipelineIdentity());
CHECK (isnil (ExitNode::NIL.getPrerequisites()));
@ -111,6 +96,8 @@ namespace test {
CHECK (13 == succubus[0].getPipelineIdentity());
CHECK (23 == succubus[1].getPipelineIdentity());
CHECK (55 == succubus[1].getPrerequisites()->getPipelineIdentity());
CHECK (isSameObject (succubus[5], ExitNode::NIL)); // out-of-index access falls back to ExitNode::NIL
}
@ -126,16 +113,17 @@ namespace test {
engine::test::MockSegmentation builder;
ExitNode node =
builder.buildExitNodeFromSpec(MakeRec()
.attrib("mark", 13)
.scope(MakeRec()
.attrib("mark",23)
.attrib("mark", 13) // top-level: marked with hash/id = 13
.scope(MakeRec() // ... defines two nested prerequisites
.attrib("mark",23) // + Prerequisite-1 hash/id = 23
.genNode()
,MakeRec()
.attrib("mark",55)
.attrib("mark",55) // + Prerequisite-2 hash/id = 55
.genNode()
)
.genNode());
// verify generated Node is assembled according to above spec...
CHECK (13 == node.getPipelineIdentity());
auto feed = node.getPrerequisites();
CHECK (not isnil (feed));

View file

@ -1,5 +1,5 @@
/*
SegmentationDatastructure(Test) - verify basic properties of the Segmentation
SegmentationIntegration(Test) - verify basic properties of the Segmentation
Copyright (C) Lumiera.org
2010, Hermann Vosseler <Ichthyostega@web.de>
@ -20,8 +20,8 @@
* *****************************************************/
/** @file segmentation-datastructure-test.cpp
** unit test \ref SegmentationDatastructure_test
/** @file segmentation-integration-test.cpp
** integration test \ref SegmentationIntegration_test
*/
@ -86,11 +86,18 @@ namespace test {
/*****************************************************************************//**
* @test TODO blubb
*
* @test Properties and behaviour of a complete Segmentation data structure.
* - access segments keyed by nominal time
* - determine the index-Nr of a ModelPort
* - transactional remoulding of the Segmentation
* - retrieve effective changes after remoulding
* - integration with AllocationCluster memory managment
* @todo 2010 2023 a sketch for a test setup, which was meanwhile elaborated
* into the DummyPlayConnection; indeed such a component integration test
* is still required to document and cover the fixture data structure....
* @see mobject::builder::FixtureChangeDetector
*/
class SegmentationDatastructure_test : public Test
class SegmentationIntegration_test : public Test
{
virtual void
@ -110,7 +117,7 @@ namespace test {
/** Register this test class... */
LAUNCHER (SegmentationDatastructure_test, "unit fixture");
LAUNCHER (SegmentationIntegration_test, "unit fixture");

View file

@ -74105,6 +74105,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<linktarget COLOR="#599eb9" DESTINATION="ID_1552363345" ENDARROW="Default" ENDINCLINATION="623;43;" ID="Arrow_ID_940031570" SOURCE="ID_929102409" STARTARROW="None" STARTINCLINATION="738;-108;"/>
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1686092906718" HGAP="35" ID="ID_515771" MODIFIED="1686151102329" TEXT="NodeGraphAttachment_test" VSHIFT="-3">
<linktarget COLOR="#5aec6d" DESTINATION="ID_515771" ENDARROW="Default" ENDINCLINATION="1;286;" ID="Arrow_ID_1994759368" SOURCE="ID_31746915" STARTARROW="None" STARTINCLINATION="880;-201;"/>
<icon BUILTIN="button_ok"/>
</node>
</node>
@ -74211,6 +74212,17 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="yes"/>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1686186370164" ID="ID_1270139229" MODIFIED="1686186389790" TEXT="Problem: Klon-Segmente wegen Split-Splice">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1686186392505" ID="ID_581141216" MODIFIED="1686186413737" TEXT="der Algo k&#xfc;rzt Segmente oder teilt sie auf"/>
<node CREATED="1686186419019" ID="ID_1101347188" MODIFIED="1686186435605" TEXT="daf&#xfc;r wird ein Segment kopiert und &#xbb;umgeschrieben&#xab;"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686186436835" ID="ID_909527462" MODIFIED="1686186454445" TEXT="das widerspricht der Referenz-Semantik f&#xfc;r ExitNodes">
<icon BUILTIN="broken-line"/>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1686186457031" ID="ID_1533110549" MODIFIED="1686186472687" TEXT="mu&#xdf; ungekl&#xe4;rt bleiben bis MemoryManagement gekl&#xe4;rt ist">
<icon BUILTIN="hourglass"/>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686089743535" ID="ID_1592596965" MODIFIED="1686089766715" TEXT="JobTicket-Erzeugung (vorl&#xe4;ufig) endg&#xfc;litig implementieren">
@ -74262,6 +74274,10 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<arrowlink COLOR="#599eb9" DESTINATION="ID_1552363345" ENDARROW="Default" ENDINCLINATION="623;43;" ID="Arrow_ID_940031570" STARTARROW="None" STARTINCLINATION="738;-108;"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1686092906718" HGAP="35" ID="ID_1605426517" MODIFIED="1686184589923" TEXT="FixtureSegment_test" VSHIFT="-3">
<linktarget COLOR="#5aec6d" DESTINATION="ID_1605426517" ENDARROW="Default" ENDINCLINATION="-104;-6;" ID="Arrow_ID_658388334" SOURCE="ID_31746915" STARTARROW="None" STARTINCLINATION="570;-91;"/>
<icon BUILTIN="pencil"/>
</node>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1686014291202" ID="ID_252150549" MODIFIED="1686014413608" TEXT="Problem: wie kommt man an die portNum?">
<arrowlink COLOR="#fe3f50" DESTINATION="ID_1087682281" ENDARROW="Default" ENDINCLINATION="326;21;" ID="Arrow_ID_676319361" STARTARROW="None" STARTINCLINATION="309;-20;"/>
@ -74275,6 +74291,11 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686182242381" ID="ID_31746915" MODIFIED="1686182440550" TEXT="Unit-Tests">
<arrowlink COLOR="#5aec6d" DESTINATION="ID_515771" ENDARROW="Default" ENDINCLINATION="1;286;" ID="Arrow_ID_1994759368" STARTARROW="None" STARTINCLINATION="880;-201;"/>
<arrowlink COLOR="#5aec6d" DESTINATION="ID_1605426517" ENDARROW="Default" ENDINCLINATION="-104;-6;" ID="Arrow_ID_658388334" STARTARROW="None" STARTINCLINATION="570;-91;"/>
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1681742836996" ID="ID_1224963303" MODIFIED="1684878201314" TEXT="expander function to explore prerequisite JobTickets">
<icon BUILTIN="full-4"/>
@ -75104,6 +75125,64 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1685999881980" ID="ID_1237481687" MODIFIED="1685999917839" TEXT="Koppel-Facade: &#xbb;NodeGraphAttachment&#xab;">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1686184053235" ID="ID_1172335387" MODIFIED="1686184459579" TEXT="Achtung: Gefahr von &#xbb;dangling references&#xab;">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Nach aktuellem Stand verweist das JobTicket per Pointer oder Referenz auf ein ExitNode-Objekt, und diese Referenz wird sp&#228;ter an den JobFunktor durchgereicht. Irgendwo dahinter verbirgt sich <b>ein Element mit fester Identit&#228;t</b>&#160;(Referenz-Semantik), aber ich wei&#223; noch nicht wo genau. Meine Vorstellung ist, da&#223; das Segment an einer festen Position im Speicher fixiert bleibt, solange noch CalcStreams bzw. Jobs aktiv sind, die die dahinter h&#228;ngenden Render-Nodes referenzieren &#8212; das ist die Grundidee hinter dem &#187;AllocationCluster&#171;
</p>
</body>
</html></richcontent>
<icon BUILTIN="clanbomber"/>
</node>
<node CREATED="1686184460760" ID="ID_1127858198" MODIFIED="1686184569008" TEXT="behandle trotzdem dieses Descriptor-Objekt mit value-Semantik">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...und zwar, um den Umgang mit der Datenstrutur und das Testing nicht unn&#246;tig zu verkomplizieren; ich hoffe, der Umstand, da&#223; ExitNode als MoveOnly markiert ist, sorgt f&#252;r ausreichend Sicherheit (deshalb d&#252;rfte sich die Collection der ExitNodes nicht ohne Weiteres kopieren lassen)
</p>
</body>
</html></richcontent>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1686186280320" ID="ID_944603905" MODIFIED="1686186296287" TEXT="vorerst sogar &quot;Clonable&quot;">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1686186306847" ID="ID_651846502" MODIFIED="1686186315175" TEXT="weil das Memory-Management noch fehlt"/>
<node CREATED="1686186316027" ID="ID_136341744" MODIFIED="1686186330533" TEXT="Alternative w&#xe4;re: Pointer auf shared descriptor"/>
</node>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1686185213666" ID="ID_1644196914" MODIFIED="1686185224270" TEXT="k&#xf6;nnen Node-Pipelines shared sein?">
<icon BUILTIN="help"/>
<node CREATED="1686185229717" ID="ID_1132211364" MODIFIED="1686185398383" TEXT="das ist das eigentliche Problem hinter der Move/Clone-Semantik der ExitNode">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Also konkret die Frage: kann ein-und-diesselbe ProcNode mit allen darunter h&#228;ngenden Strukturen gleichzeitig von mehreren Segmenten verwendet werden? Das klingt zun&#228;chst einmal durchaus nach einer plausiblen M&#246;glichkeit, da ja die Render-Nodes selber nichts &#252;ber ihre nominelle Zeit wissen sollen; demnach w&#228;ren die Render-Nodes eine <b>persistente Datenstruktur</b>
</p>
</body>
</html></richcontent>
<icon BUILTIN="idea"/>
</node>
<node CREATED="1686185406665" ID="ID_1472855858" MODIFIED="1686185440562">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
&#10233; Render-Nodes als <b>persistente Datenstruktur</b>&#160;behandeln?
</p>
</body>
</html></richcontent>
</node>
</node>
</node>
<node CREATED="1685999923288" ID="ID_43857242" MODIFIED="1685999987298" TEXT="grunds&#xe4;tzlich">
<icon BUILTIN="yes"/>