refactor: benchmark specific section
[poolifier.git] / benchmarks / benchmarks-utils.mjs
1 import { strictEqual } from 'node:assert'
2
3 import Benchmark from 'benchmark'
4 import { bench, group } from 'mitata'
5
6 import {
7 DynamicClusterPool,
8 DynamicThreadPool,
9 FixedClusterPool,
10 FixedThreadPool,
11 Measurements,
12 PoolTypes,
13 WorkerChoiceStrategies,
14 WorkerTypes
15 } from '../lib/index.mjs'
16 import { executeTaskFunction } from './benchmarks-utils.cjs'
17
18 const buildPoolifierPool = (workerType, poolType, poolSize, poolOptions) => {
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.cjs',
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.cjs',
50 poolOptions
51 )
52 }
53 break
54 }
55 }
56
57 const runPoolifierPool = async (pool, { taskExecutions, workerData }) => {
58 return await new Promise((resolve, reject) => {
59 let executions = 0
60 for (let i = 1; i <= taskExecutions; i++) {
61 pool
62 .execute(workerData)
63 .then(() => {
64 ++executions
65 if (executions === taskExecutions) {
66 resolve({ ok: 1 })
67 }
68 return undefined
69 })
70 .catch(err => {
71 console.error(err)
72 reject(err)
73 })
74 }
75 })
76 }
77
78 export const runPoolifierBenchmarkBenchmarkJs = async (
79 name,
80 workerType,
81 poolType,
82 poolSize,
83 { taskExecutions, workerData }
84 ) => {
85 return await new Promise((resolve, reject) => {
86 const pool = buildPoolifierPool(workerType, poolType, poolSize)
87 try {
88 const suite = new Benchmark.Suite(name)
89 for (const workerChoiceStrategy of Object.values(
90 WorkerChoiceStrategies
91 )) {
92 for (const enableTasksQueue of [false, true]) {
93 if (workerChoiceStrategy === WorkerChoiceStrategies.FAIR_SHARE) {
94 for (const measurement of [
95 Measurements.runTime,
96 Measurements.elu
97 ]) {
98 suite.add(
99 `${name} with ${workerChoiceStrategy}, with ${measurement} and ${
100 enableTasksQueue ? 'with' : 'without'
101 } tasks queue`,
102 async () => {
103 await runPoolifierPool(pool, {
104 taskExecutions,
105 workerData
106 })
107 },
108 {
109 onStart: () => {
110 pool.setWorkerChoiceStrategy(workerChoiceStrategy, {
111 measurement
112 })
113 pool.enableTasksQueue(enableTasksQueue)
114 strictEqual(
115 pool.opts.workerChoiceStrategy,
116 workerChoiceStrategy
117 )
118 strictEqual(pool.opts.enableTasksQueue, enableTasksQueue)
119 strictEqual(
120 pool.opts.workerChoiceStrategyOptions.measurement,
121 measurement
122 )
123 }
124 }
125 )
126 }
127 } else {
128 suite.add(
129 `${name} with ${workerChoiceStrategy} and ${
130 enableTasksQueue ? 'with' : 'without'
131 } tasks queue`,
132 async () => {
133 await runPoolifierPool(pool, {
134 taskExecutions,
135 workerData
136 })
137 },
138 {
139 onStart: () => {
140 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
141 pool.enableTasksQueue(enableTasksQueue)
142 strictEqual(
143 pool.opts.workerChoiceStrategy,
144 workerChoiceStrategy
145 )
146 strictEqual(pool.opts.enableTasksQueue, enableTasksQueue)
147 }
148 }
149 )
150 }
151 }
152 }
153 suite
154 .on('cycle', event => {
155 console.info(event.target.toString())
156 })
157 .on('complete', function () {
158 console.info(
159 'Fastest is ' +
160 LIST_FORMATTER.format(this.filter('fastest').map('name'))
161 )
162 const destroyTimeout = setTimeout(() => {
163 console.error('Pool destroy timeout reached (30s)')
164 resolve()
165 }, 30000)
166 pool
167 .destroy()
168 .then(resolve)
169 .catch(reject)
170 .finally(() => {
171 clearTimeout(destroyTimeout)
172 })
173 .catch(() => {})
174 })
175 .run({ async: true })
176 } catch (error) {
177 pool
178 .destroy()
179 .then(() => {
180 return reject(error)
181 })
182 .catch(() => {})
183 }
184 })
185 }
186
187 export const buildPoolifierBenchmarkMitata = (
188 name,
189 workerType,
190 poolType,
191 poolSize,
192 { taskExecutions, workerData }
193 ) => {
194 try {
195 const pool = buildPoolifierPool(workerType, poolType, poolSize)
196 for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
197 for (const enableTasksQueue of [false, true]) {
198 if (workerChoiceStrategy === WorkerChoiceStrategies.FAIR_SHARE) {
199 for (const measurement of [Measurements.runTime, Measurements.elu]) {
200 group(name, () => {
201 bench(
202 `${name} with ${workerChoiceStrategy}, with ${measurement} and ${
203 enableTasksQueue ? 'with' : 'without'
204 } tasks queue`,
205 async () => {
206 pool.setWorkerChoiceStrategy(workerChoiceStrategy, {
207 measurement
208 })
209 pool.enableTasksQueue(enableTasksQueue)
210 strictEqual(
211 pool.opts.workerChoiceStrategy,
212 workerChoiceStrategy
213 )
214 strictEqual(pool.opts.enableTasksQueue, enableTasksQueue)
215 strictEqual(
216 pool.opts.workerChoiceStrategyOptions.measurement,
217 measurement
218 )
219 await runPoolifierPool(pool, {
220 taskExecutions,
221 workerData
222 })
223 }
224 )
225 })
226 }
227 } else {
228 group(name, () => {
229 bench(
230 `${name} with ${workerChoiceStrategy} and ${
231 enableTasksQueue ? 'with' : 'without'
232 } tasks queue`,
233 async () => {
234 pool.setWorkerChoiceStrategy(workerChoiceStrategy)
235 pool.enableTasksQueue(enableTasksQueue)
236 strictEqual(
237 pool.opts.workerChoiceStrategy,
238 workerChoiceStrategy
239 )
240 strictEqual(pool.opts.enableTasksQueue, enableTasksQueue)
241 await runPoolifierPool(pool, {
242 taskExecutions,
243 workerData
244 })
245 }
246 )
247 })
248 }
249 }
250 }
251 return pool
252 } catch (error) {
253 console.error(error)
254 }
255 }
256
257 const LIST_FORMATTER = new Intl.ListFormat('en-US', {
258 style: 'long',
259 type: 'conjunction'
260 })
261
262 export { executeTaskFunction }