Unified · Split
| @@ -83,6 +83,7 @@ jobs: · 82 unmodified lines | |||
| 83 | # Terminal PTY scripting is flaky in CI VMs; renderer perf checks remain enforced. | 83 | # Terminal PTY scripting is flaky in CI VMs; renderer perf checks remain enforced. |
| 84 | T3CODE_DESKTOP_PERF_RUN_TERMINAL: "0" | 84 | T3CODE_DESKTOP_PERF_RUN_TERMINAL: "0" |
| 85 | T3CODE_DESKTOP_PERF_RUN_OPTIONAL_RENDERER: "0" | 85 | T3CODE_DESKTOP_PERF_RUN_OPTIONAL_RENDERER: "0" |
| 86 | T3CODE_DESKTOP_PERF_RUN_BENCHMARK_SWEEP: "0" | ||
| 86 | T3CODE_DESKTOP_PERF_BENCHMARK_FOLLOW_UP_PASSES: "0" | 87 | T3CODE_DESKTOP_PERF_BENCHMARK_FOLLOW_UP_PASSES: "0" |
| 87 | T3CODE_ELECTRON_STARTUP_TIMEOUT_MS: "180000" | 88 | T3CODE_ELECTRON_STARTUP_TIMEOUT_MS: "180000" |
| 88 | run: xvfb-run -a bun run test:desktop-perf | 89 | run: xvfb-run -a bun run test:desktop-perf |
| @@ -95,6 +96,7 @@ jobs: · 6 unmodified lines | |||
| 95 | T3CODE_PERF_MAX_LONG_DISPATCH_COUNT: "5" | 96 | T3CODE_PERF_MAX_LONG_DISPATCH_COUNT: "5" |
| 96 | T3CODE_DESKTOP_PERF_RUN_TERMINAL: "0" | 97 | T3CODE_DESKTOP_PERF_RUN_TERMINAL: "0" |
| 97 | T3CODE_DESKTOP_PERF_RUN_OPTIONAL_RENDERER: "0" | 98 | T3CODE_DESKTOP_PERF_RUN_OPTIONAL_RENDERER: "0" |
| 99 | T3CODE_DESKTOP_PERF_RUN_BENCHMARK_SWEEP: "0" | ||
| 98 | T3CODE_DESKTOP_PERF_BENCHMARK_FOLLOW_UP_PASSES: "0" | 100 | T3CODE_DESKTOP_PERF_BENCHMARK_FOLLOW_UP_PASSES: "0" |
| 99 | T3CODE_ELECTRON_STARTUP_TIMEOUT_MS: "180000" | 101 | T3CODE_ELECTRON_STARTUP_TIMEOUT_MS: "180000" |
| 100 | run: xvfb-run -a bun run test:desktop-perf | 102 | run: xvfb-run -a bun run test:desktop-perf |
| @@ -108,6 +110,7 @@ jobs: · 7 unmodified lines | |||
| 108 | T3CODE_PERF_MAX_LONG_DISPATCH_COUNT: "5" | 110 | T3CODE_PERF_MAX_LONG_DISPATCH_COUNT: "5" |
| 109 | T3CODE_DESKTOP_PERF_RUN_TERMINAL: "0" | 111 | T3CODE_DESKTOP_PERF_RUN_TERMINAL: "0" |
| 110 | T3CODE_DESKTOP_PERF_RUN_OPTIONAL_RENDERER: "0" | 112 | T3CODE_DESKTOP_PERF_RUN_OPTIONAL_RENDERER: "0" |
| 113 | T3CODE_DESKTOP_PERF_RUN_BENCHMARK_SWEEP: "0" | ||
| 111 | T3CODE_DESKTOP_PERF_BENCHMARK_FOLLOW_UP_PASSES: "0" | 114 | T3CODE_DESKTOP_PERF_BENCHMARK_FOLLOW_UP_PASSES: "0" |
| 112 | T3CODE_ELECTRON_STARTUP_TIMEOUT_MS: "180000" | 115 | T3CODE_ELECTRON_STARTUP_TIMEOUT_MS: "180000" |
| 113 | run: xvfb-run -a bun run test:desktop-perf:post | 116 | run: xvfb-run -a bun run test:desktop-perf:post |
| @@ -6,6 +6,7 @@ import path from "node:path"; · 5 unmodified lines | |||
| 6 | import { BrowserWindow, contentTracing, type WebContents } from "electron"; | 6 | import { BrowserWindow, contentTracing, type WebContents } from "electron"; |
| 7 | import { | 7 | import { |
| 8 | resolveBenchmarkFollowUpPassCount, | 8 | resolveBenchmarkFollowUpPassCount, |
| 9 | shouldRunBenchmarkThreadSweep, | ||
| 9 | shouldRunOptionalRendererPerfInteractions, | 10 | shouldRunOptionalRendererPerfInteractions, |
| 10 | shouldRunTerminalPerfInteractions, | 11 | shouldRunTerminalPerfInteractions, |
| 11 | } from "./perfConfig"; | 12 | } from "./perfConfig"; |
| @@ -27,6 +28,10 @@ const BENCHMARK_FOLLOW_UP_PASS_COUNT = resolveBenchmarkFollowUpPassCount({ · 15 unmodified lines | |||
| 27 | process.env.T3CODE_DESKTOP_PERF_BENCHMARK_FOLLOW_UP_PASSES, | 28 | process.env.T3CODE_DESKTOP_PERF_BENCHMARK_FOLLOW_UP_PASSES, |
| 28 | CI: process.env.CI, | 29 | CI: process.env.CI, |
| 29 | }); | 30 | }); |
| 31 | const RUN_BENCHMARK_THREAD_SWEEP = shouldRunBenchmarkThreadSweep({ | ||
| 32 | T3CODE_DESKTOP_PERF_RUN_BENCHMARK_SWEEP: process.env.T3CODE_DESKTOP_PERF_RUN_BENCHMARK_SWEEP, | ||
| 33 | CI: process.env.CI, | ||
| 34 | }); | ||
| 30 | 35 | ||
| 31 | function delay(ms: number): Promise<void> { | 36 | function delay(ms: number): Promise<void> { |
| 32 | return new Promise((resolve) => setTimeout(resolve, ms)); | 37 | return new Promise((resolve) => setTimeout(resolve, ms)); |
| @@ -575,13 +580,14 @@ async function runRendererPerfInteractions( · 542 unmodified lines | |||
| 575 | return Number((sorted[middle] ?? 0).toFixed(2)); | 580 | return Number((sorted[middle] ?? 0).toFixed(2)); |
| 576 | }; | 581 | }; |
| 577 | 582 | ||
| 583 | const runBenchmarkThreadSweep = ${RUN_BENCHMARK_THREAD_SWEEP}; | ||
| 578 | const preferredThreadIds = ${JSON.stringify(benchmarkThreadIds)}.filter( | 584 | const preferredThreadIds = ${JSON.stringify(benchmarkThreadIds)}.filter( |
| 579 | (value) => typeof value === "string" && value.length > 0, | 585 | (value) => typeof value === "string" && value.length > 0, |
| 580 | ); | 586 | ); |
| 581 | const benchmarkThreadIds = preferredThreadIds.filter((threadId) => | 587 | const benchmarkThreadIds = runBenchmarkThreadSweep |
| 582 | renderedThreadIds.includes(threadId), | 588 | ? preferredThreadIds.filter((threadId) => renderedThreadIds.includes(threadId)) |
| 583 | ); | 589 | : []; |
| 584 | if (benchmarkThreadIds.length === 0) { | 590 | if (runBenchmarkThreadSweep && benchmarkThreadIds.length === 0) { |
| 585 | benchmarkThreadIds.push(...renderedThreadIds.slice(0, ${BENCHMARK_THREAD_COUNT})); | 591 | benchmarkThreadIds.push(...renderedThreadIds.slice(0, ${BENCHMARK_THREAD_COUNT})); |
| 586 | } | 592 | } |
| 587 | 593 | ||
| @@ -599,25 +605,27 @@ async function runRendererPerfInteractions( · 11 unmodified lines | |||
| 599 | }; | 605 | }; |
| 600 | 606 | ||
| 601 | const firstPassByThreadId = new Map(); | 607 | const firstPassByThreadId = new Map(); |
| 602 | for (const threadId of benchmarkThreadIds) { | ||
| 603 | await ensureThreadSwitchTarget(threadId); | ||
| 604 | firstPassByThreadId.set(threadId, await measureThreadRender(threadId)); | ||
| 605 | } | ||
| 606 | |||
| 607 | const followUpSamplesByThreadId = new Map(); | 608 | const followUpSamplesByThreadId = new Map(); |
| 608 | for (const threadId of benchmarkThreadIds) { | 609 | if (runBenchmarkThreadSweep) { |
| 609 | followUpSamplesByThreadId.set(threadId, []); | ||
| 610 | } | ||
| 611 | const followUpPassCount = ${BENCHMARK_FOLLOW_UP_PASS_COUNT}; | ||
| 612 | for (let passIndex = 0; passIndex < followUpPassCount; passIndex += 1) { | ||
| 613 | for (const threadId of benchmarkThreadIds) { | 610 | for (const threadId of benchmarkThreadIds) { |
| 614 | await ensureThreadSwitchTarget(threadId); | 611 | await ensureThreadSwitchTarget(threadId); |
| 615 | const sample = await measureThreadRender(threadId); | 612 | firstPassByThreadId.set(threadId, await measureThreadRender(threadId)); |
| 616 | const samples = followUpSamplesByThreadId.get(threadId); | 613 | } |
| 617 | if (Array.isArray(samples)) { | 614 | |
| 618 | samples.push(sample.renderMs); | 615 | for (const threadId of benchmarkThreadIds) { |
| 619 | } else { | 616 | followUpSamplesByThreadId.set(threadId, []); |
| 620 | followUpSamplesByThreadId.set(threadId, [sample.renderMs]); | 617 | } |
| 618 | const followUpPassCount = ${BENCHMARK_FOLLOW_UP_PASS_COUNT}; | ||
| 619 | for (let passIndex = 0; passIndex < followUpPassCount; passIndex += 1) { | ||
| 620 | for (const threadId of benchmarkThreadIds) { | ||
| 621 | await ensureThreadSwitchTarget(threadId); | ||
| 622 | const sample = await measureThreadRender(threadId); | ||
| 623 | const samples = followUpSamplesByThreadId.get(threadId); | ||
| 624 | if (Array.isArray(samples)) { | ||
| 625 | samples.push(sample.renderMs); | ||
| 626 | } else { | ||
| 627 | followUpSamplesByThreadId.set(threadId, [sample.renderMs]); | ||
| 628 | } | ||
| 621 | } | 629 | } |
| 622 | } | 630 | } |
| 623 | } | 631 | } |
| @@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest"; · 1 unmodified line | |||
| 2 | 2 | ||
| 3 | import { | 3 | import { |
| 4 | resolveBenchmarkFollowUpPassCount, | 4 | resolveBenchmarkFollowUpPassCount, |
| 5 | shouldRunBenchmarkThreadSweep, | ||
| 5 | shouldRunOptionalRendererPerfInteractions, | 6 | shouldRunOptionalRendererPerfInteractions, |
| 6 | shouldRunTerminalPerfInteractions, | 7 | shouldRunTerminalPerfInteractions, |
| 7 | } from "./perfConfig"; | 8 | } from "./perfConfig"; |
| @@ -207,3 +208,25 @@ describe("shouldRunOptionalRendererPerfInteractions", () => { · 199 unmodified lines | |||
| 207 | ).toBe(false); | 208 | ).toBe(false); |
| 208 | }); | 209 | }); |
| 209 | }); | 210 | }); |
| 211 | |||
| 212 | describe("shouldRunBenchmarkThreadSweep", () => { | ||
| 213 | it("defaults to enabled outside CI and disabled in CI", () => { | ||
| 214 | expect(shouldRunBenchmarkThreadSweep({ CI: "false" })).toBe(true); | ||
| 215 | expect(shouldRunBenchmarkThreadSweep({ CI: "true" })).toBe(false); | ||
| 216 | }); | ||
| 217 | |||
| 218 | it("supports explicit env overrides", () => { | ||
| 219 | expect( | ||
| 220 | shouldRunBenchmarkThreadSweep({ | ||
| 221 | T3CODE_DESKTOP_PERF_RUN_BENCHMARK_SWEEP: "1", | ||
| 222 | CI: "true", | ||
| 223 | }), | ||
| 224 | ).toBe(true); | ||
| 225 | expect( | ||
| 226 | shouldRunBenchmarkThreadSweep({ | ||
| 227 | T3CODE_DESKTOP_PERF_RUN_BENCHMARK_SWEEP: "off", | ||
| 228 | CI: "false", | ||
| 229 | }), | ||
| 230 | ).toBe(false); | ||
| 231 | }); | ||
| 232 | }); | ||
| @@ -13,6 +13,11 @@ type PerfBenchmarkEnv = { · 12 unmodified lines | |||
| 13 | CI?: string | undefined; | 13 | CI?: string | undefined; |
| 14 | }; | 14 | }; |
| 15 | 15 | ||
| 16 | type BenchmarkSweepToggleEnv = { | ||
| 17 | T3CODE_DESKTOP_PERF_RUN_BENCHMARK_SWEEP?: string | undefined; | ||
| 18 | CI?: string | undefined; | ||
| 19 | }; | ||
| 20 | |||
| 16 | const TRUE_VALUES = new Set(["1", "true", "yes", "on"]); | 21 | const TRUE_VALUES = new Set(["1", "true", "yes", "on"]); |
| 17 | const FALSE_VALUES = new Set(["0", "false", "no", "off"]); | 22 | const FALSE_VALUES = new Set(["0", "false", "no", "off"]); |
| 18 | const MAX_BENCHMARK_FOLLOW_UP_PASSES = 5; | 23 | const MAX_BENCHMARK_FOLLOW_UP_PASSES = 5; |
| @@ -52,6 +57,12 @@ export function shouldRunOptionalRendererPerfInteractions(env: OptionalRendererT · 33 unmodified lines | |||
| 52 | return !isCiEnvironment(env.CI); | 57 | return !isCiEnvironment(env.CI); |
| 53 | } | 58 | } |
| 54 | 59 | ||
| 60 | export function shouldRunBenchmarkThreadSweep(env: BenchmarkSweepToggleEnv): boolean { | ||
| 61 | const toggleOverride = parseBooleanLike(env.T3CODE_DESKTOP_PERF_RUN_BENCHMARK_SWEEP); | ||
| 62 | if (toggleOverride !== null) return toggleOverride; | ||
| 63 | return !isCiEnvironment(env.CI); | ||
| 64 | } | ||
| 65 | |||
| 55 | export function resolveBenchmarkFollowUpPassCount(env: PerfBenchmarkEnv): number { | 66 | export function resolveBenchmarkFollowUpPassCount(env: PerfBenchmarkEnv): number { |
| 56 | const raw = env.T3CODE_DESKTOP_PERF_BENCHMARK_FOLLOW_UP_PASSES?.trim(); | 67 | const raw = env.T3CODE_DESKTOP_PERF_BENCHMARK_FOLLOW_UP_PASSES?.trim(); |
| 57 | if (raw && /^\d+$/.test(raw)) { | 68 | if (raw && /^\d+$/.test(raw)) { |