Skip to content

ci: fuse duplicate PR gates and reduce repeated setup #975

Open

Description

@xiaguan

Summary

Ready-for-review pull requests currently fan out into 15 GitHub Actions jobs. Most compilation jobs start on fresh hosted runners, repeat checkout and dependency setup, and discard their local build outputs when the job ends.

Recent ordinary PR CI runs usually complete in about 6–7 minutes of wall time, with an observed 11-minute outlier. sccache is already enabled and working, so this issue is about reducing duplicated job work and runner isolation.

The release workflow is explicitly out of scope.

Measured baseline

Recent non-release PR runs:

Representative steps from the typical run:

Job Total Checkout CUDA setup Cargo gate
Qwen3 CUDA compile 5m20s 33s 45s 3m42s
Gemma 4 CUDA Clippy 6m17s 65s 88s 3m20s
Qwen3.5 CUDA compile 4m42s 31s 38s 3m12s

sccache was active in that run:

  • Qwen3 CUDA compile: 79.7% hit rate
  • Qwen3 CUDA Clippy: 84.8%
  • Gemma 4 CUDA Clippy: 92.6%
  • Qwen3.5 CUDA Clippy: 98.8%

The slow run also showed that cache hits alone do not bound wall time:

  • Qwen3.5 CUDA compile: 98.7% hits, but the Cargo step took 8m21s
  • Simulated frontend E2E: 100% hits (511/511), but the job took 9m44s

The typical run also reported cache write errors in several parallel jobs, including 94 in Qwen3 compile and 76 in Qwen3.5 compile. The logs do not expose the backend error detail, so the cause should be verified before changing cache behavior.

Current duplication

  1. The Gemma 4/Qwen3.5 matrix runs both cargo check and cargo clippy with the same package, feature, release profile, and --all-targets surface.
  2. Qwen3 has separate CUDA compile and Clippy jobs with largely overlapping package and target coverage.
  3. CPU Clippy, four CPU unit-test jobs, and simulated frontend E2E each repeat Rust/sccache setup; most also repeat protobuf installation and dependency materialization.
  4. Every CUDA job repeats recursive submodule checkout and CUDA toolkit installation.
  5. pegainfer-kernels/build.rs launches nvcc directly, so those CUDA translation units are outside the Rust RUSTC_WRAPPER=sccache path and are rebuilt on every fresh runner.

Production invariant

A ready PR must continue to fail when any currently covered surface fails:

  • DCO, attribution scripts, Rust formatting, and locked Cargo metadata
  • CPU Clippy
  • CPU unit tests for pegainfer-build, pegainfer-frontend, pegainfer-sim, and kvbm-logical
  • simulated frontend E2E
  • Qwen3, Qwen3.5, and Gemma 4 release-mode CUDA all-target compilation and lint coverage for sm_80

Before deleting a job, document which retained command covers every package, feature, and target previously checked by that job.

Proposed work

  1. Remove the feature-model compile matrix entries where the retained Clippy invocation demonstrably covers the identical package/feature/--all-targets surface.
  2. Map the Qwen3 compile and Clippy target surfaces. Remove the compile job only if the retained Clippy command fully subsumes it; otherwise consolidate both commands into one runner.
  3. Evaluate one fused CPU gate that installs dependencies once and runs CPU Clippy, unit tests, and simulated frontend E2E against the same workspace.
  4. Keep model lines in separate CUDA jobs so feature-specific build requirements remain isolated.
  5. Avoid adding composite-action wrappers solely to reduce YAML duplication; they do not share runner state.

Acceptance criteria

  • Every current gate is mapped to a retained command, with no package/feature/target coverage loss.
  • Report before/after:
    • workflow wall time
    • summed job runtime
    • per-job setup and Cargo-step duration
    • sccache hit/miss/write-error statistics
  • Use multiple completed ordinary PR runs and retain links to the raw Actions results.
  • Do not claim a CI performance improvement until the before/after data is measured.
  • If CPU fusion reduces summed runner time but increases wall time, report both results and make the tradeoff explicit.
  • Release CI remains unchanged.

Follow-ups outside this issue

  • Route direct nvcc compilation through a supported cache launcher.
  • Evaluate a prebuilt CI image with CUDA, protobuf, libibverbs, and Triton.
  • Investigate the GitHub Actions cache write errors.
  • Evaluate persistent or self-hosted runners separately.

Activity

  1. added
    enhancementNew feature or request
    hw:noneNo GPU required — CPU-only / docs / infra
    on Sep 2, 2026
  2. luicarus commented on Sep 15, 2026

    @luicarus
    Contributor

    I'd like to take this one.

    I read through ci.yml and mapped the current gates before making changes. The proposed scope in the issue looks good to me, and I'll keep the first PR within it.

    A couple of implementation details I noticed while mapping the workflow:

    • feature-model-cuda runs the compile and clippy legs over the same package / feature / release / --all-targets surface. I'll verify that the retained Clippy command gives equivalent compile coverage before removing the two compile legs.
    • The Qwen3 Clippy job appears to contain the package/target surface of qwen3-cuda-compile. One difference is that the compile job sets CUDA_PATH, PEGAINFER_CUDA_SM, and PEGAINFER_NVCC_JOBS at job scope, while the Clippy job sets them only on the Cargo step; I'll preserve the relevant environment if the jobs are consolidated.
    • For the CPU path, I'll evaluate the fused gate described in the issue so Rust/sccache/dependency setup is paid once, while keeping every existing CPU gate covered.

    Before deleting any job, I'll include a package / feature / target coverage map showing which retained command replaces it. I'll also report the before/after measurements required by the acceptance criteria across multiple completed PR runs, rather than assuming consolidation improves wall time.

    One thing I want to reconcile first: the issue mentions 15 ready-for-review jobs, while my initial count from the current workflow is 16 executions (8 single-instance + 4 cpu-unit-tests + 4 feature-model-cuda). I'll verify whether one is conditional / outside the ordinary PR path or whether the workflow has changed since the baseline was recorded.

    I'll leave the cache-write-error investigation and release workflow untouched, as they are explicitly out of scope here.

    If this scope sounds right, I'll proceed.

  3. github-actions commented on Sep 29, 2026

    @github-actions

    This issue has been inactive for 14 days. It will be closed after another 30 days unless there is new activity.

  4. FeathBow commented on Oct 11, 2026

    @FeathBow
    Collaborator

    Hi @luicarus, #1048 and #1066 covered the compile gates and the nvcc launcher, thanks. Unless you are already working on it, we will take the fused CPU gate next, with the before and after measurements the issue asks for.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requesthw:noneNo GPU required — CPU-only / docs / infra

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions