mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 01:56:16 -08:00
test(performance): address benchmark review feedback
This commit is contained in:
1 parent
77e8fd92e3
commit
0ce8901ede
9 files changed
+182
-142
No files matched your search
@@ -114,6 +114,7 @@ test('captures exact successful preload completion markers for DB return-clone a
|
||||
})
|
||||
);
|
||||
|
||||
assert.equal(api.successMarkerCount(), 2);
|
||||
assert.deepEqual(api.takeSuccessMarkers(), [
|
||||
{
|
||||
ipcCallId: 7,
|
||||
@@ -130,6 +131,7 @@ test('captures exact successful preload completion markers for DB return-clone a
|
||||
sourceEpochMs: 175.5,
|
||||
},
|
||||
]);
|
||||
assert.equal(api.successMarkerCount(), 0);
|
||||
assert.deepEqual(api.takeSuccessMarkers(), []);
|
||||
});
|
||||
|
||||
@@ -153,6 +155,7 @@ test('fails closed for malformed or invalid successful preload markers and reset
|
||||
})
|
||||
);
|
||||
}
|
||||
assert.equal(api.successMarkerCount(), 0);
|
||||
assert.deepEqual(api.takeSuccessMarkers(), []);
|
||||
|
||||
ipcMain.emit(
|
||||
@@ -164,6 +167,7 @@ test('fails closed for malformed or invalid successful preload markers and reset
|
||||
);
|
||||
api.stop();
|
||||
api.start();
|
||||
assert.equal(api.successMarkerCount(), 0);
|
||||
assert.deepEqual(api.takeSuccessMarkers(), []);
|
||||
});
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ export interface DatabaseRequestIdentityCaptureApi {
|
||||
matchDatabaseRequest(message: unknown): DatabaseRequestIdentity;
|
||||
start(): void;
|
||||
stop(): void;
|
||||
successMarkerCount(): number;
|
||||
takeSuccessMarkers(): readonly PreloadDatabaseSuccessMarker[];
|
||||
}
|
||||
|
||||
@@ -333,6 +334,7 @@ export function installDatabaseRequestIdentityCaptureInMain(
|
||||
quarantinedKeys = [];
|
||||
successMarkers = [];
|
||||
},
|
||||
successMarkerCount: () => successMarkers.length,
|
||||
takeSuccessMarkers: () => {
|
||||
const captured = Object.freeze([...successMarkers]);
|
||||
successMarkers = [];
|
||||
|
||||
@@ -158,6 +158,7 @@ describe('initial M3U import benchmark lifecycle', () => {
|
||||
assert.match(source, /status\.databaseUpsertsCompleted\s*===\s*1/);
|
||||
assert.match(source, /status\.databaseGetsCompleted\s*===\s*1/);
|
||||
assert.match(source, /status\.databasePending\s*===\s*0/);
|
||||
assert.match(source, /status\.preloadSuccessMarkers\s*===\s*2/);
|
||||
});
|
||||
|
||||
it('always disposes renderer capture before closing Electron on iteration failure', () => {
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
import type { DatabaseWorkerPeakMemoryValidity } from './database-worker-peak-memory-validity';
|
||||
import type { DatabaseWorkerRequestMetricsValidity } from './database-worker-request-metrics-validity';
|
||||
import type { M3uImportScenarioId } from './m3u-import-benchmark-contract';
|
||||
import type { M3uImportRendererCaptureMetrics } from './m3u-import-renderer-capture';
|
||||
import {
|
||||
M3U_IMPORT_INDEX_COMMIT_UNAVAILABLE_REASON,
|
||||
type M3uImportPhaseMetrics,
|
||||
} from './m3u-import-report';
|
||||
import type {
|
||||
DatabaseWorkerPostGcValidity,
|
||||
MainCaptureMetrics,
|
||||
NumericDistribution,
|
||||
PerformanceIterationKind,
|
||||
} from './m3u-refresh-cancellation-contract';
|
||||
import type { RendererRssValidity } from './renderer-rss-validity';
|
||||
|
||||
export interface M3uImportIterationResult {
|
||||
readonly channelCount: number;
|
||||
readonly fixtureBytes: number;
|
||||
readonly kind: PerformanceIterationKind;
|
||||
readonly main: MainCaptureMetrics;
|
||||
readonly phases: M3uImportPhaseMetrics;
|
||||
readonly renderer: M3uImportRendererCaptureMetrics;
|
||||
readonly runId: string;
|
||||
readonly scenarioId: M3uImportScenarioId;
|
||||
}
|
||||
|
||||
export interface M3uImportBenchmarkManifest {
|
||||
readonly channelCount: number;
|
||||
readonly fixtureBytes: number;
|
||||
readonly fixtureSha256: string;
|
||||
readonly gitCommit: string;
|
||||
readonly gitDiffSha256: string;
|
||||
readonly gitDirty: boolean;
|
||||
readonly measuredRuns: number;
|
||||
readonly memoryAccounting: {
|
||||
readonly databaseWorkerRss: 'unavailable-per-worker-thread';
|
||||
readonly mainRss: 'electron-main-process-including-worker-threads-and-native-memory';
|
||||
readonly nativeAndSqliteMemory: 'included-in-main-rss-not-separately-attributable';
|
||||
readonly rendererRss: 'separate-renderer-process';
|
||||
readonly workerJsHeap: 'separate-v8-isolate';
|
||||
};
|
||||
readonly runtime: {
|
||||
readonly arch: string;
|
||||
readonly cdpPort: number;
|
||||
readonly electronVersion: string;
|
||||
readonly harnessNodeVersion: string;
|
||||
readonly platform: string;
|
||||
};
|
||||
readonly scenario: M3uImportScenarioId;
|
||||
readonly syntheticSeed: number;
|
||||
readonly variant: string;
|
||||
readonly warmupRuns: number;
|
||||
}
|
||||
|
||||
export interface M3uImportMeasuredSummary {
|
||||
readonly angularRenderingMs: NumericDistribution;
|
||||
readonly dataAcquireMs: NumericDistribution;
|
||||
readonly databaseWorkerGetEventLoopDelayMaxMs: NumericDistribution;
|
||||
readonly databaseWorkerGetEventLoopDelayP95Ms: NumericDistribution;
|
||||
readonly databaseWorkerGetEventLoopDelayP99Ms: NumericDistribution;
|
||||
readonly databaseWorkerGetEventLoopUtilization: NumericDistribution;
|
||||
readonly databaseWorkerGetThreadCpuSystemMicros: NumericDistribution;
|
||||
readonly databaseWorkerGetThreadCpuUserMicros: NumericDistribution;
|
||||
readonly databaseWorkerEventLoopDelayMaxMs: NumericDistribution;
|
||||
readonly databaseWorkerEventLoopDelayP95Ms: NumericDistribution;
|
||||
readonly databaseWorkerEventLoopDelayP99Ms: NumericDistribution;
|
||||
readonly databaseWorkerEventLoopUtilization: NumericDistribution;
|
||||
readonly databaseWorkerExternalPeakBytes: NumericDistribution;
|
||||
readonly databaseWorkerHeapPeakBytes: NumericDistribution;
|
||||
readonly databaseWorkerPostGcHeapBytes: NumericDistribution;
|
||||
readonly databaseWorkerThreadCpuSystemMicros: NumericDistribution;
|
||||
readonly databaseWorkerThreadCpuUserMicros: NumericDistribution;
|
||||
readonly databaseWorkerToMainCloneProxyMs: NumericDistribution;
|
||||
readonly databaseWorkerUpsertEventLoopDelayMaxMs: NumericDistribution;
|
||||
readonly databaseWorkerUpsertEventLoopDelayP95Ms: NumericDistribution;
|
||||
readonly databaseWorkerUpsertEventLoopDelayP99Ms: NumericDistribution;
|
||||
readonly databaseWorkerUpsertEventLoopUtilization: NumericDistribution;
|
||||
readonly databaseWorkerUpsertThreadCpuSystemMicros: NumericDistribution;
|
||||
readonly databaseWorkerUpsertThreadCpuUserMicros: NumericDistribution;
|
||||
readonly ipcStructuredCloneProxyMs: NumericDistribution;
|
||||
readonly mainToDatabaseWorkerCloneProxyMs: NumericDistribution;
|
||||
readonly mainToRendererCloneProxyMs: NumericDistribution;
|
||||
readonly m3uParsingMs: NumericDistribution;
|
||||
readonly mainEventLoopDelayMaxMs: NumericDistribution;
|
||||
readonly mainEventLoopDelayP95Ms: NumericDistribution;
|
||||
readonly mainEventLoopDelayP99Ms: NumericDistribution;
|
||||
readonly mainEventLoopUtilization: NumericDistribution;
|
||||
readonly mainHeapPeakBytes: NumericDistribution;
|
||||
readonly mainHeapPostGcBytes: NumericDistribution;
|
||||
readonly mainRssPeakBytes: NumericDistribution;
|
||||
readonly mainRssPostGcBytes: NumericDistribution;
|
||||
readonly normalizationMs: NumericDistribution;
|
||||
readonly playlistDeserializationMs: NumericDistribution;
|
||||
readonly playlistSerializationMs: NumericDistribution;
|
||||
readonly rendererFrameGapMs: NumericDistribution;
|
||||
readonly rendererHeartbeatDelayMs: NumericDistribution;
|
||||
readonly rendererHeapPeakBytes: NumericDistribution;
|
||||
readonly rendererHeapPostGcBytes: NumericDistribution;
|
||||
readonly rendererLongTaskCount: number;
|
||||
readonly rendererLongTaskMs: NumericDistribution;
|
||||
readonly rendererRssPeakBytes: NumericDistribution;
|
||||
readonly rendererToMainCloneProxyMs: NumericDistribution;
|
||||
readonly responsiveEvents: number;
|
||||
readonly sqliteReadMs: NumericDistribution;
|
||||
readonly sqliteWriteMs: NumericDistribution;
|
||||
readonly storeImportDispatchMs: NumericDistribution;
|
||||
readonly storePublishChannelsMs: NumericDistribution;
|
||||
readonly storeUpdateMs: NumericDistribution;
|
||||
readonly totalMs: NumericDistribution;
|
||||
readonly unresponsiveEvents: number;
|
||||
}
|
||||
|
||||
export interface M3uImportBenchmarkSummary {
|
||||
readonly iterations: readonly M3uImportIterationResult[];
|
||||
readonly manifest: M3uImportBenchmarkManifest;
|
||||
readonly measured: M3uImportMeasuredSummary;
|
||||
readonly notApplicable: {
|
||||
readonly cancelAcknowledgementLatencyMs: 'scenario-has-no-cancellation';
|
||||
readonly databaseWorkerRss: 'unavailable-per-worker-thread';
|
||||
readonly indexAndCommitMs: typeof M3U_IMPORT_INDEX_COMMIT_UNAVAILABLE_REASON;
|
||||
readonly nativeAndSqliteMemory: 'included-in-main-rss-not-separately-attributable';
|
||||
readonly playlistRefreshWorker: 'not-used-by-initial-import';
|
||||
};
|
||||
readonly validity: {
|
||||
readonly databaseWorkerPeakMemory: DatabaseWorkerPeakMemoryValidity;
|
||||
readonly databaseWorkerPostGc: DatabaseWorkerPostGcValidity;
|
||||
readonly databaseWorkerRequestMetrics: DatabaseWorkerRequestMetricsValidity;
|
||||
readonly rendererRss: RendererRssValidity;
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
import { it } from 'node:test';
|
||||
|
||||
import { PERFORMANCE_ITERATION_KIND } from './m3u-refresh-cancellation-contract';
|
||||
@@ -16,6 +18,16 @@ import {
|
||||
TEST_M3U_FIXTURE_BYTES,
|
||||
} from './m3u-import-report.test-helpers';
|
||||
|
||||
it('keeps summary aggregation below the hard line limit without a suppression', () => {
|
||||
const source = readFileSync(
|
||||
resolve(process.cwd(), 'src/performance/m3u-import-summary.ts'),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
assert.doesNotMatch(source, /eslint-disable max-lines/);
|
||||
assert.ok(source.split(/\r?\n/).length <= 400);
|
||||
});
|
||||
|
||||
it('summarizes measured runs only while preserving per-process memory boundaries', () => {
|
||||
const warmup = createM3uImportIterationResult({
|
||||
channelCount: TEST_M3U_CHANNEL_COUNT,
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* eslint-disable max-lines -- The formal summary keeps its complete measured schema and aggregation contract together. */
|
||||
import type { M3uImportRendererCaptureMetrics } from './m3u-import-renderer-capture';
|
||||
import type { M3uImportScenarioId } from './m3u-import-benchmark-contract';
|
||||
import type {
|
||||
DatabaseWorkerPostGcValidity,
|
||||
MainCaptureMetrics,
|
||||
NumericDistribution,
|
||||
PerformanceIterationKind,
|
||||
@@ -16,138 +14,24 @@ import {
|
||||
import {
|
||||
deriveM3uImportPhaseMetrics,
|
||||
M3U_IMPORT_INDEX_COMMIT_UNAVAILABLE_REASON,
|
||||
type M3uImportPhaseMetrics,
|
||||
} from './m3u-import-report';
|
||||
import { summarizeNumbers } from './performance-statistics';
|
||||
import {
|
||||
assessDatabaseWorkerPeakMemoryValidity,
|
||||
type DatabaseWorkerPeakMemoryValidity,
|
||||
} from './database-worker-peak-memory-validity';
|
||||
import { assessDatabaseWorkerPeakMemoryValidity } from './database-worker-peak-memory-validity';
|
||||
import { assessDatabaseWorkerPostGcValidity } from './database-worker-post-gc-validity';
|
||||
import {
|
||||
assessDatabaseWorkerRequestMetricsValidity,
|
||||
type DatabaseWorkerRequestMetricsValidity,
|
||||
} from './database-worker-request-metrics-validity';
|
||||
import {
|
||||
assessRendererRssValidity,
|
||||
type RendererRssValidity,
|
||||
} from './renderer-rss-validity';
|
||||
import { assessDatabaseWorkerRequestMetricsValidity } from './database-worker-request-metrics-validity';
|
||||
import { assessRendererRssValidity } from './renderer-rss-validity';
|
||||
import type {
|
||||
M3uImportBenchmarkManifest,
|
||||
M3uImportBenchmarkSummary,
|
||||
M3uImportIterationResult,
|
||||
} from './m3u-import-summary-contract';
|
||||
|
||||
export interface M3uImportIterationResult {
|
||||
readonly channelCount: number;
|
||||
readonly fixtureBytes: number;
|
||||
readonly kind: PerformanceIterationKind;
|
||||
readonly main: MainCaptureMetrics;
|
||||
readonly phases: M3uImportPhaseMetrics;
|
||||
readonly renderer: M3uImportRendererCaptureMetrics;
|
||||
readonly runId: string;
|
||||
readonly scenarioId: M3uImportScenarioId;
|
||||
}
|
||||
|
||||
export interface M3uImportBenchmarkManifest {
|
||||
readonly channelCount: number;
|
||||
readonly fixtureBytes: number;
|
||||
readonly fixtureSha256: string;
|
||||
readonly gitCommit: string;
|
||||
readonly gitDiffSha256: string;
|
||||
readonly gitDirty: boolean;
|
||||
readonly measuredRuns: number;
|
||||
readonly memoryAccounting: {
|
||||
readonly databaseWorkerRss: 'unavailable-per-worker-thread';
|
||||
readonly mainRss: 'electron-main-process-including-worker-threads-and-native-memory';
|
||||
readonly nativeAndSqliteMemory: 'included-in-main-rss-not-separately-attributable';
|
||||
readonly rendererRss: 'separate-renderer-process';
|
||||
readonly workerJsHeap: 'separate-v8-isolate';
|
||||
};
|
||||
readonly runtime: {
|
||||
readonly arch: string;
|
||||
readonly cdpPort: number;
|
||||
readonly electronVersion: string;
|
||||
readonly harnessNodeVersion: string;
|
||||
readonly platform: string;
|
||||
};
|
||||
readonly scenario: M3uImportScenarioId;
|
||||
readonly syntheticSeed: number;
|
||||
readonly variant: string;
|
||||
readonly warmupRuns: number;
|
||||
}
|
||||
|
||||
export interface M3uImportMeasuredSummary {
|
||||
readonly angularRenderingMs: NumericDistribution;
|
||||
readonly dataAcquireMs: NumericDistribution;
|
||||
readonly databaseWorkerGetEventLoopDelayMaxMs: NumericDistribution;
|
||||
readonly databaseWorkerGetEventLoopDelayP95Ms: NumericDistribution;
|
||||
readonly databaseWorkerGetEventLoopDelayP99Ms: NumericDistribution;
|
||||
readonly databaseWorkerGetEventLoopUtilization: NumericDistribution;
|
||||
readonly databaseWorkerGetThreadCpuSystemMicros: NumericDistribution;
|
||||
readonly databaseWorkerGetThreadCpuUserMicros: NumericDistribution;
|
||||
readonly databaseWorkerEventLoopDelayMaxMs: NumericDistribution;
|
||||
readonly databaseWorkerEventLoopDelayP95Ms: NumericDistribution;
|
||||
readonly databaseWorkerEventLoopDelayP99Ms: NumericDistribution;
|
||||
readonly databaseWorkerEventLoopUtilization: NumericDistribution;
|
||||
readonly databaseWorkerExternalPeakBytes: NumericDistribution;
|
||||
readonly databaseWorkerHeapPeakBytes: NumericDistribution;
|
||||
readonly databaseWorkerPostGcHeapBytes: NumericDistribution;
|
||||
readonly databaseWorkerThreadCpuSystemMicros: NumericDistribution;
|
||||
readonly databaseWorkerThreadCpuUserMicros: NumericDistribution;
|
||||
readonly databaseWorkerToMainCloneProxyMs: NumericDistribution;
|
||||
readonly databaseWorkerUpsertEventLoopDelayMaxMs: NumericDistribution;
|
||||
readonly databaseWorkerUpsertEventLoopDelayP95Ms: NumericDistribution;
|
||||
readonly databaseWorkerUpsertEventLoopDelayP99Ms: NumericDistribution;
|
||||
readonly databaseWorkerUpsertEventLoopUtilization: NumericDistribution;
|
||||
readonly databaseWorkerUpsertThreadCpuSystemMicros: NumericDistribution;
|
||||
readonly databaseWorkerUpsertThreadCpuUserMicros: NumericDistribution;
|
||||
readonly ipcStructuredCloneProxyMs: NumericDistribution;
|
||||
readonly mainToDatabaseWorkerCloneProxyMs: NumericDistribution;
|
||||
readonly mainToRendererCloneProxyMs: NumericDistribution;
|
||||
readonly m3uParsingMs: NumericDistribution;
|
||||
readonly mainEventLoopDelayMaxMs: NumericDistribution;
|
||||
readonly mainEventLoopDelayP95Ms: NumericDistribution;
|
||||
readonly mainEventLoopDelayP99Ms: NumericDistribution;
|
||||
readonly mainEventLoopUtilization: NumericDistribution;
|
||||
readonly mainHeapPeakBytes: NumericDistribution;
|
||||
readonly mainHeapPostGcBytes: NumericDistribution;
|
||||
readonly mainRssPeakBytes: NumericDistribution;
|
||||
readonly mainRssPostGcBytes: NumericDistribution;
|
||||
readonly normalizationMs: NumericDistribution;
|
||||
readonly playlistDeserializationMs: NumericDistribution;
|
||||
readonly playlistSerializationMs: NumericDistribution;
|
||||
readonly rendererFrameGapMs: NumericDistribution;
|
||||
readonly rendererHeartbeatDelayMs: NumericDistribution;
|
||||
readonly rendererHeapPeakBytes: NumericDistribution;
|
||||
readonly rendererHeapPostGcBytes: NumericDistribution;
|
||||
readonly rendererLongTaskCount: number;
|
||||
readonly rendererLongTaskMs: NumericDistribution;
|
||||
readonly rendererRssPeakBytes: NumericDistribution;
|
||||
readonly rendererToMainCloneProxyMs: NumericDistribution;
|
||||
readonly responsiveEvents: number;
|
||||
readonly sqliteReadMs: NumericDistribution;
|
||||
readonly sqliteWriteMs: NumericDistribution;
|
||||
readonly storeImportDispatchMs: NumericDistribution;
|
||||
readonly storePublishChannelsMs: NumericDistribution;
|
||||
readonly storeUpdateMs: NumericDistribution;
|
||||
readonly totalMs: NumericDistribution;
|
||||
readonly unresponsiveEvents: number;
|
||||
}
|
||||
|
||||
export interface M3uImportBenchmarkSummary {
|
||||
readonly iterations: readonly M3uImportIterationResult[];
|
||||
readonly manifest: M3uImportBenchmarkManifest;
|
||||
readonly measured: M3uImportMeasuredSummary;
|
||||
readonly notApplicable: {
|
||||
readonly cancelAcknowledgementLatencyMs: 'scenario-has-no-cancellation';
|
||||
readonly databaseWorkerRss: 'unavailable-per-worker-thread';
|
||||
readonly indexAndCommitMs: typeof M3U_IMPORT_INDEX_COMMIT_UNAVAILABLE_REASON;
|
||||
readonly nativeAndSqliteMemory: 'included-in-main-rss-not-separately-attributable';
|
||||
readonly playlistRefreshWorker: 'not-used-by-initial-import';
|
||||
};
|
||||
readonly validity: {
|
||||
readonly databaseWorkerPeakMemory: DatabaseWorkerPeakMemoryValidity;
|
||||
readonly databaseWorkerPostGc: DatabaseWorkerPostGcValidity;
|
||||
readonly databaseWorkerRequestMetrics: DatabaseWorkerRequestMetricsValidity;
|
||||
readonly rendererRss: RendererRssValidity;
|
||||
};
|
||||
}
|
||||
export type {
|
||||
M3uImportBenchmarkManifest,
|
||||
M3uImportBenchmarkSummary,
|
||||
M3uImportIterationResult,
|
||||
M3uImportMeasuredSummary,
|
||||
} from './m3u-import-summary-contract';
|
||||
|
||||
export function createM3uImportIterationResult(input: {
|
||||
readonly channelCount: number;
|
||||
|
||||
@@ -268,7 +268,8 @@ async function waitForDatabaseSettlement(
|
||||
status.databaseRequests === 2 &&
|
||||
status.databaseUpsertsCompleted === 1 &&
|
||||
status.databaseGetsCompleted === 1 &&
|
||||
status.databasePending === 0
|
||||
status.databasePending === 0 &&
|
||||
status.preloadSuccessMarkers === 2
|
||||
);
|
||||
},
|
||||
{ timeout: 120_000 }
|
||||
|
||||
@@ -70,6 +70,7 @@ export interface MainCaptureStatus {
|
||||
readonly playlistResponsesFailed: number;
|
||||
readonly playlistResponses: number;
|
||||
readonly playlistResponsesSucceeded: number;
|
||||
readonly preloadSuccessMarkers: number;
|
||||
}
|
||||
|
||||
export interface MainCaptureRolloverResult {
|
||||
@@ -1188,6 +1189,8 @@ export async function installMainCapture(
|
||||
entry['type'] === 'playlist-response' &&
|
||||
entry['success'] === true
|
||||
).length,
|
||||
preloadSuccessMarkers:
|
||||
databaseRequestIdentityCapture.successMarkerCount(),
|
||||
}),
|
||||
start: async (options: MainCaptureStartOptions): Promise<void> => {
|
||||
databaseWorkerPostGcCutoffApi.beginCapture();
|
||||
|
||||
@@ -128,17 +128,19 @@ therefore `N/A` with
|
||||
Instrumentation is development-only, opt-in, fail-neutral, and count-only. It
|
||||
must not scan or log playlist payloads to generate metadata. Renderer
|
||||
long-task, frame-gap, and heartbeat samples are clipped to the measured
|
||||
operation boundary. Formal comparison fails closed after writing raw results
|
||||
if exact-window renderer RSS, database-worker peak heap/external samples, or
|
||||
the database worker's explicit post-GC heap is missing or incoherent. Both
|
||||
initial-import database requests in every measured run must also contain
|
||||
coherent event-loop delay, event-loop utilization, and thread-CPU metrics;
|
||||
the validity record exposes the exact expected and valid request counts rather
|
||||
than silently dropping nullable samples. An iteration failure idempotently
|
||||
stops renderer timers, closes trace listeners/output, and starts best-effort
|
||||
probe/session teardown without waiting on a wedged renderer before Electron is
|
||||
closed. A partial capture-start failure performs the same rollback before it
|
||||
escapes to the benchmark lifecycle.
|
||||
operation boundary. Main capture stops only after the upsert and route-reload
|
||||
GET responses plus both asynchronous preload success markers have arrived, so
|
||||
return-clone attribution cannot race capture shutdown. Formal comparison fails
|
||||
closed after writing raw results if exact-window renderer RSS, database-worker
|
||||
peak heap/external samples, or the database worker's explicit post-GC heap is
|
||||
missing or incoherent. Both initial-import database requests in every measured
|
||||
run must also contain coherent event-loop delay, event-loop utilization, and
|
||||
thread-CPU metrics; the validity record exposes the exact expected and valid
|
||||
request counts rather than silently dropping nullable samples. An iteration
|
||||
failure idempotently stops renderer timers, closes trace listeners/output, and
|
||||
starts best-effort probe/session teardown without waiting on a wedged renderer
|
||||
before Electron is closed. A partial capture-start failure performs the same
|
||||
rollback before it escapes to the benchmark lifecycle.
|
||||
Diagnostic artifacts require separate renderer, main, and database-worker CPU
|
||||
profiles plus renderer/main/database-worker heap snapshots and a Chromium
|
||||
trace; raw profiles remain ignored.
|
||||
|
||||
Reference in new issue
Block a user