build: use ThinLTO for release binaries (#23710)

## Why

Fat LTO makes release builds substantially slower without providing
enough measured runtime benefit to justify the release CI long pole. The
build-profile investigation found that keeping Cargo's default release
`opt-level=3` and switching from fat LTO to ThinLTO (`3/thin/1`) reduced
a clean `codex-cli` release build from 2073.893 seconds to 1243.172
seconds, a 40.06% improvement.

The resulting binary increased from 196.7 MiB to 211.8 MiB (+7.63%).
Measured runtime changes were small: the worst image workload median was
+0.86% and app-server startup was +0.31% relative to fat LTO. ThinLTO
retains cross-crate optimization while avoiding most of the fat-LTO
build cost.

This deliberately avoids global size optimization: final-executable
testing showed a substantial regression on the image request path, which
is expected to become more important as image usage grows.

## What changed

- Set the workspace release profile to `lto = "thin"`, retaining Cargo's
default release `opt-level=3`.
- Remove release and CI workflow-specific LTO overrides so
release-profile builds consistently use the workspace setting.
- Remove the now-unused Windows release workflow input and related
diagnostic output.

## Validation

- Confirmed the release profile parses with `cargo metadata --no-deps
--format-version 1`.
- CI validates release builds across the supported target matrix.
This commit is contained in:
Adam Perry @ OpenAI
2026-06-04 13:07:53 -07:00
committed by GitHub
Unverified
parent 555f8caeff
commit f97d5c3275
4 changed files with 3 additions and 18 deletions
-2
View File
@@ -167,8 +167,6 @@ jobs:
USE_SCCACHE: ${{ (startsWith(matrix.runner, 'windows') || (matrix.runner == 'macos-15-xlarge' && matrix.target == 'x86_64-apple-darwin')) && 'false' || 'true' }}
CARGO_INCREMENTAL: "0"
SCCACHE_CACHE_SIZE: 10G
# In rust-ci, representative release-profile checks use thin LTO for faster feedback.
CARGO_PROFILE_RELEASE_LTO: ${{ matrix.profile == 'release' && 'thin' || 'fat' }}
strategy:
fail-fast: false
+2 -9
View File
@@ -2,10 +2,6 @@ name: rust-release-windows
on:
workflow_call:
inputs:
release-lto:
required: true
type: string
# Cargo's libgit2 transport has been flaky when fetching git dependencies with
# nested submodules. Prefer the system git CLI across every Cargo invocation.
@@ -16,17 +12,14 @@ jobs:
build-windows-binaries:
name: Build Windows binaries - ${{ matrix.runner }} - ${{ matrix.target }} - ${{ matrix.bundle }}
runs-on: ${{ matrix.runs_on }}
# Windows release builds can exceed an hour on fat-LTO mainline releases,
# so keep the timeout aligned with the top-level release build headroom.
# Windows release builds can exceed an hour, so keep the timeout aligned
# with the top-level release build headroom.
timeout-minutes: 90
permissions:
contents: read
defaults:
run:
working-directory: codex-rs
env:
CARGO_PROFILE_RELEASE_LTO: ${{ inputs.release-lto }}
strategy:
fail-fast: false
matrix:
-6
View File
@@ -149,9 +149,6 @@ jobs:
run:
working-directory: codex-rs
env:
# 2026-03-04: temporarily change releases to use thin LTO because
# Ubuntu ARM is timing out at 60 minutes.
CARGO_PROFILE_RELEASE_LTO: ${{ contains(github.ref_name, '-alpha') && 'thin' || 'thin' }}
# Use the git CLI instead of Cargo's libgit2 path for git dependencies.
# macOS release runners have intermittently failed to fetch nested
# submodules through SecureTransport/libgit2, especially libwebrtc's
@@ -325,7 +322,6 @@ jobs:
for binary in ${{ matrix.binaries }}; do
build_args+=(--bin "$binary")
done
echo "CARGO_PROFILE_RELEASE_LTO: ${CARGO_PROFILE_RELEASE_LTO}"
cargo build --target "$target" --release --timings "${build_args[@]}"
- name: Upload Cargo timings
@@ -1330,8 +1326,6 @@ jobs:
if: ${{ github.event_name != 'workflow_dispatch' || inputs.release_mode == 'build_unsigned' }}
needs: tag-check
uses: ./.github/workflows/rust-release-windows.yml
with:
release-lto: ${{ contains(github.ref_name, '-alpha') && 'thin' || 'fat' }}
secrets: inherit
argument-comment-lint-release-assets:
+1 -1
View File
@@ -501,7 +501,7 @@ debug = "none"
strip = "symbols"
[profile.release]
lto = "fat"
lto = "thin"
split-debuginfo = "off"
# Because we bundle some of these executables with the TypeScript CLI, we
# remove everything to make the binary as small as possible.