link: strip the emitted program binary (-s), 6.4 MB -> 2.1 MB #39

Manually merged
hkowalski merged 5 commits from feat/039-link-strip-the-emitted-program-binary-s-6-4-mb into master 2026-02-18 15:28:50 +01:00
Owner

link: strip the emitted program binary (-s), 6.4 MB -> 2.1 MB

Along the way:

  • ckc run: report actual app runtime, not the docker round-trip
  • S2: String concatenation (host-backed ck_rt_alloc) -- greeter runs
  • M-start: per-actor arena substrate (single-actor beginning of M1)
  • P2.1: test-fn execution + non-fatal (soft) Assert

Touches 41 files: current-state.md, docs/impl/memory-model/M1-arena-substrate.md, docs/impl/runtime-testing/README.md, docs/impl/runtime/03-meta-wire.md, docs/impl/runtime/R1-executor-core.md, docs/impl/runtime/README.md and 35 more.

link: strip the emitted program binary (-s), 6.4 MB -> 2.1 MB Along the way: - ckc run: report actual app runtime, not the docker round-trip - S2: String concatenation (host-backed ck_rt_alloc) -- greeter runs - M-start: per-actor arena substrate (single-actor beginning of M1) - P2.1: test-fn execution + non-fatal (soft) Assert Touches 41 files: `current-state.md`, `docs/impl/memory-model/M1-arena-substrate.md`, `docs/impl/runtime-testing/README.md`, `docs/impl/runtime/03-meta-wire.md`, `docs/impl/runtime/R1-executor-core.md`, `docs/impl/runtime/README.md` and 35 more.
Author
Owner

Split. The decision in try_emit is a pure function now, with its own tests in src/rust/crates/ck_lower/src/codegen/assert.rs.

Split. The decision in `try_emit` is a pure function now, with its own tests in `src/rust/crates/ck_lower/src/codegen/assert.rs`.
Author
Owner

It said what I assumed. Reworded in src/rust/crates/ck_rt/src/arena.rs so it names the input that broke it, which is what the bug report will need.

It said what I assumed. Reworded in `src/rust/crates/ck_rt/src/arena.rs` so it names the input that broke it, which is what the bug report will need.
praghunathan left a comment

Yes. The commit messages carried me through all 41 files, which is not always true.

Yes. The commit messages carried me through all 41 files, which is not always true.
@ -0,0 +33,4 @@
/// `Some(result)`; otherwise `None`, so the caller falls through to its ordinary
/// call handling. Keeps the assert special-casing (and its branching) out of the
/// codegen root's `emit_effect`.
pub(super) fn try_emit(
Owner

try_emit reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?

`try_emit` reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?
@ -0,0 +157,4 @@
/// is always valid and `size` is forced `>= 1`, so the layout cannot fail.
const LAYOUT_INVARIANT: &str = "host_fallback: a (size >= 1, align = 1) layout is always valid";
let size = if n == 0 { 1 } else { n };
let layout = std::alloc::Layout::from_size_align(size, 1).expect(LAYOUT_INVARIANT);
Owner

The expect message on layout is the only thing a user sees if this fires. Does it say what they should do, or only what we assumed?

The expect message on `layout` is the only thing a user sees if this fires. Does it say what they should do, or only what we assumed?
@ -0,0 +185,4 @@
}
// SAFETY: the caller's contract (above) guarantees `ptr` is valid for `len`
// immutable bytes; a bounded, read-only slice materialization.
let bytes = unsafe { std::slice::from_raw_parts(ptr, len) };
Owner

An unsafe block around bytes. What invariant makes it sound, and where is that written down? A // SAFETY: line would save the next reader the audit.

An unsafe block around `bytes`. What invariant makes it sound, and where is that written down? A `// SAFETY:` line would save the next reader the audit.
Author
Owner

SAFETY comment added above bytes in src/rust/crates/ck_rt/src/assert.rs, and a debug assertion for the invariant, so a violation fails a test rather than a user.

SAFETY comment added above `bytes` in `src/rust/crates/ck_rt/src/assert.rs`, and a debug assertion for the invariant, so a violation fails a test rather than a user.
mdoorn approved these changes 2026-02-18 10:11:04 +01:00
mdoorn left a comment

Second read on src/rust/crates/ck_lower/src/codegen/assert.rs. Nothing to add.

Second read on `src/rust/crates/ck_lower/src/codegen/assert.rs`. Nothing to add.
The `cc` link now passes `-s`, discarding the symbol table + DWARF at
link time. Both link entry points funnel through link_executable_at, so
one flag covers host fixtures and `ckc run`. The emitted helloWorld binary
drops from 6,709,448 B (not stripped) to 2,180,576 B (stripped) -- 67% --
with `hello, world` and the actor lifecycle on the meta stream unchanged
(observability is the meta stream, not DWARF).

Remaining ~2.1 MB is static glibc + Rust std (fixed floor baseline);
current-state.md §6 tracks the deferred path (musl-static, panic=abort,
opt-level=z) as open, design-touchy debt.

Gates: cargo fmt --check clean; clippy 0/0; cargo test --workspace pass;
helloWorld runs stripped in the ckc container.
`finished execution in Nms` timed the whole `docker exec` round-trip
(process spawn, container I/O, meta readback) and mislabeled it as app
runtime -- ~27ms for a program that runs in microseconds. Now the run
path derives the app span from what the floor observed on the meta
stream (first ActorSpawned -> last ActorDespawned) and prints two
distinct lines: `app execution:` and `container round-trip:`.

Meta-wire: each record gains an 8-byte LE emit timestamp
([len][ts][body]) stamped by the floor (ck_rt::emit), best-effort (0 on
clock failure) -- the first field of the planned common `wallclock`
envelope (docs/meta-substrate.md). Host `observed_app_runtime` scans
records for the span; meta.stream is cleared before each exec so the
span covers only that run. No faked durations -- measured every run.

Gates: fmt clean; clippy 0/0; cargo test --workspace 898 passed;
ckc run helloWorld prints `hello, world` + `app execution: 0.02ms`.
"lit" + param now lowers, completing the greeter PROGRAM: `ckc run
tests/corpus/greeter` prints `Hi, world`.

Floor: new general leaf `ck_rt_alloc(n) -> *mut u8` (host std::alloc,
no free) -- the M1-sanctioned R1-R7 interim allocator that arenas
(M1/R8) replace later. One reusable primitive; Phase 2 records/collections
build on it (not a concat-specific leaf).

Codegen (new ck_lower/codegen/concat.rs): a BinOp::Add over String
operands evaluates both to (ptr,len) -- literal / String-param Ref /
nested concat, recursively -- ck_rt_alloc(l+r), then libc memcpy x2 into
the buffer, yielding (dst, l+r). Integer + stays iadd (unchanged, only
reachable on the ->Int path). emit_arg moved into concat.rs; codegen.rs
769 lines (under the 809 cap).

Out of scope (Phase 2): the greeter test fn (mocked Log, records,
collections, Assert) is not run -- run path does not lower test fns.
greeter/trap.md kept (empty block, updated note) for harness reconciliation.

Gates: fmt clean; clippy 0/0; cargo test --workspace 901 passed;
ckc run greeter prints `Hi, world` with the clean Main lifecycle.
The running actor gets a real bump arena; ck_rt_alloc's host malloc is
retired for the actor path. Landed early (ahead of R8) per owner directive
-- R8 extends it to multi-actor + send; this is the substrate view.

Honors arenas.md: one arena per actor, hard boundary, whole-arena reclaim
on actor death (one drop, no per-object free). BumpArena = chained
Box<[u8]> blocks (pointers stable across growth) + cursor + high-water,
in a thread-local CURRENT_ARENA (floor runs one actor per carrier), so
ck_rt_alloc's C-ABI is unchanged -- codegen (S2 concat) untouched. bare
fn main still falls back to host alloc (documented, later slice).

Observability: two new closed MetaEvent variants ArenaHighWater{actor,
bytes} + ArenaReclaimed{actor} (wire tags 8/9, host reader decodes).
emit at despawn: high-water read while arena live, then reclaim (single
drop), then ArenaReclaimed. No faked values.

Deferred (cited): compiler-computed arena SIZING from bounded types (full
M1), arena-relative handles + replay (M7/R12), state/stack split + call-
slots (M2), OOM upcall (M6/R11), capability move rules + send (M4/R8).

Gate M1's own DoD: arena_reclaim_run runs greeter, asserts ArenaHighWater
> 0 (bytes=9) and ArenaReclaimed fires -- no leak across spawn/death.

Gates: fmt clean; clippy 0/0; cargo test --workspace 905 passed;
greeter -> Hi, world, helloWorld -> hello, world, both clean lifecycle.
New `ckc test <dir>`: discovers every top-level `test fn` in app modules,
lowers each body (reusing S1 user-fn machinery), emits one container
binary whose main runs `ck_rt_run_test` per test and returns the failed
count as exit code.

Floor (new ck_rt/src/assert.rs, C-ABI unsafe boundary): ck_rt_run_test
emits TestStarted, installs the actor arena, runs the body, emits
TestPassed / TestFailed{failed}, reclaims. ck_rt_assert_check(passed,
pred, hint, site) emits AssertEvaluated{kind: Soft, passed, ...} with the
REAL evaluated boolean, records a FailedAssert in a thread-local, and
RETURNS -- a failed assert never abandons the body (assert = non-fatal
meta observation, the load-bearing lock). No new MetaEvent variant needed
(the assert/test variants already existed in the closed sum + wire codec).

Codegen (new codegen/assert.rs): Assert::check/equal lower; equal desugars
to check(a == b, hint); Int == -> icmp eq; Assert::* recognized by its
ambient built-in OpId and intercepted before provider dispatch.

Harness (ck_driver/src/harness.rs): reconciles the meta stream into a
per-test pass/fail report; ckc test exits non-zero on any failure.

Gate (both directions): tests/corpus/soft_asserts + Docker-gated
soft_assert_run -- Assert::equal(1,1) passes, Assert::equal(1,2) FAILS
but the test runs to completion (TestFailed proves non-fatal). soft_asserts
is front-end-clean (no trap.md) and in the runtime-coverage allow-list.

Out (cited): Assert::guard (fatal), equal operand-diff payload, records/
variants/collections/String==/mocked-effects, per-test user-fn dedup
(latent, documented). Files split to stay under LoC caps (codegen.rs,
compile.rs) -- caps not raised.

Gates: fmt clean; clippy 0/0; cargo test --workspace 911 passed;
greeter/helloWorld unchanged; cka-clean new files.
hkowalski manually merged commit 3d5e5d1768 into master 2026-02-18 15:28:50 +01:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
northgale/cklang-bootstrap!39
No description provided.