|
| 1 | +# Case Cache |
| 2 | + |
| 3 | +The WebGPU CTS contains many tests that check that the results of an operation |
| 4 | +fall within limits defined by the WebGPU and WGSL specifications. The |
| 5 | +computation of these allowed limits can be very expensive to calculate, however |
| 6 | +the values do not vary by platform or device, and can be precomputed and reused |
| 7 | +for multiple CTS runs. |
| 8 | + |
| 9 | +## File cache |
| 10 | + |
| 11 | +To speed up execution of the CTS, the CTS git repo holds holds pre-computed |
| 12 | +test cases, serialized in a set of gzip-compressed binary files under |
| 13 | +[`src/resources/cache`](../src/resources/cache). |
| 14 | + |
| 15 | +These files are regenerated by [`src/common/tools/gen_cache.ts`](../src/common/tools/gen_cache.ts) |
| 16 | +which can be run with `npx grunt run:generate-cache`. |
| 17 | +This tool is automatically run by the various Grunt build commands. |
| 18 | + |
| 19 | +As generating the cache is expensive (hence why we build it ahead of time!) the |
| 20 | +cache generation tool will only re-build the cache files it believes may be out |
| 21 | +of date. To determine which files it needs to rebuild, the tool calculates a |
| 22 | +hash of all the transitive source TypeScript files that are used to build the |
| 23 | +output, and compares this hash to the hash stored in |
| 24 | +[`src/resources/cache/hashes.json`](`../src/resources/cache/hashes.json`). Only |
| 25 | +those cache files with differing hashes are rebuilt. |
| 26 | + |
| 27 | +Since source changes will sometimes change the hash without changing the generated cache, |
| 28 | +sometimes the cache will be regenerated unnecessarily. **This is OK, but try to avoid committing |
| 29 | +no-op regenerations - this will happen if your version of Node produces different gzip outputs |
| 30 | +than the original committer's Node did for the same input.** |
| 31 | + |
| 32 | +The cache files are copied from [`src/resources/cache`](../src/resources/cache) |
| 33 | +to the `resources/cache` subdirectory of the |
| 34 | +[`out` and `out-node` build directories](build.md#build-types), so the runner |
| 35 | +can load these cache files. |
| 36 | + |
| 37 | +The GitHub presubmit checks will error if the cache files or |
| 38 | +[`hashes.json`](`../src/resources/cache/hashes.json`) need updating. |
| 39 | + |
| 40 | +## In memory cache |
| 41 | + |
| 42 | +If a cache file cannot be found, then the [`CaseCache`](../src/webgpu/shader/execution/expression/case_cache.ts) |
| 43 | +will build the cases during CTS execution and store the results in an in-memory LRU cache. |
| 44 | + |
| 45 | +## Using the cache |
| 46 | + |
| 47 | +To add test cases to the cache: |
| 48 | + |
| 49 | +1. Import `makeCaseCache` from [`'case_cache.js'`](../src/webgpu/shader/execution/expression/case_cache.ts); |
| 50 | + |
| 51 | +```ts |
| 52 | +import { makeCaseCache } from '../case_cache.js'; // your relative path may vary |
| 53 | +``` |
| 54 | + |
| 55 | +2. Declare an exported global variable with the name `d`, assigned with the return value of `makeCaseCache()`: |
| 56 | + |
| 57 | +```ts |
| 58 | +export const d = makeCaseCache('unique/path/of/your/cache/file', { |
| 59 | + // Declare any number of fields that build the test cases |
| 60 | + name_of_your_case: () => { |
| 61 | + return fullI32Range().map(e => { // example case builder |
| 62 | + return { input: i32(e), expected: i32(-e) }; |
| 63 | + }); |
| 64 | + }, |
| 65 | +}); |
| 66 | +``` |
| 67 | + |
| 68 | +3. To load the cases from the cache, use `d.get();` |
| 69 | + |
| 70 | +```ts |
| 71 | +const cases = await d.get('name_of_your_case'); |
| 72 | +// cases will either be loaded from the cache file, loaded from the in-memory |
| 73 | +// LRU, or built on the fly. |
| 74 | +``` |
| 75 | + |
| 76 | +4. Run `npx grunt run generate-cache` to generate the new cache file. |
0 commit comments