semillero-INVIMA/benchmarks/scripts/run-query02-concurrency.js

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);
});