test: fix continuous benchmark pool implementation name
[poolifier.git] / benchmarks / benchmarks-utils.mjs
1 import crypto from 'node:crypto'
2 import fs from 'node:fs'
3 import {
4 DynamicClusterPool,
5 DynamicThreadPool,
6 FixedClusterPool,
7 FixedThreadPool,
8 PoolTypes,
9 WorkerTypes
10 } from '../lib/index.mjs'
11 import { TaskFunctions } from './benchmarks-types.mjs'
12
13 export const buildPoolifierPool = (
14 workerType,
15 poolType,
16 poolSize,
17 poolOptions
18 ) => {
19 switch (poolType) {
20 case PoolTypes.fixed:
21 switch (workerType) {
22 case WorkerTypes.thread:
23 return new FixedThreadPool(
24 poolSize,
25 './benchmarks/internal/thread-worker.mjs',
26 poolOptions
27 )
28 case WorkerTypes.cluster:
29 return new FixedClusterPool(
30 poolSize,
31 './benchmarks/internal/cluster-worker.mjs',
32 poolOptions
33 )
34 }
35 break
36 case PoolTypes.dynamic:
37 switch (workerType) {
38 case WorkerTypes.thread:
39 return new DynamicThreadPool(
40 Math.floor(poolSize / 2),
41 poolSize,
42 './benchmarks/internal/thread-worker.mjs',
43 poolOptions
44 )
45 case WorkerTypes.cluster:
46 return new DynamicClusterPool(
47 Math.floor(poolSize / 2),
48 poolSize,
49 './benchmarks/internal/cluster-worker.mjs',
50 poolOptions
51 )
52 }
53 break
54 }
55 }
56
57 export const runPoolifierTest = async (
58 pool,
59 { taskExecutions, workerData }
60 ) => {
61 return new Promise((resolve, reject) => {
62 let executions = 0
63 for (let i = 1; i <= taskExecutions; i++) {
64 pool
65 .execute(workerData)
66 .then(() => {
67 ++executions
68 if (executions === taskExecutions) {
69 return resolve({ ok: 1 })
70 }
71 return null
72 })
73 .catch(err => {
74 console.error(err)
75 return reject(err)
76 })
77 }
78 })
79 }
80
81 export const getPoolImplementationName = pool => {
82 if (pool instanceof FixedThreadPool) {
83 return 'FixedThreadPool'
84 } else if (pool instanceof DynamicThreadPool) {
85 return 'DynamicThreadPool'
86 } else if (pool instanceof FixedClusterPool) {
87 return 'FixedClusterPool'
88 } else if (pool instanceof DynamicClusterPool) {
89 return 'DynamicClusterPool'
90 }
91 }
92
93 export const LIST_FORMATTER = new Intl.ListFormat('en-US', {
94 style: 'long',
95 type: 'conjunction'
96 })
97
98 export const executeAsyncFn = async fn => {
99 try {
100 await fn()
101 } catch (e) {
102 console.error(e)
103 // eslint-disable-next-line n/no-process-exit
104 process.exit(1)
105 }
106 }
107
108 export const generateRandomInteger = (
109 max = Number.MAX_SAFE_INTEGER,
110 min = 0
111 ) => {
112 if (max < min || max < 0 || min < 0) {
113 throw new RangeError('Invalid interval')
114 }
115 max = Math.floor(max)
116 if (min != null && min !== 0) {
117 min = Math.ceil(min)
118 return Math.floor(Math.random() * (max - min + 1)) + min
119 }
120 return Math.floor(Math.random() * (max + 1))
121 }
122
123 const jsonIntegerSerialization = n => {
124 for (let i = 0; i < n; i++) {
125 const o = {
126 a: i
127 }
128 JSON.stringify(o)
129 }
130 return { ok: 1 }
131 }
132
133 /**
134 * Intentionally inefficient implementation.
135 * @param {number} n - The number of fibonacci numbers to generate.
136 * @returns {number} - The nth fibonacci number.
137 */
138 const fibonacci = n => {
139 if (n <= 1) return n
140 return fibonacci(n - 1) + fibonacci(n - 2)
141 }
142
143 /**
144 * Intentionally inefficient implementation.
145 * @param {number} n - The number to calculate the factorial of.
146 * @returns {number} - The factorial of n.
147 */
148 const factorial = n => {
149 if (n === 0) {
150 return 1
151 }
152 return factorial(n - 1) * n
153 }
154
155 const readWriteFiles = (
156 n,
157 baseDirectory = `/tmp/poolifier-benchmarks/${crypto.randomInt(
158 281474976710655
159 )}`
160 ) => {
161 if (fs.existsSync(baseDirectory) === true) {
162 fs.rmSync(baseDirectory, { recursive: true })
163 }
164 fs.mkdirSync(baseDirectory, { recursive: true })
165 for (let i = 0; i < n; i++) {
166 const filePath = `${baseDirectory}/${i}`
167 fs.writeFileSync(filePath, i.toString(), {
168 encoding: 'utf8',
169 flag: 'a'
170 })
171 fs.readFileSync(filePath, 'utf8')
172 }
173 fs.rmSync(baseDirectory, { recursive: true })
174 return { ok: 1 }
175 }
176
177 export const executeTaskFunction = data => {
178 switch (data.function) {
179 case TaskFunctions.jsonIntegerSerialization:
180 return jsonIntegerSerialization(data.taskSize || 1000)
181 case TaskFunctions.fibonacci:
182 return fibonacci(data.taskSize || 1000)
183 case TaskFunctions.factorial:
184 return factorial(data.taskSize || 1000)
185 case TaskFunctions.readWriteFiles:
186 return readWriteFiles(data.taskSize || 1000)
187 default:
188 throw new Error('Unknown task function')
189 }
190 }