From 0b9705692bd4969a13cb68d577a1118453f8f14a Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Tue, 13 Jun 2023 03:47:42 +0200 Subject: [PATCH] Dispatcher-Pipeline: now (finally) able to implement MockDispatcher MockSupport_test : PASS JobPlanningSetup_test : PASS(as far as defined) --- src/steam/engine/dispatcher.hpp | 6 +- src/steam/engine/job-ticket.cpp | 2 +- src/steam/engine/job-ticket.hpp | 11 +- src/steam/fixture/segment.hpp | 4 +- src/steam/fixture/segmentation.hpp | 3 +- src/steam/mobject/model-port.hpp | 6 + .../steam/engine/job-planning-setup-test.cpp | 5 +- tests/core/steam/engine/mock-dispatcher.hpp | 86 +++++++++++--- tests/core/steam/engine/mock-support-test.cpp | 5 +- .../steam/fixture/fixture-segment-test.cpp | 2 +- .../core/steam/play/dummy-play-connection.hpp | 18 +++ tests/core/vault/engine/dummy-job.cpp | 21 ++++ tests/core/vault/engine/dummy-job.hpp | 1 + wiki/thinkPad.ichthyo.mm | 108 ++++++++++++------ 14 files changed, 210 insertions(+), 68 deletions(-) diff --git a/src/steam/engine/dispatcher.hpp b/src/steam/engine/dispatcher.hpp index 7c1178d2f..05c40cce0 100644 --- a/src/steam/engine/dispatcher.hpp +++ b/src/steam/engine/dispatcher.hpp @@ -270,7 +270,7 @@ namespace engine { /** Package a Ticket together with a direct dependency, * to allow setup of schedule times in downstream processing */ - using TicketDepend = std::pair; + using TicketDepend = std::pair; /** @@ -305,9 +305,9 @@ namespace engine { return buildPipeline ( this->expandAll([](TicketDepend& currentLevel) { - JobTicket const* parent = currentLevel.second; + JobTicket* parent = currentLevel.second; return lib::transformIterator (parent->getPrerequisites() - ,[&parent](JobTicket const& prereqTicket) + ,[&parent](JobTicket& prereqTicket) { // parent shifted up to first pos return TicketDepend{parent, &prereqTicket}; } diff --git a/src/steam/engine/job-ticket.cpp b/src/steam/engine/job-ticket.cpp index 870f892d2..5a1fa681c 100644 --- a/src/steam/engine/job-ticket.cpp +++ b/src/steam/engine/job-ticket.cpp @@ -52,7 +52,7 @@ namespace engine { /** special »do nothing« JobTicket marker */ - const JobTicket JobTicket::NOP{}; //////////////////////////////////////////////////////////////TICKET #725 : do we actually need that for the final data structure? + JobTicket JobTicket::NOP{}; ////////////////////////////////////////////////////////////////////TICKET #725 : do we actually need that for the final data structure? JobTicket::JobTicket() : provision_{nopFunctor(), ExitNode::NIL} diff --git a/src/steam/engine/job-ticket.hpp b/src/steam/engine/job-ticket.hpp index 2ff9eaf02..45b3b4c91 100644 --- a/src/steam/engine/job-ticket.hpp +++ b/src/steam/engine/job-ticket.hpp @@ -90,6 +90,7 @@ using lib::LUID; * the JobTicket acts as _higher order function:_ a function generating * on invocation another, specific function (= the job). * + * @note JobTicket is effectively immutable after construction * @todo 4/23 WIP-WIP-WIP defining the invocation sequence and render jobs */ class JobTicket @@ -98,7 +99,7 @@ using lib::LUID; struct Prerequisite { Prerequisite* next{nullptr}; // for intrusive list - JobTicket const& prereqTicket; + JobTicket& prereqTicket; template Prerequisite (ExitNode const& node, ALO& allocateTicket) @@ -138,7 +139,7 @@ using lib::LUID; : provision_{buildProvisionSpec (exitNode, allocator)} { } - static const JobTicket NOP; + static JobTicket NOP; /////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1276 : likely to become obsolete @@ -151,11 +152,11 @@ using lib::LUID; Job createJobFor (FrameCoord coordinates) const; auto - getPrerequisites () const + getPrerequisites () { - return lib::transformIterator (this->empty()? Prerequisites::const_iterator() + return lib::transformIterator (this->empty()? Prerequisites::iterator() : provision_.prerequisites.begin() - ,[](Prerequisite const& prq) -> JobTicket const& + ,[](Prerequisite& prq) -> JobTicket& { return prq.prereqTicket; }); diff --git a/src/steam/fixture/segment.hpp b/src/steam/fixture/segment.hpp index aafd75ec7..ee10bfc76 100644 --- a/src/steam/fixture/segment.hpp +++ b/src/steam/fixture/segment.hpp @@ -70,7 +70,7 @@ namespace fixture { { using JobTicket = engine::JobTicket; using TicketAlloc = lib::AllocatorHandle; - using PortTable = std::deque>; + using PortTable = std::deque>; protected: @@ -128,7 +128,7 @@ namespace fixture { * Access the JobTicket for this segment and the given \a portNr * @remark will be created on-demand and remain stable thereafter. */ - engine::JobTicket const& + engine::JobTicket& jobTicket (size_t portNr) const { if (portNr >= portTable_.size()) diff --git a/src/steam/fixture/segmentation.hpp b/src/steam/fixture/segmentation.hpp index e09f9406d..d7ee42c52 100644 --- a/src/steam/fixture/segmentation.hpp +++ b/src/steam/fixture/segmentation.hpp @@ -83,8 +83,7 @@ namespace fixture { class Segmentation : util::NonCopyable { - ///////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1243 : preliminary implementation - + protected: /** segments of the engine in ordered sequence. */ list segments_; diff --git a/src/steam/mobject/model-port.hpp b/src/steam/mobject/model-port.hpp index 3bbfc2711..cd05d49b3 100644 --- a/src/steam/mobject/model-port.hpp +++ b/src/steam/mobject/model-port.hpp @@ -146,6 +146,12 @@ namespace mobject { return mp1.id_ != mp2.id_; } + friend bool + operator< (ModelPort const& mp1, ModelPort const& mp2) + { + return lib::HashVal(mp1.id_) < lib::HashVal(mp2.id_); + } + private: }; diff --git a/tests/core/steam/engine/job-planning-setup-test.cpp b/tests/core/steam/engine/job-planning-setup-test.cpp index e14402250..29668e72f 100644 --- a/tests/core/steam/engine/job-planning-setup-test.cpp +++ b/tests/core/steam/engine/job-planning-setup-test.cpp @@ -130,8 +130,8 @@ namespace test { ) .genNode()}; fixture::Segment const& seg = mockSegs[Time{0,15}]; // access anywhere 10s <= t < 20s - JobTicket const& ticket = seg.jobTicket(0); // get the master-JobTicket from this segment - JobTicket const& prereq = *(ticket.getPrerequisites()); // pull a prerequisite JobTicket + JobTicket& ticket = seg.jobTicket(0); // get the master-JobTicket from this segment + JobTicket& prereq = *(ticket.getPrerequisites()); // pull a prerequisite JobTicket FrameCoord coord; // Frame coordinates for invocation (placeholder) Job jobP = prereq.createJobFor(coord); // create an instance of the prerequisites for this coordinates @@ -203,6 +203,7 @@ namespace test { JobTicket const& ticket = *pipeline->second; FrameCoord dummy; + dummy.absoluteNominalTime = Time::ZERO; // actual time point is irrelevant here Job job = ticket.createJobFor(dummy); CHECK (dispatcher.verify(job, port, sink)); } diff --git a/tests/core/steam/engine/mock-dispatcher.hpp b/tests/core/steam/engine/mock-dispatcher.hpp index 5f58b1b6f..a0093d298 100644 --- a/tests/core/steam/engine/mock-dispatcher.hpp +++ b/tests/core/steam/engine/mock-dispatcher.hpp @@ -61,9 +61,10 @@ #include "lib/linked-elements.hpp" #include "lib/itertools.hpp" #include "lib/depend.hpp" +#include "lib/util.hpp" #include -#include +#include namespace steam { @@ -76,6 +77,8 @@ namespace test { using lib::time::TimeValue; using lib::time::Time; using lib::HashVal; + using util::isnil; + using util::isSameObject; ///////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1294 : organisation of namespaces / includes?? using fixture::Segmentation; @@ -170,14 +173,10 @@ namespace test { class MockSegmentation : public Segmentation { - // simulated allocator; - // must be able to handle re-entrant allocations - std::list tickets_; public: MockSegmentation() : Segmentation{} - , tickets_{} { } MockSegmentation (std::initializer_list specs) @@ -202,6 +201,9 @@ namespace test { ,& DummyJob::getFunctor()}; } + /** @internal helper for MockDispatcher */ + void duplicateExitNodeSpec (uint times); + private: /* ======== Implementation: build fake ExitNodes from test specification ==== */ @@ -226,6 +228,21 @@ namespace test { + /** + * This is some trickery to allow handling of multiple ModelPort(s) in MockDispatcher; + * actually the code using this mock setup does not need any elaborate differentiation + * of the ExitNodes structure per port, thus the first entry of the existing configuration + * is just duplicated for the given number of further ModelPorts. + * @warning this manipulation must be done prior to generating any JobTicket + */ + inline void + MockSegmentation::duplicateExitNodeSpec (uint times) + { + for (fixture::Segment& seg : segments_) + seg.exitNode = move(fixture::NodeGraphAttachment{ExitNodes{times, seg.exitNode[0]}}); + } + + /** * verify the given job instance was actually generated from this JobTicket. * @remark this test support function relies on some specific rigging, @@ -263,6 +280,9 @@ namespace test { DummyPlaybackSetup dummySetup_; MockSegmentation mockSeg_; + using PortIdxMap = std::map; + + const PortIdxMap portIdx_; public: /* == mock Dispatcher implementation == */ @@ -279,24 +299,41 @@ namespace test { UNIMPLEMENTED ("determine when to finish a planning chunk"); } + size_t resolveModelPort (ModelPort modelPort) override { - UNIMPLEMENTED ("some Map lookup in a prepared table to find out the actual slot number"); + auto entry = portIdx_.find(modelPort); + if (entry == portIdx_.end()) + throw error::Logic{"Invalid ModelPort for this Dispatcher"}; + else + return entry->second; } - + + JobTicket& - accessJobTicket (size_t, TimeValue nominalTime) override + accessJobTicket (size_t portIDX, TimeValue nominalTime) override { - UNIMPLEMENTED ("dummy implementation of the model backbone / segmentation"); + auto& seg = mockSeg_[nominalTime]; + return seg.jobTicket(portIDX); } - MockDispatcher() = default; + MockDispatcher() + : dummySetup_{} + , mockSeg_{MakeRec().genNode()} // Node: generate a single active Segment to cover all + , portIdx_{buildPortIndex()} + { + mockSeg_.duplicateExitNodeSpec(portIdx_.size()); + } MockDispatcher (std::initializer_list specs) - : mockSeg_(specs) - { } + : dummySetup_{} + , mockSeg_(specs) + , portIdx_{buildPortIndex()} + { + mockSeg_.duplicateExitNodeSpec(portIdx_.size()); + } ModelPort @@ -313,7 +350,7 @@ namespace test { * @param index number of the distinct port / connection * @return a `std::pair` * @warning as of 5/2023, there are two preconfigured "slots", - * and they are not usable in any way other then refering to their identity + * and they are not usable in any way other then referring to their identity */ play::test::DummyOutputLink getDummyConnection(uint index) @@ -326,7 +363,28 @@ namespace test { */ bool verify(Job const& job, ModelPort const& port, play::DataSink const& sink) { - UNIMPLEMENTED ("verify the job was plausibly created from this dispatcher"); + if (not dummySetup_.isSupported (port, sink)) return false; + + TimeValue nominalTime{job.parameter.nominalTime}; + size_t portIDX = resolveModelPort (port); + JobTicket& ticket = accessJobTicket (portIDX, nominalTime); + return isnil (ticket)? DummyJob::isNopJob (job) + : MockJobTicket::isAssociated (job, ticket); + } + + private: + PortIdxMap + buildPortIndex() + { + PortIdxMap newIndex; + uint i{0}; + for (auto it=dummySetup_.getAllModelPorts() + ; bool{it} + ; ++it, ++i + ) + newIndex[*it] = i; + + return newIndex; } }; diff --git a/tests/core/steam/engine/mock-support-test.cpp b/tests/core/steam/engine/mock-support-test.cpp index 3619a306a..6c513f9f1 100644 --- a/tests/core/steam/engine/mock-support-test.cpp +++ b/tests/core/steam/engine/mock-support-test.cpp @@ -326,7 +326,7 @@ namespace test { .genNode()) .genNode()}; CHECK (1 == mockSegs.size()); - JobTicket const& ticket = mockSegs[Time::ZERO].jobTicket(0); // Model-PortNr.0 + JobTicket& ticket = mockSegs[Time::ZERO].jobTicket(0); // Model-PortNr.0 auto prereq = ticket.getPrerequisites(); CHECK (not isnil (prereq)); @@ -364,7 +364,7 @@ namespace test { auto start = singleValIterator (mockSegs[Time::ZERO].jobTicket(0)); auto it = lib::explore(start) - .expand ([](JobTicket const& ticket) + .expand ([](JobTicket& ticket) { return ticket.getPrerequisites(); }) @@ -394,6 +394,7 @@ namespace test { verify_MockDispatcherSetup() { FrameCoord frame; + frame.absoluteNominalTime = Time{0,30}; { MockDispatcher dispatcher; // automatically generates some fake connection points... diff --git a/tests/core/steam/fixture/fixture-segment-test.cpp b/tests/core/steam/fixture/fixture-segment-test.cpp index 8cfecf6f5..2e35e9350 100644 --- a/tests/core/steam/fixture/fixture-segment-test.cpp +++ b/tests/core/steam/fixture/fixture-segment-test.cpp @@ -115,7 +115,7 @@ namespace test { return job.parameter.invoKey.part.a; }; - JobTicket const& ticket = seg.jobTicket(0); + JobTicket& ticket = seg.jobTicket(0); CHECK (13 == getMarker (ticket)); auto prereq = ticket.getPrerequisites(); CHECK (not isnil(prereq)); diff --git a/tests/core/steam/play/dummy-play-connection.hpp b/tests/core/steam/play/dummy-play-connection.hpp index 7505dd88e..b4d919190 100644 --- a/tests/core/steam/play/dummy-play-connection.hpp +++ b/tests/core/steam/play/dummy-play-connection.hpp @@ -136,6 +136,24 @@ namespace test { return mockBuilder_.getModelPort (index); } + /** search through all port <-> sink connections + * supported by this DummyPlayConnection + * @return `true` if found both a math on port an sink. + */ + bool + isSupported (ModelPort port, DataSink sink) + { + uint i{0}; + for (auto it=getAllModelPorts(); bool{it}; ++it, ++i) + if (port == *it) + { + auto [refPort, refSink] = getModelPort(i); + if (refSink == sink) + return true; + } + return false; + } + POutputManager provide_testOutputSlot() { diff --git a/tests/core/vault/engine/dummy-job.cpp b/tests/core/vault/engine/dummy-job.cpp index ffc13ccb8..0bc6bff62 100644 --- a/tests/core/vault/engine/dummy-job.cpp +++ b/tests/core/vault/engine/dummy-job.cpp @@ -40,11 +40,13 @@ #include "vault/engine/dummy-job.hpp" +#include "vault/engine/nop-job-functor.hpp" #include "lib/test/test-helper.hpp" #include "lib/time/timevalue.hpp" #include "vault/real-clock.hpp" #include "lib/null-value.hpp" #include "lib/hash-value.h" +#include "lib/depend.hpp" #include "lib/util.hpp" #include @@ -180,6 +182,9 @@ namespace engine { /** actual instance of the test dummy job functor */ DummyClosure dummyClosure; + /** access to the fallback-implementation for empty segments */ + lib::Depend nopFunctor; + }// (End)Implementation details @@ -255,6 +260,22 @@ namespace engine { { return dummyClosure; } + + /** @internal likewise to support the MockDispatcher diagnostics; + * locate here since this is a dedicated translation unit + * @return `true` iff the job was defined in the typical way used by + * JobTicket to generate fill jobs for empty segments. + * @see JobTicket::JobTicket::createJobFor(FrameCoord) + */ + bool + DummyJob::isNopJob (Job const& job) + { + InvocationInstanceID empty; ///////////////////////////////////////////////////////////////////////TICKET #1287 : temporary workaround until we get rid of the C base structs + JobClosure& jobFunctor = static_cast (*job.jobClosure); //////////////////////////TICKET #1287 : fix actual interface down to JobFunctor (after removing C structs) + return lumiera_invokey_eq (&util::unConst(job).parameter.invoKey, &empty) + and util::isSameObject (jobFunctor, nopFunctor()); + } + }} // namespace vault::engine diff --git a/tests/core/vault/engine/dummy-job.hpp b/tests/core/vault/engine/dummy-job.hpp index d12fb7c9a..d2828b151 100644 --- a/tests/core/vault/engine/dummy-job.hpp +++ b/tests/core/vault/engine/dummy-job.hpp @@ -68,6 +68,7 @@ namespace engine { static int invocationAdditionalKey (Job const& job); static JobClosure& getFunctor(); + static bool isNopJob (Job const&); }; }} // namespace vault::engine diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 0557dcc28..ee8d470e9 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -70119,7 +70119,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -70343,7 +70343,20 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + + + + + +

+ derzeit erzeugt die Mock-Lösung nur ein NodeGraphAttachment für ModelPort-Index ≔ 0 +

+

+ und der MockDispatcher doppelt die definierte Exit-Node struktur identisch auf +

+ +
@@ -72415,9 +72428,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - + + + @@ -72428,12 +72441,12 @@ Date:   Thu Apr 20 18:53:17 2023 +0200

- - - - + + + + - + @@ -72444,14 +72457,25 @@ Date:   Thu Apr 20 18:53:17 2023 +0200

+ + + + + +

+ ...eine billige und manipulative Implementierung in MockSegmentation +

+ +
+
- - + + - + @@ -73556,10 +73580,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - - + + + + @@ -73578,8 +73602,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + @@ -74536,7 +74560,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -74547,6 +74571,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ @@ -74977,16 +75002,16 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - - + + + + - + @@ -74997,7 +75022,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200

- +
@@ -75006,11 +75031,11 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - - - - + + + + + @@ -75032,6 +75057,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + +
@@ -75394,9 +75422,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + - + @@ -75477,8 +75505,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + + @@ -75492,8 +75521,11 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- - + + + + + @@ -75569,6 +75601,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + + +