@algochad/prisma-core
Version:
A comprehensive NestJS library that provides EF-Core-like operations using Prisma and GraphQL. Features LINQ-style query builders, advanced data manipulation, GraphQL integration with genql, and a unified API for both Prisma and GraphQL operations. Includ
783 lines โข 40.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BenchmarkUtils = void 0;
const perf_hooks_1 = require("perf_hooks");
const async_enumerable_1 = require("./collections/linq/async-enumerable");
const enumerable_1 = require("./collections/linq/enumerable");
class BenchmarkUtils {
static async measureTime(operation, operationName = 'operation') {
try {
const memoryBefore = process.memoryUsage
? process.memoryUsage().heapUsed
: 0;
const startTime = perf_hooks_1.performance.now();
const result = await operation();
const endTime = perf_hooks_1.performance.now();
const time = endTime - startTime;
const memoryAfter = process.memoryUsage
? process.memoryUsage().heapUsed
: 0;
const memoryUsage = Math.max(0, memoryAfter - memoryBefore);
console.log(`${operationName} completed in ${time.toFixed(2)}ms (Memory: ${(memoryUsage / 1024 / 1024).toFixed(2)}MB)`);
return { time, result, memoryUsage };
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(`${operationName} failed:`, errorMessage);
return { time: -1, result: null, error: errorMessage };
}
}
static generateTestData(size) {
return Array.from({ length: size }, (_, i) => ({
id: i + 1,
value: Math.random() * 1000,
name: `Item_${i + 1}`,
isActive: Math.random() > 0.3,
}));
}
static complexComputation(item) {
let result = item.value;
for (let i = 0; i < 1000; i++) {
result = Math.sqrt(result * Math.sin(result) + Math.cos(result));
}
return result;
}
static async asyncComputation(item) {
return Promise.resolve(BenchmarkUtils.complexComputation(item));
}
static async runComprehensiveBenchmark(dataSize = 10000) {
console.log(`\n๐ Starting Comprehensive Collection Benchmark (Data Size: ${dataSize})\n`);
const results = [];
console.log('๐ Testing Filter Operations...');
const filterData = BenchmarkUtils.generateTestData(dataSize);
const filterResult = await BenchmarkUtils.benchmarkOperation('Filter (isActive = true)', filterData, (enumerable) => enumerable.Where((x) => x.isActive).ToArray(), async (asyncEnumerable) => await asyncEnumerable.Where((x) => x.isActive).ToArrayAsync());
results.push(filterResult);
console.log('๐ Testing Map Operations...');
const mapData = BenchmarkUtils.generateTestData(dataSize);
const mapResult = await BenchmarkUtils.benchmarkOperation('Map (transform to string)', mapData, (enumerable) => enumerable
.Select((x) => `${x.name}_${x.value.toFixed(2)}`)
.ToArray(), async (asyncEnumerable) => await asyncEnumerable
.Select((x) => `${x.name}_${x.value.toFixed(2)}`)
.ToArrayAsync());
results.push(mapResult);
console.log('๐ Testing Complex Computation...');
const computationData = BenchmarkUtils.generateTestData(Math.min(1000, dataSize));
const computationResult = await BenchmarkUtils.benchmarkOperation('Complex Computation', computationData, (enumerable) => enumerable
.Select((x) => BenchmarkUtils.complexComputation(x))
.ToArray(), async (asyncEnumerable) => await asyncEnumerable
.Select(async (x) => await BenchmarkUtils.asyncComputation(x))
.ToArrayAsync());
results.push(computationResult);
console.log('๐ Testing Aggregation Operations...');
const aggregationData = BenchmarkUtils.generateTestData(dataSize);
const aggregationResult = await BenchmarkUtils.benchmarkOperation('Sum of values', aggregationData, (enumerable) => enumerable.Sum((x) => x?.value), async (asyncEnumerable) => await asyncEnumerable.SumAsync((x) => x.value));
results.push(aggregationResult);
console.log('๐ Testing Count Operations...');
const countData = BenchmarkUtils.generateTestData(dataSize);
const countResult = await BenchmarkUtils.benchmarkOperation('Count active items', countData, (enumerable) => enumerable.Count((x) => x.isActive), async (asyncEnumerable) => await asyncEnumerable.CountAsync((x) => x.isActive));
results.push(countResult);
console.log('๐ Testing First/Any Operations...');
const firstData = BenchmarkUtils.generateTestData(dataSize);
const firstResult = await BenchmarkUtils.benchmarkOperation('Find first active item', firstData, (enumerable) => enumerable.FirstOrDefault((x) => x.isActive), async (asyncEnumerable) => await asyncEnumerable.FirstOrDefaultAsync((x) => x.isActive));
results.push(firstResult);
console.log('๐ Testing Sorting Operations...');
const sortingData = BenchmarkUtils.generateTestData(dataSize);
const sortingResult = await BenchmarkUtils.benchmarkOperation('Sort by value (ascending)', sortingData, (enumerable) => enumerable.OrderBy((x) => x.value).ToArray(), async (asyncEnumerable) => await asyncEnumerable.OrderBy((x) => x.value).ToArrayAsync());
results.push(sortingResult);
console.log('๐ Testing Filtering + Sorting Operations...');
const filteringSortingData = BenchmarkUtils.generateTestData(dataSize);
const filteringSortingResult = await BenchmarkUtils.benchmarkOperation('Filter (isActive = true) + Sort by value (ascending)', filteringSortingData, (enumerable) => enumerable
.Where((x) => x.isActive)
.OrderBy((x) => x.value)
.ToArray(), async (asyncEnumerable) => await asyncEnumerable
.Where((x) => x.isActive)
.OrderBy((x) => x.value)
.ToArrayAsync());
results.push(filteringSortingResult);
console.log('๐ Testing Distinct Operations...');
const distinctData = BenchmarkUtils.generateTestData(dataSize);
const distinctResult = await BenchmarkUtils.benchmarkOperation('Distinct by name prefix', distinctData, (enumerable) => enumerable.DistinctBy((x) => x.name.substring(0, 5)).ToArray(), async (asyncEnumerable) => await asyncEnumerable
.Distinct((x) => x.name.substring(0, 5))
.ToArrayAsync());
results.push(distinctResult);
console.log('๐ Testing Complex Chaining Operations...');
const complexChainData = BenchmarkUtils.generateTestData(dataSize);
const complexChainResult = await BenchmarkUtils.benchmarkOperation('Complex Chain: Filter + Map + Sort + Take', complexChainData, (enumerable) => enumerable
.Where((x) => x.isActive && x.value > 100)
.Select((x) => ({ ...x, computed: x.value * 2 + x.id }))
.OrderByDescending((x) => x.computed)
.Take(50)
.ToArray(), async (asyncEnumerable) => await asyncEnumerable
.Where((x) => x.isActive && x.value > 100)
.Select((x) => ({ ...x, computed: x.value * 2 + x.id }))
.OrderByDescending((x) => x.computed)
.Take(50)
.ToArrayAsync());
results.push(complexChainResult);
console.log('๐ Testing Skip/Take Operations...');
const paginationData = BenchmarkUtils.generateTestData(dataSize);
const paginationResult = await BenchmarkUtils.benchmarkOperation('Pagination: Skip(100) + Take(50)', paginationData, (enumerable) => enumerable.Skip(100).Take(50).ToArray(), async (asyncEnumerable) => await asyncEnumerable.Skip(100).Take(50).ToArrayAsync());
results.push(paginationResult);
console.log('๐ Testing Min/Max Operations...');
const minMaxData = BenchmarkUtils.generateTestData(dataSize);
const minMaxResult = await BenchmarkUtils.benchmarkOperation('Find Min/Max values', minMaxData, (enumerable) => ({
min: enumerable.Min((x) => x.value),
max: enumerable.Max((x) => x.value),
}), async (asyncEnumerable) => ({
min: await asyncEnumerable.MinAsync((x) => x.value),
max: await asyncEnumerable.MaxAsync((x) => x.value),
}));
results.push(minMaxResult);
console.log('๐ Testing Edge Cases...');
const emptyResult = await BenchmarkUtils.benchmarkOperation('Empty Collection Processing', [], (enumerable) => enumerable.Where((x) => x.isActive).ToArray(), async (asyncEnumerable) => await asyncEnumerable
.Where((x) => x.isActive)
.ToArrayAsync());
results.push(emptyResult);
if (dataSize >= 5000) {
const largeSubsetData = BenchmarkUtils.generateTestData(1000);
const largeSubsetResult = await BenchmarkUtils.benchmarkOperation('Large Subset Processing (Top 1000 items)', largeSubsetData, (enumerable) => enumerable
.Where((x) => x.isActive)
.OrderBy((x) => x.value)
.Select((x) => ({
id: x.id,
name: x.name,
category: 'processed',
}))
.ToArray(), async (asyncEnumerable) => await asyncEnumerable
.Where((x) => x.isActive)
.OrderBy((x) => x.value)
.Select((x) => ({
id: x.id,
name: x.name,
category: 'processed',
}))
.ToArrayAsync());
results.push(largeSubsetResult);
}
console.log('๐ Testing Group By Operations...');
const groupByData = BenchmarkUtils.generateTestData(Math.min(1000, dataSize));
const groupByResult = await BenchmarkUtils.benchmarkOperation('Group by active status', groupByData, (enumerable) => {
const grouped = enumerable.GroupBy((x) => x.isActive ? 'active' : 'inactive');
return grouped.ToArray();
}, async (asyncEnumerable) => {
const allItems = await asyncEnumerable.ToArrayAsync();
const activeItems = allItems.filter((x) => x.isActive);
const inactiveItems = allItems.filter((x) => !x.isActive);
return [
{ key: 'active', items: activeItems },
{ key: 'inactive', items: inactiveItems },
];
});
results.push(groupByResult);
const synchronousTotal = results.reduce((sum, r) => sum + (r.synchronous.time > 0 ? r.synchronous.time : 0), 0);
const asynchronousTotal = results.reduce((sum, r) => sum + (r.asynchronous.time > 0 ? r.asynchronous.time : 0), 0);
const asyncSpeedup = synchronousTotal > 0
? `${(synchronousTotal / asynchronousTotal).toFixed(2)}x`
: 'N/A';
const summary = {
testDataSize: dataSize,
cpuCount: require('os').cpus().length,
results,
summary: {
synchronousTotal,
asynchronousTotal,
asyncSpeedup,
},
};
BenchmarkUtils.printBenchmarkSummary(summary);
return summary;
}
static async benchmarkOperation(operationName, testData, syncOperation, asyncOperation) {
const enumerable = new enumerable_1.Enumerable(testData);
const asyncEnumerable = async_enumerable_1.AsyncEnumerable.fromArray(testData);
const syncResult = await BenchmarkUtils.measureTime(() => {
return syncOperation(enumerable);
}, `${operationName} (Sync)`);
const asyncResult = await BenchmarkUtils.measureTime(async () => {
return await asyncOperation(asyncEnumerable);
}, `${operationName} (Async)`);
const performanceRatio = syncResult.time > 0 && asyncResult.time > 0
? syncResult.time / asyncResult.time
: 1;
const recommendation = performanceRatio > 1.1
? 'async'
: performanceRatio < 0.9
? 'sync'
: 'neutral';
return {
operation: operationName,
category: 'general',
dataSize: testData.length,
synchronous: {
time: syncResult.time,
result: syncResult.result,
error: syncResult.error,
memoryUsed: syncResult.memoryUsage,
},
asynchronous: {
time: asyncResult.time,
result: asyncResult.result,
error: asyncResult.error,
memoryUsed: asyncResult.memoryUsage,
},
performanceRatio,
recommendation,
};
}
static printBenchmarkSummary(summary) {
console.log('\n' + '='.repeat(100));
console.log('๐ BENCHMARK SUMMARY');
console.log('='.repeat(100));
console.log(`๐ Test Data Size: ${summary.testDataSize.toLocaleString()} items`);
console.log(`๐ป CPU Cores: ${summary.cpuCount}`);
console.log('='.repeat(100));
console.log('\n๐ DETAILED RESULTS:');
console.log('-'.repeat(100));
console.log('Operation'.padEnd(35) +
'Sync (ms)'.padEnd(12) +
'Async (ms)'.padEnd(12) +
'Ratio'.padEnd(8) +
'Best'.padEnd(12) +
'Recommendation');
console.log('-'.repeat(100));
summary.results.forEach((result) => {
const syncTime = result.synchronous.time > 0
? result.synchronous.time.toFixed(2)
: 'ERROR';
const asyncTime = result.asynchronous.time > 0
? result.asynchronous.time.toFixed(2)
: 'ERROR';
const times = [
{ name: 'Sync', time: result.synchronous.time },
{ name: 'Async', time: result.asynchronous.time },
].filter((t) => t.time > 0);
const best = times.length > 0
? times.reduce((min, current) => current.time < min.time ? current : min).name
: 'N/A';
const ratio = result.performanceRatio
? result.performanceRatio.toFixed(2)
: 'N/A';
const recommendation = result.recommendation
? result.recommendation === 'async'
? 'โก Async'
: result.recommendation === 'sync'
? '๐ Sync'
: 'โ๏ธ Either'
: 'N/A';
const bestFormatted = best !== 'N/A' ? `๐ ${best}` : 'N/A';
const truncatedOperation = result.operation.length > 32
? result.operation.substring(0, 29) + '...'
: result.operation;
console.log(truncatedOperation.padEnd(35) +
syncTime.padEnd(12) +
asyncTime.padEnd(12) +
ratio.padEnd(8) +
bestFormatted.padEnd(12) +
recommendation);
});
console.log('-'.repeat(100));
console.log('-'.repeat(110));
console.log('\n๐ฅ PERFORMANCE SUMMARY:');
console.log(`โก Total Synchronous Time: ${summary.summary.synchronousTotal.toFixed(2)}ms`);
console.log(`๐ Total Asynchronous Time: ${summary.summary.asynchronousTotal.toFixed(2)}ms`);
console.log(`๐ Async Speedup: ${summary.summary.asyncSpeedup}`);
console.log('='.repeat(100));
console.log('\n๐ก RECOMMENDATIONS:');
console.log('-'.repeat(100));
const syncWins = summary.results.filter((r) => r.recommendation === 'sync').length;
const asyncWins = summary.results.filter((r) => r.recommendation === 'async').length;
const neutrals = summary.results.filter((r) => r.recommendation === 'neutral').length;
console.log(`๐ Performance Analysis:`);
console.log(` โข Synchronous wins: ${syncWins} operations`);
console.log(` โข Asynchronous wins: ${asyncWins} operations`);
console.log(` โข Neutral performance: ${neutrals} operations`);
const avgSyncMemory = summary.results
.filter((r) => r.synchronous.memoryUsed &&
r.synchronous.memoryUsed > 0)
.reduce((sum, r) => sum + (r.synchronous.memoryUsed || 0), 0) /
summary.results.length;
const avgAsyncMemory = summary.results
.filter((r) => r.asynchronous.memoryUsed &&
r.asynchronous.memoryUsed > 0)
.reduce((sum, r) => sum + (r.asynchronous.memoryUsed || 0), 0) /
summary.results.length;
if (avgSyncMemory > 0 || avgAsyncMemory > 0) {
console.log(`\n๐ง Memory Usage Analysis:`);
console.log(` โข Average Sync Memory: ${(avgSyncMemory / 1024 / 1024).toFixed(2)}MB`);
console.log(` โข Average Async Memory: ${(avgAsyncMemory / 1024 / 1024).toFixed(2)}MB`);
}
console.log(`\n๐ฏ Overall Recommendations:`);
if (asyncWins > syncWins) {
console.log('โ
Asynchronous processing shows better performance for most operations');
console.log('๐ก Consider using AsyncEnumerable for CPU-intensive workloads');
}
else if (syncWins > asyncWins) {
console.log('โ
Synchronous processing shows better performance for most operations');
console.log('๐ก Consider using Enumerable for simple, fast operations');
}
else {
console.log('โ๏ธ Performance is balanced between sync and async approaches');
console.log('๐ก Choose based on your specific use case and data size');
}
if (summary.summary.asynchronousTotal < summary.summary.synchronousTotal) {
console.log('๐ Asynchronous processing shows overall performance benefits');
}
console.log(`๐ Best overall approach: ${summary.summary.asynchronousTotal <
summary.summary.synchronousTotal
? 'Asynchronous'
: 'Synchronous'} processing`);
console.log('='.repeat(100) + '\n');
}
static async quickBenchmark(dataSize = 1000) {
console.log(`\nโก Quick Benchmark (${dataSize} items)\n`);
const testData = BenchmarkUtils.generateTestData(dataSize);
const result = await BenchmarkUtils.benchmarkOperation('Filter + Map', testData, (enumerable) => enumerable
.Where((x) => x.isActive)
.Select((x) => x.value * 2)
.ToArray(), async (asyncEnumerable) => await asyncEnumerable
.Where(async (x) => x.isActive)
.Select(async (x) => x.value * 2)
.ToArrayAsync());
console.log(`Sync: ${result.synchronous.time.toFixed(2)}ms`);
console.log(`Async: ${result.asynchronous.time.toFixed(2)}ms`);
const best = [
{ name: 'Synchronous', time: result.synchronous.time },
{ name: 'Asynchronous', time: result.asynchronous.time },
]
.filter((r) => r.time > 0)
.reduce((min, current) => current.time < min.time ? current : min);
console.log(`๐ Winner: ${best.name} (${best.time.toFixed(2)}ms)\n`);
}
static async runStressTest(sizes = [1000, 5000, 10000, 50000]) {
console.log('\n๐ฅ Starting Performance Stress Test\n');
console.log('='.repeat(80));
for (const size of sizes) {
console.log(`\n๐ Testing with ${size.toLocaleString()} items:`);
console.log('-'.repeat(40));
const filterTestData = BenchmarkUtils.generateTestData(size);
const filterResult = await BenchmarkUtils.benchmarkOperation(`Filter (${size} items)`, filterTestData, (enumerable) => enumerable.Where((x) => x.isActive).ToArray(), async (asyncEnumerable) => await asyncEnumerable
.Where((x) => x.isActive)
.ToArrayAsync());
const sortTestData = BenchmarkUtils.generateTestData(size);
const sortResult = await BenchmarkUtils.benchmarkOperation(`Sort (${size} items)`, sortTestData, (enumerable) => enumerable.OrderBy((x) => x.value).ToArray(), async (asyncEnumerable) => await asyncEnumerable
.OrderBy((x) => x.value)
.ToArrayAsync());
console.log(` Filter - Sync: ${filterResult.synchronous.time.toFixed(2)}ms, Async: ${filterResult.asynchronous.time.toFixed(2)}ms`);
console.log(` Sort - Sync: ${sortResult.synchronous.time.toFixed(2)}ms, Async: ${sortResult.asynchronous.time.toFixed(2)}ms`);
}
console.log('\n='.repeat(80));
console.log('๐ Stress Test Complete');
}
static async runScalabilityTest(startSize = 1000, endSize = 10000, steps = 5) {
console.log('\n๐ Starting Scalability Analysis\n');
console.log('='.repeat(80));
const stepSize = Math.floor((endSize - startSize) / (steps - 1));
const results = [];
for (let i = 0; i < steps; i++) {
const size = startSize + i * stepSize;
console.log(`\n๐ Testing scalability with ${size.toLocaleString()} items:`);
const testData = BenchmarkUtils.generateTestData(size);
const result = await BenchmarkUtils.benchmarkOperation(`Complex Chain (${size} items)`, testData, (enumerable) => enumerable
.Where((x) => x.isActive)
.Select((x) => ({ ...x, computed: x.value * 2 }))
.OrderBy((x) => x.computed)
.Take(Math.min(100, size))
.ToArray(), async (asyncEnumerable) => await asyncEnumerable
.Where((x) => x.isActive)
.Select((x) => ({ ...x, computed: x.value * 2 }))
.OrderBy((x) => x.computed)
.Take(Math.min(100, size))
.ToArrayAsync());
results.push({
size,
syncTime: result.synchronous.time,
asyncTime: result.asynchronous.time,
});
console.log(` Sync: ${result.synchronous.time.toFixed(2)}ms`);
console.log(` Async: ${result.asynchronous.time.toFixed(2)}ms`);
}
console.log('\n๐ Scalability Summary:');
console.log('-'.repeat(60));
console.log('Size'.padEnd(15) +
'Sync (ms)'.padEnd(15) +
'Async (ms)'.padEnd(15) +
'Ratio');
console.log('-'.repeat(60));
results.forEach((result) => {
const ratio = result.syncTime / result.asyncTime;
console.log(result.size.toLocaleString().padEnd(15) +
result.syncTime.toFixed(2).padEnd(15) +
result.asyncTime.toFixed(2).padEnd(15) +
ratio.toFixed(2));
});
console.log('='.repeat(80));
}
static async runEdgeCaseTests() {
console.log('\n๐งช Starting Edge Case Tests\n');
console.log('='.repeat(80));
console.log('๐ Testing empty collections...');
const emptyTest = await BenchmarkUtils.benchmarkOperation('Empty Collection', [], (enumerable) => enumerable.Where((x) => x.isActive).ToArray(), async (asyncEnumerable) => await asyncEnumerable
.Where((x) => x.isActive)
.ToArrayAsync());
console.log(` Empty - Sync: ${emptyTest.synchronous.time.toFixed(2)}ms, Async: ${emptyTest.asynchronous.time.toFixed(2)}ms`);
console.log('๐ Testing single item...');
const singleItemData = BenchmarkUtils.generateTestData(1);
const singleTest = await BenchmarkUtils.benchmarkOperation('Single Item', singleItemData, (enumerable) => enumerable.Where((x) => x.isActive).ToArray(), async (asyncEnumerable) => await asyncEnumerable.Where((x) => x.isActive).ToArrayAsync());
console.log(` Single - Sync: ${singleTest.synchronous.time.toFixed(2)}ms, Async: ${singleTest.asynchronous.time.toFixed(2)}ms`);
console.log('๐ Testing all items match...');
const allMatchData = Array.from({ length: 1000 }, (_, i) => ({
id: i + 1,
value: Math.random() * 1000,
name: `Item_${i + 1}`,
isActive: true,
}));
const allMatchTest = await BenchmarkUtils.benchmarkOperation('All Items Match', allMatchData, (enumerable) => enumerable.Where((x) => x.isActive).ToArray(), async (asyncEnumerable) => await asyncEnumerable.Where((x) => x.isActive).ToArrayAsync());
console.log(` All Match - Sync: ${allMatchTest.synchronous.time.toFixed(2)}ms, Async: ${allMatchTest.asynchronous.time.toFixed(2)}ms`);
console.log('๐ Testing no items match...');
const noMatchData = Array.from({ length: 1000 }, (_, i) => ({
id: i + 1,
value: Math.random() * 1000,
name: `Item_${i + 1}`,
isActive: false,
}));
const noMatchTest = await BenchmarkUtils.benchmarkOperation('No Items Match', noMatchData, (enumerable) => enumerable.Where((x) => x.isActive).ToArray(), async (asyncEnumerable) => await asyncEnumerable.Where((x) => x.isActive).ToArrayAsync());
console.log(` No Match - Sync: ${noMatchTest.synchronous.time.toFixed(2)}ms, Async: ${noMatchTest.asynchronous.time.toFixed(2)}ms`);
console.log('\n='.repeat(80));
console.log('๐ Edge Case Tests Complete');
}
static async runFullBenchmarkSuite(dataSize = 10000) {
console.log('\n๐ Starting Full Benchmark Suite\n');
console.log('='.repeat(80));
console.log(`๐ Data Size: ${dataSize.toLocaleString()} items`);
console.log(`๐ป CPU Cores: ${require('os').cpus().length}`);
console.log(`๐ Start Time: ${new Date().toISOString()}`);
console.log('='.repeat(80));
try {
console.log('\n๐ฌ Phase 1: Comprehensive Benchmark');
const comprehensiveResults = await BenchmarkUtils.runComprehensiveBenchmark(dataSize);
console.log('\n๐ฅ Phase 2: Stress Testing');
await BenchmarkUtils.runStressTest([1000, 5000, dataSize]);
console.log('\n๐ Phase 3: Scalability Analysis');
await BenchmarkUtils.runScalabilityTest(1000, dataSize, 5);
console.log('\n๐งช Phase 4: Edge Case Testing');
await BenchmarkUtils.runEdgeCaseTests();
console.log('\n๐ Final Summary Report');
console.log('='.repeat(80));
console.log(`๐ End Time: ${new Date().toISOString()}`);
console.log(`โ
Total Operations Tested: ${comprehensiveResults.results.length}`);
console.log(`๐ Overall Performance: ${comprehensiveResults.summary.asyncSpeedup} async speedup`);
const successfulTests = comprehensiveResults.results.filter((r) => !r.synchronous.error && !r.asynchronous.error).length;
console.log(`โ๏ธ Successful Tests: ${successfulTests}/${comprehensiveResults.results.length}`);
if (successfulTests < comprehensiveResults.results.length) {
const failedTests = comprehensiveResults.results.length - successfulTests;
console.log(`โ Failed Tests: ${failedTests}`);
}
console.log('='.repeat(80));
console.log('๐ Full Benchmark Suite Complete!');
}
catch (error) {
console.error('\nโ Benchmark Suite Failed:', error);
throw error;
}
}
static async benchmarkCustomOperation(operation, config = {}) {
const { iterations = 10, warmupRuns = 3, trackMemory = true, showProgress = false, timeout = 30000, } = config;
if (showProgress) {
console.log(`๐ง Benchmarking "${operation.name}" (${iterations} iterations)...`);
}
for (let i = 0; i < warmupRuns; i++) {
try {
await operation.operation(operation.input);
}
catch (error) {
}
}
const times = [];
let memoryUsed = 0;
let result;
let error;
try {
for (let i = 0; i < iterations; i++) {
if (showProgress && iterations > 10) {
process.stdout.write(`\r Progress: ${i + 1}/${iterations}`);
}
const memoryBefore = trackMemory && process.memoryUsage
? process.memoryUsage().heapUsed
: 0;
const startTime = perf_hooks_1.performance.now();
result = await Promise.race([
operation.operation(operation.input),
new Promise((_, reject) => setTimeout(() => reject(new Error('Operation timed out')), timeout)),
]);
const endTime = perf_hooks_1.performance.now();
const memoryAfter = trackMemory && process.memoryUsage
? process.memoryUsage().heapUsed
: 0;
times.push(endTime - startTime);
if (trackMemory) {
memoryUsed += Math.max(0, memoryAfter - memoryBefore);
}
}
if (showProgress && iterations > 10) {
console.log();
}
}
catch (err) {
error = err instanceof Error ? err.message : String(err);
}
const averageTime = times.length > 0
? times.reduce((a, b) => a + b, 0) / times.length
: 0;
const totalTime = times.reduce((a, b) => a + b, 0);
return {
operationName: operation.name,
averageTime,
totalTime,
iterations: times.length,
memoryUsed: trackMemory ? memoryUsed / iterations : undefined,
result: result,
error,
};
}
static async benchmarkOperationsBatch(operations, config = {}) {
const { showProgress = false } = config;
if (showProgress) {
console.log(`๐ Running batch benchmark with ${operations.length} operations...`);
}
const results = await Promise.all(operations.map(async (operation, index) => {
if (showProgress) {
console.log(`\n ${index + 1}/${operations.length}: ${operation.name}`);
}
const result = await this.benchmarkCustomOperation(operation, {
...config,
showProgress: false,
});
return {
name: operation.name,
time: result.averageTime,
result: result.result,
error: result.error,
memoryUsed: result.memoryUsed,
iterations: result.iterations,
};
}));
const validResults = results.filter((r) => !r.error && r.time > 0);
if (validResults.length === 0) {
throw new Error('No valid benchmark results obtained');
}
const fastest = validResults.reduce((min, current) => current.time < min.time ? current : min);
const slowest = validResults.reduce((max, current) => current.time > max.time ? current : max);
const averageTime = validResults.reduce((sum, r) => sum + r.time, 0) /
validResults.length;
const totalTime = validResults.reduce((sum, r) => sum + r.time, 0);
return {
operations: results,
summary: {
fastest: fastest.name,
slowest: slowest.name,
averageTime,
totalTime,
},
};
}
static async benchmarkQuery(queryOperation, dataGenerator, options = {}) {
const { dataSizes = [100, 500, 1000, 5000, 10000], iterations = 5, warmupRuns = 2, trackMemory = true, scalabilityAnalysis = true, } = options;
console.log(`๐ Query scalability analysis with data sizes: ${dataSizes.join(', ')}`);
const results = [];
for (const size of dataSizes) {
console.log(` Testing with ${size.toLocaleString()} items...`);
const testData = dataGenerator(size);
const operation = {
name: `Query (${size} items)`,
operation: queryOperation,
input: testData,
iterations,
warmupRuns,
};
const benchmark = await this.benchmarkCustomOperation(operation, {
iterations,
warmupRuns,
trackMemory,
showProgress: false,
});
results.push({
dataSize: size,
time: benchmark.averageTime,
memoryUsed: benchmark.memoryUsed,
result: benchmark.result,
error: benchmark.error,
});
}
let analysis;
if (scalabilityAnalysis && results.length >= 3) {
const validResults = results.filter((r) => !r.error && r.time > 0);
if (validResults.length >= 3) {
const n = validResults.length;
const sumX = validResults.reduce((sum, r) => sum + r.dataSize, 0);
const sumY = validResults.reduce((sum, r) => sum + r.time, 0);
const sumXY = validResults.reduce((sum, r) => sum + r.dataSize * r.time, 0);
const sumX2 = validResults.reduce((sum, r) => sum + r.dataSize * r.dataSize, 0);
const slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
const correlation = slope > 0 ? Math.min(slope / 1000, 1) : 0;
let timeComplexity = 'Unknown';
let recommendation = 'Monitor performance with larger datasets';
if (correlation > 0.8) {
timeComplexity = 'Linear O(n)';
recommendation =
'Performance scales linearly with data size';
}
else if (correlation > 0.5) {
timeComplexity = 'Sub-linear or variable';
recommendation =
'Consider optimizations for large datasets';
}
else {
timeComplexity = 'Constant or very efficient';
recommendation = 'Excellent scalability characteristics';
}
analysis = {
timeComplexity,
recommendation,
linearFit: correlation,
};
}
}
return {
operation: 'Query Scalability Test',
results,
scalabilityAnalysis: analysis,
};
}
static async compareOperations(operation1, operation2, input, config = {}) {
console.log(`โ๏ธ Comparing: "${operation1.name}" vs "${operation2.name}"`);
const op1Config = {
name: operation1.name,
operation: operation1.operation,
input,
};
const op2Config = {
name: operation2.name,
operation: operation2.operation,
input,
};
const [result1, result2] = await Promise.all([
this.benchmarkCustomOperation(op1Config, config),
this.benchmarkCustomOperation(op2Config, config),
]);
const timeDifference = Math.abs(result1.averageTime - result2.averageTime);
const performanceRatio = result1.averageTime / result2.averageTime;
let fasterOperation;
let recommendation;
if (performanceRatio > 1.1) {
fasterOperation = operation2.name;
recommendation = `${operation2.name} is ${performanceRatio.toFixed(2)}x faster`;
}
else if (performanceRatio < 0.9) {
fasterOperation = operation1.name;
recommendation = `${operation1.name} is ${(1 / performanceRatio).toFixed(2)}x faster`;
}
else {
fasterOperation = 'Comparable performance';
recommendation = 'Both approaches have similar performance';
}
return {
operation1: {
name: operation1.name,
time: result1.averageTime,
result: result1.result,
error: result1.error,
memoryUsed: result1.memoryUsed,
},
operation2: {
name: operation2.name,
time: result2.averageTime,
result: result2.result,
error: result2.error,
memoryUsed: result2.memoryUsed,
},
comparison: {
fasterOperation,
timeDifference,
performanceRatio,
recommendation,
},
};
}
static async runCustomBenchmarkSuite(operations, config = {}) {
const suiteName = `Custom Benchmark Suite (${operations.length} operations)`;
console.log(`\n๐ Starting ${suiteName}`);
console.log('='.repeat(80));
const results = [];
let successfulOperations = 0;
let failedOperations = 0;
for (const [index, operation] of operations.entries()) {
console.log(`\n๐ ${index + 1}/${operations.length}: ${operation.name}`);
try {
const result = await this.benchmarkCustomOperation(operation, {
...config,
showProgress: true,
});
results.push(result);
if (!result.error) {
successfulOperations++;
console.log(` โ
Average: ${result.averageTime.toFixed(2)}ms (${result.iterations} iterations)`);
if (result.memoryUsed) {
console.log(` ๐ง Memory: ${(result.memoryUsed / 1024 / 1024).toFixed(2)}MB`);
}
}
else {
failedOperations++;
console.log(` โ Failed: ${result.error}`);
}
}
catch (error) {
failedOperations++;
const errorMessage = error instanceof Error ? error.message : String(error);
console.log(` โ Exception: ${errorMessage}`);
results.push({
operationName: operation.name,
averageTime: 0,
totalTime: 0,
iterations: 0,
result: null,
error: errorMessage,
});
}
}
const successfulResults = results.filter((r) => !r.error && r.averageTime > 0);
const avgSyncTime = successfulResults.length > 0
? successfulResults.reduce((sum, r) => sum + r.averageTime, 0) /
successfulResults.length
: 0;
const avgAsyncTime = avgSyncTime;
const overallRecommendation = successfulOperations > failedOperations
? `${((successfulOperations / operations.length) * 100).toFixed(1)}% success rate - Good performance`
: 'Multiple failures detected - Review operation implementations';
console.log('\n' + '='.repeat(80));
console.log('๐ CUSTOM BENCHMARK SUMMARY');
console.log('='.repeat(80));
console.log(`โ
Successful operations: ${successfulOperations}/${operations.length}`);
console.log(`โ Failed operations: ${failedOperations}`);
if (successfulResults.length > 0) {
console.log(`โฑ๏ธ Average execution time: ${avgSyncTime.toFixed(2)}ms`);
console.log(`๐ Fastest: ${successfulResults.reduce((min, current) => current.averageTime < min.averageTime ? current : min).operationName}`);
console.log(`๐ Slowest: ${successfulResults.reduce((max, current) => current.averageTime > max.averageTime ? current : max).operationName}`);
}
console.log(`๐ก ${overallRecommendation}`);
console.log('='.repeat(80));
return {
suiteName,
results,
summary: {
totalOperations: operations.length,
successfulOperations,
failedOperations,
avgSyncTime,
avgAsyncTime,
overallRecommendation,
},
};
}
}
exports.BenchmarkUtils = BenchmarkUtils;
//# sourceMappingURL=benchmark.utils.js.map