外观
性能测试工具
工具概述
JavaScript 算法性能测试工具是用于量化评估代码执行效率的系统化解决方案。通过精确测量时间复杂度和空间复杂度,帮助开发者识别性能瓶颈、优化关键路径,确保算法在各种规模数据下保持高效运行。
核心测试流程:
输入算法 → 执行测试套件 → 收集指标数据 → 生成分析报告
↓
性能基准对比 ← 可视化展示核心测试框架
基础性能测量
javascript
// 性能测试器基类
export class PerformanceTester {
constructor() {
this.tests = new Map();
this.results = new Map();
this.warmupRounds = 10;
this.defaultIterations = 1000;
}
// 添加测试用例
addTest(name, testFunction, setupFunction = null) {
this.tests.set(name, {
test: testFunction,
setup: setupFunction,
data: null
});
return this;
}
// 执行单次性能测试
measureSingle(name, ...args) {
const testCase = this.tests.get(name);
if (!testCase) throw new Error(`Test ${name} not found`);
// 准备工作
if (testCase.setup) {
testCase.data = testCase.setup();
}
// 预热
for (let i = 0; i < this.warmupRounds; i++) {
testCase.test(testCase.data, ...args);
}
// 正式测量
const startTime = performance.now();
const result = testCase.test(testCase.data, ...args);
const endTime = performance.now();
return {
time: endTime - startTime,
result: result,
memory: this.getMemoryUsage()
};
}
// 批量性能测试
measureBulk(name, iterations = this.defaultIterations, ...args) {
const testCase = this.tests.get(name);
if (!testCase) throw new Error(`Test ${name} not found`);
const times = [];
let results = [];
// 设置测试数据
if (testCase.setup) {
testCase.data = testCase.setup();
}
// 预热
for (let i = 0; i < this.warmupRounds; i++) {
testCase.test(testCase.data, ...args);
}
// 执行多次测试
for (let i = 0; i < iterations; i++) {
const startTime = performance.now();
const result = testCase.test(testCase.data, ...args);
const endTime = performance.now();
times.push(endTime - startTime);
results.push(result);
}
return this.analyzeResults(times, results);
}
// 分析测试结果
analyzeResults(times, results) {
const sortedTimes = [...times].sort((a, b) => a - b);
const sum = sortedTimes.reduce((a, b) => a + b, 0);
return {
iterations: times.length,
mean: sum / times.length,
median: sortedTimes[Math.floor(times.length / 2)],
min: Math.min(...times),
max: Math.max(...times),
standardDeviation: this.calculateStdDev(times),
totalTime: sum,
results: results
};
}
// 计算标准差
calculateStdDev(times) {
const mean = times.reduce((a, b) => a + b, 0) / times.length;
const squareDiffs = times.map(time => Math.pow(time - mean, 2));
const avgSquareDiff = squareDiffs.reduce((a, b) => a + b, 0) / times.length;
return Math.sqrt(avgSquareDiff);
}
// 获取内存使用情况(Node.js环境)
getMemoryUsage() {
if (typeof process !== 'undefined' && process.memoryUsage) {
return process.memoryUsage();
}
return { used: null, total: null };
}
}渐进复杂度分析
javascript
// 复杂度分析工具
export class ComplexityAnalyzer {
constructor() {
this.sizeRange = [10, 100, 1000, 10000];
this.complexityPatterns = {
'O(1)': { threshold: 1.2, pattern: 'constant' },
'O(log n)': { threshold: 2.5, pattern: 'logarithmic' },
'O(n)': { threshold: 10, pattern: 'linear' },
'O(n log n)': { threshold: 15, pattern: 'linearithmic' },
'O(n²)': { threshold: 100, pattern: 'quadratic' },
'O(2ⁿ)': { threshold: 1000, pattern: 'exponential' }
};
}
// 分析算法复杂度
async analyzeComplexity(algorithm, dataGenerator) {
const results = [];
for (const size of this.sizeRange) {
const testData = dataGenerator(size);
// 测量执行时间
const startTime = performance.now();
await algorithm(testData);
const endTime = performance.now();
results.push({
size,
time: endTime - startTime
});
}
return {
rawData: results,
complexity: this.detectComplexity(results),
growthFactor: this.calculateGrowthFactor(results)
};
}
// 检测复杂度类型
detectComplexity(results) {
const ratios = [];
for (let i = 1; i < results.length; i++) {
const timeRatio = results[i].time / results[i-1].time;
const sizeRatio = results[i].size / results[i-1].size;
ratios.push(timeRatio / sizeRatio);
}
const avgRatio = ratios.reduce((a, b) => a + b, 0) / ratios.length;
for (const [complexity, { threshold }] of Object.entries(this.complexityPatterns)) {
if (avgRatio <= threshold) {
return complexity;
}
}
return 'O(n^k)'; // 高次多项式
}
// 计算增长因子
calculateGrowthFactor(results) {
const factors = [];
for (let i = 1; i < results.length; i++) {
const timeGrowth = results[i].time / results[0].time;
const sizeGrowth = results[i].size / results[0].size;
factors.push(timeGrowth / sizeGrowth);
}
return factors.reduce((a, b) => a + b, 0) / factors.length;
}
}高级测试功能
内存泄漏检测
javascript
// 内存分析工具
export class MemoryProfiler {
constructor() {
this.snapshots = new Map();
this.leakThreshold = 1.1; // 10%增长视为潜在泄漏
}
// 创建内存快照
takeSnapshot(label) {
if (typeof global !== 'undefined' && global.gc) {
global.gc(); // 强制垃圾回收(Node.js --expose-gc)
}
const snapshot = {
timestamp: Date.now(),
memory: this.getMemoryInfo(),
stack: new Error().stack.split('\n').slice(2) // 移除前两行框架代码
};
this.snapshots.set(label, snapshot);
return snapshot;
}
// 获取内存信息
getMemoryInfo() {
if (typeof process !== 'undefined' && process.memoryUsage) {
const usage = process.memoryUsage();
return {
heapUsed: usage.heapUsed,
heapTotal: usage.heapTotal,
external: usage.external,
rss: usage.rss
};
} else if (typeof performance !== 'undefined' && performance.memory) {
// 浏览器环境
const memory = performance.memory;
return {
usedJSHeapSize: memory.usedJSHeapSize,
totalJSHeapSize: memory.totalJSHeapSize,
jsHeapSizeLimit: memory.jsHeapSizeLimit
};
}
return {};
}
// 检测内存泄漏
detectLeaks() {
const leaks = [];
const snapshotsArray = Array.from(this.snapshots.entries());
for (let i = 1; i < snapshotsArray.length; i++) {
const [currentLabel, currentSnapshot] = snapshotsArray[i];
const [previousLabel, previousSnapshot] = snapshotsArray[i - 1];
const memoryGrowth = this.calculateMemoryGrowth(
previousSnapshot.memory,
currentSnapshot.memory
);
if (memoryGrowth > this.leakThreshold) {
leaks.push({
from: previousLabel,
to: currentLabel,
growth: memoryGrowth,
timeDiff: currentSnapshot.timestamp - previousSnapshot.timestamp
});
}
}
return leaks;
}
// 计算内存增长
calculateMemoryGrowth(previous, current) {
const prevHeap = previous.heapUsed || previous.usedJSHeapSize;
const currHeap = current.heapUsed || current.usedJSHeapSize;
if (!prevHeap || !currHeap) return 0;
return currHeap / prevHeap;
}
// 长期内存监控
startLongTermMonitoring(intervalMs = 5000) {
let monitorCount = 0;
return setInterval(() => {
this.takeSnapshot(`monitor_${monitorCount++}`);
const leaks = this.detectLeaks();
if (leaks.length > 0) {
console.warn('Potential memory leaks detected:', leaks);
}
}, intervalMs);
}
}异步性能测试
javascript
// 异步操作性能测试
export class AsyncPerformanceTester extends PerformanceTester {
async measureAsync(name, iterations = this.defaultIterations, ...args) {
const testCase = this.tests.get(name);
if (!testCase) throw new Error(`Test ${name} not found`);
const times = [];
let results = [];
// 设置测试数据
if (testCase.setup) {
testCase.data = await testCase.setup();
}
// 预热
for (let i = 0; i < this.warmupRounds; i++) {
await testCase.test(testCase.data, ...args);
}
// 执行多次测试
for (let i = 0; i < iterations; i++) {
const startTime = performance.now();
const result = await testCase.test(testCase.data, ...args);
const endTime = performance.now();
times.push(endTime - startTime);
results.push(result);
}
return this.analyzeResults(times, results);
}
// 并发性能测试
async measureConcurrent(name, concurrency = 5, requestsPerWorker = 100, ...args) {
const testCase = this.tests.get(name);
if (!testCase) throw new Error(`Test ${name} not found`);
if (testCase.setup) {
testCase.data = await testCase.setup();
}
const workers = [];
const allTimes = [];
// 创建并发工作器
for (let i = 0; i < concurrency; i++) {
workers.push(this.createWorker(testCase, requestsPerWorker, ...args));
}
// 等待所有工作器完成
const results = await Promise.all(workers);
// 合并结果
for (const workerResult of results) {
allTimes.push(...workerResult.times);
}
return {
...this.analyzeResults(allTimes, results.flatMap(r => r.results)),
concurrency,
totalRequests: concurrency * requestsPerWorker,
requestsPerSecond: (concurrency * requestsPerWorker) /
(Math.max(...allTimes) / 1000)
};
}
async createWorker(testCase, requests, ...args) {
const times = [];
const results = [];
for (let i = 0; i < requests; i++) {
const startTime = performance.now();
const result = await testCase.test(testCase.data, ...args);
const endTime = performance.now();
times.push(endTime - startTime);
results.push(result);
}
return { times, results };
}
}可视化报告系统
控制台报告生成器
javascript
// 文本可视化报告
export class ConsoleReporter {
static generateReport(testResults, options = {}) {
const {
showPercentiles = true,
showHistogram = true,
width = 50
} = options;
let report = '\n' + '='.repeat(60) + '\n';
report += 'PERFORMANCE TEST REPORT\n';
report += '='.repeat(60) + '\n\n';
for (const [testName, result] of testResults) {
report += this.formatTestResult(testName, result, width);
if (showPercentiles) {
report += this.formatPercentiles(result);
}
if (showHistogram) {
report += this.formatHistogram(result, width);
}
report += '\n' + '-'.repeat(60) + '\n\n';
}
return report;
}
static formatTestResult(name, result, width) {
const header = `TEST: ${name}`.padEnd(width);
const iterations = `Iterations: ${result.iterations}`.padEnd(width);
const mean = `Mean Time: ${result.mean.toFixed(4)}ms`.padEnd(width);
const median = `Median Time: ${result.median.toFixed(4)}ms`.padEnd(width);
const minMax = `Range: ${result.min.toFixed(4)}ms - ${result.max.toFixed(4)}ms`.padEnd(width);
return `${header}\n${iterations}\n${mean}\n${median}\n${minMax}\n`;
}
static formatPercentiles(result) {
if (!result.percentiles) return '';
let percentiles = 'Percentiles:\n';
for (const [percentile, value] of Object.entries(result.percentiles)) {
percentiles += ` ${percentile}%: ${value.toFixed(4)}ms\n`;
}
return percentiles;
}
static formatHistogram(result, width) {
if (!result.histogram) return '';
const maxCount = Math.max(...result.histogram.map(bin => bin.count));
const scale = (width - 20) / maxCount;
let histogram = 'Response Time Distribution:\n';
for (const bin of result.histogram) {
const bar = '█'.repeat(Math.max(1, Math.round(bin.count * scale)));
histogram += ` ${bin.range}: ${bar} (${bin.count})\n`;
}
return histogram;
}
// 复杂度比较报告
static generateComplexityReport(analysisResults) {
let report = '\nCOMPLEXITY ANALYSIS REPORT\n';
report += '='.repeat(50) + '\n';
for (const [algorithm, analysis] of analysisResults) {
report += `Algorithm: ${algorithm}\n`;
report += `Detected Complexity: ${analysis.complexity}\n`;
report += `Growth Factor: ${analysis.growthFactor.toFixed(2)}\n\n`;
report += 'Size vs Time:\n';
for (const point of analysis.rawData) {
const size = point.size.toString().padStart(6);
const time = point.time.toFixed(2).padStart(8);
report += ` Size: ${size} | Time: ${time}ms\n`;
}
report += '\n';
}
return report;
}
}基准对比系统
javascript
// 基准测试对比工具
export class BenchmarkComparator {
constructor(baselineResults = new Map()) {
this.baselines = baselineResults;
this.tolerance = 0.1; // 10%性能差异容忍度
}
// 设置性能基准
setBaseline(name, results) {
this.baselines.set(name, {
...results,
timestamp: Date.now()
});
}
// 对比性能结果
compare(currentResults) {
const comparisons = new Map();
for (const [testName, currentResult] of currentResults) {
const baseline = this.baselines.get(testName);
if (!baseline) {
comparisons.set(testName, {
status: 'NO_BASELINE',
current: currentResult.mean,
change: null
});
continue;
}
const change = (currentResult.mean - baseline.mean) / baseline.mean;
const absoluteChange = Math.abs(change);
let status;
if (absoluteChange <= this.tolerance) {
status = 'WITHIN_TOLERANCE';
} else if (change > 0) {
status = 'REGRESSION';
} else {
status = 'IMPROVEMENT';
}
comparisons.set(testName, {
status,
current: currentResult.mean,
baseline: baseline.mean,
change,
absoluteChange
});
}
return comparisons;
}
// 生成性能回归报告
generateRegressionReport(comparisons) {
const regressions = Array.from(comparisons.entries())
.filter(([_, comp]) => comp.status === 'REGRESSION');
const improvements = Array.from(comparisons.entries())
.filter(([_, comp]) => comp.status === 'IMPROVEMENT');
let report = '\nPERFORMANCE REGRESSION REPORT\n';
report += '='.repeat(50) + '\n';
if (regressions.length > 0) {
report += '🚨 PERFORMANCE REGRESSIONS:\n';
for (const [testName, comp] of regressions) {
report += ` ${testName}: +${(comp.change * 100).toFixed(1)}% ` +
`(${comp.baseline.toFixed(2)}ms → ${comp.current.toFixed(2)}ms)\n`;
}
report += '\n';
}
if (improvements.length > 0) {
report += '✅ PERFORMANCE IMPROVEMENTS:\n';
for (const [testName, comp] of improvements) {
report += ` ${testName}: ${(comp.change * 100).toFixed(1)}% ` +
`(${comp.baseline.toFixed(2)}ms → ${comp.current.toFixed(2)}ms)\n`;
}
report += '\n';
}
if (regressions.length === 0 && improvements.length === 0) {
report += '📊 All tests within performance tolerance\n';
}
return report;
}
}实战应用示例
javascript
// 完整的性能测试套件示例
export class AlgorithmBenchmarkSuite {
constructor() {
this.tester = new AsyncPerformanceTester();
this.complexityAnalyzer = new ComplexityAnalyzer();
this.comparator = new BenchmarkComparator();
}
// 注册排序算法测试
registerSortingAlgorithms() {
// 测试数据生成器
const generateRandomArray = (size) => {
return Array.from({ length: size }, () =>
Math.floor(Math.random() * size * 10)
);
};
// 快速排序测试
this.tester.addTest(
'quickSort',
(data) => this.quickSort([...data]),
() => generateRandomArray(1000)
);
// 归并排序测试
this.tester.addTest(
'mergeSort',
(data) => this.mergeSort([...data]),
() => generateRandomArray(1000)
);
// 内置排序测试
this.tester.addTest(
'nativeSort',
(data) => [...data].sort((a, b) => a - b),
() => generateRandomArray(1000)
);
}
// 算法实现
quickSort(arr) {
if (arr.length <= 1) return arr;
const pivot = arr[Math.floor(arr.length / 2)];
const left = arr.filter(x => x < pivot);
const middle = arr.filter(x => x === pivot);
const right = arr.filter(x => x > pivot);
return [...this.quickSort(left), ...middle, ...this.quickSort(right)];
}
mergeSort(arr) {
if (arr.length <= 1) return arr;
const mid = Math.floor(arr.length / 2);
const left = this.mergeSort(arr.slice(0, mid));
const right = this.mergeSort(arr.slice(mid));
return this.merge(left, right);
}
merge(left, right) {
const result = [];
let i = 0, j = 0;
while (i < left.length && j < right.length) {
if (left[i] < right[j]) {
result.push(left[i++]);
} else {
result.push(right[j++]);
}
}
return result.concat(left.slice(i), right.slice(j));
}
// 运行完整测试套件
async runFullSuite() {
console.log('Starting algorithm benchmark suite...\n');
// 性能测试
const results = new Map();
for (const testName of ['quickSort', 'mergeSort', 'nativeSort']) {
const result = await this.tester.measureAsync(testName, 100);
results.set(testName, result);
}
// 复杂度分析
const complexityResults = new Map();
const sizeGenerator = (size) => Array.from({ length: size }, () =>
Math.floor(Math.random() * size * 10)
);
for (const algoName of ['quickSort', 'mergeSort']) {
const analysis = await this.complexityAnalyzer.analyzeComplexity(
this[algoName].bind(this),
sizeGenerator
);
complexityResults.set(algoName, analysis);
}
// 生成报告
console.log(ConsoleReporter.generateReport(results));
console.log(ConsoleReporter.generateComplexityReport(complexityResults));
return { performance: results, complexity: complexityResults };
}
}