feat(parallel): windows and Window #248
Loading…
Reference in a new issue
No description provided.
Delete branch "loop/4-parallel-windows"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #4
CONCURRENCY slice F, gap 6:
windowsandWindowinstd/parallel, over a new fork-join region in the runtime.What lands
runtime/task.c,torb_task.h): a region over the storage of one list. It is a slot of a table (chunks of 64 slots, up to 1024 chunks, allocated once), named by a number that holds the slot and a generation, so a helper task that starts after the region ended claims nothing and never touches freed memory.index * length / count, computed in 128 bits.torb_list_make_unique). That is the one copy a shared list takes, made on the caller's worker before any window exists, so it is not a crossing copy.Workers.copies(): Int(std/task) reads the pool's copy counter (gap 12), which nothing could read before.std/parallel:public type Window<Item: Plain> with Length, MutableIndex<Int, Item>:length,get,at,set,keys. It has no add/insert/removeAt and noClose, and its fields are private, so only the region builds one.public fn windows<Item: Plain>(var items: ArrayList<Item>, count: Int, body: (var window: Window<Item>) => Void): imported by name, not via the prelude.count < 1panics with a message.min(count, Workers.count()) - 1helper tasks an idle worker may take. With one worker, or with the others busy, the caller runs every window, so a region never waits on the pool.Plainfields (counted, gap 4) confines its region to the caller's worker.ScopedBinding.Window. Every binding whose type isWindow(parameters of closures and functions, receivers excepted) is scoped. It reaches the body and the functions the body hands it to. It is refused when stored in a field, returned, bound to another name, or captured by a task or an escaping closure. There is one probe per case incompiler/tests/windows.test.trb.Tests
tests/conformance/parallel-windows.trb(.workers=all, also run with 1) is the gate: 1MFloats scaled withwindows(values, 64), compared with the sequential loop, withWorkers.copies()delta 0 and the automatic leak gate.parallel-windows-borders.trb(.workers=2) covers:parallel-windows-count.trbcovers thecount < 1panic, and shows that a write through a window is visible to the caller.parallel-windows-bounds.trbcovers the out-of-bounds panic of a window.runtime/tests/pool_test.chas three new tests:Docs
docs/standard-library/parallel.mdgets a section onwindowsandWindow, coveringPlain, the borders, where windows run, and the escape rule.task.mddocumentsWorkers.copies.windows, as built".skills/is regenerated.Deviations and open points
Windowis an ordinarytype, not ashared type. The issue asks for bothshared typeandLength+MutableIndex, but a shared type implements only shared traits (trait rule 17), anda[i] = vneedsMutableIndex. TurningLength/MutableIndexinto shared traits would change every implementer, so I kept the traits and droppedshared. The window holds only a region number, a first position and a length; the escape rule of the checker, not an identity, keeps it inside the body. A known gap remains: coercing a window to a trait value (MutableIndex<Int, Float>as a parameter type) loses the marker, so a function taking the trait could keep it. The issue's probes (stored, returned, captured by spawn) are all refused.var ArrayList, not aListorBuffer: the region lends out storage, which a trait-typedListcannot. This widens toBuffer<Item>with #54 (loop decision).A panic in a body on a helper worker: inside a recovering harness (
torb test), the join could wait for a window that never finishes. A panic in a program ends the process, so this only matters under recovery. The issue does not ask for it; noting it for review.The natives are declared in
std/paralleland lowered by the C back end. The compiler itself does not use them, so the published seed needs no refresh. If CI shows otherwise, I will split per the two-commit rule.01eb114f083bfd907433Windowandwindows(CONCURRENCY slice F, gap 6) #4Checklist (head
a71d6f3, CI green): tests ok (conformance, checker probes, pool_test.c), correctness of the region ok (generation check on claim, join waits for claimed windows, 128-bit borders), scope ok (Closes #4, deviations stated), security ok, docs ok (parallel.md, task.md, CONCURRENCY.md, skills regenerated), no workflow changes.Findings
.gitattributessays "The few files that are CRLF stay so" (* -text, bytes are kept as committed). Base has CRLF incompiler/src/semantics/checker/closure.trb(524 lines),context.trb(2066) andwellknown.trb(303); at the head all three are LF. That shows as +527/-524, +2068/-2066 and +309/-303 in the diff although the real changes are 3, 2 and 6 lines (closure.trb:use markWindowBindings+ the call at l. 261; context.trb:case Window; wellknown.trb: thewindowfield + its init). It is not part of the task, makes the diff unreviewable, and ruins blame on those files. Fix: restore CRLF in these three files (e.g.unix2dos, or re-apply the 11 lines with the line endings kept) and verify withgit diff --statthat each file shows only its few lines. Nothing else in the PR needs to change.Non-blocking
torb_region_get/torb_region_setdo not check the generation of the handle. A window that escapes through the known trait-coercion gap (disclosed in the PR body) would, after the region ended, read a NULLdataor, once the slot is reused, write into another region's list. A generation check in get/set (panic instead of undefined behaviour) would close the gap cheaply until the checker handles the coercion; worth a follow-up issue.Windowandwindows(CONCURRENCY slice F, gap 6) #4Reviewed
a71d6f3. CI is green for this head; the runtime region (runtime/task.c),std/parallel, the checker rule and the tests look correct and match the PR body. One blocker, found by diffing the three checker files with line endings stripped:compiler/src/semantics/checker/closure.trb,context.trbandwellknown.trbare CRLF onmain(every line ends in\r\n) and LF at this head. The real changes are 3, 2 and 6 lines, but the diff shows ~2,900 changed lines (closure +527/-524, context +2068/-2066, wellknown +309/-303)..gitattributessays the few CRLF files "stay so" (* -text, bytes as committed). Merged as a rebase, this buries the actual change, wrecksgit blamefor these files and goes beyond the scope of #4. Please restore CRLF in those three files (e.g.unix2dos), so the diff shows only theScopedBinding.Windowcase, themarkWindowBindingscall and thewindowwell-known entry, and push. Nothing else needs to change.Non-blocking (suggestions):
runtime/task.chas 64 slots per chunk and up to 1024 chunks (TORB_REGION_CHUNK/TORB_REGION_CHUNKS). Align the wording.Checked ok: tests (conformance, borders, count, bounds,
pool_test.c, checker probes), docs/skills/CONCURRENCY.md, no secrets or new permissions,Windowdeviation fromshared typeis argued on merit and accepted.Fixed in
61d7777: the three checker files are CRLF again;git diff --stat origin/mainshows 3 / 2 / 6 added lines and nothing removed. The two non-blocking points are tracked in a follow-up issue. Re-requested review.Addressed in
61d7777: CRLF restored inclosure.trb,context.trb,wellknown.trb; the diff now shows only the 3, 2 and 6 real lines. PR body wording for the region chunks aligned withruntime/task.c(64 slots per chunk, up to 1024 chunks). The non-blocking follow-ups (generation check intorb_region_get/set, a panic in a body under a recovering harness) go to a follow-up issue.61d7777fbc0c6dad0969New head: this review was requested for
61d7777, but the PR is now at0c6dad0(CI for61d7777was cancelled, CI for0c6dad0is pending). No review posted; the review will run again for the new head once CI has finished.0c6dad09692faa85c06cCRLF restored in
closure.trb,context.trbandwellknown.trb(amended into the commit that introduced the LF rewrite, so no commit in the PR contains it; force-pushed, head2faa85c0).git diff --stat origin/main...HEADnow shows:CI green on the new head (ci run 522, pdisc run 523). The earlier run 518 failed once in the gates on
test_io_a_cancelled_wait_releases_its_registration(runtime io leak, unrelated to line endings; identical tree passed before). Non-blocking findings stay in #253.Re-review of head
2faa85c(CI green).Earlier blocker resolved:
closure.trb,context.trbandwellknown.trbare CRLF again (verified bytes at the head); the diff shows only the 3, 2 and 6 real lines, nothing removed. Changes since my review:Windowis an ordinary type with a stated rationale, doc examples aligned to the doc comment rules, and the scale test now compares item by item. Region runtime,std/parallel, checker rule, tests (conformance, borders, count, bounds,pool_test.c, checker probes) and docs/skills are unchanged in substance and still ok. Scope is #4, no secrets, no workflow changes.Non-blocking:
torb_region_get/torb_region_setdo not check the handle generation; a generation check (panic instead of UB) would cover the disclosed trait-coercion gap.values == sequentialon twoArrayList<Float>is an internal error of the native back end (see the test comment): worth its own issue.The first two are already tracked in Orion's follow-up issue; please add the third.
Windowandwindows(CONCURRENCY slice F, gap 6) #4windowsbody on a helper worker must not hang the join #258