clarify and settle the relation between Dispatcher and PlanningStepGenerator

the solution is to introduce a superinterface
and let Dispatcher augment that with the specific parts.
This way, the Job planning only has to rely on the
rather generic stuff (TimeAnchor, FrameCoord)

NOTE: this commit makes the whole JobPlanning machinery
compilable for the first time!
This commit is contained in:
Fischlurch 2012-10-10 04:35:56 +02:00
parent 3300d00cc8
commit 44435fd1db
6 changed files with 87 additions and 41 deletions

View file

@ -30,7 +30,8 @@
namespace proc {
namespace engine {
Dispatcher::~Dispatcher() { } // emit VTable here....
Dispatcher::~Dispatcher() { } // emit VTables and Typeinfo here....
FrameSequencer::~FrameSequencer() { }
/** */
@ -65,17 +66,8 @@ namespace engine {
UNIMPLEMENTED ("wrap already planned jobs, appending a continuation to pick up later");
return *this;
}
/** */
JobTicket&
Dispatcher::accessJobTicket (FrameCoord const& frameID)
{
UNIMPLEMENTED ("figure out and create the actual JobTicket, for the current segment and the given port");
}

View file

@ -49,20 +49,40 @@ namespace engine {
// class ExitNode;
/**
* @todo 11/11 extremely fuzzy at the moment
* Internal abstraction: a service within the engine
* for translating a logical calculation stream (corresponding to a PlayProcess)
* into a sequence of individual RenderJob entries for calculations and data access.
* The actual implementation of this service is tied to the low-level-model, i.e.
* the render nodes network. The Dispatcher service is used to implement the CalcStreams
* during playback and rendering; there will be a continuous, chunk-wise proceeding
* evaluation and planning of new jobs, which can then be handed over to the Scheduler
* for time-bound activation.
*
* \par usage considerations
* the asynchronous and ongoing nature of the render process mandates to avoid a central
* instance for operating this planning process. Instead, each chunk of planned jobs
* contains a continuation job, which -- on activation -- will pick up the planning
* of the next chunk. The Dispatcher interface was shaped to support this process,
* with a local JobBuilder to be used within the continuation job, and a TimeAnchor
* to represent the continuation point. All the complexities of planning jobs are
* hidden within the JobPlanningSequence, which, for the purpose of dispatching
* a series of jobs just looks like a sequence of job descriptors
*
* @todo 10/12 still WIP, but conceptually settled by now
*/
class Dispatcher
: boost::noncopyable
: public FrameLocator
{
struct JobBuilder
{
Dispatcher& dispatcher_;
TimeAnchor refPoint_;
ModelPort modelPort_;
uint channel_;
/////TODO need storage for the continuation
FrameCoord relativeFrameLocation (TimeAnchor refPoint, uint frameCountOffset);
FrameCoord relativeFrameLocation (TimeAnchor refPoint, uint frameCountOffset =0);
JobBuilder& establishNextJobs (TimeAnchor refPoint);
@ -70,11 +90,10 @@ namespace engine {
operator JobPlanningSequence()
{
UNIMPLEMENTED ("how to represent the closure for defining and scheduling jobs");
TODO ("build the continuation job if necessary, wrap the sequence");
////////TODO: use a closure based on FrameCoord plus a back-reference to the Dispatcher.
//////////// Thus actually we need a *generator* for a sequence of FrameCoord
//////////// This generator is then wrapped up into an evaluation-Monad (IterExplorer)
return JobPlanningSequence(
relativeFrameLocation(refPoint_), dispatcher_);
}
};
@ -84,11 +103,12 @@ namespace engine {
JobBuilder onCalcStream (ModelPort modelPort, uint channel);
JobTicket& accessJobTicket (FrameCoord const&);
protected:
virtual FrameCoord locateRelative (FrameCoord, uint frameCountOffset) =0;
virtual FrameCoord locateRelative (TimeAnchor, uint frameCountOffset) =0;
virtual FrameCoord locateRelative (TimeAnchor, uint frameCountOffset) =0; //////////TODO is this really an interface operation, or just a convenience shortcut?
virtual JobTicket& accessJobTicket (ModelPort, TimeValue nominalTime) =0;
};

View file

@ -39,7 +39,7 @@ namespace engine {
//using lib::time::TimeSpan;
using lib::time::Duration;
//using lib::time::FSecs;
using lib::time::Time;
using lib::time::TimeVar;
//
// class ExitNode;
@ -50,7 +50,7 @@ namespace engine {
* A frame render job can be characterised by
* - the nominal (timeline) time of the frame
* - the corresponding frame-number
* - the real wall-clock time of expected delivery
* - the real wall-clock time of expected delivery//////////////TODO : might be handy, but not sure if this information is substantial here
* - timing constraints (e.g. latency to observe) //////////////TODO : not clear if we repeat this information here
* - the actual node to pull data from
* - the segment holding that node //////////////TODO : is this information really required??
@ -64,7 +64,7 @@ namespace engine {
{
public:
Time absoluteNominalTime;
TimeVar absoluteNominalTime;
int64_t absoluteFrameNumber;
ModelPort modelPort;

View file

@ -28,8 +28,8 @@
//#include "proc/state.hpp"
#include "proc/engine/job.hpp"
#include "proc/engine/job-ticket.hpp"
#include "proc/engine/time-anchor.hpp"
//#include "proc/engine/frame-coord.hpp"
//#include "proc/engine/time-anchor.hpp"
#include "proc/engine/frame-coord.hpp"
//#include "lib/time/timevalue.hpp"
//#include "lib/time/timequant.hpp"
//#include "lib/meta/function.hpp"
@ -226,7 +226,27 @@ namespace engine {
/**
* Abstraction: a Facility to establish frame coordinates
* and identify and access the execution plan for this frame.
* @see Dispatcher the service interface actually used
*/
class FrameLocator
: public FrameSequencer
{
public:
JobTicket&
getJobTicketFor (FrameCoord location)
{
return accessJobTicket (location.modelPort, location.absoluteNominalTime);
}
protected:
virtual JobTicket& accessJobTicket (ModelPort, TimeValue nominalTime) =0;
};
/**
* Generate a sequence of starting points for Job planning,
@ -240,25 +260,22 @@ namespace engine {
*/
class PlanningStepGenerator
{
engine::FrameSequencer* locationGenerator_;
engine::FrameCoord current_;
FrameLocator* locationGenerator_;
FrameCoord currentLocation_;
public:
typedef JobPlanning value_type;
typedef JobPlanning& reference;
typedef JobPlanning * pointer;
// PlanningStepGenerator() { }
PlanningStepGenerator(engine::TimeAnchor startPoint)
: anchor_(startPoint)
PlanningStepGenerator(FrameCoord startPoint, FrameLocator& locator)
: locationGenerator_(&locator)
, currentLocation_(startPoint)
{ }
//////////////////////////////////////////////////////////////TODO actually we need two distinct services
//////////////////////////////////////////////////////////////TODO - getting the next FrameCoord
//////////////////////////////////////////////////////////////TODO - getting the JobTicket for this location
//////////////////////////////////////////////////////////////TODO Actually, the Dispatcher would provide exactly those services,
//////////////////////////////////////////////////////////////TODO but depending on the Dispatcher constitutes a cyclic dependency.
//////////////////////////////////////////////////////////////TODO There seems to be a problem hidden somewhere in this design.
// default copyable
/* === Iteration control API for IterStateWrapper== */
@ -325,10 +342,10 @@ namespace engine {
public:
// JobPlanningSequence() { }
JobPlanningSequence(engine::TimeAnchor startPoint)
JobPlanningSequence(engine::FrameCoord startPoint, FrameLocator& locator)
: ExpandedPlanningSequence(
JobPlanningChunkStartPoint(
PlanningStepGenerator(startPoint))
PlanningStepGenerator(startPoint,locator))
>>= expandPrerequisites)
{ }

View file

@ -63,8 +63,9 @@ namespace builder {
: boost::noncopyable
{
/////////////////////////////////////////////////TODO: placeholder code
/////////////////////////////////////////////////TODO: see the planned structure at http://lumiera.org/wiki/renderengine.html#Fixture
typedef ID<Pipe> PID;
// typedef ID<Struct> StID;
public:

View file

@ -83,6 +83,22 @@ namespace test {
{
UNIMPLEMENTED ("dummy implementation of the core dispatch operation");
}
FrameCoord
locateRelative (FrameCoord, uint frameCountOffset)
{
UNIMPLEMENTED ("dummy implementation of the core dispatch operation");
}
FrameCoord
locateRelative (TimeAnchor, uint frameCountOffset)
{
UNIMPLEMENTED ("dummy implementation of the core dispatch operation");
}
JobTicket&
accessJobTicket (ModelPort, TimeValue nominalTime)
{
UNIMPLEMENTED ("dummy implementation of the model backbone / segmentation");
}
public:
@ -153,7 +169,7 @@ namespace test {
CHECK (coordinates.modelPort == modelPort);
CHECK (coordinates.channelNr == channel);
JobTicket& executionPlan = dispatcher.accessJobTicket (coordinates);
JobTicket& executionPlan = dispatcher.getJobTicketFor (coordinates);
CHECK (executionPlan.isValid());
Job frameJob = executionPlan.createJobFor (coordinates); //////////////////////////////TODO this is wrong: we never create a single job!
@ -184,11 +200,11 @@ namespace test {
// Verify the planned Jobs
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #880
CHECK (!isnil (jobs));
vector<Job> plannedChunk;
lib::append_all (jobs, plannedChunk);
#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #880
uint chunksize = plannedChunk.size();
CHECK (chunksize == timings.getPlanningChunkSize());