Lumiera  0.pre.03
»edit your freedom«
scheduler-invocation.hpp
Go to the documentation of this file.
1 /*
2  SCHEDULER-INVOCATION.hpp - invocation layer of the render engine scheduler
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 
14 
51 #ifndef SRC_VAULT_GEAR_SCHEDULER_INVOCATION_H_
52 #define SRC_VAULT_GEAR_SCHEDULER_INVOCATION_H_
53 
54 
55 #include "vault/common.hpp"
56 #include "lib/nocopy.hpp"
57 #include "vault/gear/activity.hpp"
58 #include "lib/time/timevalue.hpp"
59 #include "lib/util.hpp"
60 
61 #include <queue>
62 #include <boost/lockfree/queue.hpp>
63 #include <unordered_set>
64 #include <utility>
65 
66 namespace vault{
67 namespace gear {
68 
69  using lib::time::Time;
70  using std::move;
71 
72  namespace error = lumiera::error;
73 
74  namespace {// Internal defaults
75  const size_t INITIAL_CAPACITY = 128;
76  }
77 
83  {
84  Activity* activity;
85  int64_t starting;
86  int64_t deadline;
87 
88  uint32_t manifestation :32;
89  bool isCompulsory :1;
90 
92  : activity{nullptr}
93  , starting{_raw(Time::ANYTIME)}
94  , deadline{_raw(Time::NEVER)}
95  , manifestation{0}
96  , isCompulsory{false}
97  { }
98 
99  ActivationEvent(Activity& act, Time when
100  , Time dead =Time::NEVER
102  , bool compulsory =false)
103  : activity{&act}
104  , starting{_raw(act.constrainedStart(when))}
105  , deadline{_raw(act.constrainedDeath(dead))}
106  , manifestation{manID}
107  , isCompulsory{compulsory}
108  { }
109  // default copy operations acceptable
110 
115  bool
116  operator< (ActivationEvent const& o) const
117  {
118  return starting > o.starting;
119  }
120 
121  operator bool() const { return bool{activity}; }
122  operator Activity*() const { return activity; }
123 
124  Time startTime() const { return Time{TimeValue{starting}};}
125  Time deathTime() const { return Time{TimeValue{deadline}};}
126 
127  void
128  refineTo (Activity* chain, Time when, Time dead)
129  {
130  activity = chain;
131  starting = _raw(activity->constrainedStart (when.isRegular()? when:startTime()));
132  deadline = _raw(activity->constrainedDeath (dead.isRegular()? dead:deathTime()));
133  }
134  };
135 
136 
137 
138 
139  /***************************************************/
150  {
151  using InstructQueue = boost::lockfree::queue<ActivationEvent>;
152  using PriorityQueue = std::priority_queue<ActivationEvent>;
153  using ActivationSet = std::unordered_set<ManifestationID>;
154 
155  InstructQueue instruct_;
156  PriorityQueue priority_;
157 
158  ActivationSet allowed_;
159 
160  public:
162  : instruct_{INITIAL_CAPACITY}
163  , priority_{}
164  , allowed_{}
165  { }
166 
167 
169  void
171  {
172  instruct_.consume_all([](auto&){/*obliterate*/});
173  priority_ = PriorityQueue();
174  }
175 
176 
180  void
182  {
183  bool success = instruct_.push (move (actEvent));
184  if (not success)
185  throw error::Fatal{"Scheduler entrance: memory allocation failed"};
186  }
187 
188 
193  void
195  {
196  ActivationEvent actEvent;
197  while (instruct_.pop (actEvent))
198  priority_.push (move (actEvent));
199  }
200 
201 
207  void
209  {
210  priority_.push (move (actEvent));
211  }
212 
213 
220  {
221  return priority_.empty()? ActivationEvent()
222  : priority_.top();
223  }
224 
233  {
234  ActivationEvent head = peekHead();
235  if (head)
236  priority_.pop();
237  return head;
238  }
239 
248  void
250  {
251  if (manID)
252  allowed_.insert (manID);
253  }
254 
255  void
256  drop (ManifestationID manID)
257  {
258  allowed_.erase (manID);
259  }
260 
261 
262  /* ===== query functions ===== */
263 
265  bool
266  isDue (Time now) const
267  {
268  return not priority_.empty()
269  and priority_.top().starting <= waterLevel(now);
270  }
271 
274  bool
275  isMissed (Time now) const
276  {
277  return not priority_.empty()
278  and waterLevel(now) > priority_.top().deadline;
279  }
280 
282  bool
284  {
285  return manID == ManifestationID()
286  or util::contains (allowed_, manID);
287  }
288 
290  bool
291  isOutdated (Time now) const
292  {
293  return isMissed (now)
294  or (not priority_.empty()
295  and not isActivated (priority_.top().manifestation));
296  }
297 
299  bool
300  isOutOfTime (Time now) const
301  {
302  return isMissed (now)
303  and (not priority_.empty()
304  and priority_.top().isCompulsory
305  and isActivated (priority_.top().manifestation));
306  }
307 
308  bool
309  hasPendingInput() const
310  {
311  return not instruct_.empty();
312  }
313 
314  bool
315  empty() const
316  {
317  return instruct_.empty()
318  and priority_.empty();
319  }
320 
322  Time
323  headTime() const
324  {
325  return priority_.empty()? Time::NEVER
326  : Time{TimeValue{priority_.top().starting}};
327  } //Note: 64-bit waterLevel corresponds to µ-Ticks
328 
329  private:
330  static int64_t
331  waterLevel (Time time)
332  {
333  return _raw(time);
334  }
335  };
336 
337 
338 
339 }} // namespace vault::gear
340 #endif /*SRC_VAULT_GEAR_SCHEDULER_INVOCATION_H_*/
static const Time ANYTIME
border condition marker value. ANYTIME <= any time value
Definition: timevalue.hpp:313
Record to describe an Activity, to happen within the Scheduler&#39;s control flow.
Definition: activity.hpp:226
void discardSchedule()
forcibly clear out the schedule
void feedPrioritisation(ActivationEvent actEvent)
Feed the given Activity directly into time prioritisation, effectively bypassing the thread dispatchi...
Any copy and copy construction prohibited.
Definition: nocopy.hpp:37
Time constrainedDeath(Time death)
Definition: activity.hpp:450
bool isActivated(ManifestationID manID) const
determine if Activities with the given ManifestationID shall be processed
Lumiera&#39;s internal time value datatype.
Definition: timevalue.hpp:299
void instruct(ActivationEvent actEvent)
Accept an ActivationEvent with an Activity for time-bound execution.
void activate(ManifestationID manID)
Enable entries marked with a specific ManifestationID to be processed.
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:190
Mix-Ins to allow or prohibit various degrees of copying and cloning.
bool isOutdated(Time now) const
determine if Activity at scheduler is outdated and should be discarded
Marker for current (and obsolete) manifestations of a CalcStream processed by the Render-Engine...
Definition: activity.hpp:84
bool isRegular() const
Definition: timevalue.hpp:771
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
bool isMissed(Time now) const
determine if the Activity at scheduler head missed it&#39;s deadline.
Basic set of definitions and includes commonly used together (Vault).
static const Time NEVER
border condition marker value. NEVER >= any time value
Definition: timevalue.hpp:314
bool isOutOfTime(Time now) const
detect a compulsory Activity at scheduler head with missed deadline
ActivationEvent pullHead()
Retrieve from the scheduling queue the entry with earliest start time.
a family of time value like entities and their relationships.
void feedPrioritisation()
Pick up all new events from the entrance queue and enqueue them to be retrieved ordered by start time...
basic constant internal time value.
Definition: timevalue.hpp:133
Time constrainedStart(Time start)
Definition: activity.hpp:443
Vault-Layer implementation namespace root.
bool isDue(Time now) const
Determine if there is work to do right now.
Scheduler Layer-1 : time based dispatch.
Descriptor for a piece of operational logic performed by the scheduler.