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