chore: 增加scripts目录
This commit is contained in:
463
scripts/ollama/performance-test.js
Normal file
463
scripts/ollama/performance-test.js
Normal file
@@ -0,0 +1,463 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const crypto = require('crypto');
|
||||
|
||||
/**
|
||||
* 性能测试脚本 - 对比不同处理方法的性能
|
||||
*/
|
||||
class PerformanceTest {
|
||||
constructor() {
|
||||
this.testDir = path.join(__dirname, 'test-files');
|
||||
this.results = [];
|
||||
this.setupTestEnvironment();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置测试环境
|
||||
*/
|
||||
setupTestEnvironment() {
|
||||
if (!fs.existsSync(this.testDir)) {
|
||||
fs.mkdirSync(this.testDir, { recursive: true });
|
||||
}
|
||||
|
||||
this.createTestFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建测试文件
|
||||
*/
|
||||
createTestFiles() {
|
||||
const testFiles = [
|
||||
{
|
||||
name: 'small.js',
|
||||
content: `
|
||||
function smallTest(){console.log("small test");const data={x:1,y:2};console.error("error");return data;}
|
||||
console.warn("warning");
|
||||
class Test{constructor(){console.debug("debug");}}
|
||||
`
|
||||
},
|
||||
{
|
||||
name: 'medium.js',
|
||||
content: `
|
||||
function mediumTest(){
|
||||
console.log("medium test start");
|
||||
const users = [
|
||||
{id:1,name:"Alice",console:"test"},
|
||||
{id:2,name:"Bob",age:25},
|
||||
{id:3,name:"Charlie",active:true}
|
||||
];
|
||||
|
||||
console.log("Processing users:", users.length);
|
||||
|
||||
users.forEach(user => {
|
||||
console.info("Processing user:", user.name);
|
||||
user.processed = true;
|
||||
});
|
||||
|
||||
console.debug("Processing complete");
|
||||
return users;
|
||||
}
|
||||
|
||||
class DataProcessor {
|
||||
constructor(data) {
|
||||
console.log("DataProcessor initialized");
|
||||
this.data = data;
|
||||
console.debug("Data:", data);
|
||||
}
|
||||
|
||||
process() {
|
||||
console.info("Starting data processing");
|
||||
console.time("processing");
|
||||
|
||||
const result = this.data.map(item => {
|
||||
console.debug("Processing item:", item);
|
||||
return item * 2;
|
||||
});
|
||||
|
||||
console.timeEnd("processing");
|
||||
console.log("Result:", result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
console.warn("Module loaded");
|
||||
`
|
||||
},
|
||||
{
|
||||
name: 'large.js',
|
||||
content: `
|
||||
function largeScaleProcessing(){
|
||||
console.log("Starting large scale processing");
|
||||
const startTime = Date.now();
|
||||
|
||||
// 大量数据处理
|
||||
const data = [];
|
||||
for(let i = 0; i < 1000; i++){
|
||||
console.debug("Processing item", i);
|
||||
data.push({
|
||||
id: i,
|
||||
value: Math.random() * 100,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
}
|
||||
|
||||
console.log("Generated", data.length, "items");
|
||||
|
||||
// 复杂处理逻辑
|
||||
const processedData = data.map((item, index) => {
|
||||
console.info("Processing item", index, "of", data.length);
|
||||
|
||||
if(index % 100 === 0){
|
||||
console.warn("Progress checkpoint:", index);
|
||||
}
|
||||
|
||||
return {
|
||||
...item,
|
||||
processed: true,
|
||||
calculated: item.value * 2,
|
||||
category: item.value > 50 ? "high" : "low"
|
||||
};
|
||||
});
|
||||
|
||||
console.timeEnd("processing");
|
||||
console.log("Processing complete in", Date.now() - startTime, "ms");
|
||||
|
||||
// 统计分析
|
||||
const stats = {
|
||||
total: processedData.length,
|
||||
high: processedData.filter(item => item.category === "high").length,
|
||||
low: processedData.filter(item => item.category === "low").length
|
||||
};
|
||||
|
||||
console.log("Statistics:", stats);
|
||||
console.debug("Final data sample:", processedData.slice(0, 5));
|
||||
|
||||
return { data: processedData, stats };
|
||||
}
|
||||
|
||||
class AnalyticsEngine {
|
||||
constructor() {
|
||||
console.log("AnalyticsEngine constructor");
|
||||
this.metrics = [];
|
||||
this.console = "property"; // 测试字符串中的console
|
||||
}
|
||||
|
||||
track(event, data) {
|
||||
console.info("Tracking event:", event);
|
||||
const metric = {
|
||||
event,
|
||||
data,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
this.metrics.push(metric);
|
||||
console.debug("Metric recorded:", metric);
|
||||
}
|
||||
|
||||
generateReport() {
|
||||
console.log("Generating report");
|
||||
console.time("report-generation");
|
||||
|
||||
const report = {
|
||||
totalMetrics: this.metrics.length,
|
||||
events: [...new Set(this.metrics.map(m => m.event))],
|
||||
timeRange: {
|
||||
start: Math.min(...this.metrics.map(m => m.timestamp)),
|
||||
end: Math.max(...this.metrics.map(m => m.timestamp))
|
||||
}
|
||||
};
|
||||
|
||||
console.timeEnd("report-generation");
|
||||
console.info("Report generated:", report);
|
||||
|
||||
return report;
|
||||
}
|
||||
}
|
||||
|
||||
// 执行测试
|
||||
console.warn("Large module loaded");
|
||||
const engine = new AnalyticsEngine();
|
||||
console.log("Analytics engine ready");
|
||||
`
|
||||
}
|
||||
];
|
||||
|
||||
testFiles.forEach(file => {
|
||||
const filePath = path.join(this.testDir, file.name);
|
||||
if (!fs.existsSync(filePath)) {
|
||||
fs.writeFileSync(filePath, file.content);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试方法性能
|
||||
*/
|
||||
async testMethod(methodName, processFunction) {
|
||||
console.log(`\n🧪 Testing ${methodName}...`);
|
||||
|
||||
const files = fs.readdirSync(this.testDir).filter(f => f.endsWith('.js'));
|
||||
const startTime = Date.now();
|
||||
const results = [];
|
||||
|
||||
for (const file of files) {
|
||||
const filePath = path.join(this.testDir, file);
|
||||
const inputContent = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
const fileStartTime = Date.now();
|
||||
|
||||
try {
|
||||
const outputContent = await processFunction(inputContent);
|
||||
|
||||
const fileEndTime = Date.now();
|
||||
const fileTime = fileEndTime - fileStartTime;
|
||||
|
||||
results.push({
|
||||
file,
|
||||
success: true,
|
||||
inputSize: inputContent.length,
|
||||
outputSize: outputContent.length,
|
||||
reduction: inputContent.length - outputContent.length,
|
||||
time: fileTime
|
||||
});
|
||||
|
||||
console.log(` ✅ ${file}: ${inputContent.length}→${outputContent.length} chars (${fileTime}ms)`);
|
||||
|
||||
} catch (error) {
|
||||
const fileEndTime = Date.now();
|
||||
const fileTime = fileEndTime - fileStartTime;
|
||||
|
||||
results.push({
|
||||
file,
|
||||
success: false,
|
||||
error: error.message,
|
||||
time: fileTime
|
||||
});
|
||||
|
||||
console.log(` ❌ ${file}: ${error.message} (${fileTime}ms)`);
|
||||
}
|
||||
}
|
||||
|
||||
const endTime = Date.now();
|
||||
const totalTime = endTime - startTime;
|
||||
|
||||
const successful = results.filter(r => r.success);
|
||||
const totalInputSize = successful.reduce((sum, r) => sum + r.inputSize, 0);
|
||||
const totalOutputSize = successful.reduce((sum, r) => sum + r.outputSize, 0);
|
||||
const totalReduction = totalInputSize - totalOutputSize;
|
||||
|
||||
const summary = {
|
||||
method: methodName,
|
||||
totalTime,
|
||||
files: results.length,
|
||||
successful: successful.length,
|
||||
failed: results.length - successful.length,
|
||||
totalInputSize,
|
||||
totalOutputSize,
|
||||
totalReduction,
|
||||
avgTimePerFile: totalTime / results.length
|
||||
};
|
||||
|
||||
console.log(`📊 ${methodName} Summary:`);
|
||||
console.log(` Total time: ${totalTime}ms`);
|
||||
console.log(` Success rate: ${successful.length}/${results.length}`);
|
||||
console.log(` Size reduction: ${totalReduction} chars (${((totalReduction/totalInputSize)*100).toFixed(1)}%)`);
|
||||
console.log(` Avg time per file: ${summary.avgTimePerFile.toFixed(1)}ms`);
|
||||
|
||||
this.results.push(summary);
|
||||
return summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* 正则表达式方法(快速但可能不准确)
|
||||
*/
|
||||
regexMethod(input) {
|
||||
return input.replace(/console\.(log|error|warn|info|debug|assert|trace|table|group|groupEnd|time|timeEnd)\s*\([^;]*?\);?\s*/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态机方法(中等速度,较准确)
|
||||
*/
|
||||
stateMachineMethod(input) {
|
||||
const STATES = { NORMAL: 0, IN_STRING: 1, IN_TEMPLATE_STRING: 2, IN_REGEX: 3, IN_COMMENT: 4 };
|
||||
let state = STATES.NORMAL;
|
||||
let stringChar = '';
|
||||
let result = '';
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
const char = input[i];
|
||||
const nextChar = input[i + 1];
|
||||
|
||||
switch (state) {
|
||||
case STATES.NORMAL:
|
||||
if (char === '/' && nextChar === '/') {
|
||||
state = STATES.IN_COMMENT;
|
||||
i++;
|
||||
} else if (char === '/' && nextChar === '*') {
|
||||
state = STATES.IN_COMMENT;
|
||||
i++;
|
||||
} else if (char === '"' || char === "'") {
|
||||
state = STATES.IN_STRING;
|
||||
stringChar = char;
|
||||
result += char;
|
||||
} else if (char === '`') {
|
||||
state = STATES.IN_TEMPLATE_STRING;
|
||||
result += char;
|
||||
} else if (char === '/' && !result.match(/[a-zA-Z0-9_$]$/)) {
|
||||
state = STATES.IN_REGEX;
|
||||
result += char;
|
||||
} else {
|
||||
result += char;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATES.IN_STRING:
|
||||
result += char;
|
||||
if (char === stringChar) {
|
||||
state = STATES.NORMAL;
|
||||
} else if (char === '\\') {
|
||||
result += input[++i];
|
||||
}
|
||||
break;
|
||||
|
||||
case STATES.IN_TEMPLATE_STRING:
|
||||
result += char;
|
||||
if (char === '`') {
|
||||
state = STATES.NORMAL;
|
||||
} else if (char === '\\') {
|
||||
result += input[++i];
|
||||
}
|
||||
break;
|
||||
|
||||
case STATES.IN_REGEX:
|
||||
result += char;
|
||||
if (char === '/' && !input[i-1].match(/\\/)) {
|
||||
state = STATES.NORMAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATES.IN_COMMENT:
|
||||
if (char === '\n') {
|
||||
state = STATES.NORMAL;
|
||||
result += char;
|
||||
} else if (char === '*' && nextChar === '/') {
|
||||
state = STATES.NORMAL;
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 移除console语句
|
||||
return result.replace(/console\.(log|error|warn|info|debug|assert|trace|table|group|groupEnd|time|timeEnd)\s*\([^;]*?\);?\s*/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ollama AI方法(慢但最准确)
|
||||
*/
|
||||
async ollamaMethod(input) {
|
||||
const { removeConsoleWithOllama } = require('./ollama-console-remover.js');
|
||||
return await removeConsoleWithOllama(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行所有性能测试
|
||||
*/
|
||||
async runAllTests() {
|
||||
console.log('🚀 Performance Test Suite');
|
||||
console.log('==========================');
|
||||
|
||||
// 测试正则表达式方法
|
||||
await this.testMethod('Regex (Fast)', (input) => this.regexMethod(input));
|
||||
|
||||
// 测试状态机方法
|
||||
await this.testMethod('State Machine (Medium)', (input) => this.stateMachineMethod(input));
|
||||
|
||||
// 测试Ollama方法(如果可用)
|
||||
try {
|
||||
const { checkOllamaHealth } = require('./optimized-processor.js');
|
||||
const isOllamaAvailable = await checkOllamaHealth();
|
||||
|
||||
if (isOllamaAvailable) {
|
||||
await this.testMethod('Ollama AI (Accurate)', (input) => this.ollamaMethod(input));
|
||||
} else {
|
||||
console.log('\n⚠️ Ollama not available, skipping AI method test');
|
||||
console.log(' Make sure Ollama is running: ollama serve');
|
||||
console.log(' And model is pulled: ollama pull deepseek-coder:6.7b');
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('\n❌ Could not test Ollama method:', error.message);
|
||||
}
|
||||
|
||||
this.generateReport();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成性能报告
|
||||
*/
|
||||
generateReport() {
|
||||
console.log('\n📈 Performance Comparison Report');
|
||||
console.log('=================================');
|
||||
|
||||
if (this.results.length === 0) {
|
||||
console.log('No results to compare');
|
||||
return;
|
||||
}
|
||||
|
||||
// 找出最快的和最准确的
|
||||
const fastest = this.results.reduce((min, r) => r.totalTime < min.totalTime ? r : min);
|
||||
const mostEffective = this.results.reduce((max, r) => r.totalReduction > max.totalReduction ? r : max);
|
||||
|
||||
console.log('\n🏆 Winners:');
|
||||
console.log(` Fastest: ${fastest.method} (${fastest.totalTime}ms)`);
|
||||
console.log(` Most Effective: ${mostEffective.method} (${mostEffective.totalReduction} chars removed)`);
|
||||
|
||||
console.log('\n📊 Detailed Comparison:');
|
||||
console.log('Method | Time (ms) | Files | Reduction | Avg/File');
|
||||
console.log('-----------------------|-----------|-------|-----------|----------');
|
||||
|
||||
this.results.forEach(result => {
|
||||
const method = result.method.padEnd(23);
|
||||
const time = result.totalTime.toString().padStart(9);
|
||||
const files = result.successful.toString().padStart(5);
|
||||
const reduction = result.totalReduction.toString().padStart(9);
|
||||
const avgFile = result.avgTimePerFile.toFixed(1).padStart(8);
|
||||
|
||||
console.log(`${method} | ${time} | ${files} | ${reduction} | ${avgFile}`);
|
||||
});
|
||||
|
||||
// 保存报告
|
||||
const reportData = {
|
||||
timestamp: new Date().toISOString(),
|
||||
results: this.results,
|
||||
summary: {
|
||||
fastest: fastest.method,
|
||||
mostEffective: mostEffective.method,
|
||||
totalTests: this.results.length
|
||||
}
|
||||
};
|
||||
|
||||
const reportPath = path.join(__dirname, 'performance-report.json');
|
||||
fs.writeFileSync(reportPath, JSON.stringify(reportData, null, 2));
|
||||
console.log(`\n💾 Detailed report saved to: ${reportPath}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 主程序
|
||||
async function main() {
|
||||
const tester = new PerformanceTest();
|
||||
|
||||
try {
|
||||
await tester.runAllTests();
|
||||
} catch (error) {
|
||||
console.error('❌ Performance test failed:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main().catch(console.error);
|
||||
}
|
||||
|
||||
module.exports = PerformanceTest;
|
||||
Reference in New Issue
Block a user