Loading...
Searching...
No Matches
speculationExecutorEngine.h
Go to the documentation of this file.
1//
2// Copyright 2025 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7#ifndef PXR_EXEC_VDF_SPECULATION_EXECUTOR_ENGINE_H
8#define PXR_EXEC_VDF_SPECULATION_EXECUTOR_ENGINE_H
9
11
12#include "pxr/pxr.h"
13
15
20#include "pxr/exec/vdf/node.h"
23
24PXR_NAMESPACE_OPEN_SCOPE
25
27
37template <typename DataManagerType>
39 public VdfPullBasedExecutorEngine<DataManagerType>
40{
41 // Base type definition
42 typedef
44 Base;
45
46public:
47
51 const VdfSpeculationExecutorBase &speculationExecutor,
52 DataManagerType *dataManager) :
53 VdfPullBasedExecutorEngine<DataManagerType>(
54 speculationExecutor, dataManager),
55 _writeBackExecutor(const_cast<VdfExecutorInterface *>(
56 speculationExecutor.GetNonSpeculationParentExecutor())) {
57 TF_VERIFY(_writeBackExecutor);
58 }
59
64 const VdfSchedule &schedule,
65 const VdfRequest &computeRequest,
66 VdfExecutorErrorLogger *errorLogger) {
68 schedule, computeRequest, errorLogger,
69 [](const VdfMaskedOutput &, size_t){});
70 }
71
77 template <typename F>
78 void RunSchedule(
79 const VdfSchedule &schedule,
80 const VdfRequest &computeRequest,
81 VdfExecutorErrorLogger *errorLogger,
82 F &&callback);
83
84private:
85 // MSVC errors out if Base::ExecutionStageStart is accessed in the
86 // _OutputToExecute constructor, because the enumerator is protected in the
87 // base class. GCC and clang do not consider this an error. To work around
88 // this issue, we loft the enumerator into the namespace of the derived
89 // class where _OutputToExecute() has the proper privileges across all
90 // compilers.
91 static constexpr typename Base::_ExecutionStage _ExecutionStageStart =
92 Base::ExecutionStageStart;
93
94 // This struct contains the necessary state to compute an output.
95 //
96 struct _OutputToExecute {
97
98 // Constructor that takes schedule node and output.
99 _OutputToExecute(const VdfSchedule::OutputId &outputId) :
100 outputId(outputId),
101 stage(_ExecutionStageStart),
102 numPushed(0),
103 inputsSpeculate(false)
104 { }
105
106 // The schedule identifier for the output to execute.
107 VdfSchedule::OutputId outputId;
108
109 // The current phase of this output in the execution stack.
110 typename Base::_ExecutionStage stage;
111
112 // The number of inputs that this output is waiting on.
113 int numPushed;
114
115 // Whether or not our read inputs speculate.
116 bool inputsSpeculate;
117 };
118
119 // This method adds \p output to the \p outputs vector.
120 // Returns \c true if it added a new output and \c false otherwise.
121 //
122 bool _PushBackOutputForSpeculation(
123 std::vector< _OutputToExecute > *outputs,
124 const VdfOutput &output,
125 const VdfSchedule &schedule);
126
127 // Method that makes sure that data is available for the given \p output
128 // before returning.
129 //
130 void _ExecuteOutputForSpeculation(
131 const VdfEvaluationState &state,
132 const VdfOutput &output,
133 TfBits *executedNodes,
134 TfBits *speculatedNodes);
135
136 // Write the computed output back to the write-back executor.
137 void _WriteBackComputedOutput(
138 const VdfOutput &output,
139 const VdfSchedule::OutputId &outputId,
140 const VdfSchedule &schedule);
141
142 // The parent executor this speculation engine is going to write back to.
143 VdfExecutorInterface *_writeBackExecutor;
144
145};
146
148
149template <typename DataManagerType>
150bool
152 std::vector< _OutputToExecute > *outputs,
153 const VdfOutput &output,
154 const VdfSchedule &schedule)
155{
156 VdfSchedule::OutputId outputId = schedule.GetOutputId(output);
157
158 if (outputId.IsValid()) {
159 outputs->push_back(_OutputToExecute(outputId));
160 return true;
161 }
162
163 // The output to push is not actually scheduled, which guarantees
164 // that is value will never be needed by any computations. So
165 // just skip it.
166 return false;
167}
168
169template <typename DataManagerType>
170template <typename F>
171void
173 const VdfSchedule &schedule,
174 const VdfRequest &computeRequest,
175 VdfExecutorErrorLogger *errorLogger,
176 F &&callback)
177{
178 TRACE_FUNCTION();
179
180 // Make sure the executor data manager is appropriately sized.
181 Base::_GetDataManager()->Resize(*schedule.GetNetwork());
182
183 const size_t numNodes = schedule.GetNetwork()->GetNodeCapacity();
184
185 // Has a bit set for any node that has already been run.
186 TfBits executedNodes(numNodes);
187
188 // Has a bit set for any node, which had one ore more inputs speculated.
189 TfBits speculatedNodes(numNodes);
190
191 // The persistent evaluation state
192 VdfEvaluationState state(Base::_GetExecutor(), schedule, errorLogger);
193
194 // Now execute the uncached, requested outputs.
195 VdfRequest::IndexedView requestView(computeRequest);
196 for (size_t i = 0; i < requestView.GetSize(); ++i) {
197 // Skip outputs not included in the request.
198 const VdfMaskedOutput *maskedOutput = requestView.Get(i);
199 if (!maskedOutput) {
200 continue;
201 }
202
203 // Skip outputs that have already been cached. However, we must invoke
204 // the callback to notify the client side that evaluation of the
205 // requested output has completed.
206 const VdfOutput &output = *maskedOutput->GetOutput();
207 const VdfMask &mask = maskedOutput->GetMask();
208 if (Base::_GetExecutor().GetOutputValue(output, mask)) {
209 callback(*maskedOutput, i);
210 continue;
211 }
212
213 _ExecuteOutputForSpeculation(
214 state, output, &executedNodes, &speculatedNodes);
215
216 // If we've been interrupted, bail out.
217 if (Base::_GetExecutor().HasBeenInterrupted()) {
218 break;
219 }
220
221 // Invoke the callback once the output has been evaluated, but only
222 // if the executor has not been interrupted.
223 else {
224 callback(*maskedOutput, i);
225 }
226 }
227}
228
229template <typename DataManagerType>
230void
232 const VdfEvaluationState &state,
233 const VdfOutput &output,
234 TfBits *executedNodes,
235 TfBits *speculatedNodes)
236{
237 TF_DEBUG(VDF_SEE_TRACE).Msg("{ SpeculationOutputExecuteBegin();\n");
238
239 // The current schedule
240 const VdfSchedule &schedule = state.GetSchedule();
241
242 // This is the stack of the outputs currently in the process of execution.
243 std::vector< _OutputToExecute > outputsStack;
244
245 // This is a stack used for the return values of outputs. A return value
246 // of true means that the output couldn't be evaluated due to speculation.
247 // XXX:optimization
248 // It's possible to get rid of this vector all together if outputs were
249 // allowed to write directly into their caller's stack space.
250 std::vector< bool > speculated;
251
252 // Add the initial output to start executing. This call will check for
253 // already cached values.
254 _PushBackOutputForSpeculation(&outputsStack, output, schedule);
255
256 bool hasBeenInterrupted = Base::_GetExecutor().HasBeenInterrupted();
257
258 while (!outputsStack.empty() && !hasBeenInterrupted) {
259
260 const VdfSchedule::OutputId &outputId = outputsStack.back().outputId;
261 const VdfNode &node = *schedule.GetNode(outputId);
262 typename Base::_ExecutionStage stage = outputsStack.back().stage;
263 const size_t outputIndex = outputsStack.size() - 1;
264
265 bool affective = schedule.IsAffective(outputId);
266
267 // Pop all the return values from our inputs and check to see
268 // if any of them were 'true' (meaning that they hit a speculation
269 // path).
270 bool previousStageSpeculated = false;
271 while (outputsStack.back().numPushed) {
272 outputsStack.back().numPushed--;
273 previousStageSpeculated |= speculated.back();
274 speculated.pop_back();
275 }
276
277 switch (stage) {
278
279 case Base::ExecutionStageStart:
280
281 TF_DEBUG(VDF_SEE_TRACE)
282 .Msg("{ SpeculationBeginNode(%p, \"%s\");\n",
283 &node, node.GetDebugName().c_str());
284
285 // If this is the node that started the speculation, we need to
286 // skip it. Note that this means we encountered a true data
287 // dependency cycle and have a bad result. Additionally, we may
288 // write back the bad result to any parent executors.
289 if (static_cast<const VdfSpeculationExecutorBase &>(
290 Base::_GetExecutor()).IsSpeculatingNode(&node)) {
291 speculated.push_back(true);
292 outputsStack.pop_back();
293
294 TF_DEBUG(VDF_SEE_TRACE)
295 .Msg("SpeculationEndNodeSpeculationNode(); (cycle) }\n");
296
297 continue;
298 }
299
300 // If this node has already been executed, do not run it a second
301 // time. However, make sure to push the right value onto the
302 // speculated stack, based on whether the node had inputs we
303 // speculated about, the last time it was run.
304 if (executedNodes->IsSet(VdfNode::GetIndexFromId(node.GetId()))) {
305 speculated.push_back(speculatedNodes->IsSet(
307 outputsStack.pop_back();
308
309 TF_DEBUG(VDF_SEE_TRACE)
310 .Msg("SpeculationEndNodeRedundantCompute(); }\n");
311
312 continue;
313 }
314
315 // If we are already cached for this output (or if our parent
316 // executor is), then we can provide a value, we can return early.
317 if (Base::_GetExecutor().GetOutputValue(
318 *schedule.GetOutput(outputId),
319 schedule.GetRequestMask(outputId))) {
320 speculated.push_back(false);
321 outputsStack.pop_back();
322
323 TF_DEBUG(VDF_SEE_TRACE)
324 .Msg("SpeculationEndNodeFoundCache(); }\n");
325
326 continue;
327 }
328
329 TF_DEV_AXIOM(outputsStack.back().numPushed == 0);
330
331 // The first stage of computation is to execute all the
332 // prerequisites for current output.
333 outputsStack.back().stage = Base::ExecutionStagePreRequisitesDone;
334
335 // Push back all the prerequisites
336 if (affective) {
337 for (const VdfScheduleInput &input : schedule.GetInputs(node)) {
338 if (input.input->GetSpec().IsPrerequisite()) {
339 const bool pushed = _PushBackOutputForSpeculation(
340 &outputsStack, *input.source, schedule);
341 outputsStack[outputIndex].numPushed += pushed;
342 }
343 }
344 }
345
346 // Little optimization to not go back to the top of the loop
347 // for no reason.
348 if (outputsStack[outputIndex].numPushed > 0) {
349 break;
350 } // else fall through to the next stage.
351
352
353 case Base::ExecutionStagePreRequisitesDone:
354
355
356 // Now that our prerequisites are done, unroll our return stack.
357
358
359 // Update whether or not our previousStageSpeculated
360 outputsStack.back().inputsSpeculate |= previousStageSpeculated;
361
362 // The second stage of computation is to use the prerequisites
363 // to determine what other inputs need to run to satisfy the
364 // current output.
365
366 // Mark that the next stage of computation
367 outputsStack.back().stage = Base::ExecutionStageReadsDone;
368
369 // Only need to run the reads of an output that will do something
370 // and if our pre-requisites were computed without speculation.
371 if (affective && !previousStageSpeculated) {
372
373 // Get the list of required inputs based on the prerequisite
374 // computations.
375 VdfRequiredInputsPredicate inputsPredicate =
376 node.GetRequiredInputsPredicate(VdfContext(state, node));
377
378 // Run the required reads first.
379 // Here we try to run the "read" inputs before the "read/write"
380 // inputs so that we can maximize the chance of being able to
381 // re-use the buffer.
382 if (inputsPredicate.HasRequiredReads()) {
383 for (const VdfScheduleInput &input :
384 schedule.GetInputs(node)) {
385 if (inputsPredicate.IsRequiredRead(*input.input)) {
386 const bool pushed = _PushBackOutputForSpeculation(
387 &outputsStack, *input.source, schedule);
388 outputsStack[outputIndex].numPushed += pushed;
389 }
390 }
391 }
392 }
393
394 // Little optimization to not go back to the top of the loop
395 // for no reason.
396 if (outputsStack[outputIndex].numPushed > 0) {
397 break;
398 } // else fall through to the next stage.
399
400 case Base::ExecutionStageReadsDone:
401
402 // Mark that the next stage of computation
403 outputsStack.back().stage = Base::ExecutionStageCompute;
404
405 // Mark whether or not our read inputs depend on a speculation.
406 outputsStack.back().inputsSpeculate |= previousStageSpeculated;
407
408 // Now run the read/writes last.
409 for (const VdfScheduleInput &input : schedule.GetInputs(node)) {
410 const VdfOutput *assocOutput =
411 input.input->GetAssociatedOutput();
412 if (!assocOutput) {
413 continue;
414 }
415
416 // Does this output have a pass-through scheduled?
417 const VdfSchedule::OutputId &assocOutputId =
418 schedule.GetOutputId(*assocOutput);
419 if (assocOutputId.IsValid()) {
420 if (const VdfOutput *fromBufferOutput =
421 schedule.GetFromBufferOutput(assocOutputId)) {
422 const bool pushed = _PushBackOutputForSpeculation(
423 &outputsStack, *fromBufferOutput, schedule);
424 outputsStack[outputIndex].numPushed += pushed;
425 continue;
426 }
427 }
428
429 // If the associated output is not scheduled, or it does not
430 // have a pass-through scheduled, we need to consider all
431 // connected source outputs!
432 const bool pushed = _PushBackOutputForSpeculation(
433 &outputsStack, *input.source, schedule);
434 outputsStack[outputIndex].numPushed += pushed;
435 }
436
437 // Little optimization to not go back to the top of the loop
438 // for no reason.
439 if (outputsStack[outputIndex].numPushed > 0) {
440 break;
441 } // else fall through to the next stage.
442
443
444 default:
445
446 // Mark whether or not our read/write inputs depend on
447 // a speculation.
448 outputsStack.back().inputsSpeculate |= previousStageSpeculated;
449
450 // Set a bit indicating that this node has been executed.
451 executedNodes->Set(VdfNode::GetIndexFromId(node.GetId()));
452
453 // If any of our inputs speculated, there is nothing we can do.
454 // Skip this node, but make sure to still touch its outputs.
455 if (outputsStack.back().inputsSpeculate) {
456
457 TF_DEBUG(VDF_SEE_TRACE)
458 .Msg("SpeculationSkipNode (cycle) (\"%s\"); }\n",
459 node.GetDebugName().c_str());
460
461 // This node has speculated inputs
462 speculatedNodes->Set(VdfNode::GetIndexFromId(node.GetId()));
463 speculated.push_back(true);
464
465 // Compute this node, if it is affective, or pass-through if any
466 // of the reads speculated.
467 } else if (affective) {
468 // None of our inputs speculated, we can just compute as
469 // normal.
470 Base::_ComputeNode(state, node);
471 speculated.push_back(false);
472
473 TF_DEBUG(VDF_SEE_TRACE)
474 .Msg("SpeculationComputedNode(\"%s\"); }\n",
475 node.GetDebugName().c_str());
476
477 // The node is not affective, and none of its reads or read/writes
478 // did speculate.
479 } else {
480 // None of the outputs on this node contribute to the
481 // results in the request, so we will skip over this node
482 // by passing through all the outputs with associated
483 // inputs and use the fallback value for all the outputs
484 // that don't.
485 TF_DEBUG(VDF_SEE_TRACE)
486 .Msg("SpeculationPassThrough(\"%s\"); }\n",
487 node.GetDebugName().c_str());
488
489 Base::_PassThroughNode(schedule, node);
490 speculated.push_back(false);
491
492 }
493
494 // Check interruption.
495 hasBeenInterrupted = Base::_GetExecutor().HasBeenInterrupted();
496
497 // Mark that we've visited these outputs in our parent
498 // executor. We need to tell the parent executor that
499 // we've visited this node so that we receive invalidation
500 // the next time it is required. If we don't mark the
501 // output as needing invalidation and the main executor
502 // never needs to execute it, then it will never get
503 // invalidated.
504 // Also write back any computed or pass-through data to the
505 // write back executor, so that the data can be picked up by
506 // another executor. Note, that we do NOT want to write back
507 // any data after interruption, because the buffers may
508 // contain junk.
509 VDF_FOR_EACH_SCHEDULED_OUTPUT_ID(outputId, schedule, node) {
510 const VdfOutput& output = *schedule.GetOutput(outputId);
511 if (_writeBackExecutor &&
512 !hasBeenInterrupted &&
513 !outputsStack.back().inputsSpeculate) {
514 _WriteBackComputedOutput(output, outputId, schedule);
515 }
516 Base::_GetExecutor()._TouchOutput(output);
517 }
518
519 outputsStack.pop_back();
520 }
521 }
522
523 TF_DEBUG(VDF_SEE_TRACE).Msg("SpeculationOutputExecuteEnd(); }\n");
524}
525
526template <typename DataManagerType>
527void
529 const VdfOutput &output,
530 const VdfSchedule::OutputId &outputId,
531 const VdfSchedule &schedule)
532{
533 // Retrieve the data handle.
534 const typename Base::_DataHandle dataHandle =
535 Base::_GetDataManager()->GetDataHandle(output.GetId());
536 if (!Base::_GetDataManager()->IsValidDataHandle(dataHandle)) {
537 return;
538 }
539
540 // Get the buffer data associated with the data handle.
541 VdfExecutorBufferData *bufferData =
542 Base::_GetDataManager()->GetBufferData(dataHandle);
543
544 // Get the output vector and computed output mask
545 const VdfVector *value = bufferData->GetExecutorCache();
546
547 // If the data is not available we are done. This can happen with
548 // node that manage their own buffers and choose to leave them empty.
549 if (!value) {
550 return;
551 }
552
553 const VdfMask &computedMask = bufferData->GetExecutorCacheMask();
554
555 // If the computed output mask is empty, we can bail out early. This may
556 // happen if, for example, the executor was interrupted and opted for not
557 // writing a computed output mask for the current node.
558 // Don't even bother writing back an all-zeros mask.
559 if (computedMask.IsEmpty() || computedMask.IsAllZeros()) {
560 return;
561 }
562
563 // If the output does not pass its data, we can write the full output value
564 // back to the write executor.
565 if (!output.GetAssociatedInput()) {
566 _writeBackExecutor->SetOutputValue(output, *value, computedMask);
567
568 // Reclaim locally, so that future cache lookups result in hits on
569 // the parent executor, but not the local executor.
570 //
571 // XXX
572 // This guards against client callbacks that mutate cached values (which
573 // is something we have encountered in practice), causing output values
574 // to change after the node has already run. By removing the buffer
575 // locally, we ensure that the next time we access the buffer we get it
576 // from the parent executor and modify it there. We would prefer to not
577 // support this client behavior, but for now, we choose to keep this,
578 // since it's not expensive, and safer.
579 bufferData->ResetExecutorCache();
580 }
581
582 // If the output passes its data, we may still be able to write back some
583 // or all of it.
584 else {
585 // If this output is not scheduled to pass its data, we can simply copy
586 // the entire executor cache. Alternatively, if the output is scheduled
587 // to pass its data, we can at least copy anything that will be kept at
588 // the output. Unless, however, invalidation entered somewhere between
589 // this output, and the output we are going to pass the data to. If this
590 // is the case, we want to write back the entire cache to the write back
591 // executor, making this algorithm the equivalent of mung buffer locking
592 // on the main executor!
593 const VdfMask *writeBackMask = &computedMask;
594 const VdfOutput *passToOutput = schedule.GetPassToOutput(outputId);
595 if (passToOutput &&
596 !_writeBackExecutor->HasInvalidationTimestampMismatch(
597 output, *passToOutput)) {
598 writeBackMask = &schedule.GetKeepMask(outputId);
599 }
600
601 if (!writeBackMask->IsEmpty()) {
602 _writeBackExecutor->SetOutputValue(output, *value, *writeBackMask);
603 }
604 }
605}
606
607PXR_NAMESPACE_CLOSE_SCOPE
608
609#endif
Fast bit array that keeps track of the number of bits set and can find the next set in a timely manne...
Definition: bits.h:49
void Set(size_t index)
Sets bit # index to one.
Definition: bits.h:377
bool IsSet(size_t index) const
Returns true, if bit # index is set.
Definition: bits.h:412
A context is the parameter bundle passed to callbacks of computations.
Definition: context.h:40
This object holds state that remains persistent during one round of network evaluation.
const VdfSchedule & GetSchedule() const
The schedule used for evaluation.
This object is responsible for storing the executor buffer data, comprised of the executor cache vect...
void ResetExecutorCache(const VdfMask &mask)
Reset the executor cache without releasing any memory and set the executor cache mask to mask.
const VdfMask & GetExecutorCacheMask() const
Get the available mask.
VdfVector * GetExecutorCache() const
Returns the executor cache stored at this buffer data instance.
A client may instantiate an object of this class and set it in an executor, to collect errors that ma...
Abstract base class for classes that execute a VdfNetwork to compute a requested set of values.
A VdfMask is placed on connections to specify the data flowing through them.
Definition: mask.h:37
bool IsAllZeros() const
Returns true if this mask has all entries unset.
Definition: mask.h:206
bool IsEmpty() const
Returns true if this mask is empty, i.e.
Definition: mask.h:168
Class to hold on to an externally owned output and a mask.
Definition: maskedOutput.h:32
VdfOutput * GetOutput() const
Returns the VdfOutput.
Definition: maskedOutput.h:52
const VdfMask & GetMask() const
Returns the VdfMask.
Definition: maskedOutput.h:64
size_t GetNodeCapacity() const
Returns the number of entries currently available for nodes and for which it is valid to call GetNode...
Definition: network.h:95
This is the base class for all nodes in a VdfNetwork.
Definition: node.h:53
static VdfIndex GetIndexFromId(const VdfId id)
Get the node index from the node id.
Definition: node.h:123
VDF_API const std::string GetDebugName() const
Returns the debug name for this node, if one is registered.
VdfId GetId() const
Returns the unique id of this node in its network.
Definition: node.h:116
virtual VDF_API VdfRequiredInputsPredicate GetRequiredInputsPredicate(const VdfContext &context) const
Returns a predicate, determining whether a given input and its connections are required in order to f...
A VdfOutput represents an output on a node.
Definition: output.h:32
VdfId GetId() const
The unique id of this output.
Definition: output.h:100
const VdfInput * GetAssociatedInput() const
Returns the in/out connector associated with this output.
Definition: output.h:76
This class is a collection of common functions used by pulled based executors.
_ExecutionStage
This enum describes the stages that a node goes through in execution.
This predicate determines whether a given input value is needed to fulfill the input dependencies req...
bool IsRequiredRead(const VdfInput &input) const
Is this input a required read? Note that read/writes as well as prerequisite inputs are not required ...
bool HasRequiredReads() const
Are any inputs required?
An OutputId is a small key object that, once obtained for a particular VdfOutput, can be used to quer...
Definition: schedule.h:91
bool IsValid() const
Returns whether this OutputId can be used to make queries about an output's scheduling.
Definition: schedule.h:97
Contains a specification of how to execute a particular VdfNetwork.
Definition: schedule.h:41
const VdfNetwork * GetNetwork() const
Returns the network for this schedule.
Definition: schedule.h:178
VDF_API OutputId GetOutputId(const VdfOutput &output) const
Returns a small, cheap OutputId, which can be passed to other Get* methods in this class to efficient...
VDF_API const VdfMask & GetRequestMask(const OutputId &outputId) const
Returns the request mask associated with the given OutputId.
VDF_API const VdfOutput * GetFromBufferOutput(const OutputId &outputId) const
Returns the "from buffer's" output associated with the given OutputId.
VDF_API InputsRange GetInputs(const VdfNode &node) const
Returns a range of inputs scheduled for the given node.
VDF_API const VdfMask & GetKeepMask(const OutputId &outputId) const
Returns the keep mask associated with the given OutputId.
VDF_API const VdfOutput * GetPassToOutput(const OutputId &outputId) const
Returns the "pass to" output associated with the given OutputId.
VDF_API const VdfNode * GetNode(const OutputId &outputId) const
Returns the VdfNode that owns the VdfOutput associated with the given outputId.
VDF_API bool IsAffective(const OutputId &outputId) const
Returns true if the output is expected to have an effect on its corresponding input,...
VDF_API const VdfOutput * GetOutput(const OutputId &outputId) const
Returns the scheduled VdfOutput associated with the given OutputId.
This class provides an executor engine to the speculation executor.
VdfSpeculationExecutorEngine(const VdfSpeculationExecutorBase &speculationExecutor, DataManagerType *dataManager)
Constructs an engine used by the speculation executor.
void RunSchedule(const VdfSchedule &schedule, const VdfRequest &computeRequest, VdfExecutorErrorLogger *errorLogger)
Executes the given schedule with a computeRequest and an optional /p errorLogger.
This class is used to abstract away knowledge of the cache data used for each node.
Definition: vector.h:56
#define TF_DEBUG(enumVal)
Evaluate and print debugging message msg if enumVal is enabled for debugging.
Definition: debug.h:484
#define TF_DEV_AXIOM(cond)
The same as TF_AXIOM, but compiled only in dev builds.
Definition: diagnostic.h:205
#define TF_VERIFY(cond, format,...)
Checks a condition and reports an error if it evaluates false.
Definition: diagnostic.h:266
This class contains scheduling information for an input.
Definition: scheduleNode.h:73