build(deps-dev): apply updates
[poolifier.git] / benchmarks / benchmarks-utils.mjs
CommitLineData
d5fdc57b 1import crypto from 'node:crypto'
cde5b54e 2import assert from 'node:assert'
d5fdc57b 3import fs from 'node:fs'
cde5b54e 4import Benchmark from 'benchmark'
8f810074 5import {
cdace0e5
JB
6 DynamicClusterPool,
7 DynamicThreadPool,
8 FixedClusterPool,
d9d8c14e
JB
9 FixedThreadPool,
10 PoolTypes,
cde5b54e 11 WorkerChoiceStrategies,
d9d8c14e 12 WorkerTypes
8f810074 13} from '../lib/index.mjs'
dbca3be9 14import { TaskFunctions } from './benchmarks-types.mjs'
2d2e32c2 15
479ba9f6
JB
16export const buildPoolifierPool = (
17 workerType,
18 poolType,
19 poolSize,
20 poolOptions
21) => {
22 switch (poolType) {
23 case PoolTypes.fixed:
24 switch (workerType) {
25 case WorkerTypes.thread:
26 return new FixedThreadPool(
27 poolSize,
28 './benchmarks/internal/thread-worker.mjs',
29 poolOptions
30 )
31 case WorkerTypes.cluster:
32 return new FixedClusterPool(
33 poolSize,
34 './benchmarks/internal/cluster-worker.mjs',
35 poolOptions
36 )
37 }
38 break
39 case PoolTypes.dynamic:
40 switch (workerType) {
41 case WorkerTypes.thread:
42 return new DynamicThreadPool(
43 Math.floor(poolSize / 2),
44 poolSize,
45 './benchmarks/internal/thread-worker.mjs',
46 poolOptions
47 )
48 case WorkerTypes.cluster:
49 return new DynamicClusterPool(
50 Math.floor(poolSize / 2),
51 poolSize,
52 './benchmarks/internal/cluster-worker.mjs',
53 poolOptions
54 )
55 }
56 break
57 }
58}
59
cde5b54e 60export const runPoolifierPool = async (
479ba9f6
JB
61 pool,
62 { taskExecutions, workerData }
63) => {
cde5b54e 64 return await new Promise((resolve, reject) => {
ff5e76e1 65 let executions = 0
cdace0e5 66 for (let i = 1; i <= taskExecutions; i++) {
ff5e76e1
JB
67 pool
68 .execute(workerData)
fe2f6f84 69 .then(() => {
0762fbb1 70 ++executions
cdace0e5 71 if (executions === taskExecutions) {
cde5b54e 72 resolve({ ok: 1 })
ff5e76e1
JB
73 }
74 return null
75 })
041dc05b 76 .catch(err => {
23ff945a 77 console.error(err)
cde5b54e 78 reject(err)
23ff945a 79 })
ff5e76e1
JB
80 }
81 })
82}
83
cde5b54e
JB
84export const runPoolifierPoolBenchmark = async (
85 name,
86 pool,
87 { taskExecutions, workerData }
88) => {
89 return await new Promise((resolve, reject) => {
90 try {
91 const suite = new Benchmark.Suite(name)
92 for (const workerChoiceStrategy of Object.values(
93 WorkerChoiceStrategies
94 )) {
95 for (const enableTasksQueue of [false, true]) {
96 suite.add(
97 `${name}|${workerChoiceStrategy}|${
98 enableTasksQueue ? 'with' : 'without'
99 } tasks queue`,
100 async () => {
101 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
102 pool.enableTasksQueue(enableTasksQueue)
103 assert.strictEqual(
104 pool.opts.workerChoiceStrategy,
105 workerChoiceStrategy
106 )
107 assert.strictEqual(pool.opts.enableTasksQueue, enableTasksQueue)
108 await runPoolifierPool(pool, {
109 taskExecutions,
110 workerData
111 })
112 }
113 )
114 }
115 }
116 suite
117 .on('cycle', event => {
118 console.info(event.target.toString())
119 })
120 .on('complete', async function () {
121 console.info(
122 'Fastest is ' +
123 LIST_FORMATTER.format(this.filter('fastest').map('name'))
124 )
125 await pool.destroy()
126 resolve()
127 })
128 .run({ async: true })
129 } catch (error) {
130 reject(error)
131 }
132 })
a7825346
JB
133}
134
f1c674cd
JB
135export const LIST_FORMATTER = new Intl.ListFormat('en-US', {
136 style: 'long',
137 type: 'conjunction'
138})
139
479ba9f6
JB
140export const executeAsyncFn = async fn => {
141 try {
142 await fn()
143 } catch (e) {
144 console.error(e)
145 // eslint-disable-next-line n/no-process-exit
146 process.exit(1)
147 }
148}
149
bac873bd
JB
150export const generateRandomInteger = (
151 max = Number.MAX_SAFE_INTEGER,
152 min = 0
153) => {
548140e6 154 if (max < min || max < 0 || min < 0) {
4af5c11a
JB
155 throw new RangeError('Invalid interval')
156 }
c2d7d79b 157 max = Math.floor(max)
4af5c11a 158 if (min != null && min !== 0) {
c2d7d79b 159 min = Math.ceil(min)
872585ea 160 return Math.floor(Math.random() * (max - min + 1)) + min
74750c7f 161 }
872585ea 162 return Math.floor(Math.random() * (max + 1))
74750c7f
JB
163}
164
041dc05b 165const jsonIntegerSerialization = n => {
cdace0e5
JB
166 for (let i = 0; i < n; i++) {
167 const o = {
168 a: i
169 }
170 JSON.stringify(o)
171 }
30b963d4 172 return { ok: 1 }
cdace0e5
JB
173}
174
bdacc2d2
JB
175/**
176 * Intentionally inefficient implementation.
7d82d90e
JB
177 * @param {number} n - The number of fibonacci numbers to generate.
178 * @returns {number} - The nth fibonacci number.
bdacc2d2 179 */
041dc05b 180const fibonacci = n => {
024daf59 181 if (n <= 1) return n
bdacc2d2
JB
182 return fibonacci(n - 1) + fibonacci(n - 2)
183}
184
7d82d90e
JB
185/**
186 * Intentionally inefficient implementation.
7d82d90e
JB
187 * @param {number} n - The number to calculate the factorial of.
188 * @returns {number} - The factorial of n.
189 */
041dc05b 190const factorial = n => {
7d82d90e
JB
191 if (n === 0) {
192 return 1
7d82d90e 193 }
965415bb 194 return factorial(n - 1) * n
7d82d90e
JB
195}
196
bac873bd 197const readWriteFiles = (
670734fc
JB
198 n,
199 baseDirectory = `/tmp/poolifier-benchmarks/${crypto.randomInt(
200 281474976710655
201 )}`
bac873bd 202) => {
670734fc
JB
203 if (fs.existsSync(baseDirectory) === true) {
204 fs.rmSync(baseDirectory, { recursive: true })
cdace0e5 205 }
670734fc 206 fs.mkdirSync(baseDirectory, { recursive: true })
cdace0e5
JB
207 for (let i = 0; i < n; i++) {
208 const filePath = `${baseDirectory}/${i}`
209 fs.writeFileSync(filePath, i.toString(), {
210 encoding: 'utf8',
211 flag: 'a'
212 })
213 fs.readFileSync(filePath, 'utf8')
214 }
670734fc 215 fs.rmSync(baseDirectory, { recursive: true })
30b963d4 216 return { ok: 1 }
cdace0e5
JB
217}
218
041dc05b 219export const executeTaskFunction = data => {
2d2e32c2 220 switch (data.function) {
dbca3be9 221 case TaskFunctions.jsonIntegerSerialization:
d1a9aa41 222 return jsonIntegerSerialization(data.taskSize || 1000)
dbca3be9 223 case TaskFunctions.fibonacci:
d1a9aa41 224 return fibonacci(data.taskSize || 1000)
dbca3be9 225 case TaskFunctions.factorial:
d1a9aa41 226 return factorial(data.taskSize || 1000)
dbca3be9 227 case TaskFunctions.readWriteFiles:
cdace0e5 228 return readWriteFiles(data.taskSize || 1000)
2d2e32c2 229 default:
dbca3be9 230 throw new Error('Unknown task function')
2d2e32c2
JB
231 }
232}