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

5.5 KiB

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 is the standard profiler for modern Fabric environments.

Profiling the Client Thread

To profile JevPlayer's client-side tick footprint in-game:

/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:

/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:

-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:
    {
      "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.