Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ extension JavaScriptEventLoop {
return performanceNow!.now(this: performanceNow!.performance).number!
}

func hasRun(since start: DrainInstant, for interval: Duration) -> Bool {
let (seconds, attoseconds) = interval.components
let intervalMilliseconds = Double(seconds) * 1_000 + Double(attoseconds) / 1_000_000_000_000_000
return drainClockNow() - start >= intervalMilliseconds
func drainElapsed(since start: DrainInstant) -> Duration {
.milliseconds(drainClockNow() - start)
}
#else
typealias DrainInstant = ContinuousClock.Instant
Expand All @@ -32,8 +30,8 @@ extension JavaScriptEventLoop {
ContinuousClock.now
}

func hasRun(since start: DrainInstant, for interval: Duration) -> Bool {
start.duration(to: .now) >= interval
func drainElapsed(since start: DrainInstant) -> Duration {
start.duration(to: .now)
}
#endif

Expand Down
13 changes: 12 additions & 1 deletion Sources/JavaScriptEventLoop/JobQueue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ extension JavaScriptEventLoop {

// The clock is only read while `yieldInterval` is set.
var start: DrainInstant? = yieldInterval == nil ? nil : drainClockNow()
// A clock read costs more than a small job. Read it every `clockStride` jobs, and double
// the stride (up to 256) while the drain is far from the interval.
var clockStride = 1
var jobsUntilClockRead = 1
while let job = self.claimNextFromQueue() {
#if compiler(>=5.9)
job.runSynchronously(on: self.asUnownedSerialExecutor())
Expand All @@ -54,11 +58,18 @@ extension JavaScriptEventLoop {

if let yieldInterval, queueState.headJob != nil {
if let start {
if hasRun(since: start, for: yieldInterval) {
jobsUntilClockRead -= 1
if jobsUntilClockRead > 0 { continue }
let elapsed = drainElapsed(since: start)
if elapsed >= yieldInterval {
// Keep `isSpinning` set so new jobs wait for the continuation.
queueHostTask { self.runAllJobs() }
return
}
if elapsed * 4 < yieldInterval {
clockStride = min(clockStride * 2, 256)
}
jobsUntilClockRead = clockStride
} else {
start = drainClockNow()
}
Expand Down
Loading