Job-Planning: rework pipeline to enable dependency planning
This finishes the last series of refactorings; the basic concept remains the same, but in the initial version we arranged the expander function in the pipeline to maintain a Tuple (parent, child) for the JobTickets. Unfortunately this turned out to be insufficient, since JobTicket is effectively const and responsible for a complete Sement, so there is no room to memorise a Deadline for the parent dependency. This leads to the better idea to link the JobPlanning aggregators themselves by parent-child references, which is possible since the whole dependency chain actually sits in the stack embedded into the Expander (in the pipeline)
This commit is contained in:
parent
2b92dab377
commit
dc1bbfc918
4 changed files with 148 additions and 60 deletions
|
|
@ -280,10 +280,6 @@ namespace engine {
|
|||
} // expected next to invoke pullFrom(port,sink)
|
||||
|
||||
|
||||
/** Package a Ticket together with a direct dependency,
|
||||
* to allow setup of schedule times in downstream processing */
|
||||
using TicketDepend = std::pair<JobTicket*, JobTicket*>;
|
||||
|
||||
|
||||
/**
|
||||
* Builder: connect to the JobTicket defining the actual processing
|
||||
|
|
@ -295,11 +291,11 @@ namespace engine {
|
|||
size_t portIDX = SRC::dispatcher->resolveModelPort(port);
|
||||
return buildPipeline (
|
||||
SRC::transform(
|
||||
[portIDX](PipeFrameTick& core) -> TicketDepend
|
||||
[portIDX](PipeFrameTick& core)
|
||||
{
|
||||
return {nullptr
|
||||
,& core.dispatcher->getJobTicketFor(portIDX, core.currPoint)
|
||||
};
|
||||
return JobPlanning{core.dispatcher->getJobTicketFor(portIDX, core.currPoint)
|
||||
,core.currPoint
|
||||
,core.frameNr};
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
@ -314,15 +310,9 @@ namespace engine {
|
|||
{
|
||||
return buildPipeline (
|
||||
SRC::expandAll(
|
||||
[](TicketDepend& currentLevel)
|
||||
[](JobPlanning& currentLevel)
|
||||
{
|
||||
JobTicket* parent = currentLevel.second;
|
||||
return lib::transformIterator (parent->getPrerequisites()
|
||||
,[&parent](JobTicket& prereqTicket)
|
||||
{ // parent shifted up to first pos
|
||||
return TicketDepend{parent, &prereqTicket};
|
||||
}
|
||||
);
|
||||
return currentLevel.buildDependencyPlanning();
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
@ -335,9 +325,9 @@ namespace engine {
|
|||
{
|
||||
return terminatePipeline (
|
||||
SRC::transform(
|
||||
[sink](TicketDepend& currentLevel)
|
||||
[sink](JobPlanning& currentLevel) -> JobPlanning&
|
||||
{
|
||||
return currentLevel.second; ///////////////////////////////OOO construct a JobPlanning here
|
||||
return currentLevel; ///////////////////////////////OOO the purpose of this function is no longer clear
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,31 @@
|
|||
** From a usage point of view, the _job-planning pipeline_ is an _iterator:_ for each independent
|
||||
** calculation step a new JobPlanning record appears at the output side of the pipeline, holding
|
||||
** all collected data, sufficient to generate the actual job definition, which can then be
|
||||
** handed over to the Scheduler.
|
||||
** handed over to the Scheduler.
|
||||
**
|
||||
** # Implementation of the Job-Planning pipeline
|
||||
**
|
||||
** JobPlanning acts as _working data aggregator_ within the Job-Planning pipeline; for this reason
|
||||
** all data fields are references, and the optimiser is expected to elide them, since after template
|
||||
** instantiation, JobPlanning becomes part of the overall assembled pipeline object, stacked on top
|
||||
** of the Dispatcher::PipeFrameTick, which holds and increments the current frame number. The
|
||||
** underlying play::Timings will provide a _frame grid_ to translate these frame numbers into
|
||||
** the _nominal time values_ used throughout the rest of the render calculations.
|
||||
**
|
||||
** There is one tricky detail to note regarding the handling of calculation prerequisites. The
|
||||
** typical example would be the loading and decoding of media data, which is an IO-bound task and
|
||||
** must be complete before the main frame job can be started. Since the Job-Planning pipeline is
|
||||
** generic, this kind of detail dependency is modelled as _prerequisite JobTicket,_ leading to
|
||||
** an possibly extended depth-first tree expansion, starting from the »master frame ticket« at
|
||||
** the root. This _tree exploration_ is implemented by the TreeExplorer::Expander building block,
|
||||
** which obviously has to maintain a stack of expanded child dependencies. This leads to the
|
||||
** observation, that at any point of this dependency processing, for the complete path from the
|
||||
** child prerequisite up to the root tick there is a sequence of JobPlanning instances placed
|
||||
** into this stack in the Explorer object (each level in this stack is actually an iterator
|
||||
** and handles one level of child prerequisites). The deadline calculation directly exploits
|
||||
** this known arrangement, insofar each JobPlanning has a pointer to its parent (sitting in
|
||||
** the stack level above). See the [IterExplorer unit test](\ref lib::IterTreeExplorer_test::verify_expandOperation)
|
||||
** to understand this recursive on-demand processing in greater detail.
|
||||
**
|
||||
** @warning as of 4/2023 a complete rework of the Dispatcher is underway ///////////////////////////////////////////TICKET #1275
|
||||
**
|
||||
|
|
@ -52,8 +76,7 @@
|
|||
#include "steam/play/output-slot.hpp"
|
||||
#include "steam/play/timings.hpp"
|
||||
#include "lib/time/timevalue.hpp"
|
||||
//#include "lib/iter-explorer.hpp"
|
||||
//#include "lib/iter-adapter.hpp"
|
||||
#include "lib/itertools.hpp"
|
||||
#include "lib/nocopy.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
|
|
@ -68,7 +91,6 @@ namespace engine {
|
|||
using play::Timings;
|
||||
using lib::time::Time;
|
||||
using lib::time::Duration;
|
||||
using lib::time::TimeValue; ////////TODO for FrameLocator, could be obsolete
|
||||
using util::unConst;
|
||||
using util::isnil;
|
||||
|
||||
|
|
@ -95,16 +117,19 @@ namespace engine {
|
|||
JobTicket& jobTicket_;
|
||||
Time const& nominalTime_;
|
||||
FrameCnt const& frameNr_;
|
||||
|
||||
|
||||
public:
|
||||
JobPlanning(JobTicket& ticket, Time const& nominalTime, FrameCnt const& frameNr)
|
||||
JobPlanning (JobTicket& ticket, Time const& nominalTime, FrameCnt const& frameNr)
|
||||
: jobTicket_{ticket}
|
||||
, nominalTime_{nominalTime}
|
||||
, frameNr_{frameNr}
|
||||
{ }
|
||||
|
||||
// move construction is possible
|
||||
|
||||
// using the standard copy operations
|
||||
|
||||
JobTicket& ticket() { return jobTicket_; }
|
||||
bool isTopLevel() const { return not dependentPlan_; }
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -156,7 +181,46 @@ namespace engine {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Build a sequence of dependent JobPlanning scopes for all prerequisites
|
||||
* of this current JobPlanning, and internally linked back to `*this`
|
||||
* @return an iterator which explores the prerequisites of the JobTicket.
|
||||
* @remark typical example would be to load data from file, or to require
|
||||
* the results from some other extended media calculation.
|
||||
* @see Dispatcher::PipelineBuilder::expandPrerequisites()
|
||||
*/
|
||||
auto
|
||||
buildDependencyPlanning()
|
||||
{
|
||||
return lib::transformIterator (jobTicket_.getPrerequisites()
|
||||
,[this](JobTicket& prereqTicket)
|
||||
{
|
||||
return JobPlanning{*this, prereqTicket};
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
/** link to a dependent JobPlanning, for planning of prerequisites */
|
||||
JobPlanning* dependentPlan_{nullptr};
|
||||
|
||||
/**
|
||||
* @internal construct a chained prerequisite JobPlanning,
|
||||
* attached to the dependent »parent« JobPlanning, using the same
|
||||
* frame data, but chaining up the deadlines, so that a Job created
|
||||
* from this JobPlanning needs to be completed before the »parent«
|
||||
* Job (which uses the generated data) can start
|
||||
* @see #buildDependencyPlanning()
|
||||
* @see JobPlanning_test::setupDependentJob()
|
||||
*/
|
||||
JobPlanning (JobPlanning& parent, JobTicket& prerequisite)
|
||||
: jobTicket_{prerequisite}
|
||||
, nominalTime_{parent.nominalTime_}
|
||||
, frameNr_{parent.frameNr_}
|
||||
, dependentPlan_{&parent}
|
||||
{ }
|
||||
|
||||
|
||||
|
||||
Duration
|
||||
totalLatency (Timings const& timings)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -201,8 +201,8 @@ namespace test {
|
|||
.pullFrom (port);
|
||||
|
||||
CHECK (not isnil (pipeline));
|
||||
CHECK (nullptr == pipeline->first); // is a top-level ticket
|
||||
JobTicket& ticket = *pipeline->second;
|
||||
CHECK (pipeline->isTopLevel()); // is a top-level ticket
|
||||
JobTicket& ticket = pipeline->ticket();
|
||||
|
||||
Job job = ticket.createJobFor(Time::ZERO); // actual time point is irrelevant here
|
||||
CHECK (dispatcher.verify(job, port, sink));
|
||||
|
|
@ -239,14 +239,14 @@ namespace test {
|
|||
|
||||
// the first element is identical to previous test
|
||||
CHECK (not isnil (pipeline));
|
||||
CHECK (nullptr == pipeline->first);
|
||||
Job job = pipeline->second->createJobFor (Time::ZERO);
|
||||
CHECK (pipeline->isTopLevel());
|
||||
Job job = pipeline->ticket().createJobFor (Time::ZERO);
|
||||
CHECK (11 == job.parameter.invoKey.part.a);
|
||||
|
||||
auto visualise = [](auto& pipeline) -> string
|
||||
{
|
||||
Time frame{pipeline.currPoint}; // can access the embedded PipeFrameTick core to get "currPoint" (nominal time)
|
||||
Job job = pipeline->second->createJobFor(frame); // looking always at the second element, which is the current JobTicket
|
||||
Job job = pipeline->ticket().createJobFor(frame); // looking always at the second element, which is the current JobTicket
|
||||
TimeValue nominalTime{job.parameter.nominalTime}; // job parameter holds the microseconds (gavl_time_t)
|
||||
int32_t mark = job.parameter.invoKey.part.a; // the MockDispatcher places the given "mark" here
|
||||
return _Fmt{"J(%d|%s)"} % mark % nominalTime;
|
||||
|
|
|
|||
|
|
@ -75823,7 +75823,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1686964642887" ID="ID_1372706833" MODIFIED="1686964706541" TEXT="verwende diese anstelle der erwarteten real-Grid-Time">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1686965001287" ID="ID_1948616906" MODIFIED="1686965057296">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1686965001287" ID="ID_1948616906" MODIFIED="1687137549677">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
|
|
@ -75841,7 +75841,10 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1686965163417" ID="ID_1358303460" MODIFIED="1686965216709" TEXT="eine Deadline ist Ergebnis einer Integration">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1686965322397" ID="ID_966792976" MODIFIED="1686965331679" TEXT="das JobTIcket kann die gar nicht errechnen"/>
|
||||
<node CREATED="1686965332609" ID="ID_1561329377" MODIFIED="1686965353628" TEXT="Rechnung wäre rekursiv, quadratisch"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1686965332609" ID="ID_1561329377" MODIFIED="1687137693493" TEXT="Rechnung wäre rekursiv, quadratisch">
|
||||
<linktarget COLOR="#e42d77" DESTINATION="ID_1561329377" ENDARROW="Default" ENDINCLINATION="361;27;" ID="Arrow_ID_242786471" SOURCE="ID_1507798641" STARTARROW="None" STARTINCLINATION="481;-20;"/>
|
||||
<icon BUILTIN="clanbomber"/>
|
||||
</node>
|
||||
<node CREATED="1686965354284" ID="ID_172681606" MODIFIED="1687039516255" TEXT="oder erfordert »schleppenden« Zustand">
|
||||
<arrowlink COLOR="#8e5572" DESTINATION="ID_1929351072" ENDARROW="Default" ENDINCLINATION="28;-47;" ID="Arrow_ID_753643955" STARTARROW="None" STARTINCLINATION="-70;5;"/>
|
||||
</node>
|
||||
|
|
@ -75865,7 +75868,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1687039664958" ID="ID_1390938163" MODIFIED="1687039709039" TEXT="oder muß in die dort erzeugte Datenstruktur nachträglich gespeichert werden"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1687039717162" ID="ID_59086385" MODIFIED="1687039770869" TEXT="Lösungsansatz: Expander arbeitet bereits auf JobPlanning als Datenstruktur">
|
||||
<node COLOR="#435e98" CREATED="1687039717162" ID="ID_59086385" MODIFIED="1687137591057" TEXT="Lösungsansatz: Expander arbeitet bereits auf JobPlanning als Datenstruktur">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1687039778410" ID="ID_696364803" MODIFIED="1687039807242" TEXT="damit wäre das (etwas sonderbare) Tupel aus JobPlanning-Pointern abzulösen"/>
|
||||
<node CREATED="1687040058436" ID="ID_1402323400" MODIFIED="1687040071534" TEXT="JobPlanning hätte dann einen »chaining-ctor«"/>
|
||||
|
|
@ -75920,22 +75923,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1687043634555" ID="ID_71179253" MODIFIED="1687044340413" TEXT="Umschichten der Daten">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1687044201408" ID="ID_1507798641" MODIFIED="1687047110612" TEXT="die Deadline sollte man als Wert speichern (caching)">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...denn sonst würde es genau zu rekursiven kaskadierenden (exponentiell aufwendigen) Aufrufen der Deadline-Berechnungs-Logik kommen; um das Caching zu steuern, kann ich einen Marker-Wert Time::NEVER verwenden
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1687043695271" ID="ID_497206730" MODIFIED="1687044319733" TEXT="JobTicket-parent-Pointer in JobPlanning-parent verwandeln">
|
||||
<node COLOR="#338800" CREATED="1687043634555" ID="ID_71179253" MODIFIED="1687137392702" TEXT="Umschichten der Daten">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1687043695271" ID="ID_497206730" MODIFIED="1687137643989" TEXT="JobTicket-parent-Pointer in JobPlanning-parent verwandeln">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
|
|
@ -75946,6 +75936,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#5b280f" CREATED="1687043645122" ID="ID_1471106329" MODIFIED="1687131535956" TEXT="FrameCoord müssen bereits in den TickGenerator">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
|
|
@ -75963,7 +75954,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="smily_bad"/>
|
||||
</node>
|
||||
<node CREATED="1687047139677" ID="ID_1123653637" MODIFIED="1687047160987" TEXT="es bläht den TickGenerator auf und macht ihn asymetrisch"/>
|
||||
<node CREATED="1687047169092" ID="ID_1819824079" MODIFIED="1687047186765">
|
||||
<node COLOR="#4a4398" CREATED="1687047169092" ID="ID_1819824079" MODIFIED="1687137416207">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
|
|
@ -75980,7 +75971,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node CREATED="1687047521489" ID="ID_1343365951" MODIFIED="1687047537890" TEXT="meistens sind sie nur halb gültig — oder redundant"/>
|
||||
<node COLOR="#435e98" CREATED="1687047541216" ID="ID_3859431" MODIFIED="1687131788560" TEXT="wichtige bestehende Verwendungen">
|
||||
<node COLOR="#435e98" CREATED="1687047541216" FOLDED="true" ID="ID_3859431" MODIFIED="1687131788560" TEXT="wichtige bestehende Verwendungen">
|
||||
<icon BUILTIN="info"/>
|
||||
<node COLOR="#338800" CREATED="1687047579697" ID="ID_737360799" MODIFIED="1687052483835" TEXT="JobTicket::createJobFor (FrameCoord)">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
|
|
@ -76083,13 +76074,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1687053133875" ID="ID_613644358" MODIFIED="1687053158627" TEXT="...und stattdessen wird direkt auf die Felder im TickGenerator verwiesen (const&)">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1687053133875" ID="ID_613644358" MODIFIED="1687137361826" TEXT="...und stattdessen wird direkt auf die Felder im TickGenerator verwiesen (const&)">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1687131811965" ID="ID_1192855537" MODIFIED="1687131818555" TEXT="Pipeline-Definition umbauen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1687131811965" ID="ID_1192855537" MODIFIED="1687137517231" TEXT="Pipeline-Definition umbauen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1687131819547" ID="ID_1957351479" MODIFIED="1687133763828" TEXT="Problem: ItemWrapper weist Werte zu">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1687131845108" ID="ID_1247271270" MODIFIED="1687131867304" TEXT="...und kann deshalb keine non-copyable-Typen handhaben">
|
||||
|
|
@ -76156,16 +76147,59 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1687137207845" ID="ID_41795599" MODIFIED="1687137250587" TEXT="JobPlanning nun bereits auf der pull-From-Ebene erzeugen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1687137268479" ID="ID_1427542554" MODIFIED="1687137280067" TEXT="chained-Planning-Konstruktor einführen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1687137281027" ID="ID_387219967" MODIFIED="1687137332964" TEXT="TransformIterator in JobPlanning erstellen">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node COLOR="#1768b8" CREATED="1687137306215" ID="ID_1183352863" MODIFIED="1687137343253" TEXT="Ohh ...alles vieeel besser so">
|
||||
<icon BUILTIN="ksmiletris"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1687044355596" ID="ID_1593217439" MODIFIED="1687044369362" TEXT="JobPlanningPipeline_test anpassen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1687044370372" ID="ID_1608005431" MODIFIED="1687044408084" TEXT="der hat bisher das JobTIcket-Tupel verwendet">
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1687044355596" ID="ID_1593217439" MODIFIED="1687137510008" TEXT="JobPlanningPipeline_test anpassen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1687044370372" ID="ID_1608005431" MODIFIED="1687137469706" TEXT="der hat bisher das JobTicket-Tupel verwendet">
|
||||
<icon BUILTIN="info"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1687044384151" ID="ID_228309908" MODIFIED="1687044397980" TEXT="ggfs speziellen Accessor schaffen?">
|
||||
<node COLOR="#338800" CREATED="1687044384151" ID="ID_228309908" MODIFIED="1687137487850" TEXT="speziellen Accessoren">
|
||||
<font NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="help"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1687137489231" ID="ID_641532111" MODIFIED="1687137497724" TEXT="ticket()">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1687137491791" ID="ID_1927053233" MODIFIED="1687137497725" TEXT="isTopLevel()">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1687137501852" ID="ID_32393171" MODIFIED="1687137508724" TEXT="Hey... läuft">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1687137618239" ID="ID_1445585564" MODIFIED="1687137626846" TEXT="Verkettung der Deadlines implementieren">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1687044201408" ID="ID_1507798641" MODIFIED="1687137690544" TEXT="die Deadline sollte man als Wert speichern (caching)">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...denn sonst würde es genau zu rekursiven kaskadierenden (exponentiell aufwendigen) Aufrufen der Deadline-Berechnungs-Logik kommen; um das Caching zu steuern, kann ich einen Marker-Wert Time::NEVER verwenden
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<arrowlink COLOR="#e42d77" DESTINATION="ID_1561329377" ENDARROW="Default" ENDINCLINATION="361;27;" ID="Arrow_ID_242786471" STARTARROW="None" STARTINCLINATION="481;-20;"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1687137710306" ID="ID_1967222999" MODIFIED="1687137719434" TEXT="Refactoring: Berechnung symmetrisch machen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1687137733390" ID="ID_1496251627" MODIFIED="1687137744225" TEXT="top-Level: Deadline stammt von den Timings"/>
|
||||
<node CREATED="1687137744907" ID="ID_348107888" MODIFIED="1687137759424" TEXT="Prerequisite: Deadline stammt vom dependent Plan"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue