Skip to content

osbench: persist and the disk's cached rows run on ToyOS's DATA, the bench's NVMe - #1097

Merged
Japabu merged 7 commits into
mainfrom
bench-disk
Oct 28, 2026
Merged

Japabu merged 7 commits into
mainfrom
bench-disk

Conversation

@Japabu

@Japabu Japabu commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

ToyOS's persistent rows run on the bench's NVMe. #1079 staged this patch until ToyOS could designate its own DATA, which #1085 brought. Rebased on #1095 (370d7d9f6), so ToyOS boots off the same NVMe.

Problem and result

In #1079, persist compared ToyOS's boot stick with Linux's NVMe and read "the media differ". Now ToyOS's persistent filesystem is DATA's /home: the bench's TOYOS-DATA partition, through the DATA file server and the NVMe driver, medium nvme. Linux's is its home, ext4 on the same NVMe namespace. persist runs the durable rows and then files' operations as fs.disk.*, on both systems, so those rows can resolve. This is the disk and filesystem scoreboard toward Linux parity.

Changes

  • osbench:

    • ToyOS's persistent_dir is /home with medium nvme, a constant that the metal row alone makes true;
    • storage runs durable rows, then files::suite(disk);
    • ToyOS's files keeps /tmp;
    • on Linux, fs.disk.mount carries the superblock options, and served_by names the device's write-cache mode;
    • the compare's SETUP reads fs.disk.served_by.
  • The osbench metal row judges DATA with hostdisk::left_alone and the loader's volumes:

    • Mounted passes;
    • Formatted is the format boot, no measured run, with its duration stated;
    • Foreign or memory is refused.
  • README: the disk rows' rules, as procedure:

    • one NVMe, and the compare refuses differing media;
    • each system's own filesystem;
    • one durability, which each side's recorded fields show;
    • one procedure for the cache: each row reads files it wrote in its run, no cache is dropped, and ToyOS's 32 MiB and 2 s write-back is part of what is measured.

    It also says that ToyOS's log volume shares the NVMe.

  • Issues: each disk row ToyOS loses, with its evidence:

    • a-clean-fsync-on-data-writes-the-superblock-and-flushes-the-disk;
    • a-sequential-read-of-a-file-as-large-as-datas-clean-cache-reads-the-disk, whose host probe confirms the cause;
    • a-file-server-request-costs-three-to-twelve-times-a-kernel-file-call;
    • toyos-durable-writes-on-the-t14s-nvme-run-six-times-slower-in-some-boots;
    • a-created-fsynced-and-unlinked-file-costs-toyos-more-than-linux.

    The comparison record and the 64 MiB record are updated.

nvme_leaves_the_benchs_disk_alone's designated premise came with #1085, so it is not in this PR.

What the landing head's validation shows (069cbbeb8)

One ToyOS boot and two Linux runs per bench. Each was judged PASS, exit 0, from a tree pinned at 069cbbeb8 (r4). So no row resolves yet; the scoreboard's further pairs are where these become verdicts.

row T14: ToyOS vs Linux AMD: ToyOS vs Linux reading
persist.fsync_clean 0.46 ms vs 23 µs 1.26 ms vs 64–66 µs ToyOS's. A clean fsync syncs the whole volume, and Mounted::sync writes the superblock, so it costs a block write and a Flush. Linux's clean fsync takes tens of µs.
persist.write_4k_fsync 1.10 vs 1.01–1.04 ms 2.60 vs 2.99–3.58 ms About parity: a durable write costs a Flush either way. The T14 ran six times slower in 2 of 5 boots, and partway through a third, with no storage change between; that is recorded as unexplained.
persist.append_4k_fsync 1.01 vs 0.91–1.20 ms 2.93 vs 3.30–3.78 ms About parity, and ToyOS's lower on the AMD.
persist.create_fsync_unlink 1.17 vs 0.95–0.97 ms 3.53 vs 3.26–3.28 ms ToyOS 8–22% dearer; filed, not yet attributed.
persist.seq_write_fsync 347 vs 527–585 MB/s 298 vs 544–548 MB/s ToyOS's: mostly the server's copy, plus its flushes.
fs.disk.read_4k_at and the other cached ops 18.2 vs 0.72–0.74 µs 20.5 vs 1.46–1.47 µs ToyOS's: the file server's round trip, 3 to 12 times ToyOS's own kernel /tmp.
fs.disk.seq_read.4096 431 vs 7,760–7,780 MB/s 151 vs 5,084–5,089 MB/s ToyOS's: its cache. FIFO eviction of a file just over CLEAN_LIMIT; a host probe shows every pass missing.

Setup, and why it explains none of these:

  • Linux's clocksource was tsc in every landing-head run.
  • The two systems write different regions of one NVMe.
  • Their free space differs, which would favour ToyOS's fresh volume.
  • ToyOS's log writes share the device; every boot's persist completed.

Checks

Evidence: index.

  • cargo run -- --ci host at b4121ccc0: exit 0, 105 steps green. Every commit since (069cbbeb8 to the head) changes only issue records.
  • The osbench row at b4121ccc0:
  • Metal at the landing head, 069cbbeb8: run on both benches, Linux, ToyOS, Linux, and the judge passed on each, exit 0 (r4). The c8f3fbfb0 runs passed too (r2, r3).
  • The cache probe: its whole patch is republished as the probe that ran (r3, with a correction in the index).
  • The Linux half's sha256 is 98d8b7f2…f796; both musl targets check.

Risks

  • ToyOS is at or near Linux on the durable writes (write_4k_fsync, append_4k_fsync) on both benches, and loses every other disk row. Each loss is filed; this PR measures them and doesn't fix them.

🤖 Generated with Claude Code

Japabu added a commit that referenced this pull request Oct 28, 2026
#1097's AMD validation reads persist.fsync_clean at 1.23 ms under ToyOS
against 57-70 us under Linux on the same NVMe. Mounted::sync writes the
superblock on every commit, so the cache owes a Flush even where nothing
changed. #1067's handoff named this open and unfiled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Japabu

Japabu commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

Review of #1097 at c8f3fbf

The branch has since moved to 8267716, which adds one issue record. I note it at the end.

Architecture

The design fits. A ToyOS program cannot ask what holds /home, so sys::persistent_dir states nvme as a constant, and the osbench metal row is the gate that makes the constant true. That is the smallest honest arrangement, and sys/toyos.rs says so. Moving fs.disk.* into persist and deleting files::targets also removes the only ToyOS-only target. The procedure is fair: both systems use one device, one row order, each its own filesystem, and every file is written in its run. Net change is +125/−53. Most of the growth is the judge (about 45 lines in tests/toyos.rs) and the README section.

Several things the README states as rules are false or unsupported. That includes two of its four fairness claims: durability and cache state. One of them is contradicted by the PR's own AMD validation.

Findings

BLOCKER tests/guest/osbench/README.md:160-161 and src/sys/linux.rs:509: the README says a nobarrier mount would show in fs.disk.mount. It would not.

  • mount_of reads mountinfo's per-mount options (field 6) and drops the per-superblock options after - (field 11). ext4's barrier/nobarrier is a superblock option, so it can only appear in field 11. The AMD run confirms this: it recorded fs.disk.mount=ext4_rw,relatime, and fs.mem.mount shows no tmpfs size=.
  • Consequence: the README's evidence for Linux's side of the one-durability rule cannot detect the setting it claims to detect.
  • Fix: put the super options into mount_options; mount_of already splits that side of the line. Or delete the claim.

BLOCKER README.md:165-167 and src/files.rs:3-4: "fs.disk.* are cached reads on both, and no row reads the disk cold" and "on the disk these are the cached path" are false for ToyOS.

  • Writes. DATA's cache flushes, including an NVMe Flush, once 32 MiB is dirty (system/fileserver/src/cache.rs:50, DIRTY_LIMIT). It also syncs the whole volume 2 s after an unsynced write (writeback.rs:8). So every round of the 64 MiB fs.disk.seq_write.* writes the disk on ToyOS.
  • Reads, measured. The AMD run at c8f3fbf (evidence r2) read fs.disk.seq_read.4096 at 158 MB/s p50, with min 158 and max 426. In other words, four rounds out of five ran at about a third of the fifth. Cached 4 KiB transfers in the same boot ran at 16.9 µs for a seek plus a read (read_4k_at).
  • Reads, cause (inference, not measured). CLEAN_LIMIT is 64 MiB (cache.rs:47), exactly the file's size. Eviction follows insertion order, and a hit does not refresh a block's place (cache.rs:140-146). Once write-back cleans the file's second half, a sequential read evicts the blocks it reads next.
  • The procedure is fair: each system's write-back and cache policy is its own and part of what is compared. The README states outcomes, though, and the evidence refutes them.
  • Fix: state the rule as procedure: each row reads files it wrote in its run, and neither system's cache is dropped. Say that ToyOS's write rows include its 32 MiB and 2 s write-back.
  • Record the seq_read.4096 finding in issues/ with its evidence, as 8267716 does for fsync_clean (No silent debt). The cheapest check of the cause is a fileserver host test: a Cache over the counting disk the cache tests already use, 64 MiB written in 4 KiB calls, a flush, then five sequential reads, counting disk reads.

BLOCKER README.md:145-147, 150-153: two statements describe the medium check wrongly.

  • "The compare refuses a verdict on any row where it is not [nvme]" is wrong. The compare refuses where the media differ (compare/src/lib.rs:429-430).
  • "Every row's served_by and medium name the filesystem and the disk it measured" is false for ToyOS. There both are constants (sys/toyos.rs:395-397), so the compare's media check cannot see ToyOS's medium, and the metal row is the only guard. The code comment says this correctly; the README should say the same thing in one sentence.

BLOCKER src/files.rs:94-96: the rewrap broke the doc comment ("…and its medium. Each" / "one's comment is…"). Rejoin the line.

BLOCKER Evidence: no boot of this head's image has been judged by this head's row.

  • The AMD validation boot was started by toyos-metal boots every bench image off the bench's internal NVMe #1095's NVMe runner, and this branch's harness refused its readback (judge-pre-1095-harness.log: "boot file names no stick_secs").
  • By inspection, that kernel.log would pass both new checks: line 326 has the NVMe's TOYOS-DATA partition (type 064E3777…), line 344 has mounted the DATA volume, and there is no format line. That is inspection, not a run.
  • The T14 run is still pending. The T14 is where the in-memory version of the 64 MiB write once stalled, so it is the one that retires the seq_write risk.
  • On the AMD, persist completed in 8 s with no fileserver restart, so the risk is retired there for one boot.
  • Needed before landing: the osbench row passing at the landing head on both benches, and the T14's persist completing. The PR's Checks list should then report r2; that correction is the orchestrator's.

SUGGESTION Boot medium. No code assumes a stick. data_on_the_nvme keys on the NVMe driver's partition line and works on either boot.

SUGGESTION tests/toyos.rs:1770-1809: these duplicate tests/common/hostdisk.rs::left_alone.

  • left_alone already classifies DATA as Foreign, Formatted or Mounted from the same lines. It also checks that the NVMe opened its session on DATA, where data_on_the_nvme argues from "the file server refuses two".
  • Once toyos-metal boots every bench image off the bench's internal NVMe #1095's left_alone(log, ours) lands, Formatted means refuse and Mounted means pass, and both parsers could go.
  • If they stay:
    • The format duration and since_boot serve no decision, and their only control produced 0.000 s by substitution.
    • The "it is absent this boot" test matches only the path that mounts and then cannot serve. The other refusals print "DATA is absent this boot" and are caught by the missing mount line instead.
    • The memory path's own line ("this machine has no DATA partition…") reports as "the file server said nothing of DATA".

SUGGESTION The durability bullet's Linux half also depends on the device reporting a volatile write cache. Recording /sys/block/<disk>/queue/write_cache beside the mount would make that half evidenced rather than assumed.

8267716 (after the requested head)

The new issue matches the evidence: fsync_clean read 1,233,821 ns under ToyOS against 69,703 and 56,649 under Linux, and write_4k_fsync read 2.9 ms against 3.0–3.6 ms. It also matches lib/bcachefs/src/fs.rs:927-939: sync writes the superblock unconditionally between two cache flushes, so a Flush is owed every time. No finding.

Verdict

SEND BACK

Japabu and others added 4 commits October 28, 2026 17:14
…bench's NVMe

#1085 lets ToyOS designate its own DATA, and both benches' fourth
partitions are designated and mounted. So the follow-up staged in #1079
lands. ToyOS's persistent filesystem is DATA's /home (bcachefs crate's
format, through the DATA file server and the NVMe driver), medium nvme.
persist runs its durable rows there, then files' cached operations as
fs.disk.*, on both systems: Linux on its home, ext4 on the same NVMe. A
row whose media differ still has no verdict, and these now agree.

The osbench row refuses a boot whose DATA was not a TOYOS-DATA partition
the NVMe driver serves, mounted and not absent. It also refuses the boot
that formats a newly designated DATA as a run, stating the format's
duration. ToyOS's files group keeps /tmp alone: /home is fs.disk now. The
compare's setup reads fs.disk.served_by.

The README states the disk rows' rules:
- one NVMe for both;
- each system's own filesystem, Linux's mount options recorded;
- one durability: a sync returns after the device's cache is flushed,
  ToyOS's fsync covering its whole volume;
- one cache state: every row's files are written in its run and read
  cached on both.

#1085 already judges nvme_leaves_the_benchs_disk_alone against a
designated DATA, so that part of the staged patch is superseded and
dropped. Nothing here depends on #1095 (ToyOS booting off the internal
NVMe); the judge finds DATA by the NVMe driver's partition line, wherever
the boot came from.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#1097's AMD validation reads persist.fsync_clean at 1.23 ms under ToyOS
against 57-70 us under Linux on the same NVMe. Mounted::sync writes the
superblock on every commit, so the cache owes a Flush even where nothing
changed. #1067's handoff named this open and unfiled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and the rows' debts are filed

Rebased on #1095 (370d7d9).

- B1: Linux's fs.disk.mount now carries the superblock options too, where
  ext4's nobarrier would be, and served_by names the device's write-cache
  mode (queue/write_cache).
- B2: the README states the cache rule as procedure. Every row reads only
  files it wrote in its run, and neither cache is dropped. ToyOS's write
  rows include its 32 MiB and 2 s write-back. The 4 KiB sequential read's
  158 MB/s is filed: a host probe of the cache shows a file 16 blocks over
  CLEAN_LIMIT missing every block on every pass (16,400 requests) and one
  16 under missing none, the insertion-order eviction.
- B3: the README says the compare refuses differing media, and that
  ToyOS's medium is a constant the osbench row alone makes true.
- B4: the rewrap.
- The osbench row's judge is hostdisk::left_alone with the loader's
  volumes: Mounted passes, Formatted is the format boot (its duration
  stated), and Foreign or memory is refused. The second parser goes.
- The README says ToyOS's log volume shares the NVMe, and the image comment
  says the image, not the stick, has no DATA partition.
- issues/a-file-server-request-costs-ten-times-a-kernel-file-call.md: the
  cached fs.disk rows' 4-12x, the round trip, against Linux and ToyOS's
  own /tmp, with parity as its exit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From #1097's T14 validation: a clean fsync costs ToyOS 3.0 ms, so its Flush
on that disk costs about that, against Linux's whole write and fsync at
0.8-1.0 ms. The AMD's Samsung shows no such gap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Japabu

Japabu commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

r1 response, head 069cbbeb8 (rebased on #1095)

  • B1, fixed. mount_options carries mountinfo's superblock options (field 11), where ext4's nobarrier is. Linux's served_by names queue/write_cache (suggestion taken).
  • B2, fixed.
    • The README states the cache rule as procedure: each row reads only files it wrote in its run, and neither cache is dropped. It says ToyOS's write rows include its 32 MiB and 2 s write-back.
    • The seq_read.4096 finding is filed with its evidence and your probe. A cache over the counting disk, CLEAN_LIMIT + 16 blocks written in 4 KiB calls and flushed, made 16,400 disk requests on each of five passes; CLEAN_LIMIT - 16 made none (evidence r3 probe/, a patch applied and reverted). files.rs's header no longer claims the cached path.
  • B3, fixed. The compare refuses differing media. On ToyOS the medium is a constant that only the osbench row makes true.
  • B4, fixed.
  • B5: the landing head's runs are staged for both benches. The T14 run at c8f3fbfb0 passed with persist complete in 11 s, with no file server restart.
  • Suggestions taken:
    • the boot medium: the README says ToyOS's log volume shares the NVMe, and the image comment says "the image has no DATA partition";
    • one parser: the judge is hostdisk::left_alone(log, loader_named(loader)), with Mounted passing, Formatted the format boot and anything else refused. It passes the AMD's NVMe-runner and designated boots, and refuses the memory and format logs.

The T14 run also showed a durable write costing ToyOS six times Linux's on that disk. It is filed with the other three below-parity rows, as the owner's parity goal asks.

The landing head's T14 validation (069cbbe) read ToyOS's write_4k_fsync at
1.10 ms against Linux's 1.01-1.04 ms, where c8f3fbf's read 6.1 ms. No
storage-path code changed between them and both booted off the NVMe, so
the record states both boots and an unknown cause instead of a sixfold gap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Japabu

Japabu commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

Review r2 of #1097 at 069cbbe, with d6fc8be noted

This round was asked to review 069cbbe. The branch has since moved to d6fc8be, which replaces the T14 record and changes nothing else. Both heads are reviewed below. The metal runs at 069cbbe also cover d6fc8be, because d6fc8be touches only issues/.

Architecture

Unchanged since r1, and still a good fit. Moving the judge to hostdisk::left_alone(log, loader_named(loader)) removes the second parser. Source net is still small: tests/toyos.rs +41/−4, osbench +40/−30. Most of the growth is the README section and five issue records.

r1 blockers

  • B1, resolved. mount_of now returns mountinfo's field 11. Both benches' Linux runs at r4 record fs.disk.mount=ext4_rw,relatime_rw and served_by=…, write cache write back, so the README's durability bullet is now backed by recorded fields.
  • B2, resolved in code and README. The cache rule is now stated as procedure. The write-back limits match cache.rs:48-51 and writeback.rs. The files.rs header no longer claims the cached path. The seq_read record matches cache.rs:140-146 and :316-324: a hit does not re-queue a block, and blocks are evicted from order's front. One evidence defect remains (N3 below).
  • B3, resolved. The README now says the compare refuses differing media, and that ToyOS's medium is a constant that only the row makes true.
  • B4, resolved. files.rs:94-95 reads correctly.
  • B5, resolved. The judge tree toyos-1097-check is at 069cbbe and clean. Both ToyOS boots log supervisor: build 069cbbeb878d… clean. On both benches the osbench row printed PASS osbench, with "1 passed, 0 failed". persist finished in 9 s on each with no file server restart, and fs.disk.seq_write.1048576 completed on both, the T14 included. The Linux half's sha256 98d8b7f2…f796 matches r3/checks/linux-osbench-SHA256SUMS. compare.md shows no media refusal on the disk rows.
  • Suggestions taken: the log-volume sentence, the image comment and the single judge are all done correctly.

Rebase

Nothing this PR depends on broke. Readback::loader() and hostdisk::loader_named come from #1095. Host CI ran on the rebased tree at b4121cc (exit 0, 105 steps), and the judge compiled and passed at 069cbbe on real readbacks. Main has since moved to 9c677be (#1096, #1093); git merge-tree against it is clean, and their tests/toyos.rs hunk only adds a separate row.

Between c8f3fbf and 069cbbe, nothing under system/nvme, system/diskserver, system/fileserver or lib/bcachefs changed. The T14's acpiserver idle census is identical in both boots (MWAIT 0x31 253 µs + MWAIT 0x60 1048 µs).

Findings

BLOCKER (resolved at d6fc8be) issues/a-durable-write-on-the-t14s-nvme-costs-toyos-six-times-linuxs.md at 069cbbe: the landing head's own T14 run contradicts this record. ToyOS read write_4k_fsync 1,099,737 ns against Linux's 1,011,579–1,035,997, and fsync_clean 464,505 ns against 3,019,602 at c8f3fbf. d6fc8be restates the record with both boots, and I checked every number in its table against metal6/metal7. The two points in N1 remain.

BLOCKER N1 issues/toyos-durable-writes-on-the-t14s-nvme-took-1-to-6-ms-across-two-boots.md:24-27: two statements go beyond the evidence.

  • "The first followed DATA's format by less than a day, so the drive's own state is a candidate." This does not tell the two boots apart. fa72582's T14 boot at 12:13 still logs the DATA partition is not ours, and DATA then mounts at 16:08 (c8f3fbf) and at 16:47 (069cbbe). Both boots followed the format by hours. Either state what does distinguish the first boot (for example, that it was the first workload after the format, if a log shows that), or delete the sentence.
  • "a superblock write and a Flush where Linux issues neither." Nothing measured what Linux sends to the device on a clean fsync. 23 µs only shows that it is cheap, and a Flush to a device whose cache holds nothing dirty can also be cheap. The same claim is in the PR body ("Linux's issues neither"). The cheapest fix is to state the measurement: "where Linux's clean fsync takes 23 µs". If the cause matters, read the namespace's flush counters in /sys/block/<disk>/stat before and after the row.

BLOCKER N2 issues/a-file-server-request-costs-ten-times-a-kernel-file-call.md:22: "The disk adds nothing to these" is false for one of the five rows it covers.

  • open_close reads 18,686 ns on the NVMe at c8f3fbf, against 14,178 on 2026-10-24's in-memory DATA (r2/amd/compare-2026-10-24-full-final.md:58), which is +32%.
  • read_4k_at, stat, rename and seq_read.1048576 do agree within about 5%. r2's index was careful to name only read_4k_at, stat and rename.
  • The title's "ten times" holds for read_4k_at (12.8x) and rename (9.7x), but not for stat (4.0x) or open_close (3.1x).
  • Fix: restrict the sentence to the rows that agree and state the open_close difference as unattributed. Make the title match the table, for example "several times", or the commit message's "4 to 13 times".

BLOCKER N3 The evidence branch pr-1097, file r3/probe/probe-clean-limit.patch: the published patch is not the probe that ran.

  • It is 10 lines long and adds only a blank line, so it cannot define probe_sequential_passes_against_the_clean_limit, the test that probe.log reports.
  • The real patch, 31 lines, is still in the implementer's scratch mutations/probe-clean-limit.patch. It looks like the publishing step lost lines.
  • The seq_read record cites this probe as the confirmation of its cause, so the published evidence has to contain its source. Republish the full patch and repoint the index.

BLOCKER N4 (orchestrator's correction) The PR body no longer matches the change or its evidence.

  • It is still labelled Draft.
  • "What the validations show" is the c8f3fbf table, and its T14 write_4k_fsync cell ("its Flush on that BC501 costs about 3 ms") is contradicted by r4.
  • It names a-durable-write-on-the-t14s-nvme-costs-toyos-six-times-linuxs, which d6fc8be deletes.
  • Checks still say B5's runs are "staged … (exit 2)", and that "069cbbeb8 adds only an issue record", with d6fc8be unmentioned.
  • The evidence link is pinned at 376e93d4, which has no r4. r4 is 9369068d on pr-1097.
  • "The same rows on 2026-10-24's in-memory DATA read the same" carries N2's problem.
  • "Linux's issues neither" carries N1's problem.
  • The risk line's exception list is out of date: at r4 the AMD's append_4k_fsync is also below Linux's.
  • Needed: r4's table and judge results, the evidence link at the r4 commit, and the current record names.

SUGGESTION tests/common/hostdisk.rs:107-121, through data_on_the_nvme: r1's suggestion assumed that left_alone checks the NVMe opened a session on DATA. Under #1095's NVMe boot it does not: the loader's boot and log sessions already satisfy "at least one session, each on DATA or ours". As a result, Mounted no longer requires DATA to be the NVMe's. Today this cannot misjudge: the image has no DATA, both benches' NVMe carry a TOYOS-DATA partition, and the file server refuses two. If a session on DATA is what the row means, require it when the fate is Mounted or Formatted. That is one any over opened.

SUGGESTION issues/a-file-server-request-costs-ten-times-a-kernel-file-call.md:13-24: the /tmp column comes from the 2026-10-24 boot, but the c8f3fbf boot measured fs.mem itself (1,413 / 2,596 / 6,091 / 6,242 ns, 8,041 MB/s). Using the same boot for both columns would remove the "that boot's" sentence.

Verdict

SEND BACK. N1–N3 are wording or republishing fixes that need no new runs. N4 belongs to the orchestrator.

Japabu and others added 2 commits October 28, 2026 18:33
- N1: the T14 durable-write record drops "followed DATA's format by less than
  a day", which both boots did, and says Linux's clean fsync takes 23 us
  where it claimed Linux issues no write or Flush, which nothing measured.
- N2: the file-server record is "three to twelve times", the ratios its
  table shows. Its /tmp column is the same boot's. "The disk adds nothing"
  holds for four rows, and open_close's 32% on the NVMe is stated as
  unattributed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The last disk row ToyOS loses at #1097's landing head without a record:
8-22% dearer on both benches, where the plain durable writes are at parity.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Japabu

Japabu commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

Orchestrator: r2's N1–N4 checked against d6fc8be..ddc26a3 (issue records only, so the landing-head runs at 069cbbe still apply). N1: the T14 record states the measured 23 µs and drops the format-age candidate. N2: the record is renamed to three to twelve times, with both columns from one boot and open_close's +32% stated. N3: the full probe patch is republished at 38db2e75 with a correction note. N4: the body describes the final change and pins r4. The new create_fsync_unlink record states only its measured rows. Landing.

@Japabu
Japabu marked this pull request as ready for review October 28, 2026 17:34
@Japabu
Japabu added this pull request to the merge queue Oct 28, 2026
Japabu added a commit that referenced this pull request Oct 28, 2026
The cache kept at most 16,384 clean blocks, 64 MiB, and drops the oldest
read first without moving a block it hits. osbench's fs.disk.seq_read.4096
rereads a 64 MiB file: its blocks and the tree nodes an open reads come to
one more than the cache kept, so each fetched run evicted the blocks the
reader reached next and every pass came off the disk whole. #1097's AMD
readback has 158 MB/s p50 against 4,960-5,054 under Linux. Why one round
of five read 426 MB/s is not shown; dirty blocks are outside the clean
count, so a round run before the write-back would fit.

A host test written as the benchmark reads (write 64 MiB in 4 KiB calls,
sync, then open, read whole and close in rounds) read 16,385 blocks off the
disk in each round after the first at the old limit. It now runs on a cache
holding twice the file and reads none.

Each cache is made with its limit, and the server gives it an eighth of
physical memory: the share netstack and the compositor take for the same
reason, that nothing signals memory pressure, so the bound is all that keeps
a cache from holding the machine. The eviction order is unchanged, so a file
larger than that still misses on every pass, which #1097's
a-sequential-read-of-a-file-as-large-as-datas-clean-cache-reads-the-disk.md
records.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merged via the queue into main with commit e4bdb0a Oct 28, 2026
10 checks passed
@Japabu
Japabu deleted the bench-disk branch October 28, 2026 17:52
Japabu added a commit that referenced this pull request Oct 28, 2026
Mounted::sync committed unconditionally: it flushed the device, wrote both
superblock copies and flushed again. Under the file server's cache the
first flush costs nothing when nothing is dirty, but the superblock write
always left one owed, so every fsync on DATA paid two block writes and an
NVMe Flush. #1097's AMD readback has persist.fsync_clean at 1.23 ms against
57-70 us under Linux on the same disk.

A mount now keeps the superblock its last commit made durable. A commit
whose superblock equals it, the allocation cursor aside, writes none: under
shadowing no node the landed root reaches is written over, so an equal root
is the landed tree. The device is still flushed first, for the data pages
and bitmap blocks written in place, so a sync still returns only once
everything written before it is on the medium. The cursor is excluded
because a commit's own frees move it back after its superblock lands, and
where the next scan starts is no reason to commit. Nothing is known landed
at mount, after mkfs or after a refused sync, so each of those commits
whole.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Japabu added a commit that referenced this pull request Oct 28, 2026
…s across five boots

The 2026-10-28 scoreboard compares ToyOS at 069cbbe against each bench's
Linux as installed: 4 boots against 5 runs, interleaved (evidence branch
scoreboard-2026-10-28). Each row ToyOS loses with no owning record now has
one, with its figures, an owner and an exit:

- a small message's round trip over a native connection (ipc.reqrep.8,
  2.04x on the T14);
- the futex ping-pong (2.01x and 1.37x on the T14);
- tmpfs metadata calls (fs.mem open_close, stat, rename, mkdir_rmdir, 4.1-6.5x
  on the T14);
- process and thread spawn, and the all-CPU build (up to 3.7x on the T14,
  and 2.3x for j16 on the AMD);
- small memcpy on the AMD (64 B at 0.61 of Linux's);
- no loopback, so osbench net measures nothing;
- std's yield_now, which yields nothing.

The T14 durable-write record takes all five boots: 2 of 5 ran persist six
times slower throughout and a third turned slow partway, with nothing in the
logs to tell them apart. It gets a slug that says so, which #1097 had on its
branch after it merged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Japabu added a commit that referenced this pull request Oct 28, 2026
The cache kept at most 16,384 clean blocks, 64 MiB, and drops the oldest
read first without moving a block it hits. osbench's fs.disk.seq_read.4096
rereads a 64 MiB file: its blocks and the tree nodes an open reads come to
one more than the cache kept, so each fetched run evicted the blocks the
reader reached next and every pass came off the disk whole. #1097's AMD
readback has 158 MB/s p50 against 4,960-5,054 under Linux. Why one round
of five read 426 MB/s is not shown; dirty blocks are outside the clean
count, so a round run before the write-back would fit.

A host test written as the benchmark reads (write 64 MiB in 4 KiB calls,
sync, then open, read whole and close in rounds) read 16,385 blocks off the
disk in each round after the first at the old limit. It now runs on a cache
holding twice the file and reads none.

Each cache is made with its limit, and the server gives it an eighth of
physical memory: the share netstack and the compositor take for the same
reason, that nothing signals memory pressure, so the bound is all that keeps
a cache from holding the machine. The eviction order is unchanged, so a file
larger than that still misses on every pass, which #1097's
a-sequential-read-of-a-file-as-large-as-datas-clean-cache-reads-the-disk.md
records.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Japabu added a commit that referenced this pull request Oct 28, 2026
Each server took an eighth of physical memory, so the DATA, log and boot
servers together could keep three eighths clean, and writes fill a cache
as well as reads: a flushed block stays as a clean one. The eighth
netstack and the compositor take rests on leaving seven eighths to
everyone else, which three such shares do not. Now the log and boot roles
keep 16 MiB each, their FAT and directories, and DATA the rest of one
eighth. The interim, that nothing gives a clean block back to another job,
is the-file-servers-clean-blocks-are-given-back-to-no-other-job.md, owned
with the memory track: its exit is clean blocks dropped under the memory
service's pressure and CLEAN_SHARE deleted.

A block read in is cached only if the allocator gives it room. Box::new
cannot fail, so a miss under another job's exhaustion aborted the server
and lost what it held dirty; a refused clean block is now just not kept,
and the read is answered from the disk's bytes.

The total-memory decode lives in the SDK (toyos::system::memory_total)
for the file server, netstack and the compositor, which each had a copy.

#1097's record of the eviction cliff named CLEAN_LIMIT, which is gone;
it now names the server's limit, and stays open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Japabu added a commit that referenced this pull request Oct 28, 2026
Mounted::sync committed unconditionally: it flushed the device, wrote both
superblock copies and flushed again. Under the file server's cache the
first flush costs nothing when nothing is dirty, but the superblock write
always left one owed, so every fsync on DATA paid two block writes and an
NVMe Flush. #1097's AMD readback has persist.fsync_clean at 1.23 ms against
57-70 us under Linux on the same disk.

A mount now keeps the superblock its last commit made durable. A commit
whose superblock equals it, the allocation cursor aside, writes none: under
shadowing no node the landed root reaches is written over, so an equal root
is the landed tree. The device is still flushed first, for the data pages
and bitmap blocks written in place, so a sync still returns only once
everything written before it is on the medium. The cursor is excluded
because a commit's own frees move it back after its superblock lands, and
where the next scan starts is no reason to commit. Nothing is known landed
at mount, after mkfs or after a refused sync, so each of those commits
whole.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Japabu added a commit that referenced this pull request Oct 31, 2026
The cache kept at most 16,384 clean blocks, 64 MiB, and drops the oldest
read first without moving a block it hits. osbench's fs.disk.seq_read.4096
rereads a 64 MiB file: its blocks and the tree nodes an open reads come to
one more than the cache kept, so each fetched run evicted the blocks the
reader reached next and every pass came off the disk whole. #1097's AMD
readback has 158 MB/s p50 against 4,960-5,054 under Linux. Why one round
of five read 426 MB/s is not shown; dirty blocks are outside the clean
count, so a round run before the write-back would fit.

A host test written as the benchmark reads (write 64 MiB in 4 KiB calls,
sync, then open, read whole and close in rounds) read 16,385 blocks off the
disk in each round after the first at the old limit. It now runs on a cache
holding twice the file and reads none.

Each cache is made with its limit, and the server gives it an eighth of
physical memory: the share netstack and the compositor take for the same
reason, that nothing signals memory pressure, so the bound is all that keeps
a cache from holding the machine. The eviction order is unchanged, so a file
larger than that still misses on every pass, which #1097's
a-sequential-read-of-a-file-as-large-as-datas-clean-cache-reads-the-disk.md
records.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Japabu added a commit that referenced this pull request Oct 31, 2026
Each server took an eighth of physical memory, so the DATA, log and boot
servers together could keep three eighths clean, and writes fill a cache
as well as reads: a flushed block stays as a clean one. The eighth
netstack and the compositor take rests on leaving seven eighths to
everyone else, which three such shares do not. Now the log and boot roles
keep 16 MiB each, their FAT and directories, and DATA the rest of one
eighth. The interim, that nothing gives a clean block back to another job,
is the-file-servers-clean-blocks-are-given-back-to-no-other-job.md, owned
with the memory track: its exit is clean blocks dropped under the memory
service's pressure and CLEAN_SHARE deleted.

A block read in is cached only if the allocator gives it room. Box::new
cannot fail, so a miss under another job's exhaustion aborted the server
and lost what it held dirty; a refused clean block is now just not kept,
and the read is answered from the disk's bytes.

The total-memory decode lives in the SDK (toyos::system::memory_total)
for the file server, netstack and the compositor, which each had a copy.

#1097's record of the eviction cliff named CLEAN_LIMIT, which is gone;
it now names the server's limit, and stays open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant