1 import crypto from 'node:crypto'
2 import assert from 'node:assert'
3 import fs from 'node:fs'
4 import Benchmark from 'benchmark'
11 WorkerChoiceStrategies,
13 } from '../lib/index.mjs'
14 import { TaskFunctions } from './benchmarks-types.mjs'
16 export const buildPoolifierPool = (
25 case WorkerTypes.thread:
26 return new FixedThreadPool(
28 './benchmarks/internal/thread-worker.mjs',
31 case WorkerTypes.cluster:
32 return new FixedClusterPool(
34 './benchmarks/internal/cluster-worker.mjs',
39 case PoolTypes.dynamic:
41 case WorkerTypes.thread:
42 return new DynamicThreadPool(
43 Math.floor(poolSize / 2),
45 './benchmarks/internal/thread-worker.mjs',
48 case WorkerTypes.cluster:
49 return new DynamicClusterPool(
50 Math.floor(poolSize / 2),
52 './benchmarks/internal/cluster-worker.mjs',
60 export const runPoolifierPool = async (
62 { taskExecutions, workerData }
64 return await new Promise((resolve, reject) => {
66 for (let i = 1; i <= taskExecutions; i++) {
71 if (executions === taskExecutions) {
84 export const runPoolifierPoolBenchmark = async (
87 { taskExecutions, workerData }
89 return await new Promise((resolve, reject) => {
91 const suite = new Benchmark.Suite(name)
92 for (const workerChoiceStrategy of Object.values(
93 WorkerChoiceStrategies
95 for (const enableTasksQueue of [false, true]) {
97 `${name}|${workerChoiceStrategy}|${
98 enableTasksQueue ? 'with' : 'without'
101 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
102 pool.enableTasksQueue(enableTasksQueue)
104 pool.opts.workerChoiceStrategy,
107 assert.strictEqual(pool.opts.enableTasksQueue, enableTasksQueue)
108 await runPoolifierPool(pool, {
117 .on('cycle', event => {
118 console.info(event.target.toString())
120 .on('complete', async function () {
123 LIST_FORMATTER.format(this.filter('fastest').map('name'))
128 .run({ async: true })
135 export const LIST_FORMATTER = new Intl.ListFormat('en-US', {
140 export const executeAsyncFn = async fn => {
145 // eslint-disable-next-line n/no-process-exit
150 export const generateRandomInteger = (
151 max = Number.MAX_SAFE_INTEGER,
154 if (max < min || max < 0 || min < 0) {
155 throw new RangeError('Invalid interval')
157 max = Math.floor(max)
158 if (min != null && min !== 0) {
160 return Math.floor(Math.random() * (max - min + 1)) + min
162 return Math.floor(Math.random() * (max + 1))
165 const jsonIntegerSerialization = n => {
166 for (let i = 0; i < n; i++) {
176 * Intentionally inefficient implementation.
177 * @param {number} n - The number of fibonacci numbers to generate.
178 * @returns {number} - The nth fibonacci number.
180 const fibonacci = n => {
182 return fibonacci(n - 1) + fibonacci(n - 2)
186 * Intentionally inefficient implementation.
187 * @param {number} n - The number to calculate the factorial of.
188 * @returns {number} - The factorial of n.
190 const factorial = n => {
194 return factorial(n - 1) * n
197 const readWriteFiles = (
199 baseDirectory = `/tmp/poolifier-benchmarks/${crypto.randomInt(
203 if (fs.existsSync(baseDirectory) === true) {
204 fs.rmSync(baseDirectory, { recursive: true })
206 fs.mkdirSync(baseDirectory, { recursive: true })
207 for (let i = 0; i < n; i++) {
208 const filePath = `${baseDirectory}/${i}`
209 fs.writeFileSync(filePath, i.toString(), {
213 fs.readFileSync(filePath, 'utf8')
215 fs.rmSync(baseDirectory, { recursive: true })
219 export const executeTaskFunction = data => {
220 switch (data.function) {
221 case TaskFunctions.jsonIntegerSerialization:
222 return jsonIntegerSerialization(data.taskSize || 1000)
223 case TaskFunctions.fibonacci:
224 return fibonacci(data.taskSize || 1000)
225 case TaskFunctions.factorial:
226 return factorial(data.taskSize || 1000)
227 case TaskFunctions.readWriteFiles:
228 return readWriteFiles(data.taskSize || 1000)
230 throw new Error('Unknown task function')