freesolo-flash-dev 0.2.26__tar.gz → 0.2.27__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- freesolo_flash_dev-0.2.27/.github/workflows/auto-rebake.yml +245 -0
- freesolo_flash_dev-0.2.27/.github/workflows/bake-kernel-cache.yml +245 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/.github/workflows/worker-image.yml +36 -14
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/PKG-INFO +1 -1
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/docker/Dockerfile.kernelcache +10 -0
- freesolo_flash_dev-0.2.27/docker/Dockerfile.kernelcache.relayer +27 -0
- freesolo_flash_dev-0.2.27/docker/kernel_fingerprint.py +245 -0
- freesolo_flash_dev-0.2.27/docs/cli-theme/README.md +32 -0
- freesolo_flash_dev-0.2.27/docs/cli-theme/before-after-dark.png +0 -0
- freesolo_flash_dev-0.2.27/docs/cli-theme/before-after-light.png +0 -0
- freesolo_flash_dev-0.2.27/docs/cli-theme/gallery-dark.png +0 -0
- freesolo_flash_dev-0.2.27/docs/cli-theme/gallery-light.png +0 -0
- freesolo_flash_dev-0.2.27/docs/cli-theme/help-dark.png +0 -0
- freesolo_flash_dev-0.2.27/docs/cli-theme/help-light.png +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/cli/__init__.py +100 -9
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/cli/commands.py +38 -21
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/cli/envpush.py +21 -22
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/cli/render.py +158 -2
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/__init__.py +10 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/adapter.py +123 -23
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/hf.py +40 -3
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/lora.py +211 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/rl.py +29 -11
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/envs/adapter.py +48 -9
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/checkpoints.py +35 -10
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/pyproject.toml +2 -2
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_checkpoints.py +100 -4
- freesolo_flash_dev-0.2.27/tests/test_cli_help.py +96 -0
- freesolo_flash_dev-0.2.27/tests/test_cli_render_theme.py +312 -0
- freesolo_flash_dev-0.2.27/tests/test_kernel_fingerprint.py +132 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_verifiers.py +81 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_vl_warmstart_adapter_keys.py +38 -0
- freesolo_flash_dev-0.2.27/tests/test_vl_warmstart_recombine.py +351 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/uv.lock +1 -1
- freesolo_flash_dev-0.2.26/.github/workflows/bake-kernel-cache.yml +0 -154
- freesolo_flash_dev-0.2.26/tests/test_cli_render_theme.py +0 -159
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/.dockerignore +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/.env.example +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/.github/workflows/ci.yml +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/.github/workflows/main-source-guard.yml +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/.github/workflows/publish-dev.yml +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/.github/workflows/publish-image.yml +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/.github/workflows/publish.yml +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/.github/workflows/version-parity.yml +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/.gitignore +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/Dockerfile +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/Dockerfile.worker +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/LICENSE +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/README.md +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/build/kernel_cache/.gitignore +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/build/kernel_cache/.keep +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/docker/bake_kernel_cache.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/docker/bake_pod_entry.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/docker/make_rp_handler.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/docs/cli-style/README.md +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/docs/cli-style/generate.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/docs/cli-style/index.html +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/docs/cli-style/preview.png +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/docs/kernel-cache.md +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/_channel.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/_fileio.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/_logging.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/_update_check.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/catalog.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/cli/__main__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/cli/training_doc.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/client/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/client/config.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/client/http.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/client/runtime_secrets.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/client/specs.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/cost/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/cost/analytical.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/cost/facts.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/cost/spec.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/cost/types.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/accounting.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/chalk_kernels.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/multiturn_rollout.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/recipe.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/vram.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/__main__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/_pkg.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/decoding.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/finalize.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/gpu_setup.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/grpo.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/heartbeat.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/kernel_warmup.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/packing.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/perf/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/perf/attn.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/perf/diagnostics.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/perf/lifecycle.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/perf/liger.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/perf/loraplus.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/perf/memory.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/sft.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/engine/worker/wandb_log.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/envs/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/envs/base.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/envs/registry.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/_auth.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/_http.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/_instance.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/_instance_bootstrap.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/_poll.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/allocator.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/base.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/lambdalabs/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/lambdalabs/api.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/lambdalabs/auth.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/lambdalabs/gpus.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/lambdalabs/jobs/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/lambdalabs/jobs/builders.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/lambdalabs/preflight.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/lambdalabs/pricing.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/lambdalabs/train.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/preflight.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/realized.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/runpod/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/runpod/api.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/runpod/auth.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/runpod/cost.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/runpod/gpus.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/runpod/jobs.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/runpod/keys.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/runpod/preflight.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/runpod/preload.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/runpod/pricing.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/runpod/slots.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/runpod/train/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/runpod/train/deps.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/providers/runpod/train/endpoints.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/py.typed +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/runner/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/runner/checkpoints.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/runner/deploy.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/runner/lifecycle.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/schema/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/schema/fields.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/serve/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/serve/deploy.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/serve/export.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/serve/pricing.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/__main__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/_deps.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/_locks.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/_runtime.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/app.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/auth.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/billing.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/billing_retry.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/db.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/environment_registry.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/envs.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/reconcile.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/routes/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/routes/envs.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/routes/meta.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/routes/runs.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/routes/serving.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/server/run_registry.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/flash/spec.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/infisical-entrypoint.sh +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/scripts/build_dev_dist.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/_helpers/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/_helpers/runner.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/_helpers/specs.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/conftest.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/fixtures/math_eval.jsonl +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/fixtures/math_train.jsonl +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/live/__init__.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/live/conftest.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/live/test_lambda_live.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/live/test_runpod_live.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_agent_flash_cli_contract.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_algorithms.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_allocator.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_backend_jobspec_contract.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_billing_retry.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_cancel_remote.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_catalog_consistency.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_chalk_kernels.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_cli_commands.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_cli_errors.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_cli_estimate.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_cli_managed.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_client.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_client_server_integration.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_config_overrides.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_cost_analytical.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_cost_equation.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_cost_estimate.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_cost_hardware.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_cost_models.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_cost_rewards.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_dev_channel.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_disk_gb.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_endpoint_name.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_env_install.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_env_publish.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_env_push.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_env_rate_limit_resolve.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_envs_coverage.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_export.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_flash_mvp.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_flash_worker.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_github_urlopen_retry.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_gpus.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_grpo_mask_aware.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_grpo_params.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_grpo_sleep_gate.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_idle_endpoint_reaper.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_jobs.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_kernel_cache.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_kv_util.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_lambda_runner.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_logging.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_login_perms.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_managed_hf_repo.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_metrics_schema_agent_contract.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_mig_guard.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_multiturn_rollout.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_open_model_policy.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_orchestrator_flash.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_packing.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_poll_helpers.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_preflight.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_provider_routing.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_provider_teardown_robustness.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_providers_symmetry.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_realized_cost.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_resolve_params_b.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_resume_on_retry.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_runmgmt.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_runpod_api_delete.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_runpod_key_fingerprint.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_runpod_key_waterfall.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_runpod_slots.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_serve.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_server_api.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_server_billing.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_server_db.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_serving_contract.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_spec_and_validation.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_thinking_config.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_update_check.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_version.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_vl_weight_sync.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_wandb_naming.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_warmstart_cross_repo.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_weight_cache.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_worker_dryrun.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_worker_hardexit.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_worker_image.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_worker_init_heartbeat.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_worker_stack.py +0 -0
- {freesolo_flash_dev-0.2.26 → freesolo_flash_dev-0.2.27}/tests/test_worker_thinking.py +0 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
name: auto-rebake per-arch kernel cache
|
|
2
|
+
|
|
3
|
+
# Keeps the per-arch ghcr.io/freesolo-co/flash-worker:cu128-sm* images fresh whenever the :cu128 base
|
|
4
|
+
# is rebuilt. Each cu128-smXX is physically `FROM :cu128` + a baked mega-cache, so a new base leaves
|
|
5
|
+
# the per-arch tags pointing at the OLD base until rebaked. "Out of date" has two flavors, keyed off
|
|
6
|
+
# the fp_cache / fp_base labels worker-image.yml stamps on :cu128 (docker/kernel_fingerprint.py):
|
|
7
|
+
#
|
|
8
|
+
# * fp_cache changed -> the baked Triton/Inductor mega-cache is INVALID -> a real GPU re-warm is
|
|
9
|
+
# required (bake-kernel-cache.yml). PAID, and AUTO-fired by this detection (no manual approval) --
|
|
10
|
+
# fp_cache only moves on a deliberate toolchain bump, so spend stays tied to real need.
|
|
11
|
+
# * fp_cache same but fp_base changed -> the cache is still valid, the base just moved (FA wheel /
|
|
12
|
+
# causal-conv1d / rp_handler / a non-kernel dep) -> a FREE re-layer grafts the existing cache onto
|
|
13
|
+
# the fresh base (docker/Dockerfile.kernelcache.relayer), no GPU.
|
|
14
|
+
# * both same -> skip (this is the pure-flash-code case the old reminder over-fired on).
|
|
15
|
+
#
|
|
16
|
+
# The gate READS the published labels (authoritative for what was actually built, incl. a manual FA3
|
|
17
|
+
# override) rather than recomputing from the checkout, and aborts unless the base's revision label ==
|
|
18
|
+
# the build's head_sha (so a superseded base build or a `tag=...` dispatch that never touched :cu128
|
|
19
|
+
# can't trigger a stale rebake).
|
|
20
|
+
|
|
21
|
+
on:
|
|
22
|
+
workflow_run:
|
|
23
|
+
workflows: ["flash worker image"]
|
|
24
|
+
types: [completed]
|
|
25
|
+
|
|
26
|
+
permissions:
|
|
27
|
+
contents: read
|
|
28
|
+
packages: write
|
|
29
|
+
actions: read
|
|
30
|
+
issues: write
|
|
31
|
+
|
|
32
|
+
# Scope the group to the triggering base build's commit so a no-op completion (e.g. a tag=cu128-test
|
|
33
|
+
# worker-image run, whose head_sha differs) can't cancel an in-flight real bake. The revision guard
|
|
34
|
+
# already neutralizes superseded runs, so a global cancel-in-progress isn't needed.
|
|
35
|
+
concurrency:
|
|
36
|
+
group: auto-rebake-${{ github.event.workflow_run.head_sha }}
|
|
37
|
+
cancel-in-progress: true
|
|
38
|
+
|
|
39
|
+
env:
|
|
40
|
+
BASE: ghcr.io/freesolo-co/flash-worker:cu128
|
|
41
|
+
|
|
42
|
+
jobs:
|
|
43
|
+
gate:
|
|
44
|
+
if: github.event.workflow_run.conclusion == 'success'
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
outputs:
|
|
47
|
+
proceed: ${{ steps.base.outputs.proceed }}
|
|
48
|
+
relayer_sms: ${{ steps.classify.outputs.relayer_sms }}
|
|
49
|
+
gpu_sms: ${{ steps.classify.outputs.gpu_sms }}
|
|
50
|
+
fp_cache: ${{ steps.base.outputs.fp_cache }}
|
|
51
|
+
fp_base: ${{ steps.base.outputs.fp_base }}
|
|
52
|
+
base_ref: ${{ steps.base.outputs.base_ref }}
|
|
53
|
+
base_revision: ${{ steps.base.outputs.revision }}
|
|
54
|
+
steps:
|
|
55
|
+
- uses: actions/checkout@v6
|
|
56
|
+
with:
|
|
57
|
+
ref: ${{ github.event.workflow_run.head_sha }}
|
|
58
|
+
|
|
59
|
+
- name: Install crane
|
|
60
|
+
run: |
|
|
61
|
+
curl -sSL https://github.com/google/go-containerregistry/releases/download/v0.20.2/go-containerregistry_Linux_x86_64.tar.gz \
|
|
62
|
+
| sudo tar -xz -C /usr/local/bin crane
|
|
63
|
+
crane version
|
|
64
|
+
|
|
65
|
+
- name: Log in to GHCR
|
|
66
|
+
uses: docker/login-action@v3
|
|
67
|
+
with:
|
|
68
|
+
registry: ghcr.io
|
|
69
|
+
username: ${{ github.actor }}
|
|
70
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
71
|
+
|
|
72
|
+
- name: Read base labels
|
|
73
|
+
id: base
|
|
74
|
+
env:
|
|
75
|
+
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
|
|
76
|
+
run: |
|
|
77
|
+
# canonical digest ref (repo@sha256, no tag) so every tool (crane/docker/runpod) accepts it.
|
|
78
|
+
digest=$(crane digest "$BASE")
|
|
79
|
+
repo=${BASE%:*}
|
|
80
|
+
cfg=$(crane config "$repo@$digest")
|
|
81
|
+
fpc=$(echo "$cfg" | jq -r '.config.Labels["co.freesolo.flash.kernelcache.fp_cache"] // ""')
|
|
82
|
+
fpb=$(echo "$cfg" | jq -r '.config.Labels["co.freesolo.flash.kernelcache.fp_base"] // ""')
|
|
83
|
+
rev=$(echo "$cfg" | jq -r '.config.Labels["org.opencontainers.image.revision"] // ""')
|
|
84
|
+
echo "base_ref=$repo@$digest" >> "$GITHUB_OUTPUT"
|
|
85
|
+
echo "fp_cache=$fpc" >> "$GITHUB_OUTPUT"
|
|
86
|
+
echo "fp_base=$fpb" >> "$GITHUB_OUTPUT"
|
|
87
|
+
echo "revision=$rev" >> "$GITHUB_OUTPUT"
|
|
88
|
+
# Only proceed if this base IS the build that triggered us: its revision label must match the
|
|
89
|
+
# build's head_sha. Guards (a) a newer base that already superseded this run, and (b) a
|
|
90
|
+
# `tag=cu128-test` dispatch that never updated :cu128 (the workflow_run payload can't reveal
|
|
91
|
+
# the dispatch tag). An unlabeled base (pre-rollout) also no-ops here.
|
|
92
|
+
if [ -n "$fpc" ] && [ "$rev" = "$HEAD_SHA" ]; then
|
|
93
|
+
echo "proceed=true" >> "$GITHUB_OUTPUT"
|
|
94
|
+
echo "base $BASE@$digest is rev $rev (== head_sha) fp_cache=$fpc fp_base=$fpb"
|
|
95
|
+
else
|
|
96
|
+
echo "proceed=false" >> "$GITHUB_OUTPUT"
|
|
97
|
+
echo "::notice::auto-rebake no-op: base rev '$rev' != head_sha '$HEAD_SHA' (or base unlabeled)"
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
- name: Classify arches
|
|
101
|
+
id: classify
|
|
102
|
+
if: steps.base.outputs.proceed == 'true'
|
|
103
|
+
env:
|
|
104
|
+
FP_CACHE: ${{ steps.base.outputs.fp_cache }}
|
|
105
|
+
FP_BASE: ${{ steps.base.outputs.fp_base }}
|
|
106
|
+
REV: ${{ steps.base.outputs.revision }}
|
|
107
|
+
run: |
|
|
108
|
+
# arch list is the single source of truth in deps.py (mirrored by the bake matrix; a test
|
|
109
|
+
# pins that mirror). textual parse -> no flash import / uv sync needed.
|
|
110
|
+
arches=$(python3 -c "import re,pathlib; t=pathlib.Path('flash/providers/runpod/train/deps.py').read_text(); m=re.search(r'BAKED_PER_SM_ARCHES\s*=\s*frozenset\(\{([^}]+)\}\)', t); print(' '.join(re.findall(r'sm\d+', m.group(1))))")
|
|
111
|
+
relayer=(); gpu=()
|
|
112
|
+
summary="| arch | published fp_cache | published fp_base | action |\n|---|---|---|---|\n"
|
|
113
|
+
for sm in $arches; do
|
|
114
|
+
img="ghcr.io/freesolo-co/flash-worker:cu128-$sm"
|
|
115
|
+
if cfg=$(crane config "$img" 2>/dev/null); then
|
|
116
|
+
pc=$(echo "$cfg" | jq -r '.config.Labels["co.freesolo.flash.kernelcache.fp_cache"] // ""')
|
|
117
|
+
pb=$(echo "$cfg" | jq -r '.config.Labels["co.freesolo.flash.kernelcache.fp_base"] // ""')
|
|
118
|
+
else
|
|
119
|
+
pc="(missing)"; pb="(missing)"
|
|
120
|
+
fi
|
|
121
|
+
if [ "$pc" != "$FP_CACHE" ]; then
|
|
122
|
+
gpu+=("$sm"); action="GPU re-warm (cache invalid)"
|
|
123
|
+
elif [ "$pb" != "$FP_BASE" ]; then
|
|
124
|
+
relayer+=("$sm"); action="re-layer (free)"
|
|
125
|
+
else
|
|
126
|
+
action="up to date"
|
|
127
|
+
fi
|
|
128
|
+
echo "$sm: pc=$pc pb=$pb -> $action"
|
|
129
|
+
summary="$summary| $sm | \`$pc\` | \`$pb\` | $action |\n"
|
|
130
|
+
done
|
|
131
|
+
if [ ${#relayer[@]} -gt 0 ]; then
|
|
132
|
+
relayer_json=$(printf '%s\n' "${relayer[@]}" | jq -R . | jq -cs .)
|
|
133
|
+
else
|
|
134
|
+
relayer_json='[]'
|
|
135
|
+
fi
|
|
136
|
+
gpu_csv=$(IFS=,; echo "${gpu[*]}")
|
|
137
|
+
echo "relayer_sms=$relayer_json" >> "$GITHUB_OUTPUT"
|
|
138
|
+
echo "gpu_sms=$gpu_csv" >> "$GITHUB_OUTPUT"
|
|
139
|
+
{
|
|
140
|
+
echo "### auto-rebake plan (base rev \`$REV\`, fp_cache \`$FP_CACHE\` fp_base \`$FP_BASE\`)"
|
|
141
|
+
echo ""
|
|
142
|
+
echo -e "$summary"
|
|
143
|
+
echo ""
|
|
144
|
+
echo "re-layer (free): \`$relayer_json\` | GPU re-warm (paid, auto-started): \`${gpu_csv:-none}\`"
|
|
145
|
+
} >> "$GITHUB_STEP_SUMMARY"
|
|
146
|
+
|
|
147
|
+
# FYI notification (not an action item -- the bake auto-runs). Keeps a heads-up + cost trail of
|
|
148
|
+
# which arches a paid GPU re-warm fired for.
|
|
149
|
+
- name: Notify GPU re-bake auto-started
|
|
150
|
+
if: steps.base.outputs.proceed == 'true' && steps.classify.outputs.gpu_sms != ''
|
|
151
|
+
env:
|
|
152
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
153
|
+
GPU_SMS: ${{ steps.classify.outputs.gpu_sms }}
|
|
154
|
+
REV: ${{ steps.base.outputs.revision }}
|
|
155
|
+
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
156
|
+
run: |
|
|
157
|
+
title="kernel-cache: per-arch GPU re-bake auto-started"
|
|
158
|
+
body=$(printf 'The kernel toolchain changed (fp_cache), so a PAID GPU re-warm auto-started for these per-arch images (no approval needed):\n\n- arches: `%s`\n- base rev: `%s`\n\nTrack it in the run: %s' "$GPU_SMS" "$REV" "$RUN_URL")
|
|
159
|
+
# best-effort: a labeling/permission hiccup must never fail the gate. self-heal the label so
|
|
160
|
+
# no manual setup is needed, then reuse one open issue (comment) instead of spamming new ones.
|
|
161
|
+
gh label create kernel-rebake-pending --color B60205 --description "per-arch kernel cache GPU re-bake auto-started" 2>/dev/null || true
|
|
162
|
+
existing=$(gh issue list --label kernel-rebake-pending --state open --json number -q '.[0].number' 2>/dev/null || true)
|
|
163
|
+
if [ -n "${existing:-}" ]; then
|
|
164
|
+
gh issue comment "$existing" --body "$body" || true
|
|
165
|
+
else
|
|
166
|
+
gh issue create --title "$title" --body "$body" --label kernel-rebake-pending \
|
|
167
|
+
|| gh issue create --title "$title" --body "$body" || true
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
# FREE path: graft the existing valid cache onto the fresh base, no GPU. Runs automatically.
|
|
171
|
+
relayer:
|
|
172
|
+
needs: gate
|
|
173
|
+
if: needs.gate.outputs.proceed == 'true' && needs.gate.outputs.relayer_sms != '[]' && needs.gate.outputs.relayer_sms != ''
|
|
174
|
+
runs-on: ubuntu-24.04-8core
|
|
175
|
+
strategy:
|
|
176
|
+
fail-fast: false
|
|
177
|
+
matrix:
|
|
178
|
+
sm: ${{ fromJson(needs.gate.outputs.relayer_sms || '[]') }}
|
|
179
|
+
env:
|
|
180
|
+
BASE_REF: ${{ needs.gate.outputs.base_ref }}
|
|
181
|
+
FP_CACHE: ${{ needs.gate.outputs.fp_cache }}
|
|
182
|
+
FP_BASE: ${{ needs.gate.outputs.fp_base }}
|
|
183
|
+
BASE_REVISION: ${{ needs.gate.outputs.base_revision }}
|
|
184
|
+
steps:
|
|
185
|
+
- uses: actions/checkout@v6
|
|
186
|
+
with:
|
|
187
|
+
ref: ${{ github.event.workflow_run.head_sha }}
|
|
188
|
+
|
|
189
|
+
# The graft pulls two ~20GB images (old per-arch tag + fresh base); reclaim runner disk first.
|
|
190
|
+
- name: Free disk space
|
|
191
|
+
run: |
|
|
192
|
+
sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/.ghcup \
|
|
193
|
+
/usr/local/lib/android /opt/hostedtoolcache /usr/share/swift \
|
|
194
|
+
/usr/local/share/boost /usr/local/lib/node_modules \
|
|
195
|
+
/usr/local/share/powershell /usr/share/miniconda || true
|
|
196
|
+
sudo apt-get clean || true
|
|
197
|
+
sudo docker image prune -af || true
|
|
198
|
+
df -h /
|
|
199
|
+
|
|
200
|
+
- uses: docker/setup-buildx-action@v3
|
|
201
|
+
|
|
202
|
+
- name: Log in to GHCR
|
|
203
|
+
uses: docker/login-action@v3
|
|
204
|
+
with:
|
|
205
|
+
registry: ghcr.io
|
|
206
|
+
username: ${{ github.actor }}
|
|
207
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
208
|
+
|
|
209
|
+
# Pin OLDCACHE by digest so a concurrent overwrite of the source tag can't graft a wrong cache.
|
|
210
|
+
- name: Resolve old per-arch cache digest
|
|
211
|
+
id: old
|
|
212
|
+
run: |
|
|
213
|
+
img="ghcr.io/freesolo-co/flash-worker:cu128-${{ matrix.sm }}"
|
|
214
|
+
digest=$(docker buildx imagetools inspect "$img" --format '{{.Manifest.Digest}}')
|
|
215
|
+
# canonical digest ref (repo@sha256, no tag) for the FROM in the relayer build.
|
|
216
|
+
echo "ref=${img%:*}@$digest" >> "$GITHUB_OUTPUT"
|
|
217
|
+
|
|
218
|
+
- name: Re-layer cache onto the fresh base (no GPU)
|
|
219
|
+
uses: docker/build-push-action@v6
|
|
220
|
+
with:
|
|
221
|
+
context: .
|
|
222
|
+
file: docker/Dockerfile.kernelcache.relayer
|
|
223
|
+
push: true
|
|
224
|
+
tags: ghcr.io/freesolo-co/flash-worker:cu128-${{ matrix.sm }}
|
|
225
|
+
provenance: false
|
|
226
|
+
build-args: |
|
|
227
|
+
BASE=${{ env.BASE_REF }}
|
|
228
|
+
OLDCACHE=${{ steps.old.outputs.ref }}
|
|
229
|
+
FP_CACHE=${{ env.FP_CACHE }}
|
|
230
|
+
FP_BASE=${{ env.FP_BASE }}
|
|
231
|
+
BASE_REVISION=${{ env.BASE_REVISION }}
|
|
232
|
+
|
|
233
|
+
# PAID path: re-warm the cache on a real GPU per arch. Runs automatically -- the fingerprint gate
|
|
234
|
+
# above is the only thing that decides it fires (only when fp_cache changed), so no manual approval.
|
|
235
|
+
gpu-warm:
|
|
236
|
+
needs: gate
|
|
237
|
+
if: needs.gate.outputs.proceed == 'true' && needs.gate.outputs.gpu_sms != ''
|
|
238
|
+
uses: ./.github/workflows/bake-kernel-cache.yml
|
|
239
|
+
with:
|
|
240
|
+
sms: ${{ needs.gate.outputs.gpu_sms }}
|
|
241
|
+
fp_cache: ${{ needs.gate.outputs.fp_cache }}
|
|
242
|
+
fp_base: ${{ needs.gate.outputs.fp_base }}
|
|
243
|
+
base_ref: ${{ needs.gate.outputs.base_ref }}
|
|
244
|
+
base_revision: ${{ needs.gate.outputs.base_revision }}
|
|
245
|
+
secrets: inherit
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
name: flash worker kernel-cache (per-arch)
|
|
2
|
+
|
|
3
|
+
# Builds per-SM worker images with the compiled-kernel mega-cache baked in, killing the ~10-15 min
|
|
4
|
+
# first-use JIT on a cold worker (the regression #194 reintroduced). Each matrix leg:
|
|
5
|
+
# 1. offloads the warmup to a RunPod GPU of that arch (GH runners have none) -> build/kernel_cache,
|
|
6
|
+
# 2. docker build --build-arg BUILD_KERNEL_CACHE=true -> ghcr.io/freesolo-co/flash-worker:cu128-<sm>,
|
|
7
|
+
# 3. pushes it. Activate by setting FLASH_WORKER_IMAGE_PER_SM=1 on the control plane so the
|
|
8
|
+
# allocator selects the cu128-<sm> tag per GPU class (see flash/providers/runpod/train/deps.py).
|
|
9
|
+
#
|
|
10
|
+
# Depends on the base ghcr.io/freesolo-co/flash-worker:cu128 image existing (worker-image.yml) — the
|
|
11
|
+
# warmup runs INSIDE it so the cache matches the image's pinned torch/triton/fla/liger toolchain.
|
|
12
|
+
#
|
|
13
|
+
# Secrets: RUNPOD_API_KEY (the warmup GPU pod) + HF_TOKEN (the temp dataset that ferries code + the
|
|
14
|
+
# cache artifact) are pulled from Infisical (/flash, prod) via the bootstrap INFISICAL_CLIENT_ID /
|
|
15
|
+
# CLIENT_SECRET / PROJECT_ID repo secrets; the GHCR push uses the default GITHUB_TOKEN. Heavy + paid,
|
|
16
|
+
# but UNGATED: the fingerprint detection in auto-rebake.yml decides WHEN this runs (only on a real
|
|
17
|
+
# kernel-toolchain change), so there is no manual approval step. Invoked by hand (workflow_dispatch)
|
|
18
|
+
# OR automatically by auto-rebake.yml (workflow_call) when the kernel toolchain changed.
|
|
19
|
+
|
|
20
|
+
on:
|
|
21
|
+
workflow_dispatch:
|
|
22
|
+
inputs:
|
|
23
|
+
sms:
|
|
24
|
+
description: "comma-separated sm list to bake; default is all validated arches"
|
|
25
|
+
default: "sm80,sm86,sm89,sm90,sm120"
|
|
26
|
+
required: false
|
|
27
|
+
# auto-rebake.yml calls this for the EXPENSIVE path (the cache is invalid and must be re-warmed on a
|
|
28
|
+
# real GPU). It passes the arch subset, the fingerprints to stamp, and a digest-pinned base so the
|
|
29
|
+
# warm runs inside the exact :cu128 the per-arch tag will sit on.
|
|
30
|
+
workflow_call:
|
|
31
|
+
inputs:
|
|
32
|
+
sms:
|
|
33
|
+
type: string
|
|
34
|
+
required: true
|
|
35
|
+
fp_cache:
|
|
36
|
+
type: string
|
|
37
|
+
required: false
|
|
38
|
+
default: ""
|
|
39
|
+
fp_base:
|
|
40
|
+
type: string
|
|
41
|
+
required: false
|
|
42
|
+
default: ""
|
|
43
|
+
base_ref:
|
|
44
|
+
type: string
|
|
45
|
+
required: false
|
|
46
|
+
default: "ghcr.io/freesolo-co/flash-worker:cu128"
|
|
47
|
+
base_revision:
|
|
48
|
+
type: string
|
|
49
|
+
required: false
|
|
50
|
+
default: ""
|
|
51
|
+
|
|
52
|
+
permissions:
|
|
53
|
+
contents: read
|
|
54
|
+
packages: write
|
|
55
|
+
|
|
56
|
+
jobs:
|
|
57
|
+
# Ungated: the PAID RunPod bake runs as soon as it's called/dispatched. The decision of WHEN to run
|
|
58
|
+
# lives in auto-rebake.yml's fingerprint gate (it only invokes this when fp_cache changed), so a
|
|
59
|
+
# second manual approval here would be redundant. Re-add an `approve` job with `environment: gpu-bake`
|
|
60
|
+
# (and `needs: approve`) if you ever want a human checkpoint back.
|
|
61
|
+
bake:
|
|
62
|
+
runs-on: ubuntu-24.04-8core
|
|
63
|
+
strategy:
|
|
64
|
+
fail-fast: false
|
|
65
|
+
matrix:
|
|
66
|
+
include:
|
|
67
|
+
- {
|
|
68
|
+
sm: sm80,
|
|
69
|
+
arch: "8.0",
|
|
70
|
+
gpu_type_id: "NVIDIA A100 80GB PCIe",
|
|
71
|
+
allowed_cuda: "",
|
|
72
|
+
}
|
|
73
|
+
- {
|
|
74
|
+
sm: sm86,
|
|
75
|
+
arch: "8.6",
|
|
76
|
+
gpu_type_id: "NVIDIA RTX A6000",
|
|
77
|
+
allowed_cuda: "",
|
|
78
|
+
}
|
|
79
|
+
- {
|
|
80
|
+
sm: sm89,
|
|
81
|
+
arch: "8.9",
|
|
82
|
+
gpu_type_id: "NVIDIA GeForce RTX 4090",
|
|
83
|
+
allowed_cuda: "",
|
|
84
|
+
}
|
|
85
|
+
- {
|
|
86
|
+
sm: sm90,
|
|
87
|
+
arch: "9.0",
|
|
88
|
+
gpu_type_id: "NVIDIA H100 80GB HBM3",
|
|
89
|
+
allowed_cuda: "",
|
|
90
|
+
}
|
|
91
|
+
# Blackwell needs CUDA-13 hosts to JIT its PTX (matches min_cuda_for in the provider). Bake
|
|
92
|
+
# sm120 on the RTX Pro 6000 (Server Edition): it's the same sm120 (cache is sm-keyed, so it's
|
|
93
|
+
# valid for RTX 5090 too) but has far better secure-cloud on-demand capacity -- the RTX 5090
|
|
94
|
+
# pool repeatedly returned "machine does not have the resources" at create_pod.
|
|
95
|
+
- {
|
|
96
|
+
sm: sm120,
|
|
97
|
+
arch: "12.0",
|
|
98
|
+
gpu_type_id: "NVIDIA RTX PRO 6000 Blackwell Server Edition",
|
|
99
|
+
allowed_cuda: "13.0",
|
|
100
|
+
}
|
|
101
|
+
# Datacenter Blackwell (sm100, distinct from the sm120 RTX Pro 6000). B200 has 180 GB and
|
|
102
|
+
# good secure-cloud capacity. CUDA-13 host like the other Blackwell parts. NOT in the default
|
|
103
|
+
# `sms` list yet (B200 is unvalidated) -- bake it explicitly via `sms=sm100` until a smoke
|
|
104
|
+
# passes, then add it to the default.
|
|
105
|
+
- {
|
|
106
|
+
sm: sm100,
|
|
107
|
+
arch: "10.0",
|
|
108
|
+
gpu_type_id: "NVIDIA B200",
|
|
109
|
+
allowed_cuda: "13.0",
|
|
110
|
+
}
|
|
111
|
+
steps:
|
|
112
|
+
# Gate FIRST (no checkout needed) so skipped arches do no crane / checkout / build work.
|
|
113
|
+
- name: Should bake ${{ matrix.sm }}?
|
|
114
|
+
id: gate
|
|
115
|
+
run: |
|
|
116
|
+
req="${{ inputs.sms || 'sm80,sm86,sm89,sm90,sm120' }}"
|
|
117
|
+
req="${req// /}" # tolerate spaces, e.g. "sm80, sm86"
|
|
118
|
+
case ",$req," in
|
|
119
|
+
*,${{ matrix.sm }},*) echo "run=true" >> "$GITHUB_OUTPUT" ;;
|
|
120
|
+
*) echo "run=false" >> "$GITHUB_OUTPUT"; echo "skipping ${{ matrix.sm }}" ;;
|
|
121
|
+
esac
|
|
122
|
+
|
|
123
|
+
- name: Install crane
|
|
124
|
+
if: steps.gate.outputs.run == 'true'
|
|
125
|
+
run: |
|
|
126
|
+
curl -sSL https://github.com/google/go-containerregistry/releases/download/v0.20.2/go-containerregistry_Linux_x86_64.tar.gz \
|
|
127
|
+
| sudo tar -xz -C /usr/local/bin crane
|
|
128
|
+
crane version
|
|
129
|
+
|
|
130
|
+
- name: Log in to GHCR
|
|
131
|
+
if: steps.gate.outputs.run == 'true'
|
|
132
|
+
uses: docker/login-action@v3
|
|
133
|
+
with:
|
|
134
|
+
registry: ghcr.io
|
|
135
|
+
username: ${{ github.actor }}
|
|
136
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
137
|
+
|
|
138
|
+
# Resolve the base + fingerprints BEFORE checkout, so the checkout (hence the warmed flash code)
|
|
139
|
+
# is pinned to the EXACT commit the base was built from. auto-rebake passes everything (fast path);
|
|
140
|
+
# a manual dispatch READS the labels off the published base, so the per-arch image always matches
|
|
141
|
+
# the base it extends (same source of truth as the gate) instead of recomputing from the checkout.
|
|
142
|
+
- name: Resolve base + fingerprints
|
|
143
|
+
id: base
|
|
144
|
+
if: steps.gate.outputs.run == 'true'
|
|
145
|
+
run: |
|
|
146
|
+
if [ -n "${{ inputs.fp_cache }}" ]; then
|
|
147
|
+
echo "ref=${{ inputs.base_ref }}" >> "$GITHUB_OUTPUT"
|
|
148
|
+
echo "fp_cache=${{ inputs.fp_cache }}" >> "$GITHUB_OUTPUT"
|
|
149
|
+
echo "fp_base=${{ inputs.fp_base }}" >> "$GITHUB_OUTPUT"
|
|
150
|
+
echo "revision=${{ inputs.base_revision }}" >> "$GITHUB_OUTPUT"
|
|
151
|
+
else
|
|
152
|
+
base="${{ inputs.base_ref || 'ghcr.io/freesolo-co/flash-worker:cu128' }}"
|
|
153
|
+
digest=$(crane digest "$base"); repo=${base%:*}
|
|
154
|
+
cfg=$(crane config "$repo@$digest")
|
|
155
|
+
echo "ref=$repo@$digest" >> "$GITHUB_OUTPUT"
|
|
156
|
+
echo "fp_cache=$(echo "$cfg" | jq -r '.config.Labels["co.freesolo.flash.kernelcache.fp_cache"] // ""')" >> "$GITHUB_OUTPUT"
|
|
157
|
+
echo "fp_base=$(echo "$cfg" | jq -r '.config.Labels["co.freesolo.flash.kernelcache.fp_base"] // ""')" >> "$GITHUB_OUTPUT"
|
|
158
|
+
echo "revision=$(echo "$cfg" | jq -r '.config.Labels["org.opencontainers.image.revision"] // ""')" >> "$GITHUB_OUTPUT"
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
# Pin the checkout to the base's source commit so the warmed flash code matches the base exactly
|
|
162
|
+
# (the cache is content-keyed by the code that compiled it). Falls back to the event sha if the
|
|
163
|
+
# base predates the revision label.
|
|
164
|
+
- uses: actions/checkout@v6
|
|
165
|
+
if: steps.gate.outputs.run == 'true'
|
|
166
|
+
with:
|
|
167
|
+
ref: ${{ steps.base.outputs.revision || github.sha }}
|
|
168
|
+
|
|
169
|
+
- name: Install uv
|
|
170
|
+
if: steps.gate.outputs.run == 'true'
|
|
171
|
+
uses: astral-sh/setup-uv@v5
|
|
172
|
+
with:
|
|
173
|
+
# no cache: the post-run cache-prune calls `uv`, but the "Free disk space" step deletes
|
|
174
|
+
# /opt/hostedtoolcache (where setup-uv put uv), so the post step fails ("uv not found") and
|
|
175
|
+
# marks the whole job red even though the bake + push already succeeded.
|
|
176
|
+
enable-cache: false
|
|
177
|
+
|
|
178
|
+
- name: Sync deps (flash + runpod + hf)
|
|
179
|
+
if: steps.gate.outputs.run == 'true'
|
|
180
|
+
run: uv sync --extra server
|
|
181
|
+
|
|
182
|
+
- name: Install Infisical CLI
|
|
183
|
+
if: steps.gate.outputs.run == 'true'
|
|
184
|
+
run: |
|
|
185
|
+
curl -1sLf 'https://dl.cloudsmith.io/public/infisical/infisical-cli/setup.deb.sh' | sudo -E bash
|
|
186
|
+
sudo apt-get update && sudo apt-get install -y infisical
|
|
187
|
+
|
|
188
|
+
# RUNPOD_API_KEY + HF_TOKEN come from Infisical (/flash, prod) -- mirrors infisical-entrypoint.sh;
|
|
189
|
+
# the CLI takes the project UUID directly (the secrets-action wants a slug). `env -u
|
|
190
|
+
# FLASH_CHALK_SPEC` drops any chalk-spec override living in /flash so the bake always warms the
|
|
191
|
+
# repo-default chalk (the value the fingerprint hashed) -- otherwise the image could be warmed with
|
|
192
|
+
# one chalk and labeled with another. BASE_IMAGE is digest-pinned so the warm runs inside the EXACT
|
|
193
|
+
# base the per-arch tag will sit on.
|
|
194
|
+
- name: Warm kernels on a RunPod ${{ matrix.sm }} GPU -> build/kernel_cache
|
|
195
|
+
if: steps.gate.outputs.run == 'true'
|
|
196
|
+
env:
|
|
197
|
+
INFISICAL_CLIENT_ID: ${{ secrets.INFISICAL_CLIENT_ID }}
|
|
198
|
+
INFISICAL_CLIENT_SECRET: ${{ secrets.INFISICAL_CLIENT_SECRET }}
|
|
199
|
+
INFISICAL_PROJECT_ID: ${{ secrets.INFISICAL_PROJECT_ID }}
|
|
200
|
+
BASE_IMAGE: ${{ steps.base.outputs.ref }}
|
|
201
|
+
run: |
|
|
202
|
+
INFISICAL_TOKEN="$(infisical login --method=universal-auth \
|
|
203
|
+
--client-id="$INFISICAL_CLIENT_ID" --client-secret="$INFISICAL_CLIENT_SECRET" \
|
|
204
|
+
--silent --plain)"
|
|
205
|
+
export INFISICAL_TOKEN
|
|
206
|
+
infisical run --projectId "$INFISICAL_PROJECT_ID" --env prod --path /flash -- \
|
|
207
|
+
env -u FLASH_CHALK_SPEC \
|
|
208
|
+
uv run python docker/bake_kernel_cache.py \
|
|
209
|
+
--arch "${{ matrix.arch }}" --sm "${{ matrix.sm }}" \
|
|
210
|
+
--gpu-type-id "${{ matrix.gpu_type_id }}" \
|
|
211
|
+
--allowed-cuda "${{ matrix.allowed_cuda }}" \
|
|
212
|
+
--image "$BASE_IMAGE" \
|
|
213
|
+
--out build/kernel_cache
|
|
214
|
+
|
|
215
|
+
- name: Free disk space
|
|
216
|
+
if: steps.gate.outputs.run == 'true'
|
|
217
|
+
run: |
|
|
218
|
+
sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/.ghcup \
|
|
219
|
+
/usr/local/lib/android /opt/hostedtoolcache /usr/share/swift \
|
|
220
|
+
/usr/local/share/boost /usr/local/lib/node_modules \
|
|
221
|
+
/usr/local/share/powershell /usr/share/miniconda || true
|
|
222
|
+
sudo apt-get clean || true
|
|
223
|
+
sudo docker image prune -af || true
|
|
224
|
+
df -h /
|
|
225
|
+
|
|
226
|
+
- uses: docker/setup-buildx-action@v3
|
|
227
|
+
if: steps.gate.outputs.run == 'true'
|
|
228
|
+
|
|
229
|
+
# thin layer FROM the SAME base the warmup ran inside -> the cache toolchain always matches the
|
|
230
|
+
# shipped image (rebuilding the full Dockerfile.worker from the checkout could drift from the
|
|
231
|
+
# published base and bake a cache that silently won't load). GHCR auth from the login step above.
|
|
232
|
+
- name: Build + push baked per-sm image (thin layer on the warmed base)
|
|
233
|
+
if: steps.gate.outputs.run == 'true'
|
|
234
|
+
uses: docker/build-push-action@v6
|
|
235
|
+
with:
|
|
236
|
+
context: .
|
|
237
|
+
file: docker/Dockerfile.kernelcache
|
|
238
|
+
push: true
|
|
239
|
+
tags: ghcr.io/freesolo-co/flash-worker:cu128-${{ matrix.sm }}
|
|
240
|
+
provenance: false
|
|
241
|
+
build-args: |
|
|
242
|
+
BASE=${{ steps.base.outputs.ref }}
|
|
243
|
+
FP_CACHE=${{ steps.base.outputs.fp_cache }}
|
|
244
|
+
FP_BASE=${{ steps.base.outputs.fp_base }}
|
|
245
|
+
BASE_REVISION=${{ steps.base.outputs.revision }}
|
|
@@ -36,17 +36,40 @@ on:
|
|
|
36
36
|
# so handler changes (e.g. the weight-cache preload branch) MUST rebuild the image. flash/**
|
|
37
37
|
# covers the handler source (endpoints.py); the generator lives outside flash/, so watch it too.
|
|
38
38
|
- docker/make_rp_handler.py
|
|
39
|
+
# The fp_cache/fp_base labels are computed by this script at build time, so a change to the
|
|
40
|
+
# fingerprint logic must rebuild :cu128 to re-stamp them (else auto-rebake never reclassifies).
|
|
41
|
+
- docker/kernel_fingerprint.py
|
|
39
42
|
|
|
40
43
|
permissions:
|
|
41
44
|
contents: read
|
|
42
45
|
packages: write
|
|
43
46
|
|
|
47
|
+
# A newer base build supersedes an older one: cancel the in-flight run so auto-rebake (which triggers
|
|
48
|
+
# on this workflow's completion) only ever reasons about the latest :cu128. The tag is in the group so
|
|
49
|
+
# a non-prod `tag=cu128-test` dispatch can't cancel an in-flight prod `cu128` push on the same ref
|
|
50
|
+
# (which would leave :cu128 unpublished for that commit and auto-rebake blind to it).
|
|
51
|
+
concurrency:
|
|
52
|
+
group: worker-image-${{ github.ref }}-${{ github.event.inputs.tag || 'cu128' }}
|
|
53
|
+
cancel-in-progress: true
|
|
54
|
+
|
|
44
55
|
jobs:
|
|
45
56
|
build:
|
|
46
57
|
runs-on: ubuntu-24.04-8core
|
|
58
|
+
# Single source for the FlashAttention wheels: used BOTH as build-args and as fingerprint inputs
|
|
59
|
+
# (so a wheel bump moves fp_base). Keep FA3_SPEC in sync with Dockerfile.worker's ARG default.
|
|
60
|
+
env:
|
|
61
|
+
FA2_SPEC: https://github.com/mjun0812/flash-attention-prebuild-wheels/releases/download/v0.9.0/flash_attn-2.8.3%2Bcu128torch2.10-cp312-cp312-linux_x86_64.whl
|
|
62
|
+
FA3_SPEC: ${{ github.event.inputs.flash_attn_3_spec || 'https://github.com/windreamer/flash-attention3-wheels/releases/download/2026.03.19-850211f/flash_attn_3-3.0.0%2B20260318.cu128torch2100cxx11abitrue.8afc61-cp39-abi3-linux_x86_64.whl' }}
|
|
47
63
|
steps:
|
|
48
64
|
- uses: actions/checkout@v6
|
|
49
65
|
|
|
66
|
+
# Compute the kernel-cache fingerprints (stdlib-only, no uv sync) and stamp them as labels on
|
|
67
|
+
# :cu128 below, so auto-rebake.yml can read what this base was built from. Fails the build if a
|
|
68
|
+
# pin can't be parsed -- a silent miss would let a stale per-arch cache ship as a cold-JIT.
|
|
69
|
+
- name: Compute kernel fingerprints
|
|
70
|
+
id: fp
|
|
71
|
+
run: python3 docker/kernel_fingerprint.py --format github --fa2-spec "$FA2_SPEC" --fa3-spec "$FA3_SPEC" >> "$GITHUB_OUTPUT"
|
|
72
|
+
|
|
50
73
|
- name: Free disk space
|
|
51
74
|
run: |
|
|
52
75
|
sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/.ghcup \
|
|
@@ -77,21 +100,20 @@ jobs:
|
|
|
77
100
|
# so a fork run must not push to its own owner namespace and leave the real image stale.
|
|
78
101
|
tags: ghcr.io/freesolo-co/flash-worker:${{ github.event.inputs.tag || 'cu128' }}
|
|
79
102
|
provenance: false
|
|
103
|
+
# Stamp the kernel-cache fingerprints + the source commit so auto-rebake.yml can read what
|
|
104
|
+
# this base was built from (docker/kernel_fingerprint.py is the source of truth).
|
|
105
|
+
labels: |
|
|
106
|
+
co.freesolo.flash.kernelcache.fp_cache=${{ steps.fp.outputs.fp_cache }}
|
|
107
|
+
co.freesolo.flash.kernelcache.fp_base=${{ steps.fp.outputs.fp_base }}
|
|
108
|
+
org.opencontainers.image.revision=${{ github.sha }}
|
|
80
109
|
# Install a PREBUILT flash-attn wheel instead of compiling from source (a multi-arch
|
|
81
110
|
# source compile is huge and OOM-kills the runner). The wheel matches the base exactly
|
|
82
|
-
# (cu128 / torch2.10 / cp312).
|
|
111
|
+
# (cu128 / torch2.10 / cp312). FA specs come from the job-level env (single source).
|
|
83
112
|
build-args: |
|
|
84
|
-
FLASH_ATTN_SPEC
|
|
85
|
-
FLASH_ATTN_3_SPEC=${{
|
|
113
|
+
FLASH_ATTN_SPEC=${{ env.FA2_SPEC }}
|
|
114
|
+
FLASH_ATTN_3_SPEC=${{ env.FA3_SPEC }}
|
|
86
115
|
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
-
|
|
90
|
-
|
|
91
|
-
run: |
|
|
92
|
-
echo "::warning title=Rebake per-SM images::A new :cu128 base was published. If FLASH_WORKER_IMAGE_PER_SM=1 is enabled, run bake-kernel-cache.yml to refresh cu128-sm{80,86,89,90,120}, else workers run stale baked deps."
|
|
93
|
-
{
|
|
94
|
-
echo "### ⚠️ Per-SM kernel-cache images may now be stale"
|
|
95
|
-
echo ""
|
|
96
|
-
echo "A fresh \`:cu128\` base was just published. If \`FLASH_WORKER_IMAGE_PER_SM=1\` is enabled, re-run **bake-kernel-cache.yml** to refresh the per-arch \`cu128-sm*\` tags, or workers will run the previous baked deps."
|
|
97
|
-
} >> "$GITHUB_STEP_SUMMARY"
|
|
116
|
+
# When :cu128 is republished the per-arch cu128-sm* tags go stale. auto-rebake.yml now handles
|
|
117
|
+
# that automatically on this workflow's completion: a free re-layer when only the base moved, or
|
|
118
|
+
# a one-click GPU re-warm when the kernel toolchain changed (it reads the fp_cache/fp_base labels
|
|
119
|
+
# stamped above vs each published per-arch tag). The old manual reminder is gone.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: freesolo-flash-dev
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.27
|
|
4
4
|
Summary: Flash — managed LoRA post-training (SFT/GRPO) for Freesolo environments, driven by the `flash` CLI
|
|
5
5
|
Project-URL: Homepage, https://github.com/freesolo-co/flash
|
|
6
6
|
Project-URL: Repository, https://github.com/freesolo-co/flash
|
|
@@ -16,3 +16,13 @@ ENV TRITON_CACHE_DIR=/opt/flash/kernelcache/triton \
|
|
|
16
16
|
TORCHINDUCTOR_CACHE_DIR=/opt/flash/kernelcache/inductor
|
|
17
17
|
|
|
18
18
|
COPY build/kernel_cache/ /opt/flash/kernelcache/
|
|
19
|
+
|
|
20
|
+
# Fingerprint + base-revision stamps so auto-rebake.yml can read what this image was baked from and
|
|
21
|
+
# decide skip / re-layer / re-warm (docker/kernel_fingerprint.py is the source of truth for the
|
|
22
|
+
# values). Default to "unknown" so a hand build still works; CI always passes the real ones.
|
|
23
|
+
ARG FP_CACHE=unknown
|
|
24
|
+
ARG FP_BASE=unknown
|
|
25
|
+
ARG BASE_REVISION=unknown
|
|
26
|
+
LABEL co.freesolo.flash.kernelcache.fp_cache=$FP_CACHE \
|
|
27
|
+
co.freesolo.flash.kernelcache.fp_base=$FP_BASE \
|
|
28
|
+
org.opencontainers.image.revision=$BASE_REVISION
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Cheap per-arch RE-LAYER: graft the EXISTING baked mega-cache onto a freshly rebuilt :cu128 base,
|
|
2
|
+
# with NO GPU. Used by auto-rebake.yml when fp_cache is unchanged (the cache is still valid) but the
|
|
3
|
+
# base moved (fp_base changed) -- e.g. an FA2/FA3/causal-conv1d/rp_handler bump. The valid cache
|
|
4
|
+
# already lives inside the currently-published per-arch tag, so OLDCACHE IS the cache store; we just
|
|
5
|
+
# re-stack it on the new base. This is what makes a base-only change free (vs a paid GPU re-warm).
|
|
6
|
+
#
|
|
7
|
+
# BASE and OLDCACHE are passed DIGEST-PINNED by the gate so a concurrent base/tag overwrite can't
|
|
8
|
+
# graft the cache onto the wrong base.
|
|
9
|
+
ARG BASE=ghcr.io/freesolo-co/flash-worker:cu128
|
|
10
|
+
ARG OLDCACHE=ghcr.io/freesolo-co/flash-worker:cu128-sm89
|
|
11
|
+
FROM ${OLDCACHE} AS oldcache
|
|
12
|
+
FROM ${BASE}
|
|
13
|
+
|
|
14
|
+
# Match Dockerfile.worker / Dockerfile.kernelcache so the layer is self-contained even on an older base.
|
|
15
|
+
ENV TRITON_CACHE_DIR=/opt/flash/kernelcache/triton \
|
|
16
|
+
TORCHINDUCTOR_CACHE_DIR=/opt/flash/kernelcache/inductor
|
|
17
|
+
|
|
18
|
+
# Pull the warmed cache straight out of the old per-arch image -- no GPU, no external cache store.
|
|
19
|
+
COPY --from=oldcache /opt/flash/kernelcache /opt/flash/kernelcache
|
|
20
|
+
|
|
21
|
+
# Re-stamp with the CURRENT fingerprints (fp_cache unchanged, fp_base + revision are the new base's).
|
|
22
|
+
ARG FP_CACHE=unknown
|
|
23
|
+
ARG FP_BASE=unknown
|
|
24
|
+
ARG BASE_REVISION=unknown
|
|
25
|
+
LABEL co.freesolo.flash.kernelcache.fp_cache=$FP_CACHE \
|
|
26
|
+
co.freesolo.flash.kernelcache.fp_base=$FP_BASE \
|
|
27
|
+
org.opencontainers.image.revision=$BASE_REVISION
|