# JoeyLib cross-port performance (UBER benchmark) Regenerated 2026-06-30. ST/Amiga/DOS columns are fresh measurements from the headless harness (`scripts/bench-atarist.sh` Hatari, `bench-amiga.sh` FS-UAE, `bench-dos.sh` DOSBox). The IIgs column is the perf reference: the generic+override redesign was bit-identical on IIgs (MAME `iigs-verify` checksum 0817FE), so its codegen — and thus its ops/sec — is unchanged from the last IIgs capture. Every non-IIgs cell is a ratio (port / IIgs); the directive is that every target meet or beat the IIgs floor (>= 1.0x). Sprite ops now meet or beat the IIgs on BOTH 68k targets after this session's work (compiled DRAW emitters + raw-plane-byte save/restore); they were the dominant violations (down to 0.13x). The ST column is honest for the first time — the ST port was crashing on first present (user-mode I/O poke) until the `Super(0L)` fix in jlpInit. Genuine remaining sub-1.0x cells and why: * **ST jlDrawCircle (0.61-0.65x)** — inherent planar-outline cost: a 4-plane word RMW per sparse outline pixel (8 memory accesses) vs the IIgs single nibble, amplified by ST video-DMA contention. Cycle-bound; ~0.80x ceiling even fully optimized. Not winnable in this format. * **Amiga jlFillCircle (0.82x)** — already asm span-fill (long-store middles); closing the gap needs a blitter area-fill rewrite (risk: the blitter has wedged the system before). * **ST jlSpriteSaveAndDraw (0.97x)** — ST runs save+draw as two dispatched ops; the IIgs fuses them. Marginal. * **ST jlTileFill (0.98x), Amiga jlFillRect 80x80 (0.95x)** — within noise. * **ST jlFillRect 320x200 (0.53x)** — ARTIFACT: the IIgs reference (60) is the SEI-inflated full-screen reading (see the ceiling note below; honest ~28). Against the honest reference ST is ~1.1x. Same caveat for surfaceClear / stagePresent full. | Op | IIgs (ops/sec) | Amiga (vs IIGS) | Atari ST (vs IIGS) | DOS (vs IIGS) | | --- | --- | --- | --- | --- | | jlSurfaceClear | 28 | 2.68x | 1.32x | 449.21x | | jlPaletteSet | 678 | 9.09x | 4.27x | 22.01x | | jlScbSetRange | 1005 | 3.62x | 1.86x | 14.20x | | jlDrawPixel | 1755 | 2.04x | 1.18x | 9.40x | | jlDrawLine H | 682 | 2.26x | 1.61x | 26.93x | | jlDrawLine V | 90 | 1.70x | 1.14x | 145.83x | | jlDrawLine diag | 35 | 1.14x | 1.06x | 475.37x | | jlDrawRect 100x100 | 75 | 1.67x | 1.16x | 206.49x | | jlDrawCircle r=16 | 232 | 1.20x | **0.65x** | 64.79x | | jlDrawCircle r=80 | 56 | 1.16x | **0.61x** | 301.25x | | jlFillRect 16x16 | 450 | 1.24x | 1.11x | 36.04x | | jlFillRect 80x80 | 75 | **0.95x** | 1.33x | 205.09x | | jlFillRect 320x200 | 60 | 1.13x | **0.53x** | 188.92x | | jlFillCircle r=40 | 38 | **0.82x** | 1.39x | 398.24x | | jlSamplePixel | 1916 | 3.42x | 1.92x | 18.04x | | jlTileFill | 1252 | 1.74x | **0.98x** | 10.60x | | jlTileCopy | 997 | 1.80x | 1.04x | 7.88x | | jlTileCopyMasked | 498 | 1.81x | 1.10x | 32.48x | | jlTilePaste | 1106 | 1.99x | 1.12x | 14.64x | | jlTileSnap | 1473 | 2.29x | 1.53x | 9.96x | | jlSpriteSaveUnder | 528 | 1.05x | 1.29x | 23.69x | | jlSpriteDraw | 438 | 2.09x | 1.09x | 23.85x | | jlSpriteRestoreUnder | 487 | 1.08x | 1.11x | 34.83x | | jlSpriteSaveAndDraw | 277 | 1.23x | **0.97x** | 53.79x | | jlStagePresent full | 42 | 7.81x | 1.10x | 412.17x | | jlInputPoll | 273 | 13.94x | 4.19x | 37.87x | | jlKeyDown | 3382 | 7.75x | 3.76x | 18.94x | | jlKeyPressed | 3345 | 7.66x | 3.81x | 18.73x | | jlMouseX | 4170 | 10.40x | 5.22x | 26.30x | | joeyJoyConnected | 3378 | 7.71x | 3.71x | 18.96x | | jlAudioFrameTick | 4106 | 8.00x | 2.50x | 12.42x | | jlAudioIsPlayingMod | 3536 | 9.30x | 4.33x | 26.78x | | surfaceMarkDirtyRect (via jlFillRect 32x32) | 240 | 1.42x | 1.31x | 47.12x | > **IIgs full-screen ceiling (~29 ops/sec).** A full-screen op moves > 32000 bytes = 16000 word-stores x 6 cyc (STA long,X / PEI, both > 3 cyc/byte) / 2.8 MHz ~= 34 ms ~= 29 ops/sec maximum. So > `jlSurfaceClear`, `jlFillRect 320x200`, and `jlStagePresent full` > cannot legitimately exceed ~29; a higher reading means the benchmark > clock was perturbed. The clock is `jlFrameCount` = the VBL-interrupt- > driven GetTick, so an op that holds `SEI` while it runs can over- > report its ops/sec. Treat full-screen IIgs numbers above ~29 as > inflated and cross-check against the cycle model.