Skip to content

Feature: Event Tick Adaptive Throttle

Tsu edited this page Jun 5, 2026 · 2 revisions

This feature lets Stratum reduce non-critical event listener load during overloaded ticks.

Where It Lives

Patched EventManager.TriggerGameTick(...) in:

  • patches/VintagestoryLib/Vintagestory.Common/EventManager.cs.patch

Adaptive Entity Listener Logic

When the previous tick is overloaded, Stratum can multiply effective intervals for non-critical entity listeners.

bool stratumAdaptiveThrottle = stratumEvtCfg != null
        && stratumEvtCfg.Enabled
        && stratumEvtCfg.AdaptiveThrottleWhenOverloaded
        && stratumEvtCfg.AdaptiveOverloadedMultiplier > 1
        && StratumRuntime.PreviousTickOverloaded;
int stratumAdaptiveMul = stratumAdaptiveThrottle ? Math.Max(1, stratumEvtCfg!.AdaptiveOverloadedMultiplier) : 1;
int stratumAdaptiveCritMs = stratumEvtCfg != null ? Math.Max(0, stratumEvtCfg.AdaptiveCriticalIntervalMs) : 50;
int stratumEffectiveInterval = gameTickListener.Millisecondinterval;
if (stratumAdaptiveThrottle && stratumEffectiveInterval > stratumAdaptiveCritMs)
{
    stratumEffectiveInterval *= stratumAdaptiveMul;
}

So low-interval critical listeners keep normal cadence, while higher-interval listeners can be throttled during overload.

Block Listener Gating Hook

Block listeners are also routed through a gate hook:

if (ShouldTriggerBlockGameTick(gameTickListenerBlock, ellapsedMilliseconds, world))
{
    gameTickListenerBlock.OnTriggered(world, gameTickListenerBlock.Pos, ellapsedMilliseconds);
    blockListenersTriggered++;
}
else
{
    gameTickListenerBlock.LastUpdateMilliseconds = ellapsedMilliseconds;
    blockListenersSkipped++;
}

With extension points:

protected virtual bool ShouldTriggerBlockGameTick(GameTickListenerBlock listener, long ellapsedMilliseconds, IWorldAccessor world)
{
    return true;
}

protected virtual void RecordBlockGameTickListeners(int ready, int triggered, int skipped)
{
}

Subsection Timings and Slow Listener Capture

If event subsection timings are enabled, Stratum records timing buckets like:

  • eventTick.gtEntity
  • eventTick.gtBlock
  • eventTick.dcEntity
  • eventTick.dcBlock

It can also record slow listener timings with configurable thresholds.

Alloc Pressure Reduction

The patch also avoids per-tick key list allocation for single delayed block callbacks by reusing:

private List<BlockPos> singleDelayedCallbackBlockKeys = new List<BlockPos>();

Source of Truth

  • patches/VintagestoryLib/Vintagestory.Common/EventManager.cs.patch
  • VintagestoryLib/Vintagestory.Common/EventManager.cs
  • sources/VintagestoryLib/Vintagestory.Server/StratumConfig.cs (Performance.EventTick)

Clone this wiki locally