X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=benchmarks%2Fbenchmarks-utils.mjs;h=16a656107fc6f00973fe7bdc6541a6bab2794a2b;hb=1fd60f0d2f318468bddcc599052dbce81fab6a8e;hp=d2f4fc23e344966f3acddd5fcb5048469fee418f;hpb=932da73291d65036a331363d6301072c023d1bd9;p=poolifier.git diff --git a/benchmarks/benchmarks-utils.mjs b/benchmarks/benchmarks-utils.mjs index d2f4fc23..16a65610 100644 --- a/benchmarks/benchmarks-utils.mjs +++ b/benchmarks/benchmarks-utils.mjs @@ -1,114 +1,20 @@ -import crypto from 'crypto' -import fs from 'fs' +import { strictEqual } from 'node:assert' + +import { bench, clear, group, run } from 'tatami-ng' + import { DynamicClusterPool, DynamicThreadPool, FixedClusterPool, - FixedThreadPool + FixedThreadPool, + Measurements, + PoolTypes, + WorkerChoiceStrategies, + WorkerTypes } from '../lib/index.mjs' -import { PoolTypes, WorkerFunctions, WorkerTypes } from './benchmarks-types.mjs' - -export async function runTest (pool, { taskExecutions, workerData }) { - return new Promise((resolve, reject) => { - let executions = 0 - for (let i = 1; i <= taskExecutions; i++) { - pool - .execute(workerData) - .then(() => { - ++executions - if (executions === taskExecutions) { - return resolve({ ok: 1 }) - } - return null - }) - .catch(err => { - console.error(err) - return reject(err) - }) - } - }) -} - -export function generateRandomInteger (max = Number.MAX_SAFE_INTEGER, min = 0) { - if (max < min || max < 0 || min < 0) { - throw new RangeError('Invalid interval') - } - max = Math.floor(max) - if (min != null && min !== 0) { - min = Math.ceil(min) - return Math.floor(Math.random() * (max - min + 1)) + min - } - return Math.floor(Math.random() * (max + 1)) -} - -function jsonIntegerSerialization (n) { - for (let i = 0; i < n; i++) { - const o = { - a: i - } - JSON.stringify(o) - } -} - -/** - * Intentionally inefficient implementation. - * @param {number} n - The number of fibonacci numbers to generate. - * @returns {number} - The nth fibonacci number. - */ -function fibonacci (n) { - if (n <= 1) return n - return fibonacci(n - 1) + fibonacci(n - 2) -} - -/** - * Intentionally inefficient implementation. - * @param {number} n - The number to calculate the factorial of. - * @returns {number} - The factorial of n. - */ -function factorial (n) { - if (n === 0) { - return 1 - } - return factorial(n - 1) * n -} - -function readWriteFiles ( - n, - baseDirectory = `/tmp/poolifier-benchmarks/${crypto.randomInt( - 281474976710655 - )}` -) { - if (fs.existsSync(baseDirectory) === true) { - fs.rmSync(baseDirectory, { recursive: true }) - } - fs.mkdirSync(baseDirectory, { recursive: true }) - for (let i = 0; i < n; i++) { - const filePath = `${baseDirectory}/${i}` - fs.writeFileSync(filePath, i.toString(), { - encoding: 'utf8', - flag: 'a' - }) - fs.readFileSync(filePath, 'utf8') - } - fs.rmSync(baseDirectory, { recursive: true }) -} - -export function executeWorkerFunction (data) { - switch (data.function) { - case WorkerFunctions.jsonIntegerSerialization: - return jsonIntegerSerialization(data.taskSize || 1000) - case WorkerFunctions.fibonacci: - return fibonacci(data.taskSize || 1000) - case WorkerFunctions.factorial: - return factorial(data.taskSize || 1000) - case WorkerFunctions.readWriteFiles: - return readWriteFiles(data.taskSize || 1000) - default: - throw new Error('Unknown worker function') - } -} +import { executeTaskFunction } from './benchmarks-utils.cjs' -export function buildPool (workerType, poolType, poolSize, poolOptions) { +const buildPoolifierPool = (workerType, poolType, poolSize, poolOptions) => { switch (poolType) { case PoolTypes.fixed: switch (workerType) { @@ -121,7 +27,7 @@ export function buildPool (workerType, poolType, poolSize, poolOptions) { case WorkerTypes.cluster: return new FixedClusterPool( poolSize, - './benchmarks/internal/cluster-worker.mjs', + './benchmarks/internal/cluster-worker.cjs', poolOptions ) } @@ -130,19 +36,127 @@ export function buildPool (workerType, poolType, poolSize, poolOptions) { switch (workerType) { case WorkerTypes.thread: return new DynamicThreadPool( - poolSize / 2, - poolSize * 3, + Math.floor(poolSize / 2), + poolSize, './benchmarks/internal/thread-worker.mjs', poolOptions ) case WorkerTypes.cluster: return new DynamicClusterPool( - poolSize / 2, - poolSize * 3, - './benchmarks/internal/cluster-worker.mjs', + Math.floor(poolSize / 2), + poolSize, + './benchmarks/internal/cluster-worker.cjs', poolOptions ) } break } } + +const runPoolifierPool = async (pool, { taskExecutions, workerData }) => { + for (let i = 1; i <= taskExecutions; i++) { + await pool.execute(workerData) + } +} + +export const runPoolifierBenchmarkTatamiNg = async ( + name, + workerType, + poolType, + poolSize, + { taskExecutions, workerData } +) => { + try { + const pool = buildPoolifierPool(workerType, poolType, poolSize) + for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) { + for (const enableTasksQueue of [false, true]) { + if (workerChoiceStrategy === WorkerChoiceStrategies.FAIR_SHARE) { + for (const measurement of [Measurements.runTime, Measurements.elu]) { + group(name, () => { + bench( + `${name} with ${workerChoiceStrategy}, with ${measurement} and ${ + enableTasksQueue ? 'with' : 'without' + } tasks queue`, + async () => { + await runPoolifierPool(pool, { + taskExecutions, + workerData + }) + }, + { + before: () => { + pool.setWorkerChoiceStrategy(workerChoiceStrategy, { + measurement + }) + pool.enableTasksQueue(enableTasksQueue) + strictEqual( + pool.opts.workerChoiceStrategy, + workerChoiceStrategy + ) + strictEqual(pool.opts.enableTasksQueue, enableTasksQueue) + strictEqual( + pool.opts.workerChoiceStrategyOptions.measurement, + measurement + ) + } + } + ) + }) + } + } else { + group(name, () => { + bench( + `${name} with ${workerChoiceStrategy} and ${ + enableTasksQueue ? 'with' : 'without' + } tasks queue`, + async () => { + await runPoolifierPool(pool, { + taskExecutions, + workerData + }) + }, + { + before: () => { + pool.setWorkerChoiceStrategy(workerChoiceStrategy) + pool.enableTasksQueue(enableTasksQueue) + strictEqual( + pool.opts.workerChoiceStrategy, + workerChoiceStrategy + ) + strictEqual(pool.opts.enableTasksQueue, enableTasksQueue) + } + } + ) + }) + } + } + } + const report = await run() + clear() + await pool.destroy() + return report + } catch (error) { + console.error(error) + } +} + +export const convertTatamiNgToBmf = report => { + return report.benchmarks + .map(({ name, stats }) => { + return { + [name]: { + latency: { + value: stats?.avg, + lower_value: stats?.min, + upper_value: stats?.max + }, + throughput: { + value: stats?.iter + } + } + } + }) + .reduce((obj, item) => Object.assign(obj, item), {}) +} + +export { executeTaskFunction }