This repository has been archived on 2026-10-10. You can view files and clone it, but cannot push or open issues or pull requests.
JevPlays/docs/PERFORMANCE.md

111 lines
5.5 KiB
Markdown

# JevPlayer Performance Guide & Profiling Protocol
This document details the performance constraints, memory budgets, zero-GC strategies, and profiling protocols used to ensure **JevPlayer** runs stably for extended 1+ hour survival sessions without causing frame drops or memory growth.
---
## 1. Per-Tick Latency Budgets
Minecraft runs at 20 ticks per second (1 tick = 50.0 ms). Rendering at 60+ FPS requires the client thread to complete all per-frame and per-tick tasks within a fraction of this window.
| Pipeline Phase | Target Budget (Average) | Hard Threshold (Worst Case) | Execution Thread |
| :--- | :--- | :--- | :--- |
| **World Sensor Perception** | $< 0.15 \text{ ms}$ | $< 0.80 \text{ ms}$ | Client Main Thread |
| **Legal Action Masking** | $< 0.05 \text{ ms}$ | $< 0.20 \text{ ms}$ | Client Main Thread |
| **Reflex Evaluation** | $< 0.03 \text{ ms}$ | $< 0.15 \text{ ms}$ | Client Main Thread |
| **Watchdog Verification** | $< 0.02 \text{ ms}$ | $< 0.10 \text{ ms}$ | Client Main Thread |
| **Actuator Dispatch (Baritone)** | $< 0.05 \text{ ms}$ | $< 0.75 \text{ ms}$ | Client Main Thread |
| **Total Client Tick Overhead** | **$< 0.30 \text{ ms}$** | **$< 2.00 \text{ ms}$** | **Client Main Thread** |
| **Decision Query (Jev HTTP/2)** | $70 \text{ -- } 250 \text{ ms}$ | $< 500 \text{ ms}$ | Background Daemon Thread |
| **Decision Query (Mock Heuristic)** | $< 0.50 \text{ ms}$ | $< 2.00 \text{ ms}$ | Background Daemon Thread |
---
## 2. Allocation Avoidance & Zero-GC Strategies
Frequent garbage collection cycles on the client JVM cause perceptible micro-stuttering. JevPlayer incorporates strict allocation-minimization practices:
### Reusable Buffers for Prompt Formatting
- Instead of creating short-lived `String` instances on every tick, `StateSnapshot` formats its state prompt into pre-allocated `StringBuilder` instances.
- Primitive fields (`float health`, `int food`, `int level`, `long timeOfDay`, `int coalCount`, etc.) are directly formatted without boxed object wrappers (`Integer`, `Float`).
### Bounded Collections & Ring Buffers
- `ActionHistoryEntry` instances are stored in a fixed-size ring buffer (capacity 10). When new history arrives, the oldest entry is overwritten in-place without expanding or reallocating arrays.
- Legal actions use `EnumSet<ActionType>`, backed by a single 64-bit primitive long bitmask. Adding, removing, or checking legal actions requires zero memory allocations.
### HUD Rendering Throttling
- Minecraft invokes HUD rendering callbacks on every frame (60 to 144+ times per second).
- String assembly and metric calculations are throttled to update at most once every `hudRefreshRateMs` (default: 200 ms). Between updates, the HUD simply renders the cached text components.
### Non-Blocking HTTP Client
- All remote I/O is performed using Java's built-in `java.net.http.HttpClient` configured with:
- HTTP/2 multiplexing.
- Connection reuse and TLS session caching.
- A fixed daemon thread pool (`Executors.newSingleThreadExecutor(...)`).
---
## 3. Profiling with Spark
[Spark](https://spark.lucko.me/) is the standard profiler for modern Fabric environments.
### Profiling the Client Thread
To profile JevPlayer's client-side tick footprint in-game:
```text
/spark profile --thread Client --timeout 60
```
When the 60-second profile concludes, inspect the call tree under:
- `net.minecraft.client.MinecraftClient.tick()`
- Look for `com.typesafe.jevplayer` packages.
- Ensure total sampling percentage for `com.typesafe.jevplayer` remains $< 0.5\%$ of client tick time.
### Profiling Memory Allocation Rate
To identify any memory allocations generated by JevPlayer:
```text
/spark heap --alloc
```
Filter classes for `com.typesafe.jevplayer`. Memory allocation rate should be $< 5 \text{ KB/sec}$ during steady-state autonomous play.
---
## 4. Profiling with Java Flight Recorder (JFR)
Java Flight Recorder is built directly into OpenJDK and provides low-overhead JVM diagnostics.
### Launching with JFR Enabled
Add the following JVM argument in the Gradle `runClient` task or Minecraft launcher:
```bash
-XX:+UnlockDiagnosticVMOptions \
-XX:+DebugNonSafepoints \
-XX:StartFlightRecording=dumponexit=true,filename=jevplayer-profile.jfr,settings=profile
```
### Key Metrics to Validate in JDK Mission Control
1. **Garbage Collection Pauses:**
- Verify that young-gen GC pause times remain $< 5 \text{ ms}$.
- Confirm that old-gen full GCs do not occur during a 1-hour session.
2. **Thread Allocations:**
- Filter the "Allocation in new TLAB" and "Allocation outside TLAB" views by `com.typesafe.jevplayer`.
- Confirm that no tick-level allocation loops exist.
3. **Socket I/O:**
- Confirm that all `java.net.http` network activity is confined to the `jev-decision-worker` thread.
---
## 5. One-Hour Soak Test Validation Protocol
Before recording or deploying an episode:
1. Launch singleplayer survival in mock mode:
```json
{
"mockMode": true,
"confidenceThreshold": 0.65,
"fairMode": true
}
```
2. Enable HUD overlay (`F8`) and let the bot play undisturbed for 60 minutes (72,000 game ticks).
3. Verify the following exit criteria:
- **No Out-Of-Memory (OOM):** Heap usage remains flat with normal sawtooth GC reclamation.
- **No Deadlocks:** Worker threads terminate cleanly when leaving world.
- **Watchdog Stability:** If the bot gets stuck in terrain, watchdog recovers within 45 seconds without operator intervention.
- **Kill Switch:** Pressing `F9` immediately releases all Baritone controls and stops autonomous ticking.