All games

BananaBread

Scrap · 51 0.1 h played, 0 crashes

A first person shooter on the Cube 2 engine, with bots and an in-game map editor: the BananaBread content in Debian's cube2-data.

Genre
shooter first-person
Players
online multiplayer bots
Input
made for keyboard and mouse
View
3D first-person
Content
map editor
Engine
Cube 2

Played sessions

Testing is done with Walnut's rating tool (walnut-rate, on the console): how ratings are made and submitted.

Builds: Walnut 0.1, cube2-data 1.3-1

The platform builds under it (3)
Linux kernel6.12.111+ps3.747 Walnut's build
Mesa26.2.4-1+ps3.721 Walnut's build
ps3rsx0.735+k6.12.111+ps3.747 Walnut's build
DateLauncherRulesPlayEndedPicture
2026-10-24 Cube2:Demo 1.03 minquit ok Details

Download all sessions as CSV (one row per session, the aspects as columns)

Rating history

The rating on each version it was tested on, newest first: each row is rated from that version's sessions alone, under the newest rules those sessions have the data for.

VersionTestedMedalRules Frame rateSmoothnessSoundPictureStabilityDisplayLoad Play
Walnut 0.1
cube2-data 1.3-1
2026-10-24 Scrap · 51 1.0 --9610090-100 0.1 h
1 test

Scripted benchmarks

Not rated: tests of driver and game changes. A script plays the same scene on the PS3 again and again (the desktop stopped, vsync off) to compare two builds of the game or of the graphics driver. The numbers say which build is faster; they never feed the medal.

How the script plays it: BananaBread with cube2-data 1.3's maps. base: the user's recorded demo, copied to ~/.cube2/demo/bench.dmo and played with `mode -1; map bench`.

The recipe's full description

BananaBread (Debian's cube2, so this recipe is still called sauerbraten; our build: textures compressed at upload on Mesa too) with cube2-data 1.3's maps (the BananaBread content). base: the user's recorded demo (assets/sauerbraten-bench.dmo, 2026-10-17: an FFA round on cave with two bots, 93 s of game time, recorded by the local server with `recorddemo 1` and a map reload, saved with getdemo), copied to ~/.cube2/demo/bench.dmo and played with `mode -1; map bench` (demo mode on the local server, as the data's `demo` command does it: the server's setupdemoplayback reads <demodir>/bench.dmo and sends the recorded packets, so the client loads cave from them and runs `mapstart`; at the end, "demo playback finished" and the client runs `demoend`). A CubeScript (-x) counts frames (a sleep re-armed every frame, wall time from getmillis 1): each playback ("loop") prints "ps3bench: loop <k>: <n> frames in <ms> ms: <fps> fps, longest <ms> ms" at its end (fps= and maxms= are loop 1's, the whole first playback). Steady state: the window opens 60 s after the first mapstart (the map loaded) and closes at the playback's end; demoend plays the demo again (a reload, left out of the window: it reopens at the next mapstart) until the window holds ~120 s (114 s: the rest of loop 1 and loop 2), then "ps3bench: steady <n> frames in <ms> ms: <fps> fps, longest <ms> ms" and quit. The script marks the window ("ps3bench: window on/off": WIN_ON_RE, WIN_OFF_RE) so the HUD metrics use the same pieces. The bots in a demo are played back, not simulated: every run is the same. variant spawn: the method before the demo: -l loads map "cave" (its only player start, so every run looks from the same spot) and the player stands still; the script counts frames for 30 s from 10 s after the first frame and prints "ps3bench: <n> frames in <ms> ms: <fps> fps, longest <ms> ms" (fps=, maxms=), then its own steady window, 60 s after the first frame for 120 s (STEADY_RE), and quits. The view is static: one view's rendering once loading is over. The gun, towers and *skin variants use it (the hud gun and the other map only exist there). getfps itself averages only the last 60 frames. Settings go into ~/.cube2/autoexec.cfg (run after config.cfg, so the player's saved fullscreen or vsync can't override them); both files are restored after the run. Our cube2 (ps3.N, gamedb/engines/cube2/technical.md) ships the memory defaults of gamedb/engines/cube2/packages/cube2/patches: CPU skinning (gpuskel 0: GPU skinning indexes a bone array in the vertex shader, which nv30 compiles to if/else trees, 11 fps against 28; no GPU skinning shaders are built then), sky boxes and cube maps from their 256x256 .dds (skydds 1), lightmaps' CPU copies freed after upload (lmfreedata 1), dynamic light and water fade shader variants only as far as maxdynlights, waterrefract and waterfade ask. "base" is that; every variant below changes one thing (or, lean, the bundle that is meant to ship). Memory per run: during.log has MemAvailable and SwapFree every 5 s, bench.txt their lowest.

42 variants of the recipe
base stands for the gamethe recipe as it is, without a variant
gpuskelGPU skinning on (the old default): shaders for it are built, the hud gun and players use them
cpuskelthe old default spelled out (base is CPU skinning now)
pngskysky and env map from the PNGs (six 2048x2048, decoded twice at load) instead of the 256x256 .dds
keeplmlightmaps' CPU copies kept (24 MB in cave)
dyn5dynamic light shader variants: all five that the stock engine builds (maxdynlights 5 also draws five), or fewer. Lights and muzzle flashes light the world less
dyn1-
dyn0-
nofadewater: no fade under the surface (no fade variants of every world shader), or no reflection and refraction at all (two extra scene passes when water is in view)
nowater-
sd2the world shaders without specular and parallax (shaderdetail 2: no spec map; 1: no parallax either, the menu's "low detail"): fewer texture reads per pixel, fewer variants
sd1-
nobumpmdlno normal-mapped or env-mapped models: far fewer model shader programs
tex1textures dropped by a mip level (texreduce 1: a quarter of the memory of the DDS and JPG ones) or capped in size (maxtexsize also caps the sky and the lightmap textures)
tex2-
maxtex512-
tc512compress the uncompressed textures from 512 or 256 pixels up (default 1024): water, models, particles, the HUD. Look for ragged text and HUD edges
tc256-
snd22sound at 22 kHz: the decoded samples are half the size
leanthe bundle meant to ship if the single steps hold: no water passes, low-detail shaders, models without bump, one dynamic light, compressed 512 textures, 22 kHz sound
notcno texture compression at all (as upstream on Mesa): VRAM and load time against base
spawnhud gun: -l starts mode 1 (coop edit), where the player spawns with the pistol, and cube2-data 1.3 (the BananaBread content) has no pistol or fist hud gun model (models/hudguns: chaing gl rifle rocket shotg), so nothing is drawn. This switches to the grenade launcher (1 grenade at spawn) 2 s after the first frame, which adds the one skeletal model that CPU or GPU skinning has to move the method before the demo (recipe header)
gun-
gungputhe same with GPU skinning, to compare against gun
towersthe biggest map with one player start (66 lights, an 8192 world)
spuskinCPU skinning through libspeq (our cube2 0006, ps3-spu's skin.spu), on the hud gun of variant gun (hands 1497 + grenade launcher 1683 vertices with tangent frames: the only skinned model on cave): on the SPEs, with libspeq's vector code on the PPE, or the engine's own loop (as before 0006). SPEQ_DEBUG=1 puts libspeq's counters in the log every 10 s and at exit (batches on the SPEs, mean and max wait, timeouts, errors); gun itself is the default, auto
ppeskin-
offskin-
demosputhe same three on the recorded demo (base): the two bots' player models are skinned too, more work than the gun alone (the user, 2026-10-18: the spawn runs showed no demo). With sauerbraten-nonfree-data (the licensed suite) the player models and guns have their real meshes.
demoppe-
demooff-
demothe recorded demo: the same as base (named for the runs made before base became the demo)
nouniFewer GL calls per frame (our cube2 0007-0009, each behind a cvar that is 1 by default; on cave under llvmpipe as GL 2.1 without GL_EXT_gpu_shader4, like the PS3: 1657 GL calls and 199 draws a frame with all off, 1300 and 199 with all on, with the hud gun; the same pixels). Each variant turns one off, to see what it is worth: slot and global shader uniforms sent only when their value changed (gluniformcache)
notmua batch's textures bound together, right before its draw, a glActiveTexture per unit that changes (glbatchtmu)
nopartparticle vertices uploaded by renderers that have particles only, one glBufferData each (glpartvbo)
allbatchoffall of them off: the drawing of ps3.315 and before
rgbspuDXT1 of RGB sources (libspeq 2026-10-18, packages/walnut/tools/ps3-spu/doc/dxt-rgb.md): the JPG and other alpha-less textures reach libspeq as 3 bytes a pixel ("speq: s3tc dxt1 ... comps 3" lines), which it used to encode on the PPE (165 ms for a 1024x1024, a hitch mid-game); now the SPEs take them. rgbppe sends them back to the PPE encoder (the old behaviour), rgbspu is the default with the same logging, so the pair differs in the switch alone: stall_cpu_s, load time and the "comps 3 ... spu/ppe" lines.
rgbppe-
oqlagThe water's occlusion query (docs/HOTPATHS.md, target 1): drawreflections waited for this frame's result, the GPU behind (10% of the CPU spun in nv30_query_result). oqlag: our cube2 0010's oqwaterlag 1, this frame's result only if it is in, else last frame's (the first frame water shows again has its last reflection); oqnowait: the stock oqwait 0, every query not in yet counts as visible (the reflection passes then run whenever the result is late). The Mesa side is an ENVS token: NV30_QUERY_WAIT=US sleeps on the fence after US microseconds of spinning (base, pixels the same)
oqnowait-
shortnormalsWorld normals and tangents as GL_SHORT normalized (our cube2 0011, vanormalshort; docs/MEMORY.md): nv30 can't fetch the stock GL_BYTE ones, so u_vbuf converts them at every world draw and nouveau keeps a malloc copy of every world vertex buffer to read them from. shortnormals uploads them as shorts (the RSX fetches those: no conversion, no copies; cave's world buffers 4.40 -> 5.50 MB of VRAM); off by default (on llvmpipe ~170 pixels a frame differ by 1-2 levels). bytenormals is the stock layout spelled out. With NV30_SYSMEM_STATS=300 (an ENVS token, Mesa 0037) the sysmem_* columns show the copies go
bytenormals-

One table, a header row per batch (what it tested and what came out). Conditions: what a variant adds to the recipe (its environment switches) and what ran alongside (the stall recorder, a profiler); a column appears only when this game has a value in it. Rows marked invalid or not comparable say why.

What the run length means

"warm-up + 120 s" is a steady-state run, which leaves out a 60 s warm-up and measures 120 s or more; "whole run" counted everything from the start, the way runs before 2026-10-17 did.

Variant Conditions Steady fps
in the window
1% low
fps
Stalls
frames over 100 ms
fps
whole run
Build Run length ram free
MiB
vram
MiB
stall play s
seconds
longest play ms
ms
sound faults per min
faults a minute
cpu
seconds
underruns
underruns
longest ms
ms
stall disk s
seconds
stall swap s
seconds
stall reclaim s
seconds
stall gpu s
seconds
stall cpu s
seconds
Note
Suite summary 2026-10-20 · suite-summary-2026-10
Tested: Not a test run: the suite's 13 benchmarked games (15 rows, with OpenArena's two renderers and OpenTTD's two blitters) gathered with their known numbers as of October 2026, each value naming the batch or document it came from.
Result: It is the calibration of the rating formula (rules 1): the scale was tried on these numbers before any game was rated, and the GameDB calibration table is generated from it. Benchmarks never give a medal; medals come from played sessions only.
BananaBread the recipe as it is 39.1 25.6 - - - warm-up + 120 s 25 117 0.1 103 40 - - - - - - - - right, 60-181 underruns a run
batch ssdroot11 Mesa 0044: NV30_MINMAX_VMX=1 against unset on Sauerbraten base and OpenArena gl2min x3 (SSD root .472 Mesa ps3.545~dev) 2026-10-20 · 2026-10-20-ssdroot11-minmax-vmx
Tested: Whether Mesa 0044 (the AltiVec index scan) helps or hurts games other than SuperTuxKart: BananaBread and OpenArena opengl2, three rounds.
Result: Neutral in both (39.37 against 39.64 fps, 61.7 against 62.7), as their draws rarely run the scan. 0044 only pays where those loops run, in SuperTuxKart.
What we saw

12 runs rotated, none interfered.

  • BananaBread: 39.64 fps unset against 39.37 with 0044 (x0.993). 1% low 26.9 against 25.7. Load 7.0 against 7.2 s.
  • OpenArena opengl2: 62.7 against 61.7 fps (x0.984). 1% low 7.6 against 7.5.
base stall recorder at 10 ms 39.6 26.9 0 36.2 Kernel ps3.472, Mesa ps3.545~dev warm-up + 120 s 23.0 117.0 0.0 78.2 - 230.4 141 78.2 0.0 0 0 0 0
base stall recorder at 10 ms
switch minmax_vmx1
39.4 25.7 1 36.1 Kernel ps3.472, Mesa ps3.545~dev warm-up + 120 s 26.5 117.0 0.2 139.1 - 232.4 154 139.1 0 0 0 0 0.1
batch ssdroot7 DUMPON=1 repro of the OpenAL wedge: SuperTuxKart x4 OpenArena x3 ClassiCube x3 Sauerbraten x3 (SSD root .472 Mesa ps3.545~dev) 2026-10-19 · 2026-10-19-ssdroot7-openal-wedge
Tested: How often OpenAL's sound output wedges (stops) in four games, with a full system dump taken the moment it happens, to find the cause.
Result: The wedge hit 3 of 4 SuperTuxKart runs, 1 of 3 OpenArena, 1 of 3 ClassiCube and none of 3 BananaBread, as early as 21 s in. The dumps showed the sound card's DMA stopping in the kernel's snd_ps3 driver. Investigation runs: their numbers are not for comparison.
What we saw

Investigation runs, not for fps: a dump freezes the game for seconds, and the dump mode itself costs (OpenArena's window was 71 s at 57 fps against 94 s at 62 fps without it). Only the 8 of 13 runs without a dump have numbers, and they are not comparable with other batches.

  • Webcam picture right in all 13 runs.
  • Runs where OpenAL wedged: SuperTuxKart 3 of 4 (dumps at 48, 33 and 286 s), OpenArena 1 of 3 (at 21.6 s), ClassiCube 1 of 3 (at 103.6 s), BananaBread 0 of 3 (underruns 96-171).
  • The dumped SuperTuxKart runs left no result; their counts come from the game log and they make no numbers.
  • Finding from the dumps: the sound card's DMA stops (the snd_ps3 driver's interrupt chain).
base stall recorder at 10 ms 39.4 26.3 1 36.0 Kernel ps3.472, Mesa ps3.545~dev warm-up + 120 s 24.3 117.0 0.1 128.9 - 231.6 152 128.9 0 0 0 0 0.1
batch ssdroot7 Mesa 0042: NV30_QUERY_KICK=2 and =0 against unset on Sauerbraten base x3 (SSD root .472 Mesa ps3.545~dev) 2026-10-19 · 2026-10-19-ssdroot7-query-kick
Tested: Whether Mesa 0042 (submitting a query's batch when its result is wanted instead of at its end; modes 2 and 0) cuts BananaBread's CPU time, whose water reflection query spent 5.6% there; three rounds.
Result: Neutral: 39.8 and 39.6 fps against 39.4 unset, inside a 1 fps spread, and the CPU time unchanged at 231-232 s. Nothing to turn on.
What we saw

9 runs rotated, 3 per arm, none interfered, webcam picture right in all.

  • Steady fps: unset 39.4, mode 2 39.8 (+1.2%), mode 0 39.6. All inside a 1 fps spread.
  • 1% low 26.6 unset against 27.1 with either mode. Gameplay stalls: 0-1 frames unset (0.2 s at most), 1-3 with mode 2 (0.1-0.4 s), 1 with mode 0.
  • CPU 231 s unset, 231 s with mode 2, 232 s with mode 0: the expected 5% saving is not there.
  • Not in this batch: a Mesa 0043 run that wedged the GPU (analysed separately), and two Endless Sky smoke runs killed when VRAM ran out.
base stall recorder at 10 ms 39.4 26.6 1 36.2 Kernel ps3.472, Mesa ps3.545~dev warm-up + 120 s 23.3 117.0 0.2 159.5 - 231.4 141 159.5 0.0 0 0 0 0.1
base stall recorder at 10 ms
switch query_kick0
39.6 27.1 1 36.3 Kernel ps3.472, Mesa ps3.545~dev warm-up + 120 s 24.4 117.0 0.1 130.3 - 232.4 132 130.3 0 0 0 0 0.1
base stall recorder at 10 ms
switch query_kick2
39.8 27.1 1 36.6 Kernel ps3.472, Mesa ps3.545~dev warm-up + 120 s 26.5 117.0 0.2 136.9 - 231.3 134 136.9 0 0 0 0.0 0.1
batch ssdroot6 libpng: libpng16 1.6.59 +ps3.560 against Debian's stock on SuperTuxKart lean x3 and Sauerbraten base x3 and OpenArena gl2min x2 (SSD root .472 Mesa ps3.545~dev zlib-ng on both arms) 2026-10-19 · 2026-10-19-ssdroot6-libpng
Tested: Whether our libpng (1.6.59 +ps3.560) cuts load times against Debian's, mainly on SuperTuxKart, whose load profile showed 4 s of PNG decoding; BananaBread and OpenArena as controls, zlib-ng on in both arms.
Result: Yes for SuperTuxKart: PNG decoding in the load fell from 4.0 to 1.6 s (-60%, as predicted) and the whole load from 30.3 to 27.6 s (-9%), with gameplay unchanged. Nothing measurable for BananaBread and OpenArena. Our libpng later replaced Debian's on the PS3.
What we saw

Webcam picture right in all runs.

  • SuperTuxKart, 3 rounds: round 1 was interfered (a login and mouse moves) and left out, so 2 runs per arm.
  • SuperTuxKart's PNG decoding in the load: 4.0 s with Debian's library against 1.6 s with ours (-2.4 s, -60%). The zlib part stays 3.4 s in both.
  • SuperTuxKart's load: 30.3 s against 27.6 s (-2.8 s, -9%). The main thread's CPU over the load: 24.0 against 21.1-21.7 s.
  • SuperTuxKart gameplay unchanged: 20 against 19.5 fps (HUD), 1% low 11.9 against 11.5, 10 frames over 100 ms in both.
  • One SuperTuxKart run with Debian's library aborted after the full race; cause not looked at.
  • BananaBread: load 7.19 against 7.25 s, 39.5 fps in both. libpng is too small a part of its load to show.
  • OpenArena (control, 2 runs): load 6.80 against 6.62 s, 63.1 against 61.1 fps (noise). CPU 231-241 s with Debian's libraries against 211 s with ours, not explained.
  • OpenAL's wedge messages (its sound output stalling) showed in 8 of the 10 SuperTuxKart runs of this and the previous batch, in both arms.
base stall recorder at 10 ms
switch zng
39.4 26.6 0 36.4 Kernel ps3.472, Mesa ps3.545~dev warm-up + 120 s 25.1 117.0 0.0 86.7 - 231.6 123 86.7 0.0 0 0 0 0
base stall recorder at 10 ms
switch zng
switch ldstock-png
39.5 27.1 0 36.6 Kernel ps3.472, Mesa ps3.545~dev warm-up + 120 s 21.8 117.0 0.0 95.3 - 231.8 113 95.3 0.0 0 0 0 0
batch ssdroot5 load-time libraries: libvorbis +ps3.549 and zlib-ng against stock on SuperTuxKart lean and Sauerbraten base x3, JSIMD=none x2 (SSD root .472 Mesa ps3.544) 2026-10-19 · 2026-10-19-ssdroot5-load-libraries
Tested: Whether our libvorbis (+ps3.549) and zlib-ng shorten load times against Debian's libraries, on SuperTuxKart and BananaBread, three rounds; plus two runs with libjpeg-turbo's AltiVec code turned off to see whether it is in use.
Result: Small gains on SuperTuxKart's load: 0.7 s from libvorbis and 0.9 s from zlib-ng. BananaBread's load and all frame rates were unchanged. Both libraries became defaults later (our libvorbis replaces Debian's; zlib-ng is loaded for every game), and the AltiVec test showed libjpeg-turbo's AltiVec path is in use.
What we saw

Load-time profiling on, 22 runs.

  • SuperTuxKart load: 31.5 s with our libvorbis against 32.2 s with Debian's (-0.7 s); 30.6 s with zlib-ng (-0.9 s).
  • SuperTuxKart with libjpeg-turbo's AltiVec code off: 32.6 s (+1 s), so that code is in use.
  • BananaBread's load unchanged within the spread (8.4, 7.5 and 8.1 s).
  • Gameplay frame rates unchanged.
base stall recorder at 10 ms
start-up profile
39.1 25.3 2 35.2 Kernel ps3.472, Mesa ps3.544 warm-up + 120 s 21.4 117.0 0.3 221.0 - 234.0 157 221.0 0.0 0 0.1 0 0.2
base stall recorder at 10 ms
start-up profile
switch ldstock-vorbis
39.4 25.9 2 34.9 Kernel ps3.472, Mesa ps3.544 warm-up + 120 s 22.1 117.0 0.2 146.0 - 223.2 120 146.0 0 0 0 0 0.1
base stall recorder at 10 ms
start-up profile
switch zng
39.1 25.4 0 35.4 Kernel ps3.472, Mesa ps3.544 warm-up + 120 s 23.1 117.0 0.0 82.8 - 233.7 165 82.8 0.0 0 0 0 0
batch ssdroot2 P2: ps3rsx shadow_fast (PS3RSX_SHADOW_FAST=1 against off, STALLS=1) 2026-10-19 · 2026-10-19-ssdroot2-shadow-fast
Tested: A faster path in the ps3rsx kernel driver for copying GPU commands (shadow_fast), switched on and off on ClassiCube, BananaBread and X-Moto.
Result: No gain in frame rate, stalls or CPU on any of the three games, so the switch stays off. The code it touches is only 2-6% of the CPU in the first place.
What we saw
  • Same boot, two runs per arm interleaved, kernel .472, ps3rsx 0.443, set per run and put back.
  • ClassiCube: steady 46.11 fps in both arms. 1% low 30.1 off, 29.7 on. CPU 80.3 against 86.3 s, within the 79.8-86.6 s the same setup showed across the boot.
  • BananaBread: 39.15 fps off against 39.7 on (the unprofiled baseline spread is 39.06-40.3). Stalls 0.05 against 0.15 s, VRAM equal.
  • X-Moto: 158.4 against 159.0 fps, 1% low 98.1 against 97.5.
  • No gain resolved at two runs on three games; the switch stays off.
  • In the ClassiCube and BananaBread profiles, the code the switch affects is 2-6% of the CPU, the most it could save.
base stall recorder at 10 ms 39.2 25.6 0.5 36.1 - warm-up + 120 s 27.5 117.0 0.1 95.6 - 233.7 160.0 95.6 0.1 0.0 0.0 0.0 0.1
base stall recorder at 10 ms
switch rsx_shadow_fast1
39.7 26.1 1.0 36.3 - warm-up + 120 s 20.8 120.3 0.1 118.3 - 229.4 115.0 118.3 0.1 0.0 0.0 0.0 0.1
batch ssdroot2 P2: Mesa 0038 NV30_FORCE_DXT=opaque against off (MEM=1 STALLS=1 NV30_FORCE_DXT_STATS=50) 2026-10-19 · 2026-10-19-ssdroot2-force-dxt
Tested: Mesa 0038, a switch that compresses opaque textures to DXT on upload to save VRAM, against off on BananaBread, SuperTuxKart and OpenArena.
Result: In BananaBread it cuts peak VRAM from 119.8 MB (the cap) to 73-78 MB with no frame rate change and a slightly softer picture. It compresses nothing in SuperTuxKart and OpenArena, whose textures it skips, so no effect there.
What we saw
  • Same boot, two runs per arm interleaved, both arms with the compression statistics on.
  • BananaBread: 73 textures compressed (88 MB raw to 11 MB stored, all DXT1; 4 turned back, 17 skipped for alpha). Peak VRAM 119.8 MB (the cap) to 73-78 MB. GPU buffers at mid-run 351 to 215 MB. Memory in use -3.5 MB.
  • BananaBread steady 39.9 fps off against 39.0 on (unprofiled baseline runs span 39.1-40.3, so no fps change resolved). 1% low 26.0 against 23.9 (two runs, spread 22.9-26.2). Stalls 0.5 against 0.55 s.
  • BananaBread's picture is slightly softer and darker on the webcam (grey difference 10, against 1-2 between repeats): lossy, as expected.
  • SuperTuxKart lean: nothing compressed (182 textures skipped for alpha, 173 for format, 22 too small, 6 non-power-of-two; the game's own compression already covers its opaque ones). VRAM 98.5 against 97.3 MB, HUD 20 against 21 fps, stalls 2.8 against 1.7 s: noise.
  • OpenArena OpenGL 2: nothing compressed (2238 uploads in formats the switch does not take). VRAM 120.1 against 119.7 MB, steady 56.3 against 55.8: no effect.
  • OpenArena ran 56 fps in both arms against 60-63 unprofiled earlier the same boot: the statistics or drift, not separated.
base stall recorder at 10 ms
switch force_dxt_stats50
40.0 25.9 4.0 36.5 - warm-up + 120 s 21.4 117.0 0.5 184.5 - 218.3 65.5 184.5 0.0 0.0 0.2 0.0 0.2
base stall recorder at 10 ms
switch force_dxtopaque_force_dxt_stats50
39.0 23.9 4.0 36.0 - warm-up + 120 s 26.5 73.8 0.6 176.5 - 234.1 173.0 176.5 0.1 0.0 0.1 0.0 0.4
batch ssdroot2 P1b: gameplay profiles on the SSD root (PERF=1 MEM=1 x1) 2026-10-19 · 2026-10-19-ssdroot2-gameplay-profiles
Tested: Where the CPU goes during play in seven games on the SSD root, profiled with perf over the measured window.
Result: Mesa is the biggest share in BananaBread (62.8%) and ClassiCube, the game itself in SuperTuxKart, OpenArena and Luanti, and OpenTTD spends half its time in the kernel. Profiled runs, not for frame rates; OpenTTD was profiled at its title screen, not in play.
What we saw
  • Same boot, one run per game, perf at 499 Hz over the window. Profiled runs are for profiles, not fps (OpenArena 56 against 60 unprofiled).
  • Share of the game process's samples:
  • BananaBread: Mesa 62.8%, the GPU kernel driver 4.8, the game 10.5.
  • ClassiCube: Mesa 41.2, kernel 20.1, the GPU kernel driver 7.1.
  • SuperTuxKart: the game 36.5, Mesa 35.5, libc 15.1.
  • OpenArena: the game 27.6, Mesa 23.1, other 20.4 (OpenAL 12.4, libdeflate 3.9).
  • Luanti: the game 47.2 (its mesh-update thread 20.7% of all samples), Mesa 14.6, libc 13.7.
  • dsda-doom: Mesa 22.3, the game 20.5, audio 30 (FluidSynth 15, libspeq 12).
  • OpenTTD: kernel 49.5 (36.7 replaying deferred interrupts, 8.3 page table invalidation, 5.1 clearing GPU memory mappings when buffers are created), audio 17. It ran at its title screen (a menu, not gameplay: 18 fps, 4172 underruns).
  • Mesa has no symbols in these profiles (to be resolved on the PC later). SuperTuxKart's fps is the HUD's.

not comparable gameplay profiles (PERF=1 MEM=1), slower than plain runs.
base
not comparable
perf recording 38.3 23.5 3 36.1 - warm-up + 120 s 25.1 117.0 0.4 164.9 - 236.0 171 164.9 - - - - -
batch ssdroot2 P1a: start-up profiles on the SSD root (PERF_LOAD=1 STALLS=1 x1) 2026-10-19 · 2026-10-19-ssdroot2-startup-profiles
Tested: Where the start-up time goes now that the system runs from the SSD: one profiled start of each of five games, from a cold cache.
Result: Loads are 39-61% shorter than on USB and are now mostly CPU work on the main thread (47-77%), with the disk only 13-26%. The biggest remaining costs are named per game (map inflate, PNG and zlib decoding, Luanti's map generation). Profiled runs, not for frame rates.
What we saw
  • Same boot as the SSD baseline, cold page cache, one run per game.
  • Time to the end of the loading screens, against the USB profiles of batch 17: BananaBread 7.7 s (19.8), OpenArena 14.2 (28.1), Luanti 26.1 (43.1), SuperTuxKart 31.5 (54.3), ClassiCube 7.5 (13.9). That is -39 to -61%.
  • The main thread's disk wait in the load fell from 4.8-18.6 s to 1.0-3.2 s (BananaBread 1.9, OpenArena 2.1, Luanti 3.0, SuperTuxKart 3.2, ClassiCube 1.0).
  • The main thread's CPU stayed about the same (BananaBread 3.9 s against 4.1, OpenArena 8.7 against 9.0, SuperTuxKart 23.8 against 22.5, ClassiCube 3.2 against 2.9).
  • So loads are now 47-77% CPU on the main thread, not fully CPU-bound: disk 13-26%, the rest GPU, memory reclaim, waiting to run and sleeps.
  • Biggest costs now: BananaBread zlib 1.6 s (inflating the map); OpenArena the game's own load path 3.9 s (shader scripts, mipmaps); Luanti map generation 8.6 s plus a 15 s hold; SuperTuxKart PNG 4.2, zlib 3.9, audio 2.2 and JPEG 2.1 s; ClassiCube the game 1.5 s and the dynamic linker 0.6 s.
  • Profiled runs are for profiles, not fps.

not comparable start-up profiles (PERF_LOAD=1 STALLS=1), slower than plain runs.
base
not comparable
stall recorder at 10 ms
start-up profile
38.8 25.2 0 35.3 - warm-up + 120 s 23.0 117.0 0.0 84.0 - 235.5 160 84.0 0 0 0 0 0
batch ssdroot1+2 A: baseline on the SSD root (kernel .472 Mesa .476 ps3rsx 0.443 ps3-gpu-tools 0.477~dev) 2026-10-19 · 2026-10-19-ssdroot1-baseline
Tested: A new baseline with the whole system running from the internal SSD instead of a USB disk, on five games, to see what it does to loads, stalls and frame rates. This console has an upgraded SSD; a stock PS3 has a hard disk.
Result: Loads are 35-58% shorter (BananaBread 16.9 to 7.1 s, SuperTuxKart 53.6 to 31.1 s) and BananaBread's gameplay stalls almost vanish, while frame rates stay about the same apart from OpenArena (55.9 to 60.4). It also showed SuperTuxKart's own "Average FPS" is its physics tick rate, so its fps is taken from the HUD from here on.
What we saw
  • Same boot, kernel 6.12.111+ps3.472, root on the internal SSD (an upgraded SSD; a stock PS3 has a hard disk).
  • 5 of 17 runs left out as interfered (SSH logins, a key press, a polling loop at the batch switch).
  • Load against the USB root (other boots, older Mesa for some games): BananaBread 7.1 s against 16.9, OpenArena 6.9 against 10.7, Luanti 25.0 against 40.8, SuperTuxKart 31.1 against 53.6, ClassiCube 7.6 against 14.2.
  • The load's disk wait: 1.3-3.4 s against 5.5-10.9 s.
  • Gameplay stalls: BananaBread 0.05 s against 1.6, OpenArena 0.2 against 0.3, Luanti 3.5 against 2.5 (memory reclaim 1.6 s against 0.4), SuperTuxKart 0.2 s (one run).
  • Steady fps about the same: BananaBread 39.1 against 38.5, Luanti 46 against 46, SuperTuxKart 22 (HUD) against 20, ClassiCube 48.1 against 45.9 (falling to 46.1 later in the session with nothing changed). OpenArena gained: 60.4 against 55.9.
  • SuperTuxKart's own 'Average FPS' (105-111) is its physics tick rate (120 Hz for 180 s, 21602 ticks in every run), not rendered frames. Its fps cells are the HUD median from now on.
  • Photos show the right scenes. Luanti's photos at 60 and 150 s fall on the flight path's turn over the sea (cyan, no terrain), because the load is shorter than on USB: not a missing world.
  • Microphone: OpenArena audible; the other games mostly at the room-hum level.
base stall recorder at 10 ms 39.1 25.5 1.5 36.0 Kernel ps3.472, Mesa ps3.476, ps3rsx 0.443 warm-up + 120 s 24.9 117.0 0.2 123.9 - 234.0 169.0 123.9 0.0 0.0 0.0 0.0 0.2
batch ssd1: SSD game data and SSD swap spill against the USB disk (Sauerbraten base x3, OpenArena gl2min) 2026-10-18 · 2026-10-18-ssd1
Tested: Whether putting game data, and also the swap overflow, on an SSD instead of the USB disk shortens loads and stalls in BananaBread and OpenArena.
Result: Game data alone on the SSD leaves BananaBread unchanged, because its binaries, libraries and shader cache still load from USB. OpenArena loads 28% faster, but with too few runs to be more than indicative.
What we saw
  • Same boot, kernel 6.12.111+ps3.472, root on USB. Three arms: all on USB, game data on the SSD, game data and swap on the SSD.
  • BananaBread, three complete rounds (9 runs): the SSD lifts only the game data. The load's disk wait stays 4.8-5.5 s (USB 5.5, SSD 4.9, SSD plus swap 5.4).
  • BananaBread load 16.9, 15.9, 16.4 s; the gap is round 1's cold start (round 3: 15.4, 15.4, 15.3). Stalls 1.6, 1.0, 1.6 s; 1% low 24.1, 26.4, 24.1; steady 38.5, 39.3, 38.5 fps. No clear effect.
  • OpenArena OpenGL 2: load 10.7 s on USB to 7.7 and 7.6 s on the SSD (-28%). Map-reload stalls in the window 52 to 41-44 s. Gameplay-only stalls about 0 in every arm, steady 55.9-56.1 fps. Only 2, 1 and 3 runs per arm: indicative.
  • One OpenArena SSD run left out (a key press at 195 s). A last OpenArena run was killed by the operator and is invalid.
  • The picture showed in all 16 runs.
base stall recorder at 10 ms 38.5 24.1 4 32.7 - warm-up + 120 s 19.7 117.0 1.6 459.1 - 234.8 184 459.1 0.2 0.0 0 0 0.2
base stall recorder at 10 ms
switch gdssd
39.3 26.4 3 34.2 - warm-up + 120 s 21.3 117.0 1.0 406.9 - 230.5 127 406.9 0.0 0.0 0 0 0.1
base stall recorder at 10 ms
switch gdssd
switch swssd
38.5 24.1 5 33.7 - warm-up + 120 s 21.3 117.0 1.6 454.3 - 233.6 153 454.3 0.2 0.0 0 0 0.2
batch 17: ETR uncapped, start-up profiles x5, shader cache cold/warm, OpenArena gl2 memory variants, Mesa sysmem switches, Sauerbraten shortnormals 2026-10-18 · 2026-10-18-batch17
Tested: A mixed batch: ioquake3 462's new colour path and memory variants for OpenArena's OpenGL 2 renderer, Mesa's system-memory copy switches, BananaBread's short normals, a warm shader cache, Extreme Tux Racer without a frame cap, and start-up profiles.
Result: ioquake3 462 cuts OpenArena's stalls from 9-11 s to 0.7-2.6 s at 57-60 fps, Mesa's system-memory switches fix the old colour path's stalls, and BananaBread's short normals give +17%. The shader cache gives no faster loads and Extreme Tux Racer's 59 fps is not a vsync cap.
What we saw
  • Same boot as batch 16 (kernel .433), ioquake3 462, Mesa 442~dev, cube2 442~dev. One BananaBread run with a key press left out.
  • OpenArena OpenGL 2 on ioquake3 462 (compact colours by default): steady 57-60 fps, stalls 0.7-2.6 s. On the 396 build in batch 16: 51-53 fps and 9-11 s.
  • The old 16-bit colour path: 52-53 fps, 12.9 s of stalls, 20 s of swap stalls.
  • Packed animated model frames: 20 MB less VRAM, same stalls. Gamma-correct mipmaps computed per channel: the lowest stalls (0.7-0.9 s).
  • Mesa's system-memory copy plus buffer invalidation on the old colour path: stalls 9.9 and 12.3 s to 1.5 and 1.4 s, swap stalls 20-26 s to 0.6-1.1 s, steady 53-54 to 59 fps.
  • BananaBread with short normals: 38.7 to 45.4 fps (+17%), stalls equal, VRAM +4 MB.
  • Shader cache cold against warm: no load gain (OpenArena 10.3 s cold, 10.6 s warm; BananaBread 17.4 against 18.4 s).
  • Extreme Tux Racer without a frame cap: still 59 fps, so not a vsync cap.
base stall recorder at 10 ms
start-up profile
37.8 23.9 5 30.6 - warm-up + 120 s 16.9 117.0 1.5 547.3 - 238.9 202 547.3 0.3 0.1 0 0.0 0.2
base stall recorder at 10 ms
start-up profile
switch sccold
38.0 24.4 5 31.4 - warm-up + 120 s 16.0 117.0 1.3 460.0 - 238.6 183 460.0 0.3 0.1 0 0 0.3
base stall recorder at 10 ms
start-up profile
switch scprime
37.6 24.0 3 30.6 - warm-up + 120 s 21.9 117.0 1.2 525.7 - 238.8 184 525.7 0.5 0.1 0 0 0.1
base stall recorder at 10 ms
start-up profile
switch scwarm
38.7 24.7 5 32.5 - warm-up + 120 s 24.2 117.0 1.5 474.2 - 236.2 183 474.2 0.1 0.0 0.1 0 0.2
base stall recorder at 10 ms
switch sysmem_stats300
38.8 25.0 4 33.0 - warm-up + 120 s 19.1 117.0 1.2 473.4 - 234.7 167 473.4 0.1 0.0 0 0 0.2
shortnormals stall recorder at 10 ms
switch sysmem_stats300
45.1 30.4 4.0 38.4 - warm-up + 120 s 19.6 121.0 1.6 511.5 - 236.4 183.0 511.5 0.3 0.0 0.0 0.0 0.2
batch 16: game prefetch A/B, idle fix on/off (433), ClassiCube chunks1, X-Moto stream, Luanti lean parts 2026-10-18 · 2026-10-18-batch16
Tested: Several checks on kernel .433: a game-data prefetch, the idle-CPU fix on and off, ClassiCube's chunk setting, X-Moto's streaming draw path, and the parts of Luanti's lean settings one at a time.
Result: The prefetch gives no gain and makes Luanti worse, so it was turned off by default. The idle fix is confirmed clean (gameplay stalls 0.4 s against 8-9 s); ClassiCube's chunk setting gains 4.7% and X-Moto's streaming 1%. Luanti's chunk size 3 is what empties the world in lean.
What we saw
  • Same boot, kernel .433 with the idle fix and no kicker, interference detector on (3 runs disturbed by SSH logins left out).
  • Prefetch against none, three runs each: no gain. BananaBread load 18.1-18.6 s against 15.2-18.8; OpenArena OpenGL 2 about 0.5 s faster; Luanti worse (load +1-4 s, two runs with 3 s hitches). Default turned off.
  • Idle fix on and off, two runs each: gameplay stall time 0.4 and 0.4 s against 9.0 and 7.9 s, longest frame 0.22-0.38 s against 2.2-2.8 s. Clean.
  • ClassiCube's alternative chunk drawing: 48.1 fps against 46.0 (+4.7%).
  • X-Moto with its streaming draw path: 162.1 against 160.6 (+1%).
  • Luanti with chunk size 3 renders a black void at 150 s: it is the part of lean that empties the world. Server unloading and active block range 2 render, but stall more (6.3 and 6.7 s against about 2.5).
base stall recorder at 10 ms 38.8 24.1 4 32.4 - warm-up + 120 s 22.0 117.0 1.4 514.0 - 235.0 159 514.0 0.1 0.0 0 0 0.2
base stall recorder at 10 ms
switch gpffetch
38.8 25.3 2 32.8 - warm-up + 120 s 21.6 117.0 1.0 517.6 - 235.4 185 517.6 0.2 0.0 0 0 0.1
Sauerbraten NV30_QUERY_WAIT=200 repeat (Mesa ps3.416~dev, kick) 2026-10-18 · 2026-10-18-query-wait-repeat
Tested: A repeat of BananaBread with the occlusion query wait capped at 200, to check the 45.6 fps single run of the previous batch.
Result: No gain: 23.0 and 33.4 fps against 26.0 and 37.9 without the cap; the earlier result was a lucky single run. The switch stays off.
What we saw
  • Same boot, two runs each, interleaved.
  • Steady fps: 26.0 and 37.9 without the cap, 23.0 and 33.4 with it. Smooth fps: 30.0 and 40.3 without, 32.1 and 35.9 with.
  • No gain; the earlier 45.6 was a lucky single run.
  • CPU lower with the cap: 96-197 s against 151-232 s.
  • Run-to-run swing is large in the first-person demo, so subtle A/Bs need more rounds. The switch stays off.
base waker kick at 10 ms 32.0 13.9 13.0 30.9 Mesa ps3.416~dev warm-up + 120 s 19.4 119.1 2.8 456.5 - 191.5 130.0 456.5 - - - - -
base waker kick at 10 ms
switch query_wait200
28.2 10.2 12.0 30.7 Mesa ps3.416~dev warm-up + 120 s 18.9 119.1 4.6 1777.2 - 146.6 121.5 1777.2 - - - - -
Mesa ps3.416~dev hot spots (staging pool, query wait), cube2 355 oqlag, xmoto 362 stream, ClassiCube chunks1 (kick) 2026-10-18 · 2026-10-18-mesa-416-hot-spots
Tested: Fixes for driver hot spots in Mesa ps3.416 (a staging buffer pool, a cap on waiting for occlusion queries) and game-side changes: BananaBread's lagged water occlusion queries, X-Moto's streaming draw path and ClassiCube's chunk setting.
Result: ClassiCube's chunk setting gains 5% and X-Moto's streaming shortens the worst frame; the staging pool saves 4% CPU at the same frame rate. BananaBread's big jump with the query wait cap was a single run and did not hold up in the repeat.
What we saw
  • Same boot, one run each. BananaBread's demo is now first-person with the full data (gun and HUD visible): heavier than the earlier spectator runs, not comparable.
  • ClassiCube with its alternative chunk drawing (neighbouring faces in one draw): 50.9 fps against 48.4 (+5%). The staging pool: same fps, CPU -4%.
  • BananaBread: as built 25.0 fps steady and 30.3 smooth. With the query wait capped at 200: 45.6 and 50.0, 1% low 4.9 to 16.9. With the water's occlusion queries lagged a frame: 39.4 and 43.5. Single runs, repeat pending.
  • X-Moto with its streaming draw path: 163.1 fps against 160.4, longest frame 146 against 404 ms.
base waker kick at 10 ms 25 4.9 28 30.1 Mesa ps3.416~dev warm-up + 120 s 15.0 119.7 8.6 900.4 - 153.3 151 900.4 - - - - -
base waker kick at 10 ms
switch query_wait200
45.6 16.9 18 27.7 Mesa ps3.416~dev warm-up + 120 s 18.5 119.7 5.7 998.3 - 202.3 156 998.3 - - - - -
oqlag waker kick at 10 ms 39.4 14.7 20 35.5 Mesa ps3.416~dev warm-up + 120 s 17.9 119.7 8.2 1531.0 - 228.9 164 1531.0 - - - - -
batch 8: STK lean, OpenTTD gl, ClassiCube/dsda batching, malloc presets, profiles (Mesa ps3.408, kick) 2026-10-18 · 2026-10-18-batch8
Tested: A mixed batch: SuperTuxKart's lean settings, OpenTTD's OpenGL driver, draw batching in ClassiCube and dsda-doom, memory allocator presets, and profiles of OpenArena and Luanti.
Result: SuperTuxKart lean runs 21.4 fps against 13 with far fewer stalls, OpenTTD's GL driver doubles its frame rate, dsda-doom's batching gains 3% while ClassiCube's loses 4%, and the allocator presets were noise. One Luanti profiling run was disturbed by a mouse click.
What we saw
  • Same boot.
  • SuperTuxKart: the track draws (webcam). Lean settings 21.4 fps smooth against 13 as built, stalls 2.4 against 13.5 s.
  • OpenTTD with the GL driver: right picture, 21 fps (8-12 with software drawing).
  • ClassiCube with batching 47.3 fps against 49.4 with the old drawing (-4%), but 1% low 31 against 27.6.
  • dsda-doom GL renderer with batching 55.9 against 54.2 (+3%), 1% low 40.8 against 36.5.
  • Memory allocator presets: inconsistent between rounds (noise).
  • OpenArena OpenGL 2 renderer: 55 s of stalls, longest 16 s, 66 MB swapped out. Luanti: 10 s of stalls, 51 MB swapped out.
  • Interference (found by the later scan): the profiled Luanti run had a right click in its measured window, so distrust that cell.
base waker kick at 10 ms 39.2 26.4 6.0 30.7 Mesa ps3.408 warm-up + 120 s 23.2 117.0 2.1 690.2 - 231.5 167.0 690.2 - - - - -
base waker kick at 10 ms
switch mmmap
39.9 19.8 9.0 35.1 Mesa ps3.408 warm-up + 120 s 19.9 118.3 2.1 538.1 - 193.2 133.5 538.1 - - - - -
base waker kick at 10 ms
switch mtrim
38.2 21.5 8.0 33.9 Mesa ps3.408 warm-up + 120 s 21.5 117.7 2.0 462.6 - 232.1 118.5 462.6 - - - - -
ioquake3 ps3.396 (r_keepImages + cl_preloadLate), libspeq 0.394 (RGB DXT on SPEs), Mesa ps3.408 default LUT; recorder + kick 2026-10-18 · 2026-10-18-ioquake3-396
Tested: ioquake3 ps3.396, which keeps loaded images and preloads the late-loading ones so OpenArena stops loading in the middle of the demo; also libspeq 0.394's RGB texture compression on the SPUs, on BananaBread.
Result: OpenArena's gameplay stalls go from 9-10 s to none and the steady rate rises from about 65 to 70.6 fps. BananaBread shows no difference because its demo uploads no RGB textures to compress; on its own the SPU compressor is far faster than the PPE.
What we saw
  • Same boot, two runs each, with the stall recorder and the waker kick. Mesa ps3.408 with the vertex lookup table on by default.
  • OpenArena, keeping images plus preloading against the old loading: gameplay stall time 0.0 and 0.0 s against 9.9 and 9.0 s, longest frame 64 and 47 ms against 1057 and 807 ms, steady 70.4 and 70.8 fps against 64.6 and 65.9.
  • BananaBread, RGB compression on the SPUs against the PPE: identical (39 fps). Its demo uploads no RGB DXT1 textures (only a few DXT5), so the RGB path isn't exercised.
  • The compression test alone: a 1024x1024 RGB texture in 1.0 ms on 4 SPUs against about 175 ms on the PPE.
rgbppe SPEQ_S3TC_RGB=ppe
SPEQ_DEBUG=1
stall recorder at 10 ms
waker kick at 10 ms
39.4 25.8 3.0 33.2 Mesa ps3.408 warm-up + 120 s 23.0 117.0 1.1 478.1 - 232.5 132.5 478.1 0.2 0.0 0.0 0.0 0.1
rgbspu SPEQ_DEBUG=1
stall recorder at 10 ms
waker kick at 10 ms
39.1 25.9 2.5 32.9 Mesa ps3.408 warm-up + 120 s 19.9 117.0 0.7 500.4 - 233.2 145.0 500.4 0.1 0.1 0.0 0.0 0.2
Mesa ps3.407 NV30_TRANSLATE_LUT, yquake2 ps3.408 kiss4k, luanti ps3.405 trim16 (all with WAKER kick) 2026-10-18 · 2026-10-18-mesa-407-lut
Tested: Three changes: Mesa ps3.407's lookup table for 8-bit vertex attributes on BananaBread, Yamagi Quake II's memory cut (kiss4k) and Luanti's trim16 setting.
Result: The lookup table speeds BananaBread up by 53%, and Yamagi's memory cut ends its stalls (22.6 s to 0.05 s). Luanti's trim16 gave no gain and more stalls, so it was rejected.
What we saw
  • Same boot, two runs each, all with the 10 ms waker kick.
  • BananaBread demo with the lookup table for 8-bit vertex attributes: steady 25.9 to 39.6 fps (+53%), 1% low 18.3 to 26.9.
  • Yamagi Quake II with kiss4k: memory in use 125 to 56 MB, swap used 80 to 9 MB, gameplay stall time 22.6 to 0.05 s, longest frame 4.5 s to 91 ms, steady 65.7 to 68.7 fps.
  • Luanti trim16: no gain and more stalls (3.35 to 8.6 s). Rejected.
  • Pictures right on the webcam.
base waker kick at 10 ms 25.9 18.2 4.0 21.7 Mesa ps3.407 warm-up + 120 s 18.4 118.3 1.1 512.3 - 231.6 111.5 512.3 - - - - -
base waker kick at 10 ms
switch translate_lut1
39.6 26.9 4.5 33.4 Mesa ps3.407 warm-up + 120 s 19.0 117.0 1.4 507.1 - 231.1 108.0 507.1 - - - - -
stall recorder (ps3-gpu-tools 0.385), ioquake3 ps3.379 (atlas off), Sauerbraten demo + nonfree data 2026-10-17 · 2026-10-17-stall-recorder
Tested: The first runs with the stall recorder (ps3-gpu-tools 0.385), which logs why each long frame happened, on OpenArena (ioquake3 ps3.379, atlas off) and BananaBread's demo with its full data.
Result: The recorder costs 5.6% of a thread. OpenArena's hitches are CPU work on the main thread (texture and skin loads mid-demo), BananaBread's are disk reads from the USB drive. Fewer OpenArena stalls with the recorder on was left unexplained.
What we saw
  • Same boot. The recorder's own cost: 5.6% of a thread.
  • OpenArena, recorder off and on alternated: stall time 41.4, 17.9, 34.9, 17.6 s. The runs with it on had fewer stalls: unexplained, to be rechecked.
  • OpenArena's stalls are CPU: about 700 ms of main-thread time each, from skin and texture loads in the middle of the demo, with compression on the PPE for RGB textures.
  • BananaBread's demo with skinning on the SPUs, on the PPE, and off: 25.8, 25.5 and 25.3 fps steady, 3-4 stalls each. The causes are file faults and disk reads from the USB hard disk.
  • BananaBread's load is 16.5 s, of which 5.3 s is disk.
  • Picture checked on the webcam.
demooff SPEQ_SKIN=off 25.3 17.6 4 20.6 - warm-up + 120 s 22.0 117.0 - - - 233.7 167 494.2 0.1 0.0 0 0.0 0.3
demoppe SPEQ_SKIN=ppe
SPEQ_DEBUG=1
25.5 18.3 3 21.7 - warm-up + 120 s 24.3 117.0 - - - 233.1 154 511.7 0.3 0.0 0 0 0.1
demospu SPEQ_SKIN=spu
SPEQ_DEBUG=1
25.8 18.8 4 21.8 - warm-up + 120 s 18.2 117.0 - - - 233.3 134 469.3 0.3 0.0 0 0 0.2
Luanti ps3.364 batching, Neverball ps3.370 batching, Sauerbraten libspeq 0.381 skinning (spawn) 2026-10-17 · 2026-10-17-luanti-neverball-batching
Tested: Draw batching in our Luanti (ps3.364) and Neverball (ps3.370) packages against the old drawing, and BananaBread's model skinning on the SPUs, on the PPE through libspeq, or off (libspeq 0.381).
Result: Batching gives Luanti fewer stalls and shorter worst frames, and cuts Neverball's CPU from 80 to 65 s at the same frame rate. For BananaBread libspeq's PPE skinning is best; the SPU path adds hitches. One Luanti batching-off run was later found disturbed by input.
What we saw
  • Same boot.
  • Luanti, batching on against off, two runs each: steady 45.0 against 46.0 fps, stall time 6.25 against 9.1 s, longest frame 1.7 against 3.4 s, no underruns, picture right.
  • Neverball, batching on against old drawing: smooth 78.7 against 79.1 fps, CPU 65 against 80 s, stalls similar. One batched run ended before the measured window (12 demo loops were too few; now 20).
  • BananaBread (spawn point with the gun), one run each: skinning on the SPUs 23.6 fps steady with 21 stalls (4.3 s); on the PPE 28.1 fps with no stalls; off 23.0 with no stalls. libspeq's PPE path is the best; the SPU path adds hitches.
  • Interference (found by the later scan): one Luanti batching-off run had three digs (a mouse button in the game) in its warm-up. The measured window had no logged action, but the batching-off cell includes that run.
offskin SPEQ_SKIN=off 23.0 17.4 0 23.2 - warm-up + 120 s 22.9 117.0 - - - 219.7 96 75.2 - - - - -
ppeskin SPEQ_SKIN=ppe
SPEQ_DEBUG=1
28.1 20.6 0 28.0 - warm-up + 120 s 23.3 116.4 - - - 220.4 102 81.4 - - - - -
spuskin SPEQ_SKIN=spu
SPEQ_DEBUG=1
23.6 12.0 21 28.4 - warm-up + 120 s 22.1 118.8 - - - 217.9 153 614.1 - - - - -
Mesa ps3.262 + ps3rsx 0.249 2026-10-17 · 2026-10-17-mesa-262
Tested: Mesa ps3.262 (patches 0019 to 0025: fewer words sent to the GPU per draw) across the suite, against ps3.246.
Result: Big gains in several games: OpenArena +23%, Yamagi +24%, X-Moto +21%, Extreme Tux Racer and dsda-doom +15%. Armagetron fell from 60 to 51 fps, which the next batches traced. Single runs; BananaBread's drop is a memory stall, not a driver number.
What we saw
  • The patches: no relocations, the texture cache invalidated only after texture changes, no duplicate vertex-format writes, batched vertex program constants. One run per game.
  • Against ps3.246: OpenArena with compressed textures 44.2 to 54.4 fps (+23%), Yamagi 51.4 to 63.9 (+24%), X-Moto 39 to 47 (+21%), Extreme Tux Racer 46 to 53 (+15%), dsda-doom software 33 to 38 with the demo now finishing (+15%), ClassiCube 47.6 to 50.1 (+5%).
  • Neverball 78.2 to 71.5 (noise), QuakeSpasm 70.5 to 66.3 (repeated in the next batch), Luanti 53 to 53.
  • Armagetron dropped from 60 to 51 (driver frame counter).
  • BananaBread reads 28 to 8 on the counter, but it was memory-stalled (13 MB free, killed at the cap): not a driver number, and the cause is uncertain.
  • The kernel's command validator rejected nothing.
  • Single runs.
cpuskel the recipe as it is - - - 8 Mesa ps3.262, ps3rsx 0.249 whole run 12.8 140.3 - - - 120.0 207 - - - - - -
Group 4 smokes (Mesa ps3.246 + ps3rsx 0.249) 2026-10-17 · 2026-10-17-group4-smokes
Tested: First runs of the heavy games with the VRAM swap on: OpenArena's OpenGL 2 renderer with two settings, SuperTuxKart, and BananaBread with GPU and with CPU skinning.
Result: The heavy games are memory-bound, with no driver bug in sight: OpenArena's OpenGL 2 renderer made 10.7 to 13.6 fps with single stalls of 28.3 and 36.3 s. SuperTuxKart refused to start on a big-endian machine, and BananaBread's GPU skinning was far slower than CPU skinning.
What we saw
  • OpenArena, OpenGL 2 renderer with minimal settings (97 shader programs): the first launch hit the 90 s cap before the level loaded. The rerun with 240 s: 13.6 fps average, one 36.3 s stall, 31 fps on the driver's frame counter, 157.8 MB VRAM, free memory down to 9.8 MB.
  • The same with Debian's defaults (115 programs): 10.7 fps, a 28.3 s stall, 23 fps on the counter, 159.7 MB VRAM.
  • Picture right on the webcam, no driver bug seen: the game is memory-bound.
  • SuperTuxKart quit after 29 s with a fatal error: "SPMeshLoader: Not little endian machine" (a model file).
  • BananaBread with GPU skinning ran to the 170 s cap with 0 on the counter and no fps line (the game plan has 11 fps by its own counter, against 28 for CPU skinning).
  • BananaBread with CPU skinning: 19.6 fps over 601 frames, longest frame 380 ms, 135 MB VRAM, load 27 s.
  • Single runs.
base the recipe as it is - - - 0 Mesa ps3.246, ps3rsx 0.249 whole run 11.3 140.8 - - - 145.0 202 - - - - - -
cpuskel the recipe as it is - - - 19.6 Mesa ps3.246, ps3rsx 0.249 whole run 9.3 134.8 - - - 113.0 171 - - - - - -
Mesa ps3.246 + ps3rsx 0.249 2026-10-17 · 2026-10-17-mesa-246-ps3rsx-249
Tested: The first full suite round after the reboot into ps3rsx 0.249, one run per game, as a baseline.
Result: Every game ran with the right picture. The sound was right except in dsda-doom (MIDI music), BananaBread and OpenTTD. Single runs, so differences of a few fps are noise.
What we saw
  • One run per game. Frame rates by the game's own counter, or the driver's frame counter where marked:
  • Armagetron 60 (counter), ClassiCube 47.6, dsda-doom software 33 (counter, demo unfinished), Extreme Tux Racer 46 (counter), Luanti 53 (counter), Neverball 78.2.
  • OpenArena with compressed textures 44.2 (longest frame 2.1 s), QuakeSpasm 70.5, BananaBread with CPU skinning 28 (counter), X-Moto 39 (counter), Yamagi Quake II 51.4.
  • Pictures right. Sound right except dsda-doom (1161 underruns, MIDI music), BananaBread (176) and OpenTTD (1429, choppy).
  • OpenTTD used 55.5 s of CPU and has no frame rate (plain X11 path).
  • Single runs: differences of a few fps are within the run-to-run spread.
cpuskel the recipe as it is - - - 28 Mesa ps3.246, ps3rsx 0.249 whole run 9.7 140.3 - - - 116.2 176 - - - - - -
ps3rsx 0.249 first boot (Mesa ps3.246; SDL3 ps3.254) 2026-10-17 · 2026-10-17-ps3rsx-249-first-boot
Tested: The first boot with ps3rsx 0.249 and libsdl3 ps3.254: Neverball without the wedge, OpenTTD's native upload, and the first runs of Luanti and BananaBread (the Cube 2 engine).
Result: Neverball runs without wedging (76.4 and 70.2 fps), and OpenTTD rose from about 2 to 8 fps (12 with the 8-bit blitter). Luanti and BananaBread run but are memory-bound; BananaBread's first run was killed for lack of memory.
What we saw
  • The GL tests pass and switching virtual terminals works with a GL program running (those runs aren't in the records).
  • Neverball (our +ps3.257 with its own benchmark, about 23 s) runs without the wedge: 76.4 and 70.2 fps by its own count, longest frames 320 and 378 ms, 15 and 36 underruns.
  • OpenTTD with libsdl3 ps3.254 (native BGRA upload): from about 2 to 8 fps on the driver's frame counter (9.5 across the two runs), 12 fps with the 8-bit blitter. The game's own software drawing is the limit.
  • Luanti, first run: load 37 s, 67 fps on the counter (10th percentile 23, dropping to 0 while map chunks load), free memory down to 31 MB.
  • BananaBread (CPU skinning), first runs: the first was killed by the out-of-memory killer (free memory down to 10 MB); the second reached 15 fps on the counter, 236 underruns.
  • Smoke runs, single or paired.
cpuskel the recipe as it is - - - 15 Mesa ps3.246, ps3rsx 0.249 whole run 10.8 125.0 - - - 95.3 246.5 - - - - - -