Loading...
Searching...
No Matches
pageCacheBasedExecutor.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_EF_PAGE_CACHE_BASED_EXECUTOR_H
8#define PXR_EXEC_EF_PAGE_CACHE_BASED_EXECUTOR_H
9
11
12#include "pxr/pxr.h"
13
14#include "pxr/exec/ef/loftedOutputSet.h"
17
23#include "pxr/exec/vdf/output.h"
25#include "pxr/exec/vdf/types.h"
26
27PXR_NAMESPACE_OPEN_SCOPE
28
30
40template <
41 template <typename> class EngineType,
42 typename DataManagerType>
44 public VdfDataManagerBasedExecutor<DataManagerType, VdfExecutorInterface>
45{
46 typedef
48 Base;
49
50public:
54 EfPageCacheStorage *cacheStorage) :
55 _engine(*this, &this->_dataManager),
56 _cacheStorage(cacheStorage),
57 _currentCache(NULL)
58 {
59 // The pointer to the page cache storage container must always be valid.
60 TF_VERIFY(_cacheStorage);
61 }
62
66
72 virtual void SetOutputValue(
73 const VdfOutput &output,
74 const VdfVector &value,
75 const VdfMask &mask) override;
76
80 void WillDeleteNode(const VdfNode &node);
81
82protected:
83 // Returns a value for the cache that flows across \p connection.
84 virtual const VdfVector *_GetInputValue(
85 const VdfConnection &connection,
86 const VdfMask &mask) const override;
87
88 // Returns an output value for reading.
90 const VdfOutput &output,
91 const VdfMask &mask) const override;
92
93 // Clear all data in the local data manager.
94 virtual void _ClearData() override;
95
96private:
97 // Run the specified schedule.
98 virtual void _Run(
99 const VdfSchedule &schedule,
100 const VdfRequest &computeRequest,
101 VdfExecutorErrorLogger *errorLogger) override;
102
103 // Returns \c true if the values resulting from evaluation should be stored
104 // away in the page cache.
105 bool _IsCaching() const;
106
107 // Query the page cache for a value.
108 const VdfVector *_GetPageCacheValue(
109 const VdfOutput &output,
110 const VdfMask &mask) const;
111
112 // Executor data invalidation
113 bool _InvalidateOutput(
114 const VdfOutput &output,
115 const VdfMask &invalidationMask) override;
116
117 // Pre-process executor invalidation by augmenting the invalidation
118 // request to also invalidate any lofted outputs.
119 virtual bool _PreProcessInvalidation(
120 const VdfMaskedOutputVector &invalidationRequest,
121 VdfMaskedOutputVector *processedRequest) override;
122
123 // Clear data at a specified output.
124 void _ClearDataForOutput(
125 VdfId outputId, VdfId nodeId) override;
126
127private:
128 // The executor engine.
129 EngineType<DataManagerType> _engine;
130
131 // The page cache storage container.
132 EfPageCacheStorage *_cacheStorage;
133
134 // The output value cache for the currently selected page.
135 Ef_OutputValueCache *_currentCache;
136
137 // A set of outputs, which had their values sourced from the page cache
138 // during evaluation (or getting of output values.) We need to keep track
139 // of these outputs in order to allows us to later properly invalidate them.
140 mutable Ef_LoftedOutputSet _loftedOutputs;
141};
142
144
145template <template <typename> class EngineType, typename DataManagerType>
146void
148 const VdfOutput &output,
149 const VdfVector &value,
150 const VdfMask &mask)
151{
152 // Call through to the base class, to set the output value in the
153 // local data manager.
154 Base::SetOutputValue(output, value, mask);
155
156 // If the output we are setting a new value on is the key output, then
157 // also make sure to set the currently selected page in the page cache
158 // storage container.
159 if (_cacheStorage->_IsKeyOutput(output, mask)) {
160 _currentCache = _cacheStorage->_GetOrCreateCache(value);
161 }
162}
163
164template <template <typename> class EngineType, typename DataManagerType>
165void
167 const VdfNode &node)
168{
169 _loftedOutputs.RemoveAllOutputsForNode(node);
170}
171
172/* virtual */
173template <template <typename> class EngineType, typename DataManagerType>
174const VdfVector *
176 const VdfConnection &connection,
177 const VdfMask &mask) const
178{
179 // Note, this method will be called concurrently, if the engine type is
180 // a parallel engine.
181
182 // First, look for the value in the local data manager.
183 if (const VdfVector *value =
184 Base::_dataManager.GetInputValue(connection, mask)) {
185 return value;
186 }
187
188 // Then, query the page cache storage.
189 return _GetPageCacheValue(connection.GetSourceOutput(), mask);
190}
191
192/* virtual */
193template <template <typename> class EngineType, typename DataManagerType>
194const VdfVector *
197 const VdfOutput &output,
198 const VdfMask &mask) const
199{
200 // Note, this method will be called concurrently, if the engine type is
201 // a parallel engine.
202
203 // First, look for the value in the local data manager.
204 if (const VdfVector *value =
205 Base::_dataManager.GetOutputValueForReading(
206 Base::_dataManager.GetDataHandle(output.GetId()), mask)) {
207 return value;
208 }
209
210 // Then, query the page cache storage.
211 return _GetPageCacheValue(output, mask);
212}
213
214template <template <typename> class EngineType, typename DataManagerType>
215void
217 const VdfSchedule &schedule,
218 const VdfRequest &computeRequest,
219 VdfExecutorErrorLogger *errorLogger)
220{
221 // If nothing has been requested, bail out early.
222 if (computeRequest.IsEmpty()) {
223 return;
224 }
225
226 TRACE_FUNCTION();
227 TfAutoMallocTag2 tag("Ef", "EfPageCacheBasedExecutor::Run");
228
229 // Make sure the lofted node references array is sufficiently large.
230 _loftedOutputs.Resize(*schedule.GetNetwork());
231
232 // If caching is enabled, run the schedule with a callback that writes each
233 // computed output value to the page cache.
234 if (TF_VERIFY(_currentCache) && _IsCaching()) {
235 const DataManagerType &dataManager = Base::_dataManager;
236 const VdfRequest &cacheableRequest =
237 _cacheStorage->GetCacheableRequest(computeRequest);
238 VdfRequest::IndexedView cacheableView(cacheableRequest);
239 Ef_OutputValueCache *cache = _currentCache;
240 EfPageCacheStorage *storage = _cacheStorage;
241
242 _engine.RunSchedule(
243 schedule, computeRequest, errorLogger,
244 [&dataManager, &cacheableView, cache, storage]
245 (const VdfMaskedOutput &mo, size_t requestedIndex) {
246 // Lookup the value in the local data manager. This is the
247 // value to store away in the page cache. Bail out if no such
248 // value exists, or if the output is not cacheable.
249 const VdfVector *value = dataManager.GetOutputValueForReading(
250 dataManager.GetDataHandle(mo.GetOutput()->GetId()),
251 mo.GetMask());
252 if (!value || !cacheableView.Get(requestedIndex)) {
253 return;
254 }
255
256 // If the output has already been cached, bail out.
257 {
258 Ef_OutputValueCache::SharedAccess access(cache);
259 if (access.GetValue(*mo.GetOutput(), mo.GetMask())) {
260 return;
261 }
262 }
263
264 // Attempt to cache the value in the page cache.
266 storage->_Commit(mo, *value, &access);
267 });
268 }
269
270 // If caching is not enabled, run the schedule without a callback.
271 else {
272 _engine.RunSchedule(schedule, computeRequest, errorLogger);
273 }
274}
275
276template <template <typename> class EngineType, typename DataManagerType>
277bool
279{
280 return
281 _cacheStorage->IsEnabled() &&
283}
284
285template <template <typename> class EngineType, typename DataManagerType>
286const VdfVector *
288 const VdfOutput &output,
289 const VdfMask &mask) const
290{
291 // Note, this method will be called concurrently, if the engine type is
292 // a parallel engine.
293
294 // We only do this when the executor is running, because we never want
295 // external clients to receive pointers to data in the page cache, in order
296 // to avoid data races.
297 if (!_currentCache) {
298 return nullptr;
299 }
300
301 // Obtain shared read access to the current cache.
302 Ef_OutputValueCache::SharedAccess cacheAccess(_currentCache);
303
304 // Lookup the value in the current cache.
305 if (const VdfVector *cachedValue = cacheAccess.GetValue(output, mask)) {
306 // Mark this output as having been lofted into the data manager. We
307 // cannot return a cache hit if this fails.
308 if (_loftedOutputs.Add(output, mask)) {
309 // Touch the output, so that invalidation will be able to
310 // propagate down in the network.
311 Base::_TouchOutput(output);
312
313 // Return the cached value.
314 return cachedValue;
315 }
316 }
317
318 // No value found.
319 return nullptr;
320}
321
322/* virtual */
323template <template <typename> class EngineType, typename DataManagerType>
324bool
326 const VdfOutput &output,
327 const VdfMask &invalidationMask)
328{
329 // Call into the base class for output invalidation.
330 if (Base::_InvalidateOutput(output, invalidationMask)) {
331 // If some data has been invalidated, make sure to also remove the
332 // bits from the lofted output.
333 _loftedOutputs.Remove(
334 output.GetId(), output.GetNode().GetId(), invalidationMask);
335
336 // Some data has been invalidated.
337 return true;
338 }
339
340 // Nothing has been invalidated.
341 return false;
342}
343
344/* virtual */
345template <template <typename> class EngineType, typename DataManagerType>
346bool
348 const VdfMaskedOutputVector &invalidationRequest,
349 VdfMaskedOutputVector *processedRequest)
350{
351 // Bail out, if there are no lofted outputs. Return false to indicate
352 // that the originally supplied invalidationRequest shall be used.
353 const size_t numLoftedOutputs = _loftedOutputs.GetSize();
354 if (numLoftedOutputs == 0) {
355 return false;
356 }
357
358 TRACE_FUNCTION();
359
360 // Find all outputs depenending on the originally supplied request.
361 const VdfOutputToMaskMap &deps =
362 _cacheStorage->_FindDependencies(invalidationRequest);
363
364 // If there are no dependent outputs, bail out.
365 if (deps.empty()) {
366 return false;
367 }
368
369 // Reserve space to guarantee that all outputs will fit without needing to
370 // reallocate.
371 processedRequest->reserve(
372 invalidationRequest.size() +
373 std::min(numLoftedOutputs, deps.size()));
374
375 // If the invalidation request has not been augmented with lofted outputs,
376 // we can simply bail out an instead use the originally supplied
377 // invalidationRequest.
378 _loftedOutputs.CollectLoftedDependencies(deps, processedRequest);
379 if (processedRequest->empty()) {
380 return false;
381 }
382
383 // Otherwise, add all the outputs from the original invalidationRequest
384 // to the new invalidation request, which now also contains all the
385 // dependent lofted outputs.
386 processedRequest->insert(
387 processedRequest->end(),
388 invalidationRequest.begin(), invalidationRequest.end());
389
390 // The invalidation request has been modified. Return true to tell
391 // executor invalidation to use the processed request instead of the
392 // originally supplied request.
393 return true;
394}
395
396/* virtual */
397template <template <typename> class EngineType, typename DataManagerType>
398void
400 const VdfId outputId, const VdfId nodeId)
401{
402 Base::_ClearDataForOutput(outputId, nodeId);
403 _loftedOutputs.Remove(outputId, nodeId, VdfMask());
404}
405
406/* virtual */
407template <template <typename> class EngineType, typename DataManagerType>
408void
410{
411 _loftedOutputs.Clear();
412}
413
414PXR_NAMESPACE_CLOSE_SCOPE
415
416#endif
Tracks the set of lofted outputs (outputs whose values were sourced from the page cache during evalua...
An accessor that provides exclusive read/write access to the cache.
This accessor grants shared read access to the cache, preventing any concurrent write access.
An output-to-value storage for caching.
Executes a VdfNetwork to compute a requested set of values.
virtual void _ClearData() override
Virtual implementation of the ClearData call.
virtual const VdfVector * _GetOutputValueForReading(const VdfOutput &output, const VdfMask &mask) const override
Returns an output value for reading.
virtual void SetOutputValue(const VdfOutput &output, const VdfVector &value, const VdfMask &mask) override
Set an output value.
virtual const VdfVector * _GetInputValue(const VdfConnection &connection, const VdfMask &mask) const override
Returns value for the cache that flows across connection.
virtual ~EfPageCacheBasedExecutor()
Destructor.
void WillDeleteNode(const VdfNode &node)
Removes any internal references to node upon deleting the node from the VdfNetwork.
EfPageCacheBasedExecutor(EfPageCacheStorage *cacheStorage)
Constructor.
Manages a page cache and provides methods for invalidation of cached values.
static EF_API bool HasReachedMemoryLimit()
Returns true, if the upper memory limit has been reached, and the object is no longer allowed to allo...
Scoped (i.e.
Definition: mallocTag.h:249
A class that fully represents a connection between two VdfNodes.
Definition: connection.h:30
const VdfOutput & GetSourceOutput() const
Returns the output (ie. source) for this connection.
Definition: connection.h:63
Base class for executors that use a data manager.
A client may instantiate an object of this class and set it in an executor, to collect errors that ma...
A VdfMask is placed on connections to specify the data flowing through them.
Definition: mask.h:37
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
This is the base class for all nodes in a VdfNetwork.
Definition: node.h:53
VdfId GetId() const
Returns the unique id of this node in its network.
Definition: node.h:116
A VdfOutput represents an output on a node.
Definition: output.h:32
const VdfNode & GetNode() const
Returns the owning node for this output.
Definition: output.h:57
VdfId GetId() const
The unique id of this output.
Definition: output.h:100
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
This class is used to abstract away knowledge of the cache data used for each node.
Definition: vector.h:56
uint64_t VdfId
The unique identifier type for Vdf objects.
Definition: types.h:107
std::unordered_map< const VdfOutput *, VdfMask, TfHash > VdfOutputToMaskMap
A map from output pointer to mask.
Definition: types.h:104
#define TF_VERIFY(cond, format,...)
Checks a condition and reports an error if it evaluates false.
Definition: diagnostic.h:266