From e5b28074e6e33a00cbc9b8da2cf034efe942cc1c Mon Sep 17 00:00:00 2001 From: 4gray Date: Sun, 27 Sep 2026 18:51:56 +0200 Subject: [PATCH] test(performance): count SQL statements only for the launch journey Codex review: the M3U import, refresh-cancellation and Xtream benchmarks also run with IPTVNATOR_PERF_CAPTURE=1, so the statement hook wrapped every row of their bulk inserts and changed what they measure. SQL counting now also needs IPTVNATOR_PERF_COUNT_SQL=1, which only the launch journey sets; a harness test fails if another source sets it. Startup phases, the window snapshot and the read handler stay on the capture flag. Without SQL counting no ready-to-show listener is attached, so a zero is never reported for statements nobody counted. Co-Authored-By: Claude Opus 5.5 --- .../src/journeys/launch-journey-app.ts | 5 +- .../performance/journey-main-counters.spec.ts | 21 ++++++++ apps/electron-backend/src/app/app.ts | 6 ++- .../src/app/services/debug-trace.spec.ts | 30 +++++++++++ .../src/app/services/debug-trace.ts | 12 +++++ .../app/services/main-sql-statement-count.ts | 3 +- .../app/services/performance-counters.spec.ts | 31 +++++++++-- .../src/app/services/performance-counters.ts | 20 ++++++-- .../database-worker-sql-statement-count.ts | 4 +- ...-worker-sql-statement-count.wiring.spec.ts | 51 ++++++++++++------- .../app/workers/database.worker-connection.ts | 7 +-- apps/electron-backend/src/main.ts | 3 +- docs/architecture/performance-journeys.md | 6 ++- docs/architecture/sqlite-db-worker.md | 9 ++-- docs/development/electron-debugging.md | 1 + 15 files changed, 171 insertions(+), 38 deletions(-) diff --git a/apps/electron-backend-e2e/src/journeys/launch-journey-app.ts b/apps/electron-backend-e2e/src/journeys/launch-journey-app.ts index 56337851f..4e59103d8 100644 --- a/apps/electron-backend-e2e/src/journeys/launch-journey-app.ts +++ b/apps/electron-backend-e2e/src/journeys/launch-journey-app.ts @@ -129,11 +129,14 @@ export async function measureLaunchJourney( try { await cp(templateDirectory, dataDirectory, { recursive: true }); // IPTVNATOR_PERF_CAPTURE turns on the main-process counters and - // their read handler; see journey-main-counters.ts. + // their read handler, IPTVNATOR_PERF_COUNT_SQL the SQL statement + // count behind main.sqlStatementsBeforeReadyToShow; only this journey + // sets it. See journey-main-counters.ts. const env = buildElectronLaunchEnvironment( dataDirectory, launchOptions({ IPTVNATOR_PERF_CAPTURE: '1', + IPTVNATOR_PERF_COUNT_SQL: '1', IPTVNATOR_TRACE_IPC: '1', }) ); diff --git a/apps/electron-backend-e2e/src/performance/journey-main-counters.spec.ts b/apps/electron-backend-e2e/src/performance/journey-main-counters.spec.ts index 402cb4ec7..34684c01d 100644 --- a/apps/electron-backend-e2e/src/performance/journey-main-counters.spec.ts +++ b/apps/electron-backend-e2e/src/performance/journey-main-counters.spec.ts @@ -1,4 +1,6 @@ import assert from 'node:assert/strict'; +import { readdirSync, readFileSync } from 'node:fs'; +import { join, relative, resolve } from 'node:path'; import test from 'node:test'; import { @@ -124,3 +126,22 @@ test('rejects snapshots that were not frozen at the moments they claim', () => { /total-below-frozen: main.startupPhases/ ); }); + +test('only the launch journey opts into SQL statement counting', () => { + // The import benchmarks also run with IPTVNATOR_PERF_CAPTURE=1; the SQL + // hook wraps every row of a bulk insert, so they must not enable it. + const sourceRoot = resolve(__dirname, '..'); + const files = readdirSync(sourceRoot, { recursive: true }) + .map(String) + .filter( + (file) => /\.(ts|cjs)$/.test(file) && !/\.spec\.ts$/.test(file) + ); + const optedIn = files + .filter((file) => + readFileSync(join(sourceRoot, file), 'utf8').includes( + 'IPTVNATOR_PERF_COUNT_SQL' + ) + ) + .map((file) => relative(sourceRoot, join(sourceRoot, file))); + assert.deepEqual(optedIn, [join('journeys', 'launch-journey-app.ts')]); +}); diff --git a/apps/electron-backend/src/app/app.ts b/apps/electron-backend/src/app/app.ts index 0e3f957d8..e275e1e03 100644 --- a/apps/electron-backend/src/app/app.ts +++ b/apps/electron-backend/src/app/app.ts @@ -9,6 +9,7 @@ import { rendererAppName, rendererAppPort } from './constants'; import { isPerformanceCaptureEnabled, isRendererConsoleTraceEnabled, + isSqlStatementCountEnabled, isWindowTraceEnabled, performanceCounters, trace, @@ -523,7 +524,10 @@ export default class App { attachMainWindowPerformanceCounters( App.mainWindow, performanceCounters, - isPerformanceCaptureEnabled() + { + capture: isPerformanceCaptureEnabled(), + sqlStatements: isSqlStatementCountEnabled(), + } ); attachWindowTrace(App.mainWindow); App.attachWindowStateEvents(App.mainWindow); diff --git a/apps/electron-backend/src/app/services/debug-trace.spec.ts b/apps/electron-backend/src/app/services/debug-trace.spec.ts index 783d3bd55..bd3bbc958 100644 --- a/apps/electron-backend/src/app/services/debug-trace.spec.ts +++ b/apps/electron-backend/src/app/services/debug-trace.spec.ts @@ -131,3 +131,33 @@ describe('startup phase counting', () => { ]); }); }); + +describe('SQL statement count opt-in', () => { + const FLAGS = ['IPTVNATOR_PERF_CAPTURE', 'IPTVNATOR_PERF_COUNT_SQL']; + const original = FLAGS.map((name) => [name, process.env[name]] as const); + + afterEach(() => { + for (const [name, value] of original) { + if (value === undefined) { + delete process.env[name]; + } else { + process.env[name] = value; + } + } + }); + + it.each([ + [{}, false], + [{ IPTVNATOR_PERF_CAPTURE: '1' }, false], + [{ IPTVNATOR_PERF_COUNT_SQL: '1' }, false], + [{ IPTVNATOR_PERF_CAPTURE: '1', IPTVNATOR_PERF_COUNT_SQL: '1' }, true], + ])('needs both flags: %j -> %s', async (env, expected) => { + for (const name of FLAGS) { + delete process.env[name]; + } + Object.assign(process.env, env); + const { isSqlStatementCountEnabled } = await import('./debug-trace'); + + expect(isSqlStatementCountEnabled()).toBe(expected); + }); +}); diff --git a/apps/electron-backend/src/app/services/debug-trace.ts b/apps/electron-backend/src/app/services/debug-trace.ts index 17a85a7fa..d9b37eb5e 100644 --- a/apps/electron-backend/src/app/services/debug-trace.ts +++ b/apps/electron-backend/src/app/services/debug-trace.ts @@ -63,6 +63,18 @@ export function isPerformanceCaptureEnabled(): boolean { return readFlag('IPTVNATOR_PERF_CAPTURE'); } +/** + * SQL statement counting wraps every statement execution, including each + * row of a bulk insert, so it has its own opt-in on top of the capture flag: + * only the launch journey sets it, and the import benchmarks that also run + * with IPTVNATOR_PERF_CAPTURE=1 keep measuring the unwrapped workload. + */ +export function isSqlStatementCountEnabled(): boolean { + return ( + isPerformanceCaptureEnabled() && readFlag('IPTVNATOR_PERF_COUNT_SQL') + ); +} + /** * Process-wide performance counters (see `performance-counters.ts`). Every * call is a no-op unless `IPTVNATOR_PERF_CAPTURE=1`. diff --git a/apps/electron-backend/src/app/services/main-sql-statement-count.ts b/apps/electron-backend/src/app/services/main-sql-statement-count.ts index af5a1100a..30fab438a 100644 --- a/apps/electron-backend/src/app/services/main-sql-statement-count.ts +++ b/apps/electron-backend/src/app/services/main-sql-statement-count.ts @@ -7,7 +7,8 @@ import { PERFORMANCE_COUNTER } from './performance-counters'; import type { PerformanceCounterRegistry } from './performance-counters'; /** - * With IPTVNATOR_PERF_CAPTURE=1, counts the SQL statements the main process + * With IPTVNATOR_PERF_CAPTURE=1 and IPTVNATOR_PERF_COUNT_SQL=1, counts the + * SQL statements the main process * executes into `main.sqlStatements`, next to the database worker's * statements that `DatabaseWorkerClient` adds. The shared connection * (`initDatabase`, the `sql-main` trace) runs schema creation and migrations diff --git a/apps/electron-backend/src/app/services/performance-counters.spec.ts b/apps/electron-backend/src/app/services/performance-counters.spec.ts index 35ac97e17..653fe0b2e 100644 --- a/apps/electron-backend/src/app/services/performance-counters.spec.ts +++ b/apps/electron-backend/src/app/services/performance-counters.spec.ts @@ -113,23 +113,46 @@ describe('performance:read-counters handler', () => { }); describe('main window performance counters', () => { + const BOTH_FLAGS = { capture: true, sqlStatements: true }; + it('attaches nothing without the capture flag', () => { const window = new EventEmitter(); const { registry } = createRegistry(); - attachMainWindowPerformanceCounters(window, registry, false); + attachMainWindowPerformanceCounters(window, registry, { + capture: false, + sqlStatements: false, + }); expect(window.listenerCount('ready-to-show')).toBe(0); expect(registry.read().counters).toEqual({}); }); + it('freezes only the startup phases when SQL is not counted', () => { + const window = new EventEmitter(); + const { registry } = createRegistry(); + registry.increment(PERFORMANCE_COUNTER.STARTUP_PHASES, 2); + + attachMainWindowPerformanceCounters(window, registry, { + capture: true, + sqlStatements: false, + }); + window.emit('ready-to-show'); + + expect(window.listenerCount('ready-to-show')).toBe(0); + expect(registry.read().counters).toEqual({ + 'main.modulesRegisteredBeforeWindow': 2, + 'main.startupPhases': 2, + }); + }); + it('freezes startup phases at creation and SQL at ready-to-show', () => { const window = new EventEmitter(); const { registry } = createRegistry(); registry.increment(PERFORMANCE_COUNTER.STARTUP_PHASES, 2); registry.increment(PERFORMANCE_COUNTER.SQL_STATEMENTS, 3); - attachMainWindowPerformanceCounters(window, registry, true); + attachMainWindowPerformanceCounters(window, registry, BOTH_FLAGS); registry.increment(PERFORMANCE_COUNTER.STARTUP_PHASES); registry.increment(PERFORMANCE_COUNTER.SQL_STATEMENTS, 4); window.emit('ready-to-show'); @@ -154,12 +177,12 @@ describe('main window performance counters', () => { const second = new EventEmitter(); const { registry } = createRegistry(); registry.increment(PERFORMANCE_COUNTER.STARTUP_PHASES, 2); - attachMainWindowPerformanceCounters(first, registry, true); + attachMainWindowPerformanceCounters(first, registry, BOTH_FLAGS); first.emit('ready-to-show'); registry.increment(PERFORMANCE_COUNTER.STARTUP_PHASES, 5); registry.increment(PERFORMANCE_COUNTER.SQL_STATEMENTS, 5); - attachMainWindowPerformanceCounters(second, registry, true); + attachMainWindowPerformanceCounters(second, registry, BOTH_FLAGS); second.emit('ready-to-show'); expect(registry.read().counters).toMatchObject({ diff --git a/apps/electron-backend/src/app/services/performance-counters.ts b/apps/electron-backend/src/app/services/performance-counters.ts index 5caa53ac4..378ba99e4 100644 --- a/apps/electron-backend/src/app/services/performance-counters.ts +++ b/apps/electron-backend/src/app/services/performance-counters.ts @@ -91,23 +91,35 @@ export function registerPerformanceCountersHandler( return true; } +export interface MainWindowPerformanceCounterFlags { + /** IPTVNATOR_PERF_CAPTURE=1. */ + readonly capture: boolean; + /** IPTVNATOR_PERF_COUNT_SQL=1 as well; SQL is not counted otherwise. */ + readonly sqlStatements: boolean; +} + /** * Freezes the window-relative counters: the startup phases that ran before - * this window existed, and the database statements that ran before its first - * `ready-to-show`. Call right after the window is constructed. + * this window existed and, when SQL is counted, the database statements that + * ran before its first `ready-to-show`. Without SQL counting no listener is + * attached, so a zero is never reported for statements nobody counted. Call + * right after the window is constructed. */ export function attachMainWindowPerformanceCounters( window: { once(event: 'ready-to-show', listener: () => void): unknown }, registry: PerformanceCounterRegistry, - enabled: boolean + flags: MainWindowPerformanceCounterFlags ): void { - if (!enabled) { + if (!flags.capture) { return; } registry.freeze( PERFORMANCE_COUNTER.STARTUP_PHASES, PERFORMANCE_COUNTER.MODULES_REGISTERED_BEFORE_WINDOW ); + if (!flags.sqlStatements) { + return; + } window.once('ready-to-show', () => { registry.freeze( PERFORMANCE_COUNTER.SQL_STATEMENTS, diff --git a/apps/electron-backend/src/app/workers/database-worker-sql-statement-count.ts b/apps/electron-backend/src/app/workers/database-worker-sql-statement-count.ts index ddb1e7091..1f79cccc4 100644 --- a/apps/electron-backend/src/app/workers/database-worker-sql-statement-count.ts +++ b/apps/electron-backend/src/app/workers/database-worker-sql-statement-count.ts @@ -4,7 +4,9 @@ import type BetterSqlite3 from 'better-sqlite3'; * Counts the SQL statements the database worker executes and reports the * count to the main process, where `main.sqlStatements` is kept (see * `services/performance-counters.ts`). Only active with - * `IPTVNATOR_PERF_CAPTURE=1`. + * `IPTVNATOR_PERF_CAPTURE=1` and `IPTVNATOR_PERF_COUNT_SQL=1`, which only the + * launch journey sets: the import benchmarks run with the capture flag alone + * and keep measuring unwrapped statements. * * The count travels over the worker's message port, which is ordered with * the worker's responses, instead of the stdout trace lines Node forwards diff --git a/apps/electron-backend/src/app/workers/database-worker-sql-statement-count.wiring.spec.ts b/apps/electron-backend/src/app/workers/database-worker-sql-statement-count.wiring.spec.ts index 148db6058..bbaf39ab8 100644 --- a/apps/electron-backend/src/app/workers/database-worker-sql-statement-count.wiring.spec.ts +++ b/apps/electron-backend/src/app/workers/database-worker-sql-statement-count.wiring.spec.ts @@ -7,11 +7,16 @@ import { DB_WORKER_SQL_STATEMENTS_MESSAGE_TYPE } from './database-worker-sql-sta /** * Pins the worker wiring of `database-worker-sql-statement-count.ts`: with - * IPTVNATOR_PERF_CAPTURE=1 the real worker connection reports its statements - * over the parent port, without the flag it reports nothing, and the worker - * flushes the count before any response it posts. + * IPTVNATOR_PERF_CAPTURE=1 and IPTVNATOR_PERF_COUNT_SQL=1 the real worker + * connection reports its statements over the parent port, with the capture + * flag alone (the import benchmarks) or without flags it reports nothing, + * and the worker flushes the count before any response it posts. */ -const ENV_NAMES = ['IPTVNATOR_PERF_CAPTURE', 'IPTVNATOR_E2E_DATA_DIR'] as const; +const ENV_NAMES = [ + 'IPTVNATOR_PERF_CAPTURE', + 'IPTVNATOR_PERF_COUNT_SQL', + 'IPTVNATOR_E2E_DATA_DIR', +] as const; const EXECUTION_METHODS = ['run', 'get', 'all', 'iterate'] as const; describe('database worker SQL statement count wiring', () => { @@ -69,16 +74,14 @@ describe('database worker SQL statement count wiring', () => { } async function openConnection( - captureFlag: string | undefined, + flags: Partial>, expectedMessages: number ) { dataDirectory = mkdtempSync(join(tmpdir(), 'iptvnator-sql-count-')); + delete process.env['IPTVNATOR_PERF_CAPTURE']; + delete process.env['IPTVNATOR_PERF_COUNT_SQL']; + Object.assign(process.env, flags); process.env['IPTVNATOR_E2E_DATA_DIR'] = dataDirectory; - if (captureFlag === undefined) { - delete process.env['IPTVNATOR_PERF_CAPTURE']; - } else { - process.env['IPTVNATOR_PERF_CAPTURE'] = captureFlag; - } const { messages } = connectPorts(); const connection = await import('./database.worker-connection'); await connection.getWorkerDatabase(); @@ -94,8 +97,11 @@ describe('database worker SQL statement count wiring', () => { return messages; } - it('reports the connection setup statements when capture is on', async () => { - const messages = await openConnection('1', 2); + it('reports the connection setup statements when SQL counting is on', async () => { + const messages = await openConnection( + { IPTVNATOR_PERF_CAPTURE: '1', IPTVNATOR_PERF_COUNT_SQL: '1' }, + 2 + ); // Seven PRAGMAs on open, then `PRAGMA optimize` on close. expect(messages).toEqual([ @@ -105,14 +111,23 @@ describe('database worker SQL statement count wiring', () => { expect(JSON.stringify(messages)).not.toMatch(/PRAGMA|journal_mode/i); }); - it('reports nothing and leaves better-sqlite3 alone without the flag', async () => { - const messages = await openConnection(undefined, 0); + it.each([ + ['without flags', {}], + [ + 'with the capture flag alone, as the import benchmarks run', + { IPTVNATOR_PERF_CAPTURE: '1' }, + ], + ])( + 'reports nothing and leaves better-sqlite3 alone %s', + async (_label, flags) => { + const messages = await openConnection(flags, 0); - expect(messages).toEqual([]); - for (const [method, original] of originalMethods) { - expect(statementPrototype[method]).toBe(original); + expect(messages).toEqual([]); + for (const [method, original] of originalMethods) { + expect(statementPrototype[method]).toBe(original); + } } - }); + ); it('flushes the count before the worker posts a response', async () => { const { messages, workerPort } = connectPorts(); diff --git a/apps/electron-backend/src/app/workers/database.worker-connection.ts b/apps/electron-backend/src/app/workers/database.worker-connection.ts index 832fd9c29..cff5b79cc 100644 --- a/apps/electron-backend/src/app/workers/database.worker-connection.ts +++ b/apps/electron-backend/src/app/workers/database.worker-connection.ts @@ -10,7 +10,7 @@ import { registerNativeModuleSearchPaths, } from './worker-runtime-paths'; import { - isPerformanceCaptureEnabled, + isSqlStatementCountEnabled, isSqlTraceEnabled, trace, traceSqlStatement, @@ -64,8 +64,9 @@ const Database = loadBetterSqlite3(); let db: AppDatabase | null = null; let sqlite: BetterSqlite3.Database | null = null; -// IPTVNATOR_PERF_CAPTURE=1 only: the main process keeps the running total. -const sqlStatementCount = isPerformanceCaptureEnabled() +// IPTVNATOR_PERF_CAPTURE=1 with IPTVNATOR_PERF_COUNT_SQL=1 only: the main +// process keeps the running total. +const sqlStatementCount = isSqlStatementCountEnabled() ? createSqlStatementCountReporter((message) => parentPort?.postMessage(message) ) diff --git a/apps/electron-backend/src/main.ts b/apps/electron-backend/src/main.ts index af9905395..c7b20c4b6 100644 --- a/apps/electron-backend/src/main.ts +++ b/apps/electron-backend/src/main.ts @@ -6,6 +6,7 @@ import PlaylistOpenEvents from './app/events/playlist-open.events'; import SquirrelEvents from './app/events/squirrel.events'; import { isPerformanceCaptureEnabled, + isSqlStatementCountEnabled, isStartupTraceEnabled, performanceCounters, traceStartupPhase, @@ -46,7 +47,7 @@ traceStartupPhase('compile-cache', () => readCompileCacheOutcome()); // Before anything can open the shared database connection. countMainProcessSqlStatements( performanceCounters, - isPerformanceCaptureEnabled() + isSqlStatementCountEnabled() ); // Before the first portal, playlist or update request leaves this process. diff --git a/docs/architecture/performance-journeys.md b/docs/architecture/performance-journeys.md index cc06bb3f4..ce44c28a8 100644 --- a/docs/architecture/performance-journeys.md +++ b/docs/architecture/performance-journeys.md @@ -108,7 +108,11 @@ With `IPTVNATOR_PERF_CAPTURE=1`, which the journey sets, in the main process (`services/performance-counters.ts`) and `main.ts` registers the `performance:read-counters` IPC handler. Without the flag nothing is counted, no listener is attached and the handler does not exist; -the preload never exposes the channel. After the renderer probe completes, +the preload never exposes the channel. SQL statements are counted only with +`IPTVNATOR_PERF_COUNT_SQL=1` as well, because the hook wraps every statement +execution: the journey sets both, while the M3U, refresh and Xtream +benchmarks run with the capture flag alone and keep measuring unwrapped +statements. A harness test fails if any other source sets the SQL flag. After the renderer probe completes, `journey-main-counters.ts` calls the handler through `electronApp.evaluate` and the gate's tap. diff --git a/docs/architecture/sqlite-db-worker.md b/docs/architecture/sqlite-db-worker.md index 7fcae41c1..4b8e5e92d 100644 --- a/docs/architecture/sqlite-db-worker.md +++ b/docs/architecture/sqlite-db-worker.md @@ -444,8 +444,8 @@ first, this receipt remains distinct from the later authoritative exposing the pending request. Disabled profiling performs no receipt clock or transport work, and `DatabaseWorkerClient.cancel()` remains fire-and-return. -With `IPTVNATOR_PERF_CAPTURE=1`, the worker connection also counts the SQL -statements it executes and posts `performance-sql-statements` messages that +With `IPTVNATOR_PERF_CAPTURE=1` and `IPTVNATOR_PERF_COUNT_SQL=1`, the worker +connection also counts the SQL statements it executes and posts `performance-sql-statements` messages that carry only a positive count, never SQL text or bound values. Counts are coalesced per microtask and flushed before every other worker message, so a response never overtakes the statements that produced it. @@ -454,7 +454,10 @@ counter and settles nothing. Statements are counted by wrapping the execution methods of better-sqlite3's `Statement` prototype and the connection's `exec`, not through the `verbose` callback: a callback makes better-sqlite3 expand every statement's SQL, which made bulk inserts two to -four times slower. A call that throws is not counted, which matches the SQL +four times slower. Counting still adds a JavaScript call per row of a bulk +insert, so it needs `IPTVNATOR_PERF_COUNT_SQL` on top of the capture flag: +only the launch journey sets it, and the import benchmarks that run with the +capture flag measure unwrapped statements. A call that throws is not counted, which matches the SQL trace for statements that fail before execution. One `exec` call counts as one statement, so initialization passes one statement per call; the historical-upgrade test enforces it. The main process counts its diff --git a/docs/development/electron-debugging.md b/docs/development/electron-debugging.md index 038e0f7a6..1d88fc503 100644 --- a/docs/development/electron-debugging.md +++ b/docs/development/electron-debugging.md @@ -31,6 +31,7 @@ IPTVNATOR_TRACE_STARTUP=1 pnpm nx serve electron-backend - `IPTVNATOR_TRACE_PLAYER=1` traces external-player activity and bounded Embedded MPV runtime-probe stderr - `IPTVNATOR_TRACE_RENDERER_CONSOLE=1` mirrors renderer console output into the Electron terminal - `IPTVNATOR_PERF_CAPTURE=1` enables development/test-only, redacted M3U and Xtream preload IPC request/completion markers plus count-only M3U acquire/parse/normalize, Xtream main network/JSON-transform/success-response-ready/cancel-dispatch, and renderer store phase capture; renderer wrappers emit only while the benchmark installs its Symbol hook, benchmark tooling sets the flag explicitly, and production launches must leave it unset. It also keeps count-only main-process counters (startup phases, database worker SQL statements, and their values at main-window creation and `ready-to-show`) and registers the main-only `performance:read-counters` IPC handler, which the preload does not expose; see [performance journeys](../architecture/performance-journeys.md) + - `IPTVNATOR_PERF_COUNT_SQL=1`, together with `IPTVNATOR_PERF_CAPTURE=1`, also counts every SQL statement of the main-process and database-worker connections for `main.sqlStatementsBeforeReadyToShow`; it wraps each statement execution, including every row of a bulk insert, so only the launch journey sets it and the import benchmarks leave it unset - `IPTVNATOR_PERF_WORKER_PROFILING=1` enables development/test-only, request-scoped worker receive/work/response-post timestamps, thread CPU, event-loop utilization/delay, count-only playlist serialization/SQLite write/read/deserialization plus Xtream category/content/cache-clear/delete/in-source-search phase events, profiling-only worker cancel-receipt acknowledgements, valid-sample-counted isolate peak memory, and the database worker's idle-only one-shot post-GC heap probe; overlapping database requests are explicitly invalidated instead of misattributed, the performance benchmark sets the flag automatically, and production launches must leave it unset - `IPTVNATOR_DISABLE_COMPILE_CACHE=1` disables the main-process V8 compile cache; `IPTVNATOR_COMPILE_CACHE_DIR=` relocates it. The startup trace reports the outcome as `compile-cache`