- 동시접속자 기반 월간 대역폭 자동 추정 - DAU(일일활성사용자) 추정치 표시 (동접 × 10-14) - 대역폭 기반 Linode/Vultr 자동 선택 로직 - 비용 분석에 대역폭 비용 포함 - 지역 미선택시 서울/도쿄/오사카/싱가포르 기본 표시 - 지역별 서버 분리 표시 (GROUP BY instance + region) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
171 lines
4.8 KiB
TypeScript
171 lines
4.8 KiB
TypeScript
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
|
|
interface BenchmarkRow {
|
|
idproc: string;
|
|
descproc: string;
|
|
percentile: string;
|
|
nbproc: string;
|
|
perf: string;
|
|
}
|
|
|
|
const BENCHMARK_FILES = [
|
|
'pts-nginx.csv',
|
|
'pts-apache.csv',
|
|
'pts-apache-siege.csv',
|
|
'pts-node-octane.csv',
|
|
'pts-node-express-loadtest.csv',
|
|
'pts-phpbench.csv',
|
|
'pts-redis.csv',
|
|
'pts-mysqlslap.csv',
|
|
'pts-compress-7zip.csv',
|
|
'pts-compress-pbzip2.csv',
|
|
'pts-compress-gzip.csv',
|
|
'pts-postmark.csv',
|
|
'pts-compilebench.csv',
|
|
'pts-c-ray.csv',
|
|
'pts-coremark.csv',
|
|
'pts-byte.csv',
|
|
'pts-encode-mp3.csv',
|
|
'pts-encode-flac.csv',
|
|
'pts-x264.csv',
|
|
'pts-build-imagemagick.csv',
|
|
'pts-build-nodejs.csv',
|
|
'pts-build-php.csv',
|
|
];
|
|
|
|
function parseCSV(content: string): BenchmarkRow[] {
|
|
const lines = content.trim().split('\n');
|
|
const header = lines[0].split(',');
|
|
const rows: BenchmarkRow[] = [];
|
|
|
|
for (let i = 1; i < lines.length; i++) {
|
|
const values = lines[i].split(',');
|
|
if (values.length >= 6) {
|
|
rows.push({
|
|
idproc: values[1],
|
|
descproc: values[2],
|
|
percentile: values[3],
|
|
nbproc: values[4],
|
|
perf: values[5],
|
|
});
|
|
}
|
|
}
|
|
return rows;
|
|
}
|
|
|
|
function parsePerf(perf: string): { score: number; deviation: number | null } {
|
|
// Format: "496096 +/- 4671" or "496096"
|
|
const match = perf.match(/^([\d.]+)\s*(?:\+\/-\s*([\d.]+))?$/);
|
|
if (match) {
|
|
return {
|
|
score: parseFloat(match[1]),
|
|
deviation: match[2] ? parseFloat(match[2]) : null,
|
|
};
|
|
}
|
|
return { score: 0, deviation: null };
|
|
}
|
|
|
|
function parsePercentile(percentile: string): number {
|
|
// Format: "100th", "98th", "95th", etc.
|
|
const match = percentile.match(/^(\d+)/);
|
|
return match ? parseInt(match[1]) : 0;
|
|
}
|
|
|
|
function extractVendor(name: string): string {
|
|
if (name.toLowerCase().includes('amd')) return 'AMD';
|
|
if (name.toLowerCase().includes('intel')) return 'Intel';
|
|
if (name.toLowerCase().includes('arm')) return 'ARM';
|
|
if (name.toLowerCase().includes('apple')) return 'Apple';
|
|
return 'Unknown';
|
|
}
|
|
|
|
function extractCores(name: string): number | null {
|
|
// Try to extract core count from name
|
|
const match = name.match(/(\d+)-Core/i);
|
|
return match ? parseInt(match[1]) : null;
|
|
}
|
|
|
|
function escapeSQL(str: string): string {
|
|
return str.replace(/'/g, "''");
|
|
}
|
|
|
|
async function main() {
|
|
const dataDir = path.join(__dirname, '../benchmark-data/data/suite');
|
|
const processors = new Map<string, { name: string; vendor: string; cores: number | null }>();
|
|
const benchmarks: Array<{
|
|
procId: string;
|
|
benchmarkType: string;
|
|
score: number;
|
|
deviation: number | null;
|
|
percentile: number;
|
|
sampleCount: number;
|
|
}> = [];
|
|
|
|
for (const file of BENCHMARK_FILES) {
|
|
const filePath = path.join(dataDir, file);
|
|
if (!fs.existsSync(filePath)) {
|
|
console.error(`File not found: ${filePath}`);
|
|
continue;
|
|
}
|
|
|
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
const rows = parseCSV(content);
|
|
const benchmarkType = file.replace('.csv', '');
|
|
|
|
for (const row of rows) {
|
|
// Store processor info
|
|
if (!processors.has(row.idproc)) {
|
|
processors.set(row.idproc, {
|
|
name: row.descproc,
|
|
vendor: extractVendor(row.descproc),
|
|
cores: extractCores(row.descproc),
|
|
});
|
|
}
|
|
|
|
// Parse performance
|
|
const { score, deviation } = parsePerf(row.perf);
|
|
if (score > 0) {
|
|
benchmarks.push({
|
|
procId: row.idproc,
|
|
benchmarkType,
|
|
score,
|
|
deviation,
|
|
percentile: parsePercentile(row.percentile),
|
|
sampleCount: parseInt(row.nbproc) || 1,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
// Generate SQL
|
|
let sql = '-- Generated benchmark data\n\n';
|
|
|
|
// Insert processors
|
|
sql += '-- Insert processors\n';
|
|
const procArray = Array.from(processors.entries());
|
|
for (const [procId, info] of procArray) {
|
|
const cores = info.cores !== null ? info.cores : 'NULL';
|
|
sql += `INSERT OR IGNORE INTO processors (proc_id, name, vendor, cores) VALUES ('${escapeSQL(procId)}', '${escapeSQL(info.name)}', '${info.vendor}', ${cores});\n`;
|
|
}
|
|
|
|
sql += '\n-- Insert benchmark results\n';
|
|
for (const b of benchmarks) {
|
|
const deviation = b.deviation !== null ? b.deviation : 'NULL';
|
|
sql += `INSERT OR IGNORE INTO benchmark_results (processor_id, benchmark_type_id, score, score_deviation, percentile, sample_count)
|
|
SELECT p.id, bt.id, ${b.score}, ${deviation}, ${b.percentile}, ${b.sampleCount}
|
|
FROM processors p, benchmark_types bt
|
|
WHERE p.proc_id = '${escapeSQL(b.procId)}' AND bt.name = '${b.benchmarkType}';\n`;
|
|
}
|
|
|
|
// Output summary
|
|
console.log(`Processed ${processors.size} processors`);
|
|
console.log(`Processed ${benchmarks.length} benchmark results`);
|
|
|
|
// Write SQL file
|
|
fs.writeFileSync(path.join(__dirname, '../benchmark-seed.sql'), sql);
|
|
console.log('Generated benchmark-seed.sql');
|
|
}
|
|
|
|
main().catch(console.error);
|