From 9fe8fd698590c2494dc6793cfd8c08026fe88a31 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Sun, 27 Aug 2023 21:35:22 +0200 Subject: [PATCH] perf: improve node eligibility branching on worker choice strategies MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- .c8rc.json | 2 +- .../fair-share-worker-choice-strategy.ts | 8 +-- ...hted-round-robin-worker-choice-strategy.ts | 8 +-- .../least-busy-worker-choice-strategy.ts | 10 +-- .../least-elu-worker-choice-strategy.ts | 10 +-- .../least-used-worker-choice-strategy.ts | 10 +-- src/utils.ts | 69 +++++++++---------- tests/utils.test.js | 27 ++++++-- 8 files changed, 81 insertions(+), 63 deletions(-) diff --git a/.c8rc.json b/.c8rc.json index ab1b20fa..a6da2792 100644 --- a/.c8rc.json +++ b/.c8rc.json @@ -3,5 +3,5 @@ "lines": 92, "statements": 92, "functions": 95, - "branches": 92 + "branches": 90 } diff --git a/src/pools/selection-strategies/fair-share-worker-choice-strategy.ts b/src/pools/selection-strategies/fair-share-worker-choice-strategy.ts index 094e9b02..fc4bd1fd 100644 --- a/src/pools/selection-strategies/fair-share-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/fair-share-worker-choice-strategy.ts @@ -84,15 +84,15 @@ export class FairShareWorkerChoiceStrategy< let minWorkerVirtualTaskEndTimestamp = Infinity let chosenWorkerNodeKey: number | undefined for (const [workerNodeKey] of this.pool.workerNodes.entries()) { + if (!this.isWorkerNodeEligible(workerNodeKey)) { + continue + } if (this.workersVirtualTaskEndTimestamp[workerNodeKey] == null) { this.computeWorkerVirtualTaskEndTimestamp(workerNodeKey) } const workerVirtualTaskEndTimestamp = this.workersVirtualTaskEndTimestamp[workerNodeKey] - if ( - this.isWorkerNodeEligible(workerNodeKey) && - workerVirtualTaskEndTimestamp < minWorkerVirtualTaskEndTimestamp - ) { + if (workerVirtualTaskEndTimestamp < minWorkerVirtualTaskEndTimestamp) { minWorkerVirtualTaskEndTimestamp = workerVirtualTaskEndTimestamp chosenWorkerNodeKey = workerNodeKey } diff --git a/src/pools/selection-strategies/interleaved-weighted-round-robin-worker-choice-strategy.ts b/src/pools/selection-strategies/interleaved-weighted-round-robin-worker-choice-strategy.ts index 86a7f5ca..e3754382 100644 --- a/src/pools/selection-strategies/interleaved-weighted-round-robin-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/interleaved-weighted-round-robin-worker-choice-strategy.ts @@ -74,12 +74,12 @@ export class InterleavedWeightedRoundRobinWorkerChoiceStrategy< workerNodeKey < this.pool.workerNodes.length; workerNodeKey++ ) { + if (!this.isWorkerNodeEligible(workerNodeKey)) { + continue + } const workerWeight = this.opts.weights?.[workerNodeKey] ?? this.defaultWorkerWeight - if ( - this.isWorkerNodeEligible(workerNodeKey) && - workerWeight >= this.roundWeights[roundIndex] - ) { + if (workerWeight >= this.roundWeights[roundIndex]) { workerNodeId = workerNodeKey break } diff --git a/src/pools/selection-strategies/least-busy-worker-choice-strategy.ts b/src/pools/selection-strategies/least-busy-worker-choice-strategy.ts index 6fad8939..338ae379 100644 --- a/src/pools/selection-strategies/least-busy-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/least-busy-worker-choice-strategy.ts @@ -74,16 +74,16 @@ export class LeastBusyWorkerChoiceStrategy< let minTime = Infinity let chosenWorkerNodeKey: number | undefined for (const [workerNodeKey, workerNode] of this.pool.workerNodes.entries()) { + if (!this.isWorkerNodeEligible(workerNodeKey)) { + continue + } const workerTime = (workerNode.usage.runTime?.aggregate ?? 0) + (workerNode.usage.waitTime?.aggregate ?? 0) - if (this.isWorkerNodeEligible(workerNodeKey) && workerTime === 0) { + if (workerTime === 0) { chosenWorkerNodeKey = workerNodeKey break - } else if ( - this.isWorkerNodeEligible(workerNodeKey) && - workerTime < minTime - ) { + } else if (workerTime < minTime) { minTime = workerTime chosenWorkerNodeKey = workerNodeKey } diff --git a/src/pools/selection-strategies/least-elu-worker-choice-strategy.ts b/src/pools/selection-strategies/least-elu-worker-choice-strategy.ts index 00919f33..938d2072 100644 --- a/src/pools/selection-strategies/least-elu-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/least-elu-worker-choice-strategy.ts @@ -70,15 +70,15 @@ export class LeastEluWorkerChoiceStrategy< let minWorkerElu = Infinity let chosenWorkerNodeKey: number | undefined for (const [workerNodeKey, workerNode] of this.pool.workerNodes.entries()) { + if (!this.isWorkerNodeEligible(workerNodeKey)) { + continue + } const workerUsage = workerNode.usage const workerElu = workerUsage.elu?.active?.aggregate ?? 0 - if (this.isWorkerNodeEligible(workerNodeKey) && workerElu === 0) { + if (workerElu === 0) { chosenWorkerNodeKey = workerNodeKey break - } else if ( - this.isWorkerNodeEligible(workerNodeKey) && - workerElu < minWorkerElu - ) { + } else if (workerElu < minWorkerElu) { minWorkerElu = workerElu chosenWorkerNodeKey = workerNodeKey } diff --git a/src/pools/selection-strategies/least-used-worker-choice-strategy.ts b/src/pools/selection-strategies/least-used-worker-choice-strategy.ts index 4387d792..d0adbcd7 100644 --- a/src/pools/selection-strategies/least-used-worker-choice-strategy.ts +++ b/src/pools/selection-strategies/least-used-worker-choice-strategy.ts @@ -55,18 +55,18 @@ export class LeastUsedWorkerChoiceStrategy< let minNumberOfTasks = Infinity let chosenWorkerNodeKey: number | undefined for (const [workerNodeKey, workerNode] of this.pool.workerNodes.entries()) { + if (!this.isWorkerNodeEligible(workerNodeKey)) { + continue + } const workerTaskStatistics = workerNode.usage.tasks const workerTasks = workerTaskStatistics.executed + workerTaskStatistics.executing + workerTaskStatistics.queued - if (this.isWorkerNodeEligible(workerNodeKey) && workerTasks === 0) { + if (workerTasks === 0) { chosenWorkerNodeKey = workerNodeKey break - } else if ( - this.isWorkerNodeEligible(workerNodeKey) && - workerTasks < minNumberOfTasks - ) { + } else if (workerTasks < minNumberOfTasks) { minNumberOfTasks = workerTasks chosenWorkerNodeKey = workerNodeKey } diff --git a/src/utils.ts b/src/utils.ts index 21b2032b..54d0d8d6 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -67,6 +67,40 @@ export const availableParallelism = (): number => { return availableParallelism } +/** + * Returns the worker type of the given worker. + * + * @param worker - The worker to get the type of. + * @returns The worker type of the given worker. + * @internal + */ +export const getWorkerType = ( + worker: Worker +): WorkerType | undefined => { + if (worker instanceof ThreadWorker) { + return WorkerTypes.thread + } else if (worker instanceof ClusterWorker) { + return WorkerTypes.cluster + } +} + +/** + * Returns the worker id of the given worker. + * + * @param worker - The worker to get the id of. + * @returns The worker id of the given worker. + * @internal + */ +export const getWorkerId = ( + worker: Worker +): number | undefined => { + if (worker instanceof ThreadWorker) { + return worker.threadId + } else if (worker instanceof ClusterWorker) { + return worker.id + } +} + /** * Sleeps for the given amount of milliseconds. * @@ -116,41 +150,6 @@ export const average = (dataSet: number[]): number => { ) } -/** - * Returns the worker type of the given worker. - * - * @param worker - The worker to get the type of. - * @returns The worker type of the given worker. - * @internal - */ -export const getWorkerType = ( - worker: Worker -): WorkerType | undefined => { - if (worker instanceof ThreadWorker) { - return WorkerTypes.thread - } - if (worker instanceof ClusterWorker) { - return WorkerTypes.cluster - } -} - -/** - * Returns the worker id of the given worker. - * - * @param worker - The worker to get the id of. - * @returns The worker id of the given worker. - * @internal - */ -export const getWorkerId = ( - worker: Worker -): number | undefined => { - if (worker instanceof ThreadWorker) { - return worker.threadId - } else if (worker instanceof ClusterWorker) { - return worker.id - } -} - /** * Computes the median of the given data set. * diff --git a/tests/utils.test.js b/tests/utils.test.js index 6cfe99ae..ef7688d6 100644 --- a/tests/utils.test.js +++ b/tests/utils.test.js @@ -1,4 +1,6 @@ const { randomInt } = require('crypto') +const { Worker } = require('worker_threads') +const cluster = require('cluster') const { expect } = require('expect') const { CircularArray, @@ -8,6 +10,8 @@ const { availableParallelism, average, exponentialDelay, + getWorkerType, + getWorkerId, isAsyncFunction, isKillBehavior, isPlainObject, @@ -17,13 +21,28 @@ const { sleep, updateMeasurementStatistics } = require('../lib/utils') -const { KillBehaviors } = require('../lib/worker/worker-options') +const { KillBehaviors, WorkerTypes } = require('../lib') describe('Utils test suite', () => { it('Verify availableParallelism() behavior', () => { - expect(typeof availableParallelism() === 'number').toBe(true) - expect(availableParallelism()).toBeGreaterThan(0) - expect(Number.isSafeInteger(availableParallelism())).toBe(true) + const parallelism = availableParallelism() + expect(typeof parallelism === 'number').toBe(true) + expect(parallelism).toBeGreaterThan(0) + expect(Number.isSafeInteger(parallelism)).toBe(true) + }) + + it('Verify getWorkerType() behavior', () => { + expect( + getWorkerType(new Worker('./tests/worker-files/thread/testWorker.js')) + ).toBe(WorkerTypes.thread) + expect(getWorkerType(cluster.fork())).toBe(WorkerTypes.cluster) + }) + + it('Verify getWorkerId() behavior', () => { + const threadWorker = new Worker('./tests/worker-files/thread/testWorker.js') + const clusterWorker = cluster.fork() + expect(getWorkerId(threadWorker)).toBe(threadWorker.threadId) + expect(getWorkerId(clusterWorker)).toBe(clusterWorker.id) }) it.skip('Verify sleep() behavior', async () => { -- 2.34.1