Skip to content

Action Pipeline Performance ​

The evaluation basis of the Emaki action pipeline is as follows: architecturally provable advantages, a reproducible benchmark method, and the results table. This environment has no Paper/Folia server, so every quantified cell is marked "not run" with a closing condition — architecture claims are backed by source code, while numbers must be measured on a real server before they may be cited externally

Architectural advantages (source-verifiable) ​

1. Compiled once, zero parsing at runtime ​

A pipeline is compiled exactly once at config load through PipelineParser + StaticValidator into a CompiledPipeline (AST + type-checked arguments). At runtime ActionInterpreter executes that structure directly:

  • no re-tokenization, no argument type checks, no unknown-stage lookups;
  • argument rendering only runs render for values containing placeholders; pure literals are skipped;
  • compile failures are reported in full at load time (48+ rules), so a wrong stage name never surfaces only at execution

2. Gate short-circuiting and domain grouping ​

  • Gate short-circuit: a source returning Empty or a gate returning Halted enters a terminal state (stopped) immediately; all later stages are skipped with no cross-domain dispatch
  • Same-domain batching: StageGroup folds consecutive same-domain stages into one dispatch (foldable stages attach to the previous group), reducing Paper/Folia thread hops — e.g. two CONTEXT_ENTITY stages ("edit inventory" + "set XP") cause a single owner-thread transfer
  • Five-domain classification: SERVER_GLOBAL / CONTEXT_ENTITY / LOCATION_REGION / ASYNC_COMPUTE / UNDECLARED are mandatory at registration (StageRegistry.checkDomain); StageDispatcher routes by domain at runtime. Competitors generally have no domain classification, which is Emaki's structural difference on Folia

3. Zero-allocation observation on hot paths ​

The default StepReporter is NOOP (empty interface methods), so in non-debug runs every observation point is an empty call; ActionAuditLogger returns early when there is no DebugLogger. The observation layer adds no allocation or branch cost to production hot paths

4. Elimination before execution ​

Every gate's in/out counts are reported on StepReporter.gate (rendered as a funnel in dry-run/debug mode); the semantics are elimination before execution — filter/where eliminate unqualified targets before any action runs, avoiding cross-domain dispatches for invalid targets

Benchmark method (reproducible) ​

Follow the sampling discipline in .spigot-dev/guides/performance-baseline.md: only same-scenario, same-duration, same-scale runs are comparable. Three required scenarios:

ScenarioMeasuresTriggerBudget
Pipeline throughputCompleted pipeline runs per secondRun a fixed short pipeline (e.g. self | damage amount=1) in execute mode for a 120s spark sampleFill after a real-server baseline
P95 latencyEnd-to-end latency of one pipelineSame as above, with method-level sampling of ActionInterpreter.walkFill after a real-server baseline
Gate short-circuit benefitElapsed time of Halted/Empty path vs all-pass pathCompare filter 'health_percent<=0' (always eliminates everything) against filter 'health_percent<=100' (always passes)Short-circuit path should be significantly cheaper

Observation commands:

/spark profiler start --timeout 120
# run the fixed scenario...
/spark profiler stop --save-to-file

To measure grouping benefit, compare StageDispatcher.dispatch call count against dispatched stage count in the spark method profile — with batching active that ratio should be clearly below 1

Quantified results ​

MetricValueCollectedStatus
Pipeline throughput (runs/s)——not run
P95 end-to-end latency——not run
Gate short-circuit benefit (short-circuit vs all-pass)——not run
Dispatches per stage after batching——not run

Closing condition: on a Paper 26.1 server, run one spark sample per scenario above, fill the numbers back into this table with a collection date. Until then no quantified cell may be filled with estimated values

Comparison stance against competitors ​

  • Statically citable (source-level facts): five-domain thread grouping with mandatory Folia domain declarations (MythicMobs/Skript have no such mechanism); 48+ compile-time diagnostics (MythicMobs relies on runtime errors + guessing from the Wiki)
  • Not citable: any throughput, latency, or TPS number. Competitor figures are marketing claims too; re-check the source date before quoting them externally