Skip to content

Performance

How fast gorge plays Magic, measured against the other rules engines on the same machine, the same decks and one CPU core each. This page is the headline comparison for anyone choosing an engine to host games or to generate self-play data; Methodology says exactly how it was measured and how to rerun it, Engine speed covers gorge's own benchmark and profile, and Bots covers what gorge's bots cost and how well they play.

The short version (2026-10-20, one core, FDN limited decks)

  • gorge plays a random-policy game in about 10 ms, about 40× as many games per core-second as XMage (89 against 2.4 games per core-second; 29× cheaper per turn).
  • With each engine's own AI on both seats, a gorge game costs 7-9 ms, against about 1 s for Forge and XMage's default AI: 100-150× more games per core-second. The AIs are not the same kind of player (see below), so this is the price of a game with the bot each engine ships, not engine speed alone.
  • dirty-dirac, the two-player kernel checked in lockstep against gorge, is another 15-20× faster than gorge (0.6 ms a game, 23 µs a turn), at the cost of playing only its generated card pools. Its rows were measured before the 2026-10-21 kernel redesign; see dirty-dirac's rows.
  • mtg-kernel, a public Rust kernel with a few hundred cards, is about as fast as gorge on its home Burn mirror (174 against 118-143 random games per core-second) and 6-13× slower per turn on FDN pair A, the FDN pair it plays (details).
  • Search: one MCTS simulation costs 57-108 µs on dirty-dirac with a heuristic leaf, 90-177 µs with a small network leaf, and 0.9-1.6 ms on gorge, at 25-1,000 simulations per decision; almost all of it is the rules engine (details).
  • Memory: one game-playing process peaks at about 350 MB for gorge (the whole card corpus loaded), 0.9 GB for Forge and 1.2-1.3 GB for XMage with a 2 GB heap cap; mtg-kernel, with its cards compiled in, 11-16 MB.

The numbers

Each bar is the median of six runs (FDN pairs A and B, three reps each); the thin line through it spans the slowest and fastest run. Engines differ by more than three orders of magnitude, so the first two charts use a log scale: each grid line is ten times the one before. Hover a bar for its exact value and spread.

Games per core-second (log scale; higher is faster) random legal action engine's own AI 0.1 1.00 10.0 100 1,000 10,000 dirty-dirac · random: 1,722 games/core-s (min 1,580, max 1,848) dirty-dirac · random 1,722 gorge · random (auto-pay): 89.4 games/core-s (min 85.4, max 93.9) gorge · random (auto-pay) 89.4 gorge · random (manual): 105 games/core-s (min 102, max 108) gorge · random (manual) 105 XMage · random: 2.38 games/core-s (min 2.16, max 2.58) XMage · random 2.38 dirty-dirac · hbot: 1,607 games/core-s (min 1,439, max 1,763) dirty-dirac · hbot 1,607 gorge · bot (auto-pay): 107 games/core-s (min 102, max 112) gorge · bot (auto-pay) 107 gorge · bot (manual): 140 games/core-s (min 132, max 145) gorge · bot (manual) 140 XMage · simple AI: 19.3 games/core-s (min 18.6, max 19.7) XMage · simple AI 19.3 XMage · mad AI: 0.947 games/core-s (min 0.552, max 1.25) XMage · mad AI 0.947 Forge · Forge AI: 1.02 games/core-s (min 0.723, max 1.22) Forge · Forge AI 1.02

Games per core-second, log scale. FDN pairs A and B pooled, median of 6 runs, thin line = min-max. 2026-10-20, gorge ad3777023, one pinned core per run (24/26/28), load average 4.4-15; scripts/xengine-bench.sh. Filled bars: random legal action; outlined bars: the engine's own AI.

CPU microseconds per turn (log scale; lower is cheaper) random legal action engine's own AI 10.0 100 1,000 10,000 100,000 1,000,000 dirty-dirac · random: 23.3 µs/turn (min 22.8, max 24.0) dirty-dirac · random 23.3 gorge · random (auto-pay): 459 µs/turn (min 443, max 473) gorge · random (auto-pay) 459 gorge · random (manual): 233 µs/turn (min 232, max 236) gorge · random (manual) 233 XMage · random: 13,193 µs/turn (min 12,774, max 13,751) XMage · random 13,193 dirty-dirac · hbot: 35.0 µs/turn (min 31.8, max 38.6) dirty-dirac · hbot 35.0 gorge · bot (auto-pay): 525 µs/turn (min 507, max 544) gorge · bot (auto-pay) 525 gorge · bot (manual): 400 µs/turn (min 385, max 417) gorge · bot (manual) 400 XMage · simple AI: 761 µs/turn (min 743, max 791) XMage · simple AI 761 XMage · mad AI: 62,343 µs/turn (min 49,069, max 101,733) XMage · mad AI 62,343 Forge · Forge AI: 54,513 µs/turn (min 45,904, max 71,387) Forge · Forge AI 54,513

CPU µs per turn, log scale (turns count both players' turns). FDN pairs A and B pooled, median of 6 runs, thin line = min-max. 2026-10-20, gorge ad3777023, one pinned core per run (24/26/28), load average 4.4-15; scripts/xengine-bench.sh. Filled bars: random legal action; outlined bars: the engine's own AI.

Peak resident memory, MB (one game-playing process) random legal action engine's own AI 0 500 1,000 dirty-dirac · random: 356 MB (min 353, max 485) dirty-dirac · random 356 gorge · random (auto-pay): 351 MB (min 347, max 354) gorge · random (auto-pay) 351 gorge · random (manual): 349 MB (min 348, max 393) gorge · random (manual) 349 XMage · random: 1,228 MB (min 1,227, max 1,240) XMage · random 1,228 dirty-dirac · hbot: 485 MB (min 383, max 583) dirty-dirac · hbot 485 gorge · bot (auto-pay): 348 MB (min 346, max 395) gorge · bot (auto-pay) 348 gorge · bot (manual): 355 MB (min 346, max 356) gorge · bot (manual) 355 XMage · simple AI: 1,219 MB (min 1,212, max 1,232) XMage · simple AI 1,219 XMage · mad AI: 1,288 MB (min 1,243, max 1,324) XMage · mad AI 1,288 Forge · Forge AI: 882 MB (min 858, max 918) Forge · Forge AI 882

Peak RSS of one game-playing process, card database included; JVMs capped at -Xmx2g. FDN pairs A and B pooled, median of 6 runs, thin line = min-max. 2026-10-20, gorge ad3777023, one pinned core per run (24/26/28), load average 4.4-15; scripts/xengine-bench.sh. Filled bars: random legal action; outlined bars: the engine's own AI.
Engine · policy games / core-s ms / game µs / turn µs / decision turns / game peak RSS (MB)
dirty-dirac · random 1,722 (1,580–1,848) 0.584 (0.541–0.633) 23.3 (22.8–24.0) 4.62 (4.54–4.75) 25 356
gorge · random (auto-pay) 89.4 (85.4–93.9) 11.2 (10.7–11.7) 459 (443–473) 19.3 (18.8–19.7) 24 351
gorge · random (manual) 105 (102–108) 9.56 (9.23–9.78) 233 (232–236) 8.49 (8.46–8.54) 41 349
XMage · random 2.38 (2.16–2.58) 420 (387–462) 13,193 (12,774–13,751) 499 (487–518) 32 1,228
dirty-dirac · hbot 1,607 (1,439–1,763) 0.628 (0.567–0.695) 35.0 (31.8–38.6) 6.35 (5.94–6.84) 18 485
gorge · bot (auto-pay) 107 (102–112) 9.36 (8.96–9.83) 525 (507–544) 21.3 (20.9–21.7) 18 348
gorge · bot (manual) 140 (132–145) 7.16 (6.88–7.58) 400 (385–417) 14.4 (14.0–14.9) 18 355
XMage · simple AI 19.3 (18.6–19.7) 51.9 (50.7–53.9) 761 (743–791) 48.3 (47.1–50.2) 68 1,219
XMage · mad AI 0.947 (0.552–1.25) 1,121 (801–1,813) 62,343 (49,069–101,733) 2,902 (2,292–4,782) 17 1,288
Forge · Forge AI 1.02 (0.723–1.22) 983 (823–1,383) 54,513 (45,904–71,387) n/a 18 882
Per-pair detail (the summary table xengine-bench.sh prints)
engine policy pair reps games/core-s ms/game µs/turn µs/decision turns/game peak RSS MB load1 other busy
gorge random-autopay A 3 92.3 (91.9-93.9) 10.8 (10.7-10.9) 471 (468-473) 19.7 (19.5-19.7) 22.9 351 7-7 max 0%
gorge random A 3 103 (102-103) 9.74 (9.70-9.78) 232 (232-233) 8.50 (8.48-8.54) 41.9 349 7-7 max 0%
gorge bot-autopay A 3 103 (102-103) 9.70 (9.68-9.83) 540 (538-544) 21.5 (21.4-21.7) 18.0 346 6-7 max 0%
gorge bot A 3 134 (132-136) 7.45 (7.37-7.58) 412 (410-417) 14.7 (14.7-14.9) 18.1 355 6-6 max 0%
gorge random-autopay B 3 86.8 (85.4-86.8) 11.5 (11.5-11.7) 445 (443-450) 18.9 (18.8-19.0) 26.0 347 6-6 max 0%
gorge random B 3 108 (106-108) 9.28 (9.23-9.42) 233 (233-236) 8.46 (8.46-8.54) 39.8 348 6-6 max 0%
gorge bot-autopay B 3 111 (110-112) 9.02 (8.96-9.05) 509 (507-512) 21.0 (20.9-21.1) 17.7 348 5-6 max 0%
gorge bot B 3 144 (144-145) 6.95 (6.88-6.96) 388 (385-390) 14.0 (14.0-14.1) 17.9 348 5-6 max 0%
dirty-dirac random A 3 1,848 (1,845-1,848) 0.54 (0.54-0.54) 22.9 (22.8-22.9) 4.55 (4.54-4.56) 23.7 361 5-6 max 0%
dirty-dirac hbot A 3 1,457 (1,439-1,462) 0.69 (0.68-0.69) 38.1 (38.1-38.6) 6.76 (6.75-6.84) 18.0 490 5-5 max 0%
dirty-dirac random B 3 1,587 (1,580-1,598) 0.63 (0.63-0.63) 23.8 (23.7-24.0) 4.71 (4.69-4.75) 26.4 356 5-5 max 0%
dirty-dirac hbot B 3 1,763 (1,751-1,763) 0.57 (0.57-0.57) 31.8 (31.8-31.9) 5.95 (5.94-5.95) 17.9 480 4-5 max 0%
xmage random A 3 2.50 (2.40-2.58) 400 (387-416) 13,063 (12,774-13,145) 495 (487-496) 30.6 1,228 4-5 max 0%
xmage simple A 3 19.6 (19.5-19.7) 50.9 (50.7-51.3) 747 (743-753) 47.4 (47.1-47.8) 68.2 1,218 5-5 max 0%
xmage mad A 3 1.22 (1.18-1.25) 822 (801-850) 51,169 (49,069-51,492) 2,349 (2,292-2,391) 16.3 1,286 5-12 max 28%
xmage random B 3 2.32 (2.16-2.36) 430 (425-462) 13,357 (13,242-13,751) 502 (502-518) 32.2 1,232 12-14 max 7%
xmage simple B 3 19.0 (18.6-19.1) 52.7 (52.4-53.9) 774 (770-791) 49.1 (48.8-50.2) 68.1 1,221 13-14 max 0%
xmage mad B 3 0.62 (0.55-0.72) 1,610 (1,391-1,813) 91,739 (73,194-101,733) 4,255 (3,413-4,782) 17.8 1,320 10-13 max 0%
forge ai A 3 0.81 (0.72-0.97) 1,239 (1,035-1,383) 67,548 (58,991-71,387) n/a 18.3 868 10-15 max 3%
forge ai B 3 1.16 (1.07-1.22) 862 (823-932) 46,518 (45,904-50,034) n/a 18.6 902 9-13 max 0%

What the comparison shows

Engine cost. The random rows measure each engine with a policy that costs almost nothing, so they are as close to pure engine cost as each engine allows. Per turn, dirty-dirac (23 µs) is about 20× cheaper than gorge with auto-pay (459 µs), which is about 29× cheaper than XMage (13.2 ms). gorge's manual-tap random row is cheaper per turn (233 µs) but plays twice as many turns per game, because a random player tapping lands one at a time wastes mana. Forge has no random player, so it has no row here.

AI cost. Within one engine, the AI rows show what the built-in bot adds. gorge's heuristic bot ends games in 18 turns instead of 24-41, so a game with two bots is cheaper than a random game, even though each turn costs a little more (about 15% of a bot game's CPU is the bot itself, see Engine speed). XMage's base ComputerPlayer is the cheapest XMage policy per turn (0.76 ms), but its games drift to about 68 turns. XMage's default "mad" AI searches the game tree at every priority and costs 50-100 ms a turn; Forge's AI costs 46-68 ms a turn.

Search. Search bots clone and step the engine many times per decision, so the per-operation costs matter more than per-game ones: gorge clones a mid-game state in 14 µs (28 µs with GC) and clones-and-steps in 39 µs, and its MCTS search runs about 1,000-1,100 simulations per core-second at 25-100 simulations a decision (see Engine speed and Search bots below, which compares it with dirty-dirac's search).

A second comparison: decks mtg-kernel plays

mtg-kernel is a public Rust rules kernel (MIT) built for reinforcement learning on a fixed card pool. It cannot play FDN pair B (it lacks four of its cards), so it is not in the tables above. This section adds it on the two workloads it does play, measured the same way (one pinned core per run, three reps, medians with min-max): FDN pair A, which is exactly mtg-kernel's two FDN fixture decks and which every engine here plays, and the Burn mirror, the mono-red Pauper deck from mtg-kernel's own pool, which every engine except dirty-dirac plays. mtg-kernel has no standalone built-in bot, so it has a random row only (why).

What differs about mtg-kernel

  • Card pool. 452 card definitions at the measured commit: its Pauper decks plus 245 of FDN's 286 names. gorge plays about 94% of Forge's ~34,000-card corpus; XMage and Forge play every card.
  • Its FDN cards are a build option. They sit behind the cargo feature limited-fdn-fixtures, and that build plays Burn several times slower than the default build, so pair A uses the FDN build and Burn the default one.
  • Its random player is the one from its own benchmark: every priority window and every mana ability is a decision, as in gorge's manual-tap random row, which is the closest gorge row to compare with.
  • Memory is not comparable: mtg-kernel compiles its few hundred cards into the binary (11-16 MB resident), while gorge, XMage and Forge load a card database of tens of thousands of cards.

FDN pair A, every engine

CPU µs per turn, FDN pair A (log scale; lower is cheaper) random legal action engine's own AI 10.0 100 1,000 10,000 100,000 dirty-dirac · random: 22.9 µs/turn (min 22.8, max 22.9) dirty-dirac · random 22.9 gorge · random (auto-pay): 471 µs/turn (min 468, max 473) gorge · random (auto-pay) 471 gorge · random (manual): 232 µs/turn (min 232, max 233) gorge · random (manual) 232 mtg-kernel · random: 3,075 µs/turn (min 3,011, max 3,113) mtg-kernel · random 3,075 XMage · random: 13,063 µs/turn (min 12,774, max 13,145) XMage · random 13,063 dirty-dirac · hbot: 38.1 µs/turn (min 38.1, max 38.6) dirty-dirac · hbot 38.1 gorge · bot (auto-pay): 540 µs/turn (min 538, max 544) gorge · bot (auto-pay) 540 gorge · bot (manual): 412 µs/turn (min 410, max 417) gorge · bot (manual) 412 XMage · simple AI: 747 µs/turn (min 743, max 753) XMage · simple AI 747 XMage · mad AI: 51,169 µs/turn (min 49,069, max 51,492) XMage · mad AI 51,169 Forge · Forge AI: 67,548 µs/turn (min 58,991, max 71,387) Forge · Forge AI 67,548

CPU µs per turn on FDN pair A, log scale. Median of 3 runs, thin line = min-max. 2026-10-20 (17:45-18:07 UTC; mtg-kernel 18:50 UTC), gorge ad3777023, mtg-kernel 058d075e3, one pinned core per run (24/26/28); scripts/xengine-bench.sh. Filled bars: random legal action; outlined bars: the engine's own AI.
Engine · policy games / core-s ms / game µs / turn µs / decision turns / game peak RSS (MB)
dirty-dirac · random 1,848 (1,845–1,848) 0.541 (0.541–0.542) 22.9 (22.8–22.9) 4.55 (4.54–4.56) 24 361
gorge · random (auto-pay) 92.3 (91.9–93.9) 10.8 (10.7–10.9) 471 (468–473) 19.7 (19.5–19.7) 23 351
gorge · random (manual) 103 (102–103) 9.74 (9.70–9.78) 232 (232–233) 8.50 (8.48–8.54) 42 349
mtg-kernel · random 18.6 (18.4–19.4) 53.8 (51.6–54.5) 3,075 (3,011–3,113) 57.2 (56.3–57.7) 17 15.7
XMage · random 2.50 (2.40–2.58) 400 (387–416) 13,063 (12,774–13,145) 495 (487–496) 31 1,228
dirty-dirac · hbot 1,457 (1,439–1,462) 0.686 (0.684–0.695) 38.1 (38.1–38.6) 6.76 (6.75–6.84) 18 490
gorge · bot (auto-pay) 103 (102–103) 9.70 (9.68–9.83) 540 (538–544) 21.5 (21.4–21.7) 18 346
gorge · bot (manual) 134 (132–136) 7.45 (7.37–7.58) 412 (410–417) 14.7 (14.7–14.9) 18 355
XMage · simple AI 19.6 (19.5–19.7) 50.9 (50.7–51.3) 747 (743–753) 47.4 (47.1–47.8) 68 1,218
XMage · mad AI 1.22 (1.18–1.25) 822 (801–850) 51,169 (49,069–51,492) 2,349 (2,292–2,391) 16 1,286
Forge · Forge AI 0.807 (0.723–0.966) 1,239 (1,035–1,383) 67,548 (58,991–71,387) n/a 18 868

Burn mirror

CPU µs per turn, Burn mirror (log scale; lower is cheaper) random legal action engine's own AI 100 1,000 10,000 100,000 1,000,000 gorge · random (auto-pay): 267 µs/turn (min 266, max 267) gorge · random (auto-pay) 267 gorge · random (manual): 240 µs/turn (min 238, max 240) gorge · random (manual) 240 mtg-kernel · random: 367 µs/turn (min 365, max 368) mtg-kernel · random 367 XMage · random: 11,188 µs/turn (min 10,856, max 11,308) XMage · random 11,188 gorge · bot (auto-pay): 437 µs/turn (min 434, max 439) gorge · bot (auto-pay) 437 gorge · bot (manual): 308 µs/turn (min 306, max 309) gorge · bot (manual) 308 XMage · mad AI: 272,821 µs/turn (min 226,484, max 345,899) XMage · mad AI 272,821 Forge · Forge AI: 35,533 µs/turn (min 33,783, max 36,489) Forge · Forge AI 35,533

CPU µs per turn on the Burn mirror, log scale. XMage's base AI is left out: on Burn it casts nothing and every game hits the 100-turn cap. Median of 3 runs, thin line = min-max. 2026-10-20 (18:50-19:00 UTC, load average 6-36), gorge ad3777023, mtg-kernel 058d075e3, one pinned core per run (24/26/28); scripts/xengine-bench.sh. Filled bars: random legal action; outlined bars: the engine's own AI.
Engine · policy games / core-s ms / game µs / turn µs / decision turns / game peak RSS (MB)
gorge · random (auto-pay) 143 (142–143) 6.98 (6.97–7.06) 267 (266–267) 12.2 (12.1–12.2) 26 354
gorge · random (manual) 118 (117–118) 8.48 (8.45–8.53) 240 (238–240) 10.9 (10.9–10.9) 36 353
mtg-kernel · random 174 (173–174) 5.75 (5.74–5.78) 367 (365–368) 8.15 (8.11–8.15) 16 10.9
XMage · random 3.14 (2.91–3.18) 318 (315–344) 11,188 (10,856–11,308) 527 (508–534) 29 1,262
gorge · bot (auto-pay) 111 (110–112) 9.00 (8.96–9.05) 437 (434–439) 18.7 (18.6–18.7) 21 347
gorge · bot (manual) 159 (158–159) 6.30 (6.27–6.31) 308 (306–309) 12.1 (12.1–12.2) 20 352
XMage · mad AI 0.259 (0.179–0.282) 3,864 (3,547–5,597) 272,821 (226,484–345,899) 13,226 (11,010–17,280) 16 1,336
Forge · Forge AI 1.58 (1.45–1.64) 633 (609–688) 35,533 (33,783–36,489) n/a 18 892

On FDN pair A, gorge's random players spend 233-471 µs a turn against mtg-kernel's 3,075 µs; on its home Burn mirror mtg-kernel is close to gorge (367 µs a turn against 240-267 µs), and its games are shorter, so it plays 174 games per core-second against gorge's 118-143. dirty-dirac remains the fastest engine on pair A by an order of magnitude.

Search bots: cost per simulation

A search bot clones and steps the game many times per decision, so its cost is the cost of one simulation times the simulation budget. These rows put an MCTS search on both seats (dirty-dirac) or on searched priority roots (gorge) of FDN pair A at 25, 100 and 1,000 simulations per searched decision, on one pinned core, three reps; Methodology says exactly what runs and how each is counted. They measure speed only.

CPU µs per simulation (log scale; lower is cheaper) dirty-dirac gorge 10.0 100 1,000 10,000 dirty-dirac, heuristic leaf, 25 sims: 57.1 µs/sim (min 56.9, max 58.1) dirty-dirac, heuristic leaf, 25 sims 57.1 dirty-dirac, heuristic leaf, 100 sims: 74.3 µs/sim (min 73.9, max 79.6) dirty-dirac, heuristic leaf, 100 sims 74.3 dirty-dirac, heuristic leaf, 1000 sims: 108 µs/sim (min 89.9, max 109) dirty-dirac, heuristic leaf, 1000 sims 108 dirty-dirac, network leaf, 25 sims: 99.3 µs/sim (min 96.9, max 103) dirty-dirac, network leaf, 25 sims 99.3 dirty-dirac, network leaf, 100 sims: 90.0 µs/sim (min 89.4, max 95.2) dirty-dirac, network leaf, 100 sims 90.0 dirty-dirac, network leaf, 1000 sims: 177 µs/sim (min 163, max 189) dirty-dirac, network leaf, 1000 sims 177 gorge azmcts, heuristic leaf, 25 sims: 914 µs/sim (min 908, max 966) gorge azmcts, heuristic leaf, 25 sims 914 gorge azmcts, heuristic leaf, 100 sims: 942 µs/sim (min 939, max 978) gorge azmcts, heuristic leaf, 100 sims 942 gorge azmcts, heuristic leaf, 1000 sims: 1,604 µs/sim (min 1,281, max 1,687) gorge azmcts, heuristic leaf, 1000 sims 1,604

CPU µs per MCTS simulation, log scale, FDN pair A, median of 3 runs, thin line = min-max. 2026-10-20 18:35-18:41 UTC, gorge ad3777023, one pinned core per run (24/26/28), load average 17-32 (core contention at most 10%). dirty-dirac counts whole games' CPU per simulation, gorge only the search's CPU.
Search bot sims per decision µs per simulation simulations per core-second ms per searched decision ms per game games or roots per run
dirty-dirac MCTS, heuristic leaf 25 57.1 (56.9–58.1) 17,499 (17,222–17,560) 1.43 (1.42–1.45) 108 (105–113) 278-286-266
dirty-dirac MCTS, heuristic leaf 100 74.3 (73.9–79.6) 13,455 (12,560–13,527) 7.43 (7.39–7.96) 546 (535–623) 49-55-57
dirty-dirac MCTS, heuristic leaf 1000 108 (89.9–109) 9,277 (9,201–11,119) 108 (89.9–109) 8,219 (7,263–9,428) 4-4-4
dirty-dirac MCTS, network leaf 25 99.3 (96.9–103) 10,075 (9,737–10,323) 2.48 (2.42–2.57) 171 (168–174) 165-157-161
dirty-dirac MCTS, network leaf 100 90.0 (89.4–95.2) 11,107 (10,508–11,185) 9.00 (8.94–9.52) 617 (594–632) 51-48-49
dirty-dirac MCTS, network leaf 1000 177 (163–189) 5,654 (5,298–6,142) 177 (163–189) 11,792 (7,978–12,205) 4-3-3
gorge MCTS (azmcts), heuristic leaf 25 914 (908–966) 1,094 (1,035–1,102) 22.9 (22.7–24.1) n/a 1143-1131-1075
gorge MCTS (azmcts), heuristic leaf 100 942 (939–978) 1,061 (1,023–1,065) 94.2 (93.9–97.8) n/a 301-312-311
gorge MCTS (azmcts), heuristic leaf 1000 1,604 (1,281–1,687) 623 (593–780) 1,604 (1,281–1,687) n/a 26-20-20

Where a simulation's time goes, at 100 simulations:

Search bot Engine (re-deal, replay and expansion of the world) Leaf evaluator Search bookkeeping (select, backup)
dirty-dirac MCTS, heuristic leaf (79 µs a simulation) 78.8 µs (99.7%): re-deal 1.7, replaying the line 51.2, expanding the node 25.1 included in the engine column 0.24 µs
dirty-dirac MCTS, network leaf (99 µs a simulation) 82.6 µs (84%) 15.7 µs (16%): building the input 10.7, the forward pass 5.0 0.29 µs
gorge MCTS, heuristic leaf (about 940 µs a simulation) most of it: Engine.Submit 83% cumulative (game play inside the search), re-dealing the world about 3%, building the in-search bot's board 5.7% under 1% (heuristicLeafValue 0.15%) about 1% (azmcts flat)

The dirty-dirac split is its runner's per-simulation timers (wall time inside the search, so its totals differ slightly from the CPU-time table); the gorge split is a 20-second CPU profile of enginebench -row az -sims 100. In both engines almost all of a simulation is the rules engine replaying and extending a line of play; the search itself is noise, and a small network leaf adds about a quarter on dirty-dirac. The per-simulation cost grows with the budget because deeper trees replay longer lines.

dirty-dirac's rows

Every dirty-dirac figure on this page (the game rows, the FDN pair A table and the search rows) was measured on 2026-10-20 with the dirty-dirac source of that day, which pinned gorge aa421da93. That was before the kernel redesign of 2026-10-21 (dirty-dirac). The rows have not been re-run since. The redesign's own A/B, the kernel's transition benchmark on one pinned core against the pre-redesign kernel, counts about 4 % fewer instructions per transition on FDN and about 2 % fewer on BLB. Instruction counts are not CPU time, so treat the rows above as dated measurements of the earlier kernel, not as current figures.

Caveats

Not apples to apples

  • Card coverage differs. XMage and Forge implement every card; gorge implements most of Forge's corpus; dirty-dirac plays only its generated card pools, two players; mtg-kernel plays a few hundred cards. The main workload is FDN because it is the pool the first four play; mtg-kernel plays only pair A of it.
  • Policies differ. The random players are close but not identical (XMage answers non-priority asks with its base AI); the AIs differ in kind and strength. Each row's policy is spelled out in Methodology.
  • Decisions are counted differently, so µs per decision is only comparable within an engine; µs per turn is the cross-engine normaliser.
  • JVM numbers are steady state after 40 s of warm-up games; start-up (8-10 s for XMage, about 6 s for Forge to load cards) is not in the per-game numbers.
  • One shared machine. Three reps of a row ran at once on three physical cores; a gorge and a dirty-dirac row run alone on one core came out within 4% of the concurrent runs.

Provenance

Date 2026-10-20: FDN pairs A and B 17:45-18:07 UTC; search rows 18:35-18:41 UTC; mtg-kernel and the Burn mirror 18:50-19:00 UTC
Machine AMD Ryzen 9 9950X (16 cores, 32 threads), 120 GB, Linux 6.17, performance governor
Cores one per run: 24, 26, 28 (three reps at once); GOMAXPROCS=1 for Go; JVMs pinned the same way (serial GC, -Xmx2g)
Load 1-minute load average 4.4-15 for the FDN A/B tables (per-row ranges in the per-pair table), 6-36 for the Burn rows, 17-32 for the search rows; no published rep had more than 10% of its core taken by other work except one XMage mad pair-A rep (28%), whose result sits inside the other two reps' spread
gorge ad3777023 (develop), Go 1.26.3, cmd/enginebench
dirty-dirac private kernel, the source of 2026-10-20 (before the redesign), which pinned gorge aa421da93
XMage magefree/mage 6b602a1c85 (1.4.61), Temurin JDK 17.0.20.1, driver XEngineBench (gorge-compliance)
Forge gorge's Forge fork at da1c712c31 (forge-core/game/ai 2.0.16-SNAPSHOT), JDK 17.0.20.1, driver forge.oracle.GameReplay
mtg-kernel jackmaiorino/mtg-kernel 058d075e3 (2026-10-20), Rust 1.94.1, release build of examples/bench_kernel with gorge's --xengine-json mode; FDN pair A from the limited-fdn-fixtures build, Burn from the default build
Command SECS=30 scripts/xengine-bench.sh gorge dirty-dirac, then SECS=60 WARM=40 scripts/xengine-bench.sh xmage forge, with CORES="24 26 28"; the Burn rows the same with PAIRS=burn; mtg-kernel with MTGKERNEL_BENCH=… MK_PAIRS=A (FDN build) and MK_PAIRS=burn (default build); search rows as in Methodology
Measured time 30 CPU-s per gorge and dirty-dirac run; 40 s warm-up + 60 CPU-s per XMage and Forge run
Errors no stalled, unfinished or failed game in any published row. XMage's base AI on the Burn mirror ended every game at the 100-turn cap without a winner (it never casts its burn spells), so that row is left out

Engines that are not on this page were not installed on the measuring machine; Methodology says what adding one takes.