Skip to content

Caches and cache IDs in OpenColorIO

Doug Walker edited this page Mar 16, 2023 · 2 revisions

Here is a description of the various caches maintained by OCIO and the cache ID strings generated by various classes.

original: 2022-07-03 updated: 2023-03-16

Caches


File Transform cache

Purpose: Cache the results of parsing LUT files referenced by File Transforms.

What is stored: Each file format defines its own LocalCachedFile implementation which typically has pointers to OCIO OpData objects containing the parsed pieces of the LUT. The LUT file itself is not stored.

Where it is stored: It's global to the library.

What the key is made from: The absolute path to the LUT file.

Where to look: FileTransform.cpp

Public API for it: ClearAllCaches will clear it.

Environment variables: OCIO_DISABLE_ALL_CACHES turns it off.

Important notes: OCIO does not detect modifications to files made after they have been cached. The client program would need to clear the relevant caches.


File Path cache

Purpose: Quickly determine whether a file exists. Provide a fingerprint for a file.

What is stored: The fingerprint for the file, or an empty string if the file doesn't exist.

Where it is stored: It's global to the library.

What the key is made from: The absolute path to the LUT file.

Where to look: PathUtils.cpp

Public API for it: ClearAllCaches will clear it. SetComputeHashFunction allows the client program to supply an alternate function for computing the fingerprint of the file. The default function on Linux and Mac is to use the device and inode returned by the "stat" OS function. On Windows it is the device and the file path. Note that SetComputeHashFunction does not control any other behavior in OCIO aside from the fingerprint stored in this specific cache and the only use of this fingerprint is for the generation of the Config cacheID.

Important notes: OCIO does not detect modifications to files made after they have been cached. The client program would need to clear the relevant caches.


Context resolution caches

Purpose: Speed up resolving context variables from strings and resolving absolute file locations.

What is stored: The resolved strings or resolved absolute file path, along with the context variables used to do the resolution.

Where it is stored: In the Context object that performs the resolution.

What the key is made from: For m_resultsStringCache, it's the string to be resolved. For m_resultsFilepathCache, it's the FileTransform src that has had context vars replaced but is not yet an absolute path.

Where to look: Context.cpp

Public API for it: Deleting the Context object will delete the cache. Modifying many of the properties of a Context will internally call clearCaches, which clears these caches.


Config cacheID cache

Purpose: Avoid needing to recompute the cacheID, particularly if switching among various Context objects.

What is stored: The cacheID string for each Context.

Where it is stored: In the Config object it was created from.

What the key is made from: The cacheID of the Context object. (Or an empty string if the Context is null.)

Where to look: Config.cpp Config::getCacheID

Public API for it: Deleting the Config object will delete the cache. Modifying many of the properties of a Config will internally call resetCacheIDs, which clears this cache.


Processor cache

Purpose: Reduce the time it takes to convert a transform into a vector of ops.

What is stored: The Processor object instances.

Where it is stored: In the Config object it was created from.

What the key is made from: The direction, the cacheID of a "used-context" object that only consists of the context variables that were used for the Processor, and the output of operator<< on the transform. The latter simply concatenates the operator<< output from each sub-transform, containing the parameter values. Note that the transforms have not been converted to ops at this point and so LUTs are typically only FileTransforms here and the string would have the file name of the LUT.

Where to look: Config.cpp Config::getProcessor(context, transform, direction)

Public API for it: Deleting the Config object will delete the cache (but not the Processors themselves if references to them are held elsewhere). Modifying many of the properties of a Config will internally call resetCacheIDs, which clears this cache.

Environment variables: OCIO_DISABLE_ALL_CACHES or OCIO_DISABLE_PROCESSOR_CACHES turns it off.


Processor cache fall-back mechanism

Purpose: Try to find a cached Processor identical to the requested one, even though its key is different. (The benefit being to avoid needing to recalculate the embedded CPUProcessor and GPUProcessor.)

What is stored: The Processor object instances. (This is the same cache as the previous entry described above.)

Where it is stored: In the Config object it was created from.

What the key is made from: The cacheID of the new Processor is compared to the cacheID of each Processor already in the cache. See below for details of the Processor cacheID.

Where to look: Config.cpp Config::getProcessor(context, transform, direction)

Public API for it: Deleting the Config object will delete the cache (but not the Processors themselves if references to them are held elsewhere).

Environment variables: OCIO_DISABLE_ALL_CACHES or OCIO_DISABLE_PROCESSOR_CACHES turns it off. OCIO_DISABLE_CACHE_FALLBACK will turn off the fall-back mechanism.


CPU Processor cache

Purpose: Reduce the time it takes to optimize a Processor for evaluation on the CPU.

What is stored: The CPUProcessor object.

Where it is stored: In the Processor it was created from.

What the key is made from: The finalized input and output bit-depths and the optimization flags.

Where to look: Processor.cpp.

Public API for it: Deleting the Config object will delete the cache (but not the CPUProcessors themselves if references to them are held elsewhere).

Environment variables: OCIO_DISABLE_ALL_CACHES or OCIO_DISABLE_PROCESSOR_CACHES turns it off. PROCESSOR_CACHE_SHARE_DYN_PROPERTIES controls whether to cache CPUProcessors involving dynamic properties.


GPU Processor cache

Purpose: Reduce the time it takes to optimize a Processor for evaluation on the GPU.

What is stored: The GPUProcessor object.

Where it is stored: In the Processor it was created from.

What the key is made from: The optimization flags.

Where to look: Processor.cpp.

Public API for it: Deleting the Config object will delete the cache (but not the GPUProcessors themselves if references to them are held elsewhere).

Environment variables: OCIO_DISABLE_ALL_CACHES or OCIO_DISABLE_PROCESSOR_CACHES turns it off.


Optimized Processor cache

Purpose: Reduce the time it takes to optimize a Processor. (Note that getOptimizedProcessor is something that is typically only used for debugging, so this cache is not really needed but the code is the same as the CPU/GPUProcessor caches.)

What is stored: The optimized Processor object.

Where it is stored: In the Processor it was created from.

What the key is made from: The finalized input and output bit-depths and the optimization flags.

Where to look: Processor.cpp.

Public API for it: Deleting the Config object will delete the cache (but not the Processors themselves if references to them are held elsewhere).

Environment variables: OCIO_DISABLE_ALL_CACHES or OCIO_DISABLE_PROCESSOR_CACHES turns it off.



Object cacheIDs

Various OCIO classes have a getCacheID() method that returns a string. Here is some detail of how these are calculated for various objects.

In HashUtils.cpp there is a function called CacheIDHash that is used for all the hashes mentioned below. Originally an md5 hash was used but this was updated to use xxhash in OCIO 2.2 in order to reduce delays associated with calculating cacheIDs. The length of the xxhash was chosen to be 128-bits to match the md5 length.


Config

The cacheID string is comprised of two hashes separated by " : ". The first part is the hash of the Config object serialized to Yaml. The second part is obtained by collecting all the FileTransforms used in all the transforms in the Config. The resolveFileLocation is used with the Context to compute absolute file paths for each FileTransform and the File Path cache described above is used to return the fingerprint for each file. These fingerprints are concatenated into a string and a hash is calculated for them.

The Config has two getCacheID methods, one with and without a Context argument. If the Context is not provided, the one internal to the Config will be used. If a null Context is provided, the second part of the ID is an empty string.

The Config cacheID is not used within OCIO but may be used by client applications for various purposes.


Context

A string is built containing the (unresolved) search paths, working directory, environment mode, and environment variables (aka context variables). The cacheID is the hash of that string. It is stored within the object so it is only calculated once (but is cleared if attributes of the context are modified).


Lut1D, Lut3D, and Matrix Ops

A hash is calculated on the raw float/double values in the object (i.e., they are not first converted to strings). To this string is added additional characters describing the direction, interpolation setting, etc.


Other Ops

A human readable string is built with the parameter names and values. The string is somewhat different than either the serialization provided by OCIOYaml.cpp or operator<< for its related Transform. Numeric values are converted to strings with the stream precision set to seven digits. No hash is calculated.

Ops containing dynamic parameters do not print the parameter values if the dynamic aspect is currently enabled.


Op vector

In OCIO, a vector of Ops (OpVec) is what is used for all color processing. (The Ops are what have the associated CPU and GPU renderer code.) The cacheID for an OpVec is simply the concatenated string of the cacheIDs of each of its Ops. The result is a possibly somewhat long-ish (unhashed) string.


Processor

The cacheID of a Processor is obtained by computing the hash of the (un-optimized) OpVec cacheID. This value is stored in the Processor object, so it is only calculated the first time.


CPUProcessor

The cacheID is the cacheID string for the optimized OpVec prepended with strings for the finalized input/output bit-depths and optimization flags. It is stored in the object and only calculated during finalization.


GPUProcessor

The cacheID is the cacheID string for the optimized OpVec prepended with a string for the optimization flags. It is stored in the object and only calculated during finalization.


GpuShaderCreator / GpuShaderDesc

The cacheID content depends on whether shader program has been built yet. Initially it consists of the parameters that were set when creating the object, such as the shading language, function name, resource prefix, etc. After extractGpuShaderInfo has been called on the object, the cacheID also includes the hash for the entire shader program. This latter cacheID is sometimes used by clients to detect if the shader program needs to be recompiled and linked (for example, see oglapphelpers/glsl.cpp). It may be used by clients to cache shader programs.