-
Notifications
You must be signed in to change notification settings - Fork 3.9k
[CI] Cache renderer runtime artifacts #7242
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| # Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). | ||
| # All rights reserved. | ||
| # | ||
| # SPDX-License-Identifier: BSD-3-Clause | ||
|
|
||
| name: 'Renderer Cache Key' | ||
| description: 'Computes a hardware- and Isaac-Sim-specific renderer cache key and host directory' | ||
|
|
||
| inputs: | ||
| isaacsim-base-image: | ||
| description: 'Isaac Sim base image repository' | ||
| required: true | ||
| isaacsim-version: | ||
| description: 'Isaac Sim base image version' | ||
| required: true | ||
|
|
||
| outputs: | ||
| collection: | ||
| description: 'Collection prefix shared by mutually compatible renderer caches' | ||
| value: ${{ steps.compute.outputs.collection }} | ||
| key: | ||
| description: 'Immutable cache key for this workflow run' | ||
| value: ${{ steps.compute.outputs.key }} | ||
| restore-keys: | ||
| description: 'Collection prefix used to restore the newest compatible snapshot' | ||
| value: ${{ steps.compute.outputs.restore-keys }} | ||
| host-dir: | ||
| description: 'Host directory bind-mounted over renderer cache paths' | ||
| value: ${{ steps.compute.outputs.host-dir }} | ||
|
|
||
| runs: | ||
| using: composite | ||
| steps: | ||
| - name: Compute renderer cache key | ||
| id: compute | ||
| shell: bash | ||
| env: | ||
| ISAACSIM_BASE_IMAGE: ${{ inputs.isaacsim-base-image }} | ||
| ISAACSIM_VERSION: ${{ inputs.isaacsim-version }} | ||
| run: | | ||
| set -euo pipefail | ||
|
|
||
| gpu_inventory="$(nvidia-smi --query-gpu=name,driver_version --format=csv,noheader | sort -u)" | ||
| compatibility="$ISAACSIM_BASE_IMAGE:$ISAACSIM_VERSION|$RUNNER_OS|$RUNNER_ARCH|$gpu_inventory" | ||
| compatibility_hash="$(printf '%s' "$compatibility" | sha256sum | cut -c1-20)" | ||
| collection="renderer-v1-${RUNNER_OS}-${RUNNER_ARCH}-${compatibility_hash}" | ||
|
|
||
| echo "collection=${collection}" >> "$GITHUB_OUTPUT" | ||
| echo "key=${collection}-${GITHUB_SHA}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" >> "$GITHUB_OUTPUT" | ||
| echo "restore-keys=${collection}-" >> "$GITHUB_OUTPUT" | ||
| echo "host-dir=${RUNNER_TEMP}/isaaclab-renderer-cache" >> "$GITHUB_OUTPUT" | ||
|
|
||
| echo "Renderer cache collection: ${collection}" | ||
| echo "Renderer cache compatibility: ${compatibility}" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| # Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). | ||
| # All rights reserved. | ||
| # | ||
| # SPDX-License-Identifier: BSD-3-Clause | ||
|
|
||
| """Report the size and stable metadata fingerprint of a renderer cache tree.""" | ||
|
|
||
| import hashlib | ||
| import os | ||
| import pathlib | ||
| import sys | ||
|
|
||
|
|
||
| def fingerprint(root: pathlib.Path) -> str: | ||
| """Return a digest of cache file paths, sizes, and modification times.""" | ||
| digest = hashlib.sha256() | ||
| for path in sorted(path for path in root.rglob("*") if path.is_file()): | ||
| try: | ||
| stat = path.stat() | ||
| except OSError: | ||
| continue | ||
| digest.update(path.relative_to(root).as_posix().encode()) | ||
| digest.update(f"\0{stat.st_size}\0{stat.st_mtime_ns}\0".encode()) | ||
| return digest.hexdigest() | ||
|
|
||
|
|
||
| def inventory(root: pathlib.Path) -> tuple[int, int, dict[str, int]]: | ||
| """Return total bytes, file count, and bytes grouped by top-level directory.""" | ||
| total_bytes = 0 | ||
| file_count = 0 | ||
| groups: dict[str, int] = {} | ||
| for dirpath, _, filenames in os.walk(root): | ||
| for name in filenames: | ||
| path = pathlib.Path(dirpath, name) | ||
| try: | ||
| size = path.stat().st_size | ||
| except OSError: | ||
| continue | ||
| relative = path.relative_to(root) | ||
| group = relative.parts[0] if relative.parts else "." | ||
| groups[group] = groups.get(group, 0) + size | ||
| total_bytes += size | ||
| file_count += 1 | ||
| return total_bytes, file_count, groups | ||
|
|
||
|
|
||
| def main() -> int: | ||
| """Print a fingerprint or human-readable renderer cache inventory.""" | ||
| root = pathlib.Path(sys.argv[1]) | ||
| if len(sys.argv) > 2 and sys.argv[2] == "--fingerprint": | ||
| print(fingerprint(root)) | ||
| return 0 | ||
|
|
||
| label = sys.argv[2] if len(sys.argv) > 2 else "Renderer cache" | ||
| if not root.is_dir(): | ||
| print(f"{label}: directory is missing") | ||
| return 0 | ||
|
|
||
| total_bytes, file_count, groups = inventory(root) | ||
| breakdown = ", ".join(f"{name}={size / 1e6:.0f} MB" for name, size in sorted(groups.items())) or "empty" | ||
| print(f"{label}: {total_bytes / 1e6:.0f} MB across {file_count} files ({breakdown})") | ||
|
|
||
| summary = os.environ.get("GITHUB_STEP_SUMMARY") | ||
| if summary: | ||
| with open(summary, "a", encoding="utf-8") as handle: | ||
| handle.write(f"🔵 {label}: {total_bytes / 1e6:.0f} MB across {file_count} files ({breakdown})\n") | ||
| return 0 | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| raise SystemExit(main()) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| # Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). | ||
| # All rights reserved. | ||
| # | ||
| # SPDX-License-Identifier: BSD-3-Clause | ||
|
|
||
| """Tests for renderer cache inventory and change detection.""" | ||
|
|
||
| import importlib.util | ||
| from pathlib import Path | ||
|
|
||
|
|
||
| def _load_inventory_module(): | ||
| module_path = Path(__file__).with_name("renderer_cache_inventory.py") | ||
| spec = importlib.util.spec_from_file_location("renderer_cache_inventory", module_path) | ||
| assert spec is not None | ||
| assert spec.loader is not None | ||
| module = importlib.util.module_from_spec(spec) | ||
| spec.loader.exec_module(module) | ||
| return module | ||
|
|
||
|
|
||
| def test_inventory_groups_cache_files_by_top_level_directory(tmp_path: Path) -> None: | ||
| """Inventory should report every cache file without reading its contents.""" | ||
| inventory_module = _load_inventory_module() | ||
| (tmp_path / "home").mkdir() | ||
| (tmp_path / "isaac-sim").mkdir() | ||
| (tmp_path / "home" / "shader.bin").write_bytes(b"123") | ||
| (tmp_path / "isaac-sim" / "kit.bin").write_bytes(b"12345") | ||
|
|
||
| total_bytes, file_count, groups = inventory_module.inventory(tmp_path) | ||
|
|
||
| assert total_bytes == 8 | ||
| assert file_count == 2 | ||
| assert groups == {"home": 3, "isaac-sim": 5} | ||
|
|
||
|
|
||
| def test_fingerprint_changes_when_cache_file_changes(tmp_path: Path) -> None: | ||
| """A writer must publish a new snapshot when a cache artifact changes.""" | ||
| inventory_module = _load_inventory_module() | ||
| artifact = tmp_path / "shader.bin" | ||
| artifact.write_bytes(b"before") | ||
| before = inventory_module.fingerprint(tmp_path) | ||
|
|
||
| artifact.write_bytes(b"after-content") | ||
|
|
||
| assert inventory_module.fingerprint(tmp_path) != before |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,10 +37,15 @@ run_tests() { | |
| local standalone_script_runtime_group="${24}" | ||
| local warp_cache_host_dir="${25}" | ||
| local extra_uv_packages="${26}" | ||
| local renderer_cache_host_dir="${27}" | ||
| local logs_pid="" | ||
| local wait_pid="" | ||
| local docker_wait_file="/tmp/.docker_exit_${container_name}" | ||
| local docker_runtime_dir="" | ||
| local home_cache_args="" | ||
| local isaacsim_cache_dir="" | ||
| local isaacsim_compute_cache_dir="" | ||
| local kit_cache_dir="" | ||
|
|
||
| # Kill the container immediately if the runner is cancelled. | ||
| # The GitHub Actions runner can deliver HUP, INT, or TERM on cancellation | ||
|
|
@@ -240,14 +245,36 @@ run_tests() { | |
| "${docker_runtime_dir}/isaac-sim/data" \ | ||
| "${docker_runtime_dir}/isaac-sim/logs" \ | ||
| "${docker_runtime_dir}/isaac-sim/pkg" | ||
|
|
||
| kit_cache_dir="${docker_runtime_dir}/isaac-sim/kit/cache" | ||
| isaacsim_cache_dir="${docker_runtime_dir}/isaac-sim/cache" | ||
| isaacsim_compute_cache_dir="${docker_runtime_dir}/isaac-sim/computecache" | ||
| home_cache_args="" | ||
| if [ -n "$renderer_cache_host_dir" ]; then | ||
| mkdir -p \ | ||
| "${renderer_cache_host_dir}/home/cache" \ | ||
| "${renderer_cache_host_dir}/home/computecache" \ | ||
| "${renderer_cache_host_dir}/isaac-sim/kit-cache" \ | ||
| "${renderer_cache_host_dir}/isaac-sim/cache" \ | ||
| "${renderer_cache_host_dir}/isaac-sim/computecache" | ||
| kit_cache_dir="${renderer_cache_host_dir}/isaac-sim/kit-cache" | ||
| isaacsim_cache_dir="${renderer_cache_host_dir}/isaac-sim/cache" | ||
| isaacsim_compute_cache_dir="${renderer_cache_host_dir}/isaac-sim/computecache" | ||
| home_cache_args="\ | ||
| -v ${renderer_cache_host_dir}/home/cache:/tmp/isaaclab-ci-home/.cache:rw \ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Warning · Design Architecture — Cache mount covers entire XDG cache home
|
||
| -v ${renderer_cache_host_dir}/home/computecache:/tmp/isaaclab-ci-home/.nv/ComputeCache:rw" | ||
| echo "🔵 Mounting persistent renderer caches from ${renderer_cache_host_dir}" | ||
| fi | ||
|
|
||
| docker_volume_args="\ | ||
| -v ${volume_mount_source}:/workspace/isaaclab:rw \ | ||
| -v ${docker_runtime_dir}/home:/tmp/isaaclab-ci-home:rw \ | ||
| -v ${docker_runtime_dir}/isaac-sim/kit/cache:/isaac-sim/kit/cache:rw \ | ||
| ${home_cache_args} \ | ||
| -v ${kit_cache_dir}:/isaac-sim/kit/cache:rw \ | ||
| -v ${docker_runtime_dir}/isaac-sim/kit/data:/isaac-sim/kit/data:rw \ | ||
| -v ${docker_runtime_dir}/isaac-sim/kit/logs:/isaac-sim/kit/logs:rw \ | ||
| -v ${docker_runtime_dir}/isaac-sim/cache:/isaac-sim/.cache:rw \ | ||
| -v ${docker_runtime_dir}/isaac-sim/computecache:/isaac-sim/.nv/ComputeCache:rw \ | ||
| -v ${isaacsim_cache_dir}:/isaac-sim/.cache:rw \ | ||
| -v ${isaacsim_compute_cache_dir}:/isaac-sim/.nv/ComputeCache:rw \ | ||
| -v ${docker_runtime_dir}/isaac-sim/config:/isaac-sim/.nvidia-omniverse/config:rw \ | ||
| -v ${docker_runtime_dir}/isaac-sim/data:/isaac-sim/.local/share/ov/data:rw \ | ||
| -v ${docker_runtime_dir}/isaac-sim/logs:/isaac-sim/.nvidia-omniverse/logs:rw \ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 Warning · Api — Renderer cache silently requires unrelated source mount
renderer-cache-host-diris declared as an independent optional input, but its mount setup is nested inside theif [ -n "$volume_mount_source" ]block, while the analogouswarp-cache-host-diris handled outside it. A caller that supplies only the renderer cache directory gets no mounts and no diagnostic, so the cache silently does nothing. Handle the renderer mounts outside that branch, or validate and document the dependency.