diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 73a38b4..328c5ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -105,6 +105,22 @@ jobs: run: echo "out=$(nix build --impure .#${{ matrix.target }} --print-build-logs --no-link --print-out-paths)" >> "$GITHUB_OUTPUT" - name: Put bin on PATH run: echo "${{ steps.build.outputs.out }}/bin" >> "$GITHUB_PATH" + # Confirmed root cause of CI's inflated startup numbers below (see + # PR #44): without this cache, plugin files land fresh from a network + # git clone on every run, and each cold file read shows up inside + # nvim's own require()/sourcing timings (--startuptime measures the + # whole call including the read, not just execution). That's what was + # producing 100-600ms readings vs. ~25ms locally for the identical + # build -- not a slow plugin, not CPU contention, not codesign/ + # Gatekeeper overhead (all measured and ruled out, see below). Adding + # this cache alone took every matrix entry down to ~20-27ms, matching + # local numbers almost exactly. Keyed on runs-on because + # telescope-fzf-native's native build output is arch-specific. + - name: Cache lazy.nvim plugins + uses: actions/cache@v4 + with: + path: ~/.local/share/nvim/lazy + key: lazy-${{ matrix.runs-on }}-${{ hashFiles('lazy-lock.json') }} - name: Restore plugins run: nvim --headless "+Lazy! restore" +qa - name: Run smoke test @@ -116,11 +132,22 @@ jobs: # only ~2-3 minutes wall clock with plenty of concurrency headroom # (public repo, at most 3 test-matrix jobs running at once), so there's # no runtime pressure pushing this out into its own workflow. + # + # nvim's own --startuptime only instruments Lua/vimscript execution -- + # it can't see process spawn or dynamic-linker/codesign overhead before + # that. Wrapping with `time` for an outside-in wall-clock figure ruled + # that out as the main story (gap vs. nvim's own reported mean was only + # ~5-40ms/run, largest on macOS as expected from Gatekeeper/AMFI, but + # nowhere near what was inflating CI's numbers before the plugin cache + # above). Kept as a standing signal: if a future regression shows up + # here instead of in nvim's own mean, that's process-launch overhead, + # not the config's fault. - name: Benchmark startup time run: | { echo "### Startup time — ${{ matrix.name }}" echo '```' - ./scripts/benchmark-startup 10 + TIMEFORMAT='wall clock for all 10 runs: %R s (user %U s, sys %S s)' + { time ./scripts/benchmark-startup 10; } 2>&1 echo '```' } >> "$GITHUB_STEP_SUMMARY" diff --git a/scripts/benchmark-startup b/scripts/benchmark-startup index 58b1315..1cd66af 100755 --- a/scripts/benchmark-startup +++ b/scripts/benchmark-startup @@ -17,6 +17,8 @@ for ((i = 1; i <= RUNS; i++)); do times+=("$(awk 'NF { last = $1 } END { print last }' "$LOG")") done +echo "per run (chronological, ms): ${times[*]}" + printf '%s\n' "${times[@]}" | sort -n | awk ' { a[NR] = $1; sum += $1 } END {