From 81a0723abd68220198c94b1d814cc71677e30d5b Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Thu, 22 Oct 2026 16:19:03 +0200 Subject: [PATCH] ci: report the first ios launch after install apart from the cold starts after it --- .github/workflows/e2e-ios.yml | 2 +- scripts/e2e/perf.mjs | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/e2e-ios.yml b/.github/workflows/e2e-ios.yml index a82ac8e3..3e92c3af 100644 --- a/.github/workflows/e2e-ios.yml +++ b/.github/workflows/e2e-ios.yml @@ -325,7 +325,7 @@ jobs: if [ -d "$RUNNER_TEMP/base/app/BulwarkMobile.app" ]; then APPS=(--app "base=$RUNNER_TEMP/base/app/BulwarkMobile.app" "${APPS[@]}") fi - node scripts/e2e/perf.mjs "${APPS[@]}" --rounds "${{ inputs.perf_rounds || 5 }}" --cold 3 \ + node scripts/e2e/perf.mjs "${APPS[@]}" --rounds "${{ inputs.perf_rounds || 5 }}" --cold 5 \ --flows "$(ls "$GITHUB_WORKSPACE"/.maestro/perf/[0-9]-*.yaml | paste -sd, -)" --out "$OUT" - name: Upload results diff --git a/scripts/e2e/perf.mjs b/scripts/e2e/perf.mjs index 78552d6f..b8733db0 100644 --- a/scripts/e2e/perf.mjs +++ b/scripts/e2e/perf.mjs @@ -11,7 +11,10 @@ // stays signed in), // 2. cold-starts it `--cold` times: terminate, launch, wait for // `inbox-rendered`; cold start = that mark's time minus the launch time -// taken on this machine (the simulator shares the host clock), +// taken on this machine (the simulator shares the host clock). The +// first launch after the install is much slower and swings a lot (iOS +// does its first-launch work for the new binary), so it is reported on +// its own as `first-start-*`; `cold-start-*` are the launches after it, // 3. runs the Maestro interaction flows once each (open messages, switch // tabs, open compose, scroll), which produce the other marks. Each flow // is its own run, so one that fails costs only its own metric. @@ -102,7 +105,7 @@ function waitForMark(name, timeoutMs) { // ── steps ─────────────────────────────────────────────────────────────────── const samples = []; // { label, metric, ms, round } -async function coldStart(label, round) { +async function coldStart(label, round, first) { try { simctl('terminate', UDID, BUNDLE); } catch { /* not running */ } await sleep(1500); const pending = waitForMark('inbox-rendered', 120_000); @@ -114,8 +117,9 @@ async function coldStart(label, round) { console.log(` ${label} cold start: no inbox-rendered mark within 120 s`); return; } - samples.push({ label, round, metric: 'cold-start-to-inbox', ms: mark.t - t0 }); - if (bundle) samples.push({ label, round, metric: 'cold-start-to-bundle', ms: bundle.t - t0 }); + const kind = first ? 'first-start' : 'cold-start'; + samples.push({ label, round, metric: `${kind}-to-inbox`, ms: mark.t - t0 }); + if (bundle) samples.push({ label, round, metric: `${kind}-to-bundle`, ms: bundle.t - t0 }); console.log(` ${label} cold start ${mark.t - t0} ms (bundle ${bundle ? bundle.t - t0 : '?'} ms, rows ${mark.rows})`); await sleep(3000); } @@ -185,7 +189,7 @@ if (final && process.env.GITHUB_STEP_SUMMARY) fs.appendFileSync(process.env.GITH currentLabel = app.label; try { simctl('terminate', UDID, BUNDLE); } catch { /* not running */ } simctl('install', UDID, app.path); - for (let i = 0; i < coldRuns; i++) await coldStart(app.label, round); + for (let i = 0; i < coldRuns; i++) await coldStart(app.label, round, i === 0); const got = await runFlows(app.label); for (const m of got) { const metric = m.n === 'tab-switch' && m.to ? `tab-switch:${m.to}` : m.n;