Skip to content

perf(runtime): cache Folia global and region scheduler instances#105

Closed
Arbousier1 wants to merge 1 commit into
devfrom
perf/scheduler-cache-scheduler-instances
Closed

perf(runtime): cache Folia global and region scheduler instances#105
Arbousier1 wants to merge 1 commit into
devfrom
perf/scheduler-cache-scheduler-instances

Conversation

@Arbousier1

Copy link
Copy Markdown
Collaborator

Summary

Cache the Folia GlobalRegionScheduler and RegionScheduler instances to avoid repeated reflective lookups on every scheduling call.

Changes

  • Add volatile fields cachedGlobalRegionScheduler and cachedRegionScheduler to ServerScheduler.
  • globalRegionScheduler() and regionScheduler() check the cache first; on a hit, return the cached instance directly, skipping invokeNoArgs (reflective method resolution + invocation). On the first successful non-null resolution, store the result in the cache.
  • Null results (Paper server without Folia APIs) are never cached, so the existing fallback-to-BukkitScheduler behavior is preserved — the lookup still runs each time on Paper.
  • entityScheduler(Entity) is not cached because the target entity varies per call.

Behavior equivalence

  • On Folia: the scheduler instances are stable singletons for the lifetime of the server, so caching is safe. The first call resolves reflectively; all subsequent calls return the same instance.
  • On Paper: getGlobalRegionScheduler() / getRegionScheduler() do not exist, invokeNoArgs returns null, the cache stays empty, and the code falls back to BukkitScheduler.runTask exactly as before.
  • No game rules or player-visible behavior change.

Verification

Target the scheduler-reflection performance profile (ServerSchedulerReflectionBenchmark.scheduleFoliaBurst and schedulePaperBurst).

Labels: performance-ab, performance-scheduler-reflection

globalRegionScheduler() and regionScheduler() previously invoked a
reflective method lookup on plugin.getServer() on every call. On Folia,
these return stable singleton schedulers that do not change for the
lifetime of the server. Cache the resolved scheduler in a volatile field
on first successful lookup so subsequent calls skip the reflective
invokeNoArgs path entirely.

In the benchmark Folia burst (84 tasks), this eliminates 19 reflective
scheduler lookups per invocation (4 runGlobal + 16 runRegion, minus the
first call each that populates the cache). On Paper, where these methods
do not exist and invokeNoArgs returns null, the cache stays empty and
the behavior is unchanged — null is never cached so the lookup still
runs each time, preserving the existing fallback-to-BukkitScheduler
semantics.

entityScheduler(Entity) is not cached because the target entity varies
per call and there is no stable key to cache on.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@Arbousier1 Arbousier1 added performance-ab Run the base-owned paired performance gate performance-scheduler-reflection Use the scheduler reflection performance profile labels Jul 18, 2026
@Arbousier1

Copy link
Copy Markdown
Collaborator Author

Closing: AB gate returned INCONCLUSIVE_NOISE_OR_NO_GAIN. Caching Folia global/region scheduler instances did not meet the 3% median improvement threshold.

@Arbousier1 Arbousier1 closed this Jul 18, 2026
@Arbousier1
Arbousier1 deleted the perf/scheduler-cache-scheduler-instances branch July 18, 2026 03:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance-ab Run the base-owned paired performance gate performance-scheduler-reflection Use the scheduler reflection performance profile

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant