Skip to content

perf: wiring a monster attack adds about 4 ms to an idle tic that no expression accounts for #479

Description

@MarcusKainth

What kind

Cost grows where the model says it should not

Which benchmark

native/ tic timing: the resident simulation statement's CPU time per row over a 60-tic idle window and a 240-tic window that runs the chase, the shot and the attack, taken from system.query_log with parsing, analysis, planning and pipeline building subtracted. Interleaved arms on one throwaway container at the pinned digest, scripts/machine-lock.sh held per run.

The numbers

ClickHouse 26.8.2.7, three rounds interleaved, medians
arm                     window   tic        analysis   FunctionExecute/tic
main d824fc9            60       38.65 ms   21.62 s    13237
troop attack wired      60       43.20 ms   27.87 s    13393
main d824fc9            240      34.46 ms   23.48 s    20971
troop attack wired      240      35.41 ms   27.32 s    21074

statement 1,073,633 -> 1,255,576 bytes

probes on the idle window, same session
both fold bodies replaced by the empty-list answer:   main 38.42  troop 42.16  nobodies 41.18 ms
writebacks folded over the hit list (0 or 1 element):  paired median +4.42 ms against +4.55 ms

The idle tic gate is +0.5 ms against main in the same session. The wiring of A_TroopAttack and A_SargAttack misses it by about 4 ms on the idle window and passes on the active one (+1.0 ms). The two routine bodies are folds and do not run on an idle tic; removing them recovers about 1 ms. Folding the eleven per-slot writebacks over the hit list recovers 0.1 ms. About 2.8 ms of idle cost per tic is not attributed to any expression.

The machine, and how quiet it was

Apple silicon development machine, other lanes' containers stopped for the timed runs, the machine lock held, arms interleaved. Not a quiet machine: round-to-round spread on this box is 1 to 3 ms, the same size as the effect. The relative figures held across three rounds and two sessions.

What you think is happening

The added expressions that do run on an idle tic are the mt_attackers filter (over arrays the tic already builds), the fourth list of sight pairs (a map over the empty attacker list), scalars over the fold's accumulator, and the eleven arrayMaps that write the claw's columns back. None of those is large. Candidates worth measuring one at a time with QueryAnalysisMicroseconds and FunctionExecute in system.query_log: the accumulator tuple's type (a tuple carrying two Array(Tuple) members through arrayFold may be copied at every read even when empty), the added sight::asking map widening mt_pairs and so the whole of check_sight, and whether the statement's growth by 180 KB moves a per-block fixed cost that is not analysis. Every further monster routine (the hitscan monsters, the missile's impact, the barrel's blast) adds the same shape, so whichever of these it is will be paid again.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: nativeNative mode: the tic simulation and renderer as SQL, and the WAD loaderperformanceThroughput below expectation, or a regression

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions