160 lines
4.8 KiB
JavaScript
160 lines
4.8 KiB
JavaScript
const { Client } = require('../../backend/node_modules/pg');
|
|
const { performance } = require('perf_hooks');
|
|
const {
|
|
config,
|
|
ensureDir,
|
|
explainSql,
|
|
explainSummary,
|
|
query02Dir,
|
|
query02Sql,
|
|
summarizeRows,
|
|
writeCsv,
|
|
writeJson
|
|
} = require('./query02-lib');
|
|
const { getDbConfig } = require('./benchmark-lib');
|
|
|
|
const levels = String(process.env.BENCHMARK_CONCURRENCY_LEVELS || config.concurrencyLevels.join(','))
|
|
.split(',')
|
|
.map((item) => Number.parseInt(item.trim(), 10))
|
|
.filter((item) => Number.isFinite(item) && item > 0);
|
|
const requestsPerLevel = Number.parseInt(
|
|
process.env.BENCHMARK_CONCURRENCY_REQUESTS || config.concurrencyRequestsPerLevel,
|
|
10
|
|
);
|
|
|
|
const activeConnections = async (client) => {
|
|
try {
|
|
const { rows } = await client.query(
|
|
"SELECT COUNT(*)::int AS active FROM pg_stat_activity WHERE datname = current_database() AND state <> 'idle'"
|
|
);
|
|
return Number(rows[0]?.active || 0);
|
|
} catch {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
const runPool = async (items, workers, task) => {
|
|
let index = 0;
|
|
const worker = async () => {
|
|
while (index < items.length) {
|
|
const current = items[index];
|
|
index += 1;
|
|
await task(current);
|
|
}
|
|
};
|
|
await Promise.all(Array.from({ length: Math.min(workers, items.length) }, () => worker()));
|
|
};
|
|
|
|
const runOne = async (level, repetition) => {
|
|
const timestamp = new Date().toISOString();
|
|
const client = new Client(getDbConfig(level));
|
|
const connectStarted = performance.now();
|
|
await client.connect();
|
|
const connectMs = performance.now() - connectStarted;
|
|
const started = performance.now();
|
|
|
|
try {
|
|
const result = await client.query(explainSql(query02Sql));
|
|
const endpointTotal = performance.now() - started + connectMs;
|
|
const summary = explainSummary(result.rows[0]['QUERY PLAN'][0]);
|
|
const active = await activeConnections(client);
|
|
return {
|
|
phase: 'query02_concurrency',
|
|
concurrency_level: level,
|
|
query_id: 'query_02',
|
|
query_name: 'Catalogo general paginado LIMIT 25',
|
|
query_group: 'estructurada',
|
|
repetition,
|
|
timestamp,
|
|
connection_acquire_ms: connectMs,
|
|
endpoint_total_ms: endpointTotal,
|
|
sql_ms: summary.execution_ms,
|
|
planning_ms: summary.planning_ms,
|
|
execution_ms: summary.execution_ms,
|
|
rows_returned: summary.actual_rows,
|
|
estimated_rows: summary.estimated_rows,
|
|
actual_rows: summary.actual_rows,
|
|
shared_hit_blocks: summary.shared_hit_blocks,
|
|
shared_read_blocks: summary.shared_read_blocks,
|
|
temp_read_blocks: summary.temp_read_blocks,
|
|
temp_written_blocks: summary.temp_written_blocks,
|
|
active_pg_connections: active,
|
|
cpu_percent_process: 0,
|
|
memory_rss_mb: process.memoryUsage().rss / 1024 / 1024,
|
|
disk_fs_read_ops: 0,
|
|
disk_fs_write_ops: 0,
|
|
success: true,
|
|
error_message: ''
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
phase: 'query02_concurrency',
|
|
concurrency_level: level,
|
|
query_id: 'query_02',
|
|
query_name: 'Catalogo general paginado LIMIT 25',
|
|
query_group: 'estructurada',
|
|
repetition,
|
|
timestamp,
|
|
connection_acquire_ms: connectMs,
|
|
endpoint_total_ms: performance.now() - started + connectMs,
|
|
sql_ms: null,
|
|
planning_ms: null,
|
|
execution_ms: null,
|
|
rows_returned: 0,
|
|
estimated_rows: null,
|
|
actual_rows: null,
|
|
shared_hit_blocks: null,
|
|
shared_read_blocks: null,
|
|
temp_read_blocks: null,
|
|
temp_written_blocks: null,
|
|
active_pg_connections: null,
|
|
cpu_percent_process: 0,
|
|
memory_rss_mb: process.memoryUsage().rss / 1024 / 1024,
|
|
disk_fs_read_ops: 0,
|
|
disk_fs_write_ops: 0,
|
|
success: false,
|
|
error_message: String(error?.message || error)
|
|
};
|
|
} finally {
|
|
await client.end();
|
|
}
|
|
};
|
|
|
|
const main = async () => {
|
|
ensureDir(query02Dir);
|
|
const raw = [];
|
|
|
|
for (const level of levels) {
|
|
const work = Array.from({ length: requestsPerLevel }, (_, index) => index + 1);
|
|
await runPool(work, level, async (repetition) => {
|
|
const row = await runOne(level, repetition);
|
|
raw.push(row);
|
|
process.stdout.write(
|
|
`query02 concurrency=${level} ${repetition}/${requestsPerLevel} ${row.success ? 'ok' : 'fail'} ${row.endpoint_total_ms.toFixed(2)}ms\n`
|
|
);
|
|
});
|
|
}
|
|
|
|
raw.sort((a, b) => a.concurrency_level - b.concurrency_level || a.repetition - b.repetition);
|
|
const summary = summarizeRows(raw, [
|
|
'phase',
|
|
'concurrency_level',
|
|
'query_id',
|
|
'query_name',
|
|
'query_group'
|
|
]);
|
|
writeCsv(`${query02Dir}/concurrency_raw.csv`, raw);
|
|
writeCsv(`${query02Dir}/concurrency_summary.csv`, summary);
|
|
writeJson(`${query02Dir}/concurrency.json`, {
|
|
generatedAt: new Date().toISOString(),
|
|
levels,
|
|
requestsPerLevel,
|
|
summary
|
|
});
|
|
};
|
|
|
|
main().catch((error) => {
|
|
console.error(error);
|
|
process.exit(1);
|
|
});
|