|
| 1 | +# Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). |
| 2 | +# All rights reserved. |
| 3 | +# |
| 4 | +# SPDX-License-Identifier: BSD-3-Clause |
| 5 | + |
| 6 | +name: 'OVRTX Shader Cache' |
| 7 | +description: > |
| 8 | + Restores, reports on and publishes the NVIDIA driver PSO blobs (nv_shadercache) |
| 9 | + that Isaac Lab rendering tests would otherwise recompile from scratch on every |
| 10 | + run. Requires a prior checkout. |
| 11 | +
|
| 12 | + A composite action cannot span the caller's test step, so the phases are |
| 13 | + separate invocations selected by 'mode': 'restore' before the tests, then |
| 14 | + either 'report' or 'save' after them. Every mode recomputes the keys from the |
| 15 | + same key.sh, so the collection a job reads and the one it writes cannot drift. |
| 16 | +
|
| 17 | + kit/ is compiled by the RTX renderer inside the Isaac Sim image and kitless/ by |
| 18 | + the pip-installed ovrtx wheel, so each tree is a separate entry keyed by its own |
| 19 | + producer. The mount layout that fills them lives in |
| 20 | + .github/actions/run-tests/run_tests.sh. |
| 21 | +
|
| 22 | +inputs: |
| 23 | + mode: |
| 24 | + description: >- |
| 25 | + 'restore' reads the newest compatible snapshot of each tree and never |
| 26 | + writes. 'report' summarises how far the run compiled beyond what was |
| 27 | + restored. 'save' reports the same way and writes each tree the run |
| 28 | + actually added to back as a new snapshot; only the cache warmer uses it. |
| 29 | + required: true |
| 30 | + isaacsim-version: |
| 31 | + description: 'Isaac Sim image tag; identifies the exact Kit RTX build that compiles the kit/ blobs' |
| 32 | + required: true |
| 33 | + publishes: |
| 34 | + description: >- |
| 35 | + 'true' when the same job later invokes this action in 'save' mode. The |
| 36 | + restore pass then fingerprints what it restored, so the save pass can tell |
| 37 | + a run that compiled new blobs from one that only read back the snapshot it |
| 38 | + started with. Other modes ignore it; leaving it false only costs a |
| 39 | + duplicate snapshot, never a lost one. |
| 40 | + required: false |
| 41 | + default: 'false' |
| 42 | + trees: |
| 43 | + description: >- |
| 44 | + Which cache tree(s) this job needs: 'kit', 'kitless', or 'both'. A job that |
| 45 | + only exercises one render path should request just that tree, so it does |
| 46 | + not pay the restore/save cost of the tree it never populates. |
| 47 | + default: 'both' |
| 48 | + required: false |
| 49 | + |
| 50 | +outputs: |
| 51 | + host-dir: |
| 52 | + description: 'Parent directory holding both cache trees; bind-mounted into the test container' |
| 53 | + value: ${{ steps.compute.outputs.host-dir }} |
| 54 | + |
| 55 | +runs: |
| 56 | + using: composite |
| 57 | + steps: |
| 58 | + # always() here and on every post-test step below: the caller already gates |
| 59 | + # this invocation on job status, and without it the composite inherits a |
| 60 | + # failed job context and skips work that stays valid after a test failure. |
| 61 | + # This step in particular has to run in every mode, since every later step |
| 62 | + # reads its outputs. |
| 63 | + - name: Compute OVRTX shader cache keys |
| 64 | + id: compute |
| 65 | + if: always() |
| 66 | + shell: bash |
| 67 | + env: |
| 68 | + ISAACSIM_VERSION: ${{ inputs.isaacsim-version }} |
| 69 | + run: bash "$GITHUB_ACTION_PATH/key.sh" |
| 70 | + |
| 71 | + - name: Restore OVRTX kit shader cache |
| 72 | + if: inputs.mode == 'restore' && inputs.trees != 'kitless' |
| 73 | + id: restore-kit |
| 74 | + uses: actions/cache/restore@v4 |
| 75 | + with: |
| 76 | + path: ${{ steps.compute.outputs.kit-dir }} |
| 77 | + key: ${{ steps.compute.outputs.kit-key }} |
| 78 | + restore-keys: ${{ steps.compute.outputs.kit-restore-keys }} |
| 79 | + |
| 80 | + - name: Restore OVRTX kitless shader cache |
| 81 | + if: inputs.mode == 'restore' && inputs.trees != 'kit' |
| 82 | + id: restore-kitless |
| 83 | + uses: actions/cache/restore@v4 |
| 84 | + with: |
| 85 | + path: ${{ steps.compute.outputs.kitless-dir }} |
| 86 | + key: ${{ steps.compute.outputs.kitless-key }} |
| 87 | + restore-keys: ${{ steps.compute.outputs.kitless-restore-keys }} |
| 88 | + |
| 89 | + - name: Report restored OVRTX shader cache |
| 90 | + if: inputs.mode == 'restore' |
| 91 | + shell: bash |
| 92 | + env: |
| 93 | + HOST_DIR: ${{ steps.compute.outputs.host-dir }} |
| 94 | + TREES: ${{ inputs.trees }} |
| 95 | + KIT_MATCHED_KEY: ${{ steps.restore-kit.outputs.cache-matched-key }} |
| 96 | + KITLESS_MATCHED_KEY: ${{ steps.restore-kitless.outputs.cache-matched-key }} |
| 97 | + KIT_COLLECTION: ${{ steps.compute.outputs.kit-collection }} |
| 98 | + KITLESS_COLLECTION: ${{ steps.compute.outputs.kitless-collection }} |
| 99 | + PUBLISHES: ${{ inputs.publishes }} |
| 100 | + run: bash "$GITHUB_ACTION_PATH/report.sh" restore |
| 101 | + |
| 102 | + - name: Report OVRTX shader cache growth |
| 103 | + if: always() && inputs.mode != 'restore' |
| 104 | + id: growth |
| 105 | + shell: bash |
| 106 | + env: |
| 107 | + HOST_DIR: ${{ steps.compute.outputs.host-dir }} |
| 108 | + TREES: ${{ inputs.trees }} |
| 109 | + run: bash "$GITHUB_ACTION_PATH/report.sh" growth |
| 110 | + |
| 111 | + # Each tree is gated on its own file count so a populated kit/ never carries |
| 112 | + # an empty kitless/ into a published snapshot. The count is empty rather than |
| 113 | + # '0' when the growth step aborted before counting; both mean "not measured" |
| 114 | + # and both must block the save, since the snapshot would publish under a key |
| 115 | + # every consumer prefers over the last good one. |
| 116 | + # |
| 117 | + # The changed gate is a quota guard: every save writes a new immutable entry, |
| 118 | + # so a warm run that only read back what it restored would spend ~270 MB of |
| 119 | + # the repository's cache allowance on a duplicate of the snapshot it started |
| 120 | + # from. It is 'true' whenever the growth step could not rule that out. |
| 121 | + - name: Save OVRTX kit shader cache |
| 122 | + if: >- |
| 123 | + always() && inputs.mode == 'save' && inputs.trees != 'kitless' |
| 124 | + && steps.growth.outputs.kit-files != '' |
| 125 | + && steps.growth.outputs.kit-files != '0' |
| 126 | + && steps.growth.outputs.kit-changed == 'true' |
| 127 | + uses: actions/cache/save@v4 |
| 128 | + with: |
| 129 | + path: ${{ steps.compute.outputs.kit-dir }} |
| 130 | + key: ${{ steps.compute.outputs.kit-key }} |
| 131 | + |
| 132 | + - name: Save OVRTX kitless shader cache |
| 133 | + if: >- |
| 134 | + always() && inputs.mode == 'save' && inputs.trees != 'kit' |
| 135 | + && steps.growth.outputs.kitless-files != '' |
| 136 | + && steps.growth.outputs.kitless-files != '0' |
| 137 | + && steps.growth.outputs.kitless-changed == 'true' |
| 138 | + uses: actions/cache/save@v4 |
| 139 | + with: |
| 140 | + path: ${{ steps.compute.outputs.kitless-dir }} |
| 141 | + key: ${{ steps.compute.outputs.kitless-key }} |
| 142 | + |
| 143 | + - name: Verify requested OVRTX shader cache tree(s) were populated |
| 144 | + if: always() && inputs.mode == 'save' |
| 145 | + shell: bash |
| 146 | + env: |
| 147 | + TREES: ${{ inputs.trees }} |
| 148 | + KIT_FILES: ${{ steps.growth.outputs.kit-files }} |
| 149 | + KITLESS_FILES: ${{ steps.growth.outputs.kitless-files }} |
| 150 | + run: bash "$GITHUB_ACTION_PATH/verify.sh" |
0 commit comments