diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 11d27b2..346f708 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -7,23 +7,14 @@ on: pull_request: branches: [main] workflow_dispatch: - inputs: - build_mode: - description: "Build configuration" - type: choice - required: true - default: standard - options: - - standard - - nightly-experiments permissions: contents: read env: CARGO_TERM_COLOR: always + # Measure before stripping; package stripped copies separately. CARGO_PROFILE_RELEASE_STRIP: none - BUILD_MODE: ${{ inputs.build_mode || 'standard' }} jobs: build: @@ -58,21 +49,24 @@ jobs: uses: builtin:checkout - name: Configure Rust directories + # Cross remote does not traverse hidden directories under /root. run: | echo "CARGO_HOME=$RUNNER_TEMP/cargo" >> "$GITHUB_ENV" echo "RUSTUP_HOME=$RUNNER_TEMP/rustup" >> "$GITHUB_ENV" echo "$RUNNER_TEMP/cargo/bin" >> "$GITHUB_PATH" - - name: Install Rust toolchain + - name: Install standard Rust toolchain uses: actions-rust-lang/setup-rust-toolchain@ecabd13d1c56bd1345c230e542e9144811ad706f # v2 with: - toolchain: ${{ (inputs.build_mode == 'nightly-experiments' || startsWith(matrix.target, 'mips')) && 'nightly' || 'stable' }} + toolchain: ${{ startsWith(matrix.target, 'mips') && 'nightly' || 'stable' }} cache: false build-warnings: warn - - name: Install nightly standard library sources - if: inputs.build_mode == 'nightly-experiments' - run: rustup component add rust-src --toolchain nightly + - name: Install nightly toolchain and standard library sources + run: | + rustup toolchain install nightly \ + --profile minimal \ + --component rust-src - name: Install cross and binary tools run: | @@ -91,7 +85,7 @@ jobs: - name: Build, verify, package, and compare env: - # MIPS std needs CRT objects from the cross GCC toolchain. + # MIPS build-std needs cross GCC's CRT objects. RUSTFLAGS: ${{ startsWith(matrix.target, 'mips') && '-C target-feature=+crt-static -C link-self-contained=no' || '-C target-feature=+crt-static' }} CROSS_REMOTE: "true" CROSS_REMOTE_COPY_FULL_TARGET_DIR: ${{ startsWith(matrix.target, 'mips') && 'true' || 'false' }} @@ -101,29 +95,29 @@ jobs: declare -A raw_size declare -A stripped_size declare -A compressed_size - declare -a variants mkdir -p dist - cross_cmd=(cross) - if [[ "$BUILD_MODE" == "nightly-experiments" ]]; then - cross_cmd+=(+nightly) + # MIPS requires nightly build-std via Cross.toml. + # Every other standard build uses stable. + standard_toolchain=stable + if [[ "$TARGET" == mips* ]]; then + standard_toolchain=nightly fi build_variant() { local variant="$1" - local features="$2" - shift 2 + local toolchain="$2" + local features="$3" + shift 3 local binary="target/${RUST_TARGET}/release/irtt-client" local directory="dist/${variant}" local artifact="dist/irtt-client-${TARGET}-${variant}.tar.gz" - echo "::group::Build ${variant} (${features})" + echo "::group::Build ${variant} (${toolchain}, ${features})" - # Additional arguments allow individual variants to - # customize build-std, std features and panic behavior. - "${cross_cmd[@]}" build \ + cross "+${toolchain}" build \ --release \ --locked \ --target "$RUST_TARGET" \ @@ -133,8 +127,7 @@ jobs: --features "$features" \ "$@" - # Check dynamic linking without relying on pipeline - # behavior under pipefail. + # Reject dynamically linked executables. readelf --program-headers "$binary" > /tmp/program-headers.txt readelf --dynamic "$binary" > /tmp/dynamic-section.txt @@ -154,11 +147,10 @@ jobs: stat -c %s "$directory/irtt-client" ) + # Each archive contains an executable named irtt-client. tar -czf "$artifact" -C "$directory" irtt-client compressed_size[$variant]=$(stat -c %s "$artifact") - variants+=("$variant") - echo "::endgroup::" } @@ -166,7 +158,7 @@ jobs: numfmt --to=iec-i --suffix=B --format='%.1f' "$1" } - # Positive means larger than baseline; negative means smaller. + # Negative means smaller than the reference binary. delta() { awk -v base="$1" -v current="$2" 'BEGIN { if (base == 0) { @@ -177,105 +169,138 @@ jobs: }' } - reduction() { - awk -v full="$1" -v minimal="$2" 'BEGIN { - if (full == 0) { - printf "N/A" - } else { - printf "%.1f%%", 100 * (full - minimal) / full - } - }' + print_row() { + local variant="$1" + local label="$2" + local baseline="$3" + local comparison + + if [[ "$variant" == "$baseline" ]]; then + comparison="Baseline" + else + comparison=$(delta \ + "${compressed_size[$baseline]}" \ + "${compressed_size[$variant]}") + fi + + printf '| %s | %s | %s | %s | %s |\n' \ + "$label" \ + "$(human "${raw_size[$variant]}")" \ + "$(human "${stripped_size[$variant]}")" \ + "$(human "${compressed_size[$variant]}")" \ + "$comparison" } - # Standard builds preserve the existing toolchain policy: - # stable everywhere except MIPS, which requires nightly. - # - # Experimental mode uses nightly for every variant so - # compiler-version differences don't affect comparisons. + # --------------------------------------------------------- + # Standard builds: stable except MIPS. + # --------------------------------------------------------- + full_features=client if [[ "$HAS_STATS_FEATURE" == "true" ]]; then - build_variant full "client,stats" - build_variant minimal "client" - baseline="minimal" + full_features="client,stats" + fi + + build_variant full "$standard_toolchain" "$full_features" + + standard_baseline=full + if [[ "$HAS_STATS_FEATURE" == "true" ]]; then + build_variant minimal "$standard_toolchain" client + standard_baseline=minimal + fi + + # --------------------------------------------------------- + # Nightly baseline: identical compiler for all experiments. + # + # MIPS already uses nightly for standard builds, so reuse + # those binaries rather than compiling them twice. + # --------------------------------------------------------- + + if [[ "$standard_toolchain" == "nightly" ]]; then + nightly_full=full + nightly_baseline="$standard_baseline" else - # Compatibility with main before stats feature gating. - build_variant full "client" - baseline="full" + nightly_full=nightly-full + build_variant nightly-full nightly "$full_features" + + nightly_baseline=nightly-full + if [[ "$HAS_STATS_FEATURE" == "true" ]]; then + build_variant nightly-minimal nightly client + nightly_baseline=nightly-minimal + fi fi - if [[ "$BUILD_MODE" == "nightly-experiments" ]]; then - # Existing Cross.toml already rebuilds std on MIPS. - # On other targets, the normal builds use prebuilt std. + # --------------------------------------------------------- + # Nightly size experiments, always enabled. + # --------------------------------------------------------- - build_variant rebuilt-std "client" \ - -Z build-std + # Rebuild std with the ordinary std feature set. + build_variant rebuilt-std nightly client \ + -Z build-std - # Rebuild std without backtrace support, retaining - # normal panic unwinding. - build_variant no-backtrace "client" \ - -Z build-std \ - -Z build-std-features=panic-unwind + # Rebuild std without backtrace support. + # Retain normal panic unwinding. + build_variant no-backtrace nightly client \ + -Z build-std \ + -Z build-std-features=panic-unwind - # Most aggressive experiment: no unwinding, panic - # reporting, or std backtrace support. - build_variant immediate-abort "client" \ - -Z panic-immediate-abort \ - -Z build-std \ - -Z build-std-features= \ - --config 'profile.release.panic="immediate-abort"' - fi + # Aggressive option: terminate immediately on panic. + build_variant immediate-abort nightly client \ + -Z panic-immediate-abort \ + -Z build-std \ + -Z build-std-features= \ + --config 'profile.release.panic="immediate-abort"' + + # --------------------------------------------------------- + # Job summary. + # --------------------------------------------------------- { echo "### irtt-client: ${TARGET}" echo - echo "Build mode: \`${BUILD_MODE}\`" + + echo "#### Standard builds" + echo + echo "Toolchain: \`${standard_toolchain}\`" echo echo '| Variant | Unstripped | Stripped | Compressed | Compressed vs baseline |' echo '|:--|--:|--:|--:|--:|' - for variant in "${variants[@]}"; do - if [[ "$variant" == "$baseline" ]]; then - comparison="Baseline" - else - comparison=$(delta \ - "${compressed_size[$baseline]}" \ - "${compressed_size[$variant]}") - fi - - printf '| %s | %s | %s | %s | %s |\n' \ - "$variant" \ - "$(human "${raw_size[$variant]}")" \ - "$(human "${stripped_size[$variant]}")" \ - "$(human "${compressed_size[$variant]}")" \ - "$comparison" - done + print_row full "Full" "$standard_baseline" if [[ "$HAS_STATS_FEATURE" == "true" ]]; then - echo - echo '#### Full vs minimal' - echo - echo '| Unstripped reduction | Stripped reduction | Compressed reduction |' - echo '|--:|--:|--:|' - - printf '| %s | %s | %s |\n' \ - "$(reduction "${raw_size[full]}" "${raw_size[minimal]}")" \ - "$(reduction "${stripped_size[full]}" "${stripped_size[minimal]}")" \ - "$(reduction "${compressed_size[full]}" "${compressed_size[minimal]}")" - else - echo - echo "The stats feature is not available; client includes statistics." + print_row minimal "Minimal" "$standard_baseline" fi - if [[ "$BUILD_MODE" == "nightly-experiments" ]]; then + echo + echo "#### Nightly experiments" + echo + echo '| Variant | Unstripped | Stripped | Compressed | Compressed vs baseline |' + echo '|:--|--:|--:|--:|--:|' + + print_row "$nightly_full" "Nightly full" "$nightly_baseline" + + if [[ "$HAS_STATS_FEATURE" == "true" ]]; then + print_row "$nightly_baseline" "Nightly minimal" "$nightly_baseline" + fi + + print_row rebuilt-std "Rebuilt std" "$nightly_baseline" + print_row no-backtrace "No backtrace" "$nightly_baseline" + print_row immediate-abort "Immediate abort" "$nightly_baseline" + + if [[ "$standard_toolchain" == "stable" ]]; then echo - echo '#### Experiment details' + echo "Nightly vs stable baseline (compressed): $(delta \ + "${compressed_size[$standard_baseline]}" \ + "${compressed_size[$nightly_baseline]}")" + else echo - echo '- `rebuilt-std`: nightly `-Z build-std`, default std features' - echo '- `no-backtrace`: rebuilt std with `panic-unwind` only' - echo '- `immediate-abort`: rebuilt std with immediate panic termination' + echo "MIPS: standard and nightly baselines are identical." + echo "Cross.toml already enables build-std for these targets." + fi + + if [[ "$HAS_STATS_FEATURE" != "true" ]]; then echo - echo 'MIPS already uses build-std through Cross.toml.' - echo 'All measurements use the same target and nightly toolchain.' + echo "Statistics feature not detected; client includes statistics." fi } >> "$GITHUB_STEP_SUMMARY"