mirror of
https://github.com/cpvalente/ontime.git
synced 2026-09-10 16:49:41 +00:00
perf: hoist update() inner functions out of the tick path
updateIfIdle and updateIfWaitingToRoll were declared inside update(), allocating two closures on every 32ms tick. They are now module-level functions receiving the state explicitly. Behaviour is unchanged, as proven by the characterisation suite. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PVTnCfesGNGwPQJwJ9FwoD
This commit is contained in:
@@ -637,7 +637,7 @@ export function updateCore(state: RuntimeState): UpdateResult {
|
|||||||
// 2. are we waiting to roll?
|
// 2. are we waiting to roll?
|
||||||
if (state.timer.playback === Playback.Roll && state.timer.secondaryTimer !== null) {
|
if (state.timer.playback === Playback.Roll && state.timer.secondaryTimer !== null) {
|
||||||
const clockHasCrossedMidnight = hasCrossedMidnight(previousClock, now);
|
const clockHasCrossedMidnight = hasCrossedMidnight(previousClock, now);
|
||||||
return updateIfWaitingToRoll(clockHasCrossedMidnight);
|
return updateIfWaitingToRoll(state, clockHasCrossedMidnight);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. at this point we know that we are playing an event
|
// 3. at this point we know that we are playing an event
|
||||||
@@ -674,36 +674,38 @@ export function updateCore(state: RuntimeState): UpdateResult {
|
|||||||
getExpectedTimesCore(state);
|
getExpectedTimesCore(state);
|
||||||
|
|
||||||
return { hasTimerFinished: finishedNow, hasSecondaryTimerFinished: false };
|
return { hasTimerFinished: finishedNow, hasSecondaryTimerFinished: false };
|
||||||
|
}
|
||||||
|
|
||||||
function updateIfIdle() {
|
// module level so the hot path does not allocate a closure on every tick
|
||||||
// if nothing is running, nothing to do
|
function updateIfIdle(): UpdateResult {
|
||||||
return { hasTimerFinished: false, hasSecondaryTimerFinished: false };
|
// if nothing is running, nothing to do
|
||||||
|
return { hasTimerFinished: false, hasSecondaryTimerFinished: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
// module level so the hot path does not allocate a closure on every tick
|
||||||
|
function updateIfWaitingToRoll(state: RuntimeState, hasCrossedMidnight: boolean): UpdateResult {
|
||||||
|
// eslint-disable-next-line no-unused-labels -- dev code path
|
||||||
|
DEV: {
|
||||||
|
if (state.eventNow === null || state._timer.secondaryTarget === null) {
|
||||||
|
throw new Error('runtimeState.updateIfWaitingToRoll: invalid state received');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateIfWaitingToRoll(hasCrossedMidnight: boolean) {
|
// account for offset
|
||||||
// eslint-disable-next-line no-unused-labels -- dev code path
|
const offsetClock = state.clock + state.offset.absolute;
|
||||||
DEV: {
|
state.timer.phase = TimerPhase.Pending;
|
||||||
if (state.eventNow === null || state._timer.secondaryTarget === null) {
|
|
||||||
throw new Error('runtimeState.updateIfWaitingToRoll: invalid state received');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// account for offset
|
if (hasCrossedMidnight) {
|
||||||
const offsetClock = state.clock + state.offset.absolute;
|
// if we crossed midnight, we need to update the target
|
||||||
state.timer.phase = TimerPhase.Pending;
|
// this is the same logic from the roll function
|
||||||
|
state._timer.secondaryTarget = normaliseRollStart(state.eventNow.timeStart, offsetClock) as TimeOfDay;
|
||||||
if (hasCrossedMidnight) {
|
|
||||||
// if we crossed midnight, we need to update the target
|
|
||||||
// this is the same logic from the roll function
|
|
||||||
state._timer.secondaryTarget = normaliseRollStart(state.eventNow.timeStart, offsetClock) as TimeOfDay;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.timer.secondaryTimer = state._timer.secondaryTarget! - offsetClock;
|
|
||||||
return {
|
|
||||||
hasTimerFinished: false,
|
|
||||||
hasSecondaryTimerFinished: state.timer.secondaryTimer <= 0,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.timer.secondaryTimer = state._timer.secondaryTarget! - offsetClock;
|
||||||
|
return {
|
||||||
|
hasTimerFinished: false,
|
||||||
|
hasSecondaryTimerFinished: state.timer.secondaryTimer <= 0,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function roll(
|
export function roll(
|
||||||
|
|||||||
Reference in New Issue
Block a user