Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions .github/workflows/binaries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ jobs:
binaries:
name: ${{ matrix.target }}
runs-on: ${{ matrix.os }}
# A link that swaps runs for hours, not minutes: v0.1.0's macOS jobs took
# 4h11m and 4h37m under fat LTO. Fail loudly instead of holding a slot.
timeout-minutes: 90
permissions:
contents: write # upload release assets
strategy:
Expand Down Expand Up @@ -92,14 +95,14 @@ jobs:
- name: musl linker (Linux)
if: steps.published.outputs.present != 'true' && contains(matrix.target, 'musl')
run: sudo apt-get update -q && sudo apt-get install -y -q musl-tools
# One binary per invocation, on purpose. The release profile is fat LTO
# with a single codegen unit, so linking a binary is a whole-program LLVM
# pass over Arrow, DataFusion and Ballista. Cargo schedules the three
# binaries' links in parallel, and three of those do not fit in a 16 GB
# Linux runner that has no swap: the VM is torn down and the job ends
# with "The runner has received a shutdown signal", exit 143, at exactly
# this point — v0.1.0 (both musl targets) and v0.1.2 (aarch64 musl).
# macOS survives only by swapping, which is where its hours go. The
# One binary per invocation, on purpose. Linking a binary is an LTO pass
# over Arrow, DataFusion and Ballista that peaks at 7.4 GB under the thin
# profile (13.6 GB when it was fat), and Cargo schedules the three
# binaries' links in parallel. Three at once do not fit in a 16 GB Linux
# runner that has no swap: the VM is torn down and the job ends with
# "The runner has received a shutdown signal", exit 143, at exactly this
# point — v0.1.0 (both musl targets) and v0.1.2 (aarch64 musl). macOS
# survives only by swapping, which is where its hours went. The
# dependencies still compile in parallel during the first invocation;
# the second and third only link.
- name: Build
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ versions (0.x) may contain breaking changes; they are always listed under a

## [Unreleased]

### Changed

- **Release profile: thin LTO instead of fat.** Fat LTO with one codegen unit
made each binary's link a 13.6 GB whole-program pass; three in parallel
killed the 16 GB Linux release runners and left the 7 GB macOS runners
swapping for four hours per target. Thin LTO with one codegen unit peaks
at 7.4 GB and links in half the time; binaries grow about 9% (`oxide`
68 → 74 MB) and a 10M-row aggregate ran in the same 40 ms under both.
`binaries.yml` also gains a 90-minute timeout so a swapping link fails
loudly instead of holding a macOS slot.

### Fixed

- **Linux release binaries build again.** `binaries.yml` links the three
Expand Down
10 changes: 9 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,15 @@ dbg_macro = "deny"

[profile.release]
opt-level = 3
lto = "fat"
# Thin, not fat. With fat LTO each binary's link was a 13.6 GB whole-program
# pass (measured 2026-09-07, Apple Silicon): Cargo links the three binaries
# in parallel, which killed the 16 GB Linux release runners (exit 143 on
# v0.1.0 and v0.1.2) and left the 7 GB macOS runners swapping for four hours
# per target. Thin LTO with one codegen unit peaks at 7.4 GB and links in
# half the time for 9% more binary; a 10M-row aggregate ran in the same
# 40 ms under both. Sixteen codegen units would peak at 2.6 GB but cost 75%
# in size, so the single unit stays.
lto = "thin"
codegen-units = 1
strip = "symbols"
# Deliberately no `panic = "abort"`: unwinding must stay sound across PyO3/FFI
Expand Down
2 changes: 1 addition & 1 deletion docs/SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ rand = "0.10"

[profile.release]
opt-level = 3
lto = "fat"
lto = "thin" # fat LTO's 13.6 GB links did not fit the release runners; see Cargo.toml
codegen-units = 1
strip = "symbols"
# Deliberately no `panic = "abort"`: unwinding must stay sound across PyO3/FFI
Expand Down
2 changes: 1 addition & 1 deletion docs/decisions/ADR-0008-no-panic-abort.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The draft set `panic = "abort"` for release. `oxidelake-api` may expose PyO3 bin

## Decision

Keep the default `panic = "unwind"`. The release profile is `opt-level = 3`, `lto = "fat"`, `codegen-units = 1`, `strip = "symbols"`.
Keep the default `panic = "unwind"`. The release profile is `opt-level = 3`, `lto = "thin"` (fat until 0.1.3; its links did not fit the release runners), `codegen-units = 1`, `strip = "symbols"`.

## Consequences

Expand Down
Loading