
Quick answer: Start Spark while the lag is actively happening, capture long enough to include the slow event, then read the report from the server tick downward. The widest hot path is where time was spent, not automatically the component to delete. Confirm the same path appears across repeated captures before changing production.
Last reviewed: 31 August 2026. Paper 1.21 bundles Spark and identifies it as the preferred profiler.
TPS, MSPT and player experience
At 20 TPS, the server has 50 milliseconds for one tick. Sustained MSPT above that budget reduces TPS. Short 200-500 ms stalls may feel like rubber-banding, delayed hits or frozen inventories even when a broad TPS average looks healthy.
Use:
- TPS for overall tick-rate health.
- MSPT percentiles for typical and worst tick duration.
- Profiler samples for where CPU time is spent.
- GC and memory for allocation and pause behavior.
- Disk/database metrics for blocking outside CPU samples.
1. Reproduce before capturing
Write one sentence describing the symptom: “MSPT spikes when the third arena resets,” “the server stalls during unexplored chunk flight,” or “inventory clicks delay while autosave runs.” A profile without a reproduction target becomes a large chart with no question.
Record Paper build, Java version, plugins, online players and timestamp. If possible, reproduce on staging using a recent backup and synthetic players or staff.
2. Capture the active problem
Paper's documentation gives this 10-minute profile command:
Code:
/spark profiler start --timeout 600
Ten minutes is useful for intermittent load. For a short deterministic spike, start shortly before it and stop after the event. Do not profile only the quiet lobby and expect it to explain peak combat.
Spark returns a report URL. Treat it as operational data: it can reveal plugin names, server characteristics and behavior. Share it only with people you trust.
3. Read the report top-down
A flame graph is aggregated samples. Wider blocks consumed more sampled time beneath their parent path. Start at the tick thread and follow the widest path until it becomes actionable.
- A plugin namespace under an event or scheduled task points to work initiated by that plugin.
- Entity AI/pathfinding paths suggest mob density or navigation behavior.
- Chunk generation/loading paths suggest exploration, teleports or synchronous chunk access.
- Block/entity ticking paths suggest world mechanics rather than a plugin alone.
- Database/file/network waits may appear as blocking calls, but external latency needs corroborating metrics.
Do not blame the first plugin name visible in a stack. A plugin can call an API that performs legitimate expensive game work, or Paper can call a plugin listener because another system triggered the event. Read the complete ancestry.
4. Separate constant load from spikes
Use the timeline to select the slow interval where supported. Compare:
- A normal period with the same player count
- The exact slow window
- A second capture of the same event
If the hot path appears only once, investigate what was unique: first-time class loading, new chunk generation, a backup, garbage collection, DNS timeout or database reconnect.
5. Investigate memory without guessing
Rising heap usage between collections is normal. Concern begins when the post-GC floor steadily rises, full collections repeat, pauses are long or the process approaches its container limit.
Spark can report memory and GC activity and create heap summaries/dumps. Heap dumps can be large and contain sensitive server data, so create them only when needed, secure the file and avoid generating one on an already disk-starved node.
Read Java 21 and server RAM before changing heap flags. Adding RAM can delay an out-of-memory event without fixing a retained-object leak.
6. Common profile patterns
Plugin scheduled task
Confirm its interval, input size and whether it performs I/O. A scoreboard update every tick for every player can often be event-driven or cached without removing the feature.Entity pathfinding
Count entities by world/type and identify the game mechanic creating them. Apply a targeted cap, activation change or design fix rather than a global entity purge.Chunk generation
Pregenerate bounded maps, constrain random teleportation, and ensure plugins avoid synchronous access to unloaded chunks. Profile disk as well as CPU.Explosions and combat
Reproduce with the same kit, arena and player count. Compare plugins that listen to explosion, damage, projectile and inventory events. PvP tuning must preserve hit registration and intended mechanics.Database or network wait
Measure query latency and connection-pool saturation. Moving all calls “async” prevents tick blocking but does not solve exhausted pools, lost updates or unsafe callbacks into Bukkit state.7. Turn a report into an experiment
For each suspected cause, write:
- Observation: the exact hot path and time window.
- Hypothesis: why that path is expensive.
- Single change: one version, setting, map or code modification.
- Expected result: which metric should improve.
- Rollback: how to restore previous state.
- Retest: the same workload and profile duration.
This turns optimization from folklore into evidence.
What to send a developer
- Spark report URL and lag timestamp
- Exact steps that trigger the issue
- Paper build and Java version
- Plugin version and configuration relevant to the feature
- Player/entity/world counts during capture
- Recent changes
- Relevant errors, not the entire unfiltered log
- Whether staging reproduces it
For a complete workflow, continue with the Paper 1.21.11 optimization guide. If you need Shyam Studio to inspect a report, open a support request with the evidence above.
Primary sources
Attachments
Last edited: