Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
7e1dc92
Design: -mm=own compiles the ray tracer
ASDAlexander77 Oct 21, 2026
ce79ca0
Plan: -mm=own compiles the ray tracer
ASDAlexander77 Oct 21, 2026
313c309
own-raytrace T1: -mm=own: a global never reassigned is immortal
ASDAlexander77 Oct 21, 2026
510ba99
own-raytrace T1: no call's result makes a global immortal
ASDAlexander77 Oct 21, 2026
d3c303e
own-raytrace T2: -mm=own: an object literal moves into new Shared in …
ASDAlexander77 Oct 21, 2026
cfb924d
own-raytrace T3: -mm=own: an owning object literal moves anywhere a f…
ASDAlexander77 Oct 21, 2026
8a26bc6
own-raytrace T3: spec 27, owning literals moved anywhere
ASDAlexander77 Oct 21, 2026
7212994
own-raytrace T3: -mm=own: a method reached through an interface may n…
ASDAlexander77 Oct 21, 2026
e50cfc1
own-raytrace T3: -mm=own: a method reached through an interface may n…
ASDAlexander77 Oct 21, 2026
fe25ec1
own-raytrace T4: -mm=own: a field read through an interface is a plac…
ASDAlexander77 Oct 22, 2026
c939635
own-raytrace T4: spec 28, a field read through an interface
ASDAlexander77 Oct 22, 2026
1cd5e8d
own-raytrace T5: -mm=own: a read after a move goes through the new owner
ASDAlexander77 Oct 22, 2026
4d0bc60
own-raytrace T5: spec 29, a read after a move
ASDAlexander77 Oct 22, 2026
a024d51
own-raytrace T5: spec 29, teeth as measured; a store through a read
ASDAlexander77 Oct 22, 2026
aef265a
own-raytrace T5: -mm=own: an assignment to a global ends a borrow of …
ASDAlexander77 Oct 22, 2026
1edab59
own-raytrace T5b: -mm=own: a move on some paths only releases on the …
ASDAlexander77 Oct 22, 2026
6d57326
own-raytrace T5b: spec 30, a move on some paths only
ASDAlexander77 Oct 22, 2026
163c6f7
own-raytrace T5b: -mm=own: nothing read out of a released value is us…
ASDAlexander77 Oct 22, 2026
62077be
own-raytrace T5b: spec 30, uses past the join and the teeth that show…
ASDAlexander77 Oct 22, 2026
b129acc
own-raytrace T6: -mm=own: a call through a closed interface gets its …
ASDAlexander77 Oct 22, 2026
15e9534
own-raytrace T6: -mm=own: a call through a closed interface's functio…
ASDAlexander77 Oct 22, 2026
f487ef4
own-raytrace T6: spec 31, facts through a closed interface
ASDAlexander77 Oct 22, 2026
8a94fc2
own-raytrace T6: spec 31, public members and namespace exports
ASDAlexander77 Oct 22, 2026
41dc9d5
own-raytrace T6: -mm=own: closed interfaces after review - reinterpre…
ASDAlexander77 Oct 22, 2026
1a8ad11
own-raytrace T6: spec 31 after review, and a public method reachable …
ASDAlexander77 Oct 22, 2026
608d776
own-raytrace T6: -mm=own: closed interfaces, re-review 1 - member typ…
ASDAlexander77 Oct 22, 2026
cbf640b
own-raytrace T6: -mm=own: closed interfaces, re-review 2 - class-made…
ASDAlexander77 Oct 22, 2026
cc17980
own-raytrace T6: -mm=own: closed interfaces, re-review 3 - C callback…
ASDAlexander77 Oct 22, 2026
c18c14a
own-raytrace T6: -mm=own: closed interfaces, re-review 4 - C callback…
ASDAlexander77 Oct 22, 2026
eac4530
own-raytrace T6: -mm=own: closed interfaces, final patch - fields int…
ASDAlexander77 Oct 22, 2026
199d742
own-raytrace T7: -mm=own: a borrowing record's box carries its own re…
ASDAlexander77 Oct 22, 2026
08327da
own-raytrace T7: -mm=own: result facts are sets, and a returned borro…
ASDAlexander77 Oct 22, 2026
d72c4f3
own-raytrace T7: -mm=own: borrowing records, bounded where they are m…
ASDAlexander77 Oct 22, 2026
9c75584
own-raytrace T7: borrowing record negatives that read freed memory wi…
ASDAlexander77 Oct 22, 2026
237424d
own-raytrace T7: -mm=own: a borrow of a borrowing record is a use of …
ASDAlexander77 Oct 22, 2026
337e8e5
own-raytrace T7: spec 32, borrowing records
ASDAlexander77 Oct 22, 2026
d730a63
own-raytrace T8: -mm=own: reduce takes its accumulator, and a paramet…
ASDAlexander77 Oct 22, 2026
26fe86c
own-raytrace T8: spec 33, reduce takes its accumulator
ASDAlexander77 Oct 22, 2026
767500f
own-raytrace T8: own_reduce runs a promoted callback, called directly…
ASDAlexander77 Oct 22, 2026
6b98411
own-raytrace T8: say which kept parameters are released where they ar…
ASDAlexander77 Oct 22, 2026
4579830
own-raytrace T8: -mm=own: a borrow read out of a kept parameter is bo…
ASDAlexander77 Oct 22, 2026
afb37dd
own-raytrace T8: -mm=own: a call that keeps an argument and is given …
ASDAlexander77 Oct 22, 2026
0bf9ed7
own-raytrace T8: -mm=own: one value at two kept positions of a call i…
ASDAlexander77 Oct 22, 2026
6a09119
own-raytrace T8: -mm=own: a slot assigned between a move's read and t…
ASDAlexander77 Oct 22, 2026
ca14abf
own-raytrace T8: -mm=own: a self-assignment is the move's destination…
ASDAlexander77 Oct 22, 2026
6dbe224
own-raytrace T8: -mm=own: a slot assigned on some path between a move…
ASDAlexander77 Oct 22, 2026
db94c3c
own-raytrace: merge origin/main (benchmark #634, rc/own fixes #635-#645)
ASDAlexander77 Oct 22, 2026
004c3dc
own-raytrace merge: a global initializer's call borrows when its fact…
ASDAlexander77 Oct 22, 2026
c607335
own-raytrace merge: a global may be given an immortal global's value
ASDAlexander77 Oct 22, 2026
d691710
own-raytrace merge: negatives that main's own rules now reject first
ASDAlexander77 Oct 22, 2026
7484488
own-raytrace merge: an immortal static may be lent to a call that may…
ASDAlexander77 Oct 22, 2026
765b593
own-raytrace T9: a direct call's result is not a use of a borrow give…
ASDAlexander77 Oct 23, 2026
2dfc296
own-raytrace T9: the ray tracer benchmark under own
ASDAlexander77 Oct 23, 2026
50c7112
own-raytrace T1: a global's one store that may run again leaves it mo…
ASDAlexander77 Oct 23, 2026
0fd5b9b
own-raytrace merge: negatives for #639's shapes and the region-call r…
ASDAlexander77 Oct 23, 2026
f7846c9
own-raytrace T9: one helper for a call whose result is the caller's own
ASDAlexander77 Oct 23, 2026
e33af8f
own-raytrace T1: a read of a mortal global ends at its assignment
ASDAlexander77 Oct 23, 2026
ce3371b
own-raytrace final: write-guard negatives, shared helpers, spec fixes
ASDAlexander77 Oct 23, 2026
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
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,8 @@ what to do about it.
### Performance

The ray tracer benchmark in [tslang/benchmarks/raytrace](tslang/benchmarks/raytrace/README.md)
(`raytrace.ts` at 512x512, median of 7 runs, 2026-10-21) against Rust and C++ ports of the same
(`raytrace.ts` at 512x512, median of 7 runs; the `-mm=own` row measured 2026-10-23, the other rows
2026-10-21) against Rust and C++ ports of the same
code, each written twice: with plain value vectors and colors, and with every object
reference-counted on the heap the way tslang allocates them:

Expand All @@ -768,7 +769,7 @@ reference-counted on the heap the way tslang allocates them:
| `-mm=gc` | 1298 ms | 6 MB | 26x slower |
| `-mm=rc` | 599 ms | 4 MB | 12x slower |
| `-mm=none` | 703 ms | 845 MB | 14x slower |
| `-mm=own` | does not compile yet | | |
| `-mm=own` (2026-10-23) | 628 ms | 4.5 MB | 12x slower |
| C++, values (clang / MSVC) | 51 / 69 ms | | |
| Rust, values (`Copy` vectors and colors) | 55 ms | 4 MB | 1.1x slower |
| Rust, every object in an `Rc` | 492 ms | 4 MB | 9.7x slower |
Expand All @@ -779,6 +780,10 @@ Rust that allocates the same way is only 1.2x faster than `-mm=rc`, and C++ with
(atomic counts) is 1.4x slower than it. `-mm=none` is slower than
`-mm=rc` because it never frees and keeps touching fresh pages. Stack promotion makes no measurable
difference here yet: the hot allocations are returned from functions or captured by closures.
`-mm=own` builds the benchmark's copy with two source edits (the shared surfaces are `Shared<T>`
handles, and one method returns a fresh vector instead of its own field). It runs as fast as
`-mm=rc` in as little memory, counting only those two handles (its row measured 2026-10-23, when
`-mm=rc` took 638 ms and peaked at 4.5 MB).

### `-mm=own`

Expand Down
20 changes: 15 additions & 5 deletions tslang/benchmarks/raytrace/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Ray tracer: memory models vs Rust and C++

`rtbench.ts` is `test/tester/tests/raytrace.ts` at 512x512 with a pixel checksum (see its header).
`rtbench_own.ts` is the same program for `-mm=own`, with two source edits: the surfaces, which every
thing shares, are `Shared<Surface>` handles, and `Plane.normal` returns a fresh vector instead of
its own field.
`rust/` and `cpp/` each hold two ports of the same algorithm:

- `rust/src/bin/idiomatic.rs`, `cpp/idiomatic.cpp`: `Vector`/`Color` are plain values, things are
Expand All @@ -19,11 +22,11 @@ pwsh tslang/benchmarks/raytrace/bench.ps1
```

- tslang: `--emit=exe --opt --opt_level=3 --no-default-lib --mm=<model>` (`--no-default-lib`
because the file declares its own `sqrt`/`floor`/`pow`/`fabs`)
because the file declares its own `sqrt`/`floor`/`pow`/`fabs`); `-mm=own` builds `rtbench_own.ts`
- Rust: `opt-level=3`, `lto="fat"`, `codegen-units=1`, `panic="abort"`
- C++: `clang++ -std=c++20 -O3`, and `cl /std:c++20 /O2 /EHsc /MT`

## Results 2026-10-21
## Results 2026-10-21 (own rows 2026-10-23)

main 49b5f6bb, Release, Windows 11 x64; Rust 1.99.0, clang 21.1.4, MSVC from Visual Studio 18;
median of 7 runs after a warm-up. Every build prints the same checksum.
Expand All @@ -36,7 +39,8 @@ median of 7 runs after a warm-up. Every build prints the same checksum.
| tslang rc, `--no-stack-promotion` | 600 ms | | |
| tslang none | 703 ms | 845 MB | 14x |
| tslang none, `--no-stack-promotion` | 727 ms | | |
| tslang own | does not compile | | |
| tslang own (2026-10-23) | 628 ms | 4.5 MB | 12x |
| tslang own, `--no-stack-promotion` (2026-10-23) | 627 ms | | |
| Rust idiomatic | 55 ms | 4 MB | 1.1x |
| Rust Rc-boxed | 492 ms | 4 MB | 9.7x |
| C++ idiomatic (clang) | 51 ms | | 1x |
Expand All @@ -52,5 +56,11 @@ median of 7 runs after a warm-up. Every build prints the same checksum.
under rc keeps every hot-path allocation on the heap: `Vector.*`/`Color.*` results are
"returned", the `Ray`/`Intersection` literals are "converted" (to the interface) or
"recursive", and the `addLight`/`getPoint` closures are "counted-capture".
- `-mm=own` reports about 44 errors: the program shares the `Surfaces` globals, keeps owned values
in object literals, and aliases `Color.black` from two statics.
- The own rows were measured on 2026-10-23 (branch own-raytrace, the same machine, two runs of
`bench.ps1`, median of 7 each; both gave 627.5 ms), the rest of the table on 2026-10-21. In the
same session rc took 638-640 ms and peaked at 4.5 MB as well, so own runs as fast as rc and frees
as promptly, with no counts: only the two `Shared<Surface>` handles count. Peak working set is the
process's `PeakWorkingSet64`, polled while it runs.
- `-mm=own` needs `rtbench_own.ts`'s two edits: the surfaces are shared by every thing, and
`Plane.normal` returned a borrow of its own field where `Sphere.normal` returns a fresh vector, so
a caller through the `Thing` interface could not know whether it owns the result.
9 changes: 5 additions & 4 deletions tslang/benchmarks/raytrace/bench.ps1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Builds rtbench.ts under every memory model (with and without stack promotion) and the two Rust
# ports, checks that they all print the same checksum, then times each one: a warm-up run and
# $Runs timed runs, reporting min/median/max wall time.
# Builds rtbench.ts under every memory model (with and without stack promotion; -mm=own builds its
# copy rtbench_own.ts) and the Rust and C++ ports, checks that they all print the same checksum,
# then times each one: a warm-up run and $Runs timed runs, reporting min/median/max wall time.
#
# pwsh tslang/benchmarks/raytrace/bench.ps1 [-Tslang <path to tslang.exe>] [-Runs 7]
param(
Expand All @@ -19,7 +19,8 @@ foreach ($mm in "gc", "rc", "none", "own") {
$exe = Join-Path $out ("rtb_$mm" + $(if ($sp) { "_nsp" } else { "" }) + ".exe")
$flags = @("--emit=exe", "--opt", "--opt_level=3", "--no-default-lib", "--mm=$mm")
if ($sp) { $flags += "--no-stack-promotion" }
& $Tslang @flags "$PSScriptRoot\rtbench.ts" -o $exe 2>&1 | Out-Null
$src = if ($mm -eq "own") { "$PSScriptRoot\rtbench_own.ts" } else { "$PSScriptRoot\rtbench.ts" }
& $Tslang @flags $src -o $exe 2>&1 | Out-Null
if ($LASTEXITCODE -ne 0) { "{0,-22} does not compile (exit {1})" -f $name, $LASTEXITCODE; continue }
$bins += @{ n = $name; p = $exe }
}
Expand Down
Loading
Loading