From 4e24a3f3807bd30dca6785172408b66ba4bf2c61 Mon Sep 17 00:00:00 2001 From: "Michael \"Z\" Goddard" Date: Fri, 3 Nov 2017 11:52:42 -0400 Subject: [PATCH 1/2] Constant time check if thread is in doneThreads Remove indexOf tests for thread existence in doneThreads. Maintain a list of null and thread objects mirroring the index position of threads that are done in runtime.threads. Filter out null values after filtering out done threads from runtime.threads. This has a small side effect that threads that normally became DONE and were added to doneThreads before being removed or restarted will not be in doneThreads in this version. Restarted threads (_restartThread) do not appear in this version but new copies will be in Runtime this.threads supporting glow and monitor updates. Removed threads (_removeThread) do not appear in this version if they are removed after they were seen as DONE by the prior version. Threads removed before they are seen as DONE do not appear in doneThreads in the prior or this version. Threads that are removed before normally becoming DONE do not appear in doneThreads in either case. Threads that are restarted before the loop checks if the thread is done do not appear in doneThreads in either case. --- src/engine/sequencer.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js index 0a126d67e..9664290c4 100644 --- a/src/engine/sequencer.js +++ b/src/engine/sequencer.js @@ -38,7 +38,7 @@ class Sequencer { let numActiveThreads = Infinity; // Whether `stepThreads` has run through a full single tick. let ranFirstTick = false; - const doneThreads = []; + const doneThreads = this.runtime.threads.map(() => null); // Conditions for continuing to stepping threads: // 1. We must have threads in the list, and some must be active. // 2. Time elapsed must be less than WORK_TIME. @@ -54,11 +54,13 @@ class Sequencer { if (activeThread.stack.length === 0 || activeThread.status === Thread.STATUS_DONE) { // Finished with this thread. - if (doneThreads.indexOf(activeThread) < 0) { - doneThreads.push(activeThread); - } + doneThreads[i] = activeThread; continue; } + // A thread was removed, added or this thread was restarted. + if (doneThreads[i] !== null) { + doneThreads[i] = null; + } if (activeThread.status === Thread.STATUS_YIELD_TICK && !ranFirstTick) { // Clear single-tick yield from the last call of `stepThreads`. @@ -82,13 +84,13 @@ class Sequencer { ranFirstTick = true; } // Filter inactive threads from `this.runtime.threads`. - this.runtime.threads = this.runtime.threads.filter(thread => { - if (doneThreads.indexOf(thread) > -1) { + this.runtime.threads = this.runtime.threads.filter((thread, i) => { + if (doneThreads[i] === null) { return false; } return true; }); - return doneThreads; + return doneThreads.filter(Boolean); } /** From 6d82c0f115713ae729dfadc024ddf6d70e21b25f Mon Sep 17 00:00:00 2001 From: "Michael \"Z\" Goddard" Date: Fri, 3 Nov 2017 16:24:12 -0400 Subject: [PATCH 2/2] In place filter threads at end of stepThreads Skip a large array allocation by filtering done threads in place with a for loop. --- src/engine/sequencer.js | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/engine/sequencer.js b/src/engine/sequencer.js index 9664290c4..f4edc966c 100644 --- a/src/engine/sequencer.js +++ b/src/engine/sequencer.js @@ -84,13 +84,28 @@ class Sequencer { ranFirstTick = true; } // Filter inactive threads from `this.runtime.threads`. - this.runtime.threads = this.runtime.threads.filter((thread, i) => { + numActiveThreads = 0; + for (let i = 0; i < this.runtime.threads.length; i++) { + const thread = this.runtime.threads[i]; if (doneThreads[i] === null) { - return false; + this.runtime.threads[numActiveThreads] = thread; + numActiveThreads++; } - return true; - }); - return doneThreads.filter(Boolean); + } + this.runtime.threads.length = numActiveThreads; + + // Filter undefined and null values from `doneThreads`. + let numDoneThreads = 0; + for (let i = 0; i < doneThreads.length; i++) { + const maybeThread = doneThreads[i]; + if (maybeThread !== null) { + doneThreads[numDoneThreads] = maybeThread; + numDoneThreads++; + } + } + doneThreads.length = numDoneThreads; + + return doneThreads; } /**