|
| 1 | +# Remote GPU validation |
| 2 | + |
| 3 | +This workflow rebuilds one committed ABACUS revision on a remote GPU cluster, runs the test matrix in `config.ini` through Slurm, and reports each build and test group separately. It is a functional test, not a benchmark. |
| 4 | + |
| 5 | +The maintained setup runs at the [Open Source Supercomputing Center of SAI](https://www.open-sai.com/). The same client can be configured for another Slurm cluster. |
| 6 | + |
| 7 | +**Trust boundary:** the selected commit is compiled and executed as the remote SSH user. Approve only code that may run with that account's permissions. |
| 8 | + |
| 9 | +## Set up GitHub |
| 10 | + |
| 11 | +A repository administrator performs these steps once. Forks start disabled because GitHub does not copy variables or secrets from the parent repository. |
| 12 | + |
| 13 | +1. Open **Settings > Secrets and variables > Actions > Variables**, choose **New repository variable**, and set: |
| 14 | + |
| 15 | + - Name: `GPU_VALIDATION_ENABLED` |
| 16 | + - Value: `true` |
| 17 | + |
| 18 | + The value is the lowercase text `true`. If this variable is absent or has another value, the workflow skips all remote work. |
| 19 | + |
| 20 | +2. Open **Settings > Environments** and create: |
| 21 | + |
| 22 | + - `gpu-ci-scheduled`, with no required reviewers, for daily tests. |
| 23 | + - `gpu-ci-manual`, with the maintainers who may approve PR and manual tests listed as required reviewers. |
| 24 | + |
| 25 | +3. Open each environment, choose **Environment secrets > Add environment secret**, and add: |
| 26 | + |
| 27 | + - Name: `REMOTE_SSH_PRIVATE_KEY` |
| 28 | + - Value: the complete private key, including its `BEGIN` and `END` lines. |
| 29 | + |
| 30 | + Install the matching public key in `authorized_keys` for the remote account named in `config.ini`. Add the private key to both environments because they have different approval rules. Do not create a repository-level SSH secret; the workflow reads this environment secret only after entering the selected environment. |
| 31 | + |
| 32 | +Host, port, user, and the normal remote project directory are read from the trusted `[remote]` section of `config.ini`. |
| 33 | + |
| 34 | +## Run validation |
| 35 | + |
| 36 | +All GitHub methods below require `GPU_VALIDATION_ENABLED=true`. The workflow must already be present on the repository's default branch. |
| 37 | + |
| 38 | +### Test a pull request |
| 39 | + |
| 40 | +On an open pull request, add this exact comment: |
| 41 | + |
| 42 | +```text |
| 43 | +/abacus-ci gpu |
| 44 | +``` |
| 45 | + |
| 46 | +The comment cannot contain other text. The author of the comment needs Triage, Write, Maintain, or Admin permission. The bot immediately posts a link to the queued Actions run. After a reviewer approves the `gpu-ci-manual` environment, the workflow tests the PR head commit and updates that same bot comment with the result and raw-file link. |
| 47 | + |
| 48 | +### Run the daily test |
| 49 | + |
| 50 | +No manual action is needed. The workflow is scheduled every day at 20:30 UTC (`30 20 * * *`). It tests the current default branch of `deepmodeling/abacus-develop` and uses `gpu-ci-scheduled`, so it does not wait for approval. |
| 51 | + |
| 52 | +### Start a run from Actions |
| 53 | + |
| 54 | +1. Open **Actions > GPU validation > Run workflow**. |
| 55 | +2. Select the repository default branch under **Use workflow from**. |
| 56 | +3. Enter the full, lowercase 40-character commit SHA in `source_sha`. |
| 57 | +4. Leave `project_root` empty to use `config.ini`, or enter another permitted remote directory. |
| 58 | +5. Start the run and approve the `gpu-ci-manual` environment when prompted. |
| 59 | + |
| 60 | +The commit must exist in the repository where the workflow is running. For an external contributor's pull request, use the PR comment command instead. |
| 61 | + |
| 62 | +### Run from a local checkout |
| 63 | + |
| 64 | +Create an SSH host entry. The default alias is `gpu-ci`; use the host, port, user, and key for your account: |
| 65 | + |
| 66 | +```sshconfig |
| 67 | +Host gpu-ci |
| 68 | + HostName <host> |
| 69 | + Port <port> |
| 70 | + User <user> |
| 71 | + IdentityFile ~/.ssh/<private-key> |
| 72 | +``` |
| 73 | + |
| 74 | +Then run this command from a committed ABACUS checkout: |
| 75 | + |
| 76 | +```bash |
| 77 | +python3 .ci/slurm/runner.py run |
| 78 | +``` |
| 79 | + |
| 80 | +By default, the command uses the checkout's committed `HEAD`, `~/.ssh/config`, the `gpu-ci` alias, and the remote directory from `config.ini`. Uncommitted candidate-source changes are not sent. The local command does use the current `.ci/slurm` control files, including local changes to its scripts and templates. The command waits for Slurm, prints live build and test progress, downloads the results, and exits nonzero if validation fails. |
| 81 | + |
| 82 | +Local results go to `/tmp/abacus_gpu_ci_<uid>/<namespace>/<run_id>_<attempt>/`. Use `--artifacts` for a permanent local directory or `--target my-cluster` for another SSH alias. All available options and defaults are shown by: |
| 83 | + |
| 84 | +```bash |
| 85 | +python3 .ci/slurm/runner.py --help |
| 86 | +python3 .ci/slurm/runner.py run --help |
| 87 | +``` |
| 88 | + |
| 89 | +## Configuration |
| 90 | + |
| 91 | +`config.ini` is validated before jobs are submitted. |
| 92 | + |
| 93 | +- `[site]`: the resource acknowledgement, site name, and public URL shown at the end of result reports. Change these values for another cluster. |
| 94 | +- `[remote]`: SSH `host`, `port`, `user`, `project_root`, and comma-separated `allowed_project_roots`. The project root may use `~/` or an absolute path, but its remote resolved path must be below one of the allowed roots. Prefixes are also resolved remotely, so aliases such as `/home` pointing to `/org` are accepted. |
| 95 | +- `[cluster]`: Slurm `partition`, absolute `mapping_root` for the MPI mapping script, `disable_nccl_ib` (`true` or `false`), and `poll_seconds` (1-300). |
| 96 | +- `[build]`: build-job `qos`, `nodes`, `tasks_per_node`, `gpus_per_node`, and `time_seconds`. |
| 97 | +- `[resource.NAME]`: the same allocation fields plus `parallelism`, the maximum number of array tasks running at once. Each resource must have a case. There is one rank per GPU and no resource may exceed 16 GPUs. |
| 98 | +- `[case.NNN]`: contiguous, zero-padded sections with `suite`, `name`, `resource`, and `runner` (`autotest` or `cusolvermp`). |
| 99 | + |
| 100 | +Resource component labels are generated, not configured separately. A single-node resource is shown as `N GPU` or `N GPUs`; a multi-node resource is shown as `N nodes / M GPUs`. Thus `gpu1`, `gpu2`, and `gpu4` display `1 GPU`, `2 GPUs`, and `4 GPUs`; `gpu8x2` displays `2 nodes / 16 GPUs`. `case.049` is `15_rtTDDFT_GPU/19_NO_Si48_CUSOLVERMP_TDDFT_GPU`; it uses `gpu8x2` and the `cusolvermp` runner. |
| 101 | + |
| 102 | +## Results and retention |
| 103 | + |
| 104 | +On the remote cluster, a run is created below: |
| 105 | + |
| 106 | +``` |
| 107 | +<project-root>/runs/<namespace>/<run-id>-<attempt>/ |
| 108 | +``` |
| 109 | + |
| 110 | +Its `results/` directory contains `result.json`, `summary.md`, build and case logs, Slurm output, module/tool records, and status files. The coordinator and working data are alongside it while the run is active. After results are collected, the client archives `results/` and `jobs/` as: |
| 111 | + |
| 112 | +``` |
| 113 | +<project-root>/archives/<namespace>/<run-id>-<attempt>.tar.gz |
| 114 | +``` |
| 115 | + |
| 116 | +The client removes archived files older than 72 hours when preparing a later run, and removes the active run after archiving. On the GitHub runner, `ARTIFACT_ROOT` is `${runner.temp}/gpu-ci-artifacts`; it contains the collected `results/`, `run.json`, and `client.log`. CI uploads that directory as `gpu-validation-<run-id>-<attempt>` and retains it for 30 days. A pull-request comment links to the Actions run and the uploaded raw files. If the client stops before completion, the remote run is left in place so that its detached coordinator and Slurm jobs are not interrupted. |
| 117 | + |
| 118 | +Source is sent as a compressed Git bundle. The remote Git cache keeps the three most recent PR or manual revisions, the latest two daily dates, the first daily revision of every UTC month, and one weekly revision for the current month. Weekly revisions from earlier months are removed. Concurrent runs reserve the cache revisions they use, so another run cannot remove their transfer base. |
| 119 | + |
| 120 | +## Troubleshooting |
| 121 | + |
| 122 | +**SSH fails.** Check the `[remote]` values in `config.ini`, that the key matches the configured account, and that the target is reachable. CI uses the committed `.ci/slurm/known_hosts` with strict host-key checking. Test the same target with the SSH config before retrying; do not disable host-key checking. |
| 123 | + |
| 124 | +**A module cannot be loaded.** `modules.sh` sources Lmod, purges modules, and loads `cmake/3.31.6` and the configured ABACUS dependency module. Ask the site administrator to provide or update those modules. Modules provide the compiler, CUDA, MPI, and library dependencies; do not add library paths to CI (`LD_LIBRARY_PATH`, `CPATH`, or `CMAKE_PREFIX_PATH`) or hard-code site paths. |
| 125 | + |
| 126 | +**CMake or linking fails.** Inspect `results/configure.log`, `build.log`, `install.log`, `CMakeCache.txt`, `tools.txt`, and `ldd.txt`. The build uses Unix Makefiles, CUDA architecture 70, CUDA MPI, cuSOLVERMP, cuBLASMP, and NCCL parallel-device options. A missing runtime library causes the `ldd` check to fail; fix the module environment rather than adding a CI path. |
| 127 | + |
| 128 | +**A job stays pending or times out.** Check the selected partition and QoS, GPU availability, node and task limits, and the `time_seconds` value for that resource. Slurm output is in `results/`; an allocation or queue delay is an infrastructure issue, not a case failure. |
| 129 | + |
| 130 | +**MPI/PMIx initialization fails.** Both runners retry once after a recognized MPI startup failure. If it persists, inspect the attempt logs and the loaded MPI module, Slurm allocation, and mapping file. |
0 commit comments