From 901cd823dd3610f3133336923094b776554b7b15 Mon Sep 17 00:00:00 2001 From: Administrator Date: Sun, 21 Jun 2026 04:20:32 +0200 Subject: [PATCH] perf(diag): enrich event-loop-delay log with active-resource histogram MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make the single high-concurrency measurement decisive. The ELD line now appends process.getActiveResourcesInfo() as a compact type-histogram, so one run splits all three readings in a single line: high mean/p99 means the main thread is CPU-blocked (workers/cap justified); low delay with many TCPSocketWrap/FSReqCallback/GetAddrInfoReqWrap resources means IO-bound queueing (threadpool/socket tuning, not workers); low delay with few resources means it is not saturated at all. Pure metrics — no credential-redaction path touched. Co-Authored-By: Claude Opus 4.8 (1M context) --- main.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/main.js b/main.js index 3a22ca7..aeb168c 100644 --- a/main.js +++ b/main.js @@ -197,7 +197,15 @@ function _maybeLogEventLoopDelay(activeJobs) { const max = (_eventLoopDelay.max / ns).toFixed(1); const p99 = (_eventLoopDelay.percentile(99) / ns).toFixed(1); const stddev = (_eventLoopDelay.stddev / ns).toFixed(1); - logInfo('perf', `eventloop-delay active=${activeJobs} mean=${mean}ms p99=${p99}ms max=${max}ms stddev=${stddev}ms threadpool=${process.env.UV_THREADPOOL_SIZE}`); + let resStr = ''; + try { + const info = process.getActiveResourcesInfo(); + const hist = {}; + for (const t of info) hist[t] = (hist[t] || 0) + 1; + const top = Object.entries(hist).sort((a, b) => b[1] - a[1]).slice(0, 6).map(([k, v]) => `${k}:${v}`).join(','); + resStr = ` resources=${info.length} {${top}}`; + } catch {} + logInfo('perf', `eventloop-delay active=${activeJobs} mean=${mean}ms p99=${p99}ms max=${max}ms stddev=${stddev}ms threadpool=${process.env.UV_THREADPOOL_SIZE}${resStr}`); _eventLoopDelay.reset(); } catch {} }