mirror of
https://github.com/zed-industries/zed.git
synced 2026-08-26 17:42:21 +00:00
Adds a narrow `benchmarks` feature to `multi_buffer`, gating `MultiBuffer::build_simple_for_benchmarks`/`build_random_for_benchmarks` as production-faithful equivalents of `build_simple`/`build_random` that do not require any crate's test-support. `display_map`/`editor_render` now call the new functions instead, and `benchmarks` requests `multi_buffer/benchmarks` instead of `multi_buffer/test-support`. `build_random_for_benchmarks` is a dedicated duplicate of `randomly_edit_excerpts`, substituting a vendored `BenchmarkRandomCharIter` for `util::RandomCharIter` (the only test-support-only dependency it has), guarded against drift by a new parity test asserting byte-identical output against `build_random` for the same rng sequence. Extends script/check-gpui-bench-feature-isolation to prove the direct benchmarks -> multi_buffer/test-support edge is gone and that multi_buffer's benchmarks feature itself resolves no test-support.
209 lines
9.4 KiB
Bash
Executable file
209 lines
9.4 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
# `gpui`'s `bench` feature must stay usable without pulling in `test-support`,
|
|
# so that `#[gpui::bench]` consumers only compile production-capable code
|
|
# rather than transitively depending on test-only APIs. This walks the
|
|
# resolved feature graph for `gpui` built with only `bench` enabled and fails
|
|
# if `test-support` shows up anywhere in it.
|
|
cd "$(dirname "$0")/.."
|
|
|
|
output=$(cargo tree \
|
|
--offline \
|
|
--package gpui \
|
|
--no-default-features \
|
|
--features bench \
|
|
--edges features \
|
|
--invert gpui)
|
|
|
|
if echo "${output}" | grep --quiet 'gpui feature "test-support"'; then
|
|
echo "gpui's \"bench\" feature pulls in \"test-support\":"
|
|
echo "${output}"
|
|
exit 1
|
|
fi
|
|
|
|
# The real `crates/benchmarks` package requests `current_headless_renderer()`
|
|
# through `gpui_platform`, which on macOS delegates to `gpui_macos` and
|
|
# `gpui_apple` for the real Metal-backed headless renderer. Each of those
|
|
# crates gates that renderer behind its own `test-support` feature as well as
|
|
# a narrower `bench` feature, so `benchmarks` must resolve only `bench` on
|
|
# them: otherwise `#[gpui::bench]` consumers in `benchmarks` would compile
|
|
# whichever crate's interactive-only test doubles alongside their production
|
|
# code, same as the `gpui`-level problem this script already guards against.
|
|
# `gpui_macos`/`gpui_apple` only exist in the dependency graph on macOS, since
|
|
# their crate roots are `#![cfg(target_os = "macos")]`, so this half of the
|
|
# check only runs there.
|
|
if [[ "$(uname -s)" == "Darwin" ]]; then
|
|
for platform_crate in gpui_platform gpui_macos gpui_apple; do
|
|
output=$(cargo tree \
|
|
--offline \
|
|
--package benchmarks \
|
|
--edges features \
|
|
--invert "${platform_crate}")
|
|
|
|
if echo "${output}" | grep --quiet "${platform_crate} feature \"test-support\""; then
|
|
echo "benchmarks pulls \"test-support\" into \"${platform_crate}\":"
|
|
echo "${output}"
|
|
exit 1
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# `crates/benchmarks/Cargo.toml` used to also directly request `test-support`
|
|
# from `agent`, `editor`, `language_model`, `lsp`, and `project`, entirely to
|
|
# build the `edit_file_tool` benchmark's `TestAppContext`/`FakeFs`/
|
|
# `FakeLspAdapter`/`FakeLanguageModel`/`Project::test` harness. That benchmark
|
|
# now lives in its own `edit_file_tool_benchmarks` package (see its crate
|
|
# docs), so `benchmarks` no longer needs any test-only surface from those five
|
|
# crates at all. Unlike the `theme`/`util` check below, this checks the whole
|
|
# resolved graph rather than only a direct edge: nothing else `benchmarks`
|
|
# depends on has a legitimate reason to reach `test-support` through any of
|
|
# them either.
|
|
for isolated_crate in agent editor language_model project; do
|
|
# `agent` is no longer in `benchmarks`' resolved graph at all (not merely
|
|
# test-support-free), so `cargo tree --invert` fails to find it; that is
|
|
# the strongest possible form of isolation, so treat it as a pass rather
|
|
# than an error.
|
|
if ! output=$(cargo tree \
|
|
--offline \
|
|
--package benchmarks \
|
|
--edges features \
|
|
--invert "${isolated_crate}" 2>&1); then
|
|
if echo "${output}" | grep --quiet 'did not match any packages'; then
|
|
continue
|
|
fi
|
|
echo "failed to resolve \"${isolated_crate}\" in benchmarks' dependency graph:"
|
|
echo "${output}"
|
|
exit 1
|
|
fi
|
|
|
|
if echo "${output}" | grep --quiet "${isolated_crate} feature \"test-support\""; then
|
|
echo "benchmarks pulls \"test-support\" into \"${isolated_crate}\":"
|
|
echo "${output}"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
# `lsp` and `language` are not part of the loop below: `markdown_renderer`
|
|
# (the only benchmark left that needs either) directly calls test-only APIs
|
|
# with no production equivalent — `LanguageRegistry::test`,
|
|
# `language::rust_lang` — independent of `edit_file_tool`. `language/
|
|
# test-support` enables both `lsp/test-support` and `settings/test-support`
|
|
# directly, so both keep showing up transitively despite `benchmarks` no
|
|
# longer requesting either itself. This is real, tracked debt, not a gap in
|
|
# this script: `theme`, `util`, `settings`, and `multi_buffer` are the crates
|
|
# whose benchmark usage turned out to need no test-only API at all
|
|
# (`theme::LoadThemes`, `theme_settings::init`), one narrow enough to vendor
|
|
# into `benchmarks::bench_utils` instead (`util::RandomCharIter`, a
|
|
# synthetic-text generator with no production analogue), or one narrow
|
|
# enough to move behind its own dedicated feature instead of `test-support`
|
|
# (`settings`'s and `multi_buffer`'s `benchmarks` features, gating
|
|
# `SettingsStore::benchmarks`/`benchmark_settings` and `MultiBuffer::
|
|
# build_simple_for_benchmarks`/`build_random_for_benchmarks` respectively —
|
|
# see `crates/settings/src/settings_file.rs` and
|
|
# `crates/multi_buffer/src/multi_buffer.rs`, which keep their fixtures
|
|
# byte-identical to the `test-support` versions' so switching does not change
|
|
# what a benchmark measures). So `benchmarks` no longer needs a direct
|
|
# `test-support` edge to any of the four. This checks only for a *direct*
|
|
# edge from `benchmarks` to each crate's `test-support` feature, not for the
|
|
# feature's absence from the whole resolved graph, since `language` keeps
|
|
# populating `settings/test-support` (transitively) until it gets the same
|
|
# treatment; `multi_buffer` is checked separately below since nothing else
|
|
# `benchmarks` depends on populates its `test-support` feature at all
|
|
# anymore.
|
|
for foundational_crate in theme util settings; do
|
|
output=$(cargo tree \
|
|
--offline \
|
|
--package benchmarks \
|
|
--edges features \
|
|
--charset ascii \
|
|
--invert "${foundational_crate}")
|
|
|
|
# Cargo tree fully expands a given (package, feature-set) node only the
|
|
# first time it appears, printing every later re-visit as a bare `(*)`
|
|
# back-reference instead of repeating its dependents. So the crate's
|
|
# un-suffixed "test-support" feature line is where its direct dependents
|
|
# are actually listed; checking the couple of lines after it for a
|
|
# "benchmarks" edge is enough to catch a direct request without also
|
|
# matching the expected indirect one from `language`.
|
|
if echo "${output}" \
|
|
| grep -A2 "[|\`]-- ${foundational_crate} feature \"test-support\"\$" \
|
|
| grep --quiet 'benchmarks v'; then
|
|
echo "benchmarks directly requests \"${foundational_crate}\"'s \"test-support\" feature:"
|
|
echo "${output}"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
# The loop above proves `benchmarks` no longer *requests* `settings`'
|
|
# `test-support`; this proves it still gets the deterministic settings it
|
|
# needs some other way, so a future edit can't silently drop the feature
|
|
# request and have `display_map`/`editor_render`/`markdown_renderer` start
|
|
# reading plain default settings (different font/size/theme) without any
|
|
# isolation check catching it.
|
|
output=$(cargo tree \
|
|
--offline \
|
|
--package benchmarks \
|
|
--edges features \
|
|
--invert settings)
|
|
if ! echo "${output}" | grep --quiet 'settings feature "benchmarks"'; then
|
|
echo "benchmarks no longer requests settings' \"benchmarks\" feature:"
|
|
echo "${output}"
|
|
exit 1
|
|
fi
|
|
|
|
# `crates/benchmarks/Cargo.toml` used to directly request `multi_buffer`'s
|
|
# `test-support` feature, entirely to reach `MultiBuffer::build_simple`/
|
|
# `build_random` for `display_map`/`editor_render`'s fixtures. `multi_buffer`
|
|
# now exposes `build_simple_for_benchmarks`/`build_random_for_benchmarks`
|
|
# behind its own narrow `benchmarks` feature instead (see
|
|
# `crates/multi_buffer/Cargo.toml` and `crates/multi_buffer/src/
|
|
# multi_buffer.rs`), so unlike `theme`/`util`/`settings` above, this checks
|
|
# `multi_buffer`'s `test-support` feature is absent from `benchmarks`' whole
|
|
# resolved graph, not just as a direct edge: nothing else `benchmarks`
|
|
# depends on has a legitimate reason to reach it either.
|
|
output=$(cargo tree \
|
|
--offline \
|
|
--package benchmarks \
|
|
--edges features \
|
|
--invert multi_buffer)
|
|
if echo "${output}" | grep --quiet 'multi_buffer feature "test-support"'; then
|
|
echo "benchmarks pulls multi_buffer's \"test-support\" feature:"
|
|
echo "${output}"
|
|
exit 1
|
|
fi
|
|
|
|
# The check above proves `benchmarks` no longer reaches `multi_buffer`'s
|
|
# `test-support` feature; this proves `multi_buffer`'s own `benchmarks`
|
|
# feature (which `build_simple_for_benchmarks`/`build_random_for_benchmarks`
|
|
# live behind) doesn't itself resolve to any dependency's `test-support`,
|
|
# the same guarantee the top of this script proves for `gpui`'s `bench`
|
|
# feature.
|
|
output=$(cargo tree \
|
|
--offline \
|
|
--package multi_buffer \
|
|
--no-default-features \
|
|
--features benchmarks \
|
|
--edges features \
|
|
--invert multi_buffer)
|
|
if echo "${output}" | grep --quiet 'test-support'; then
|
|
echo "multi_buffer's \"benchmarks\" feature pulls in \"test-support\":"
|
|
echo "${output}"
|
|
exit 1
|
|
fi
|
|
|
|
# `edit_file_tool_benchmarks` is the isolated package `edit_file_tool` moved
|
|
# into. It is intentionally *not* held to the isolation bar above, including
|
|
# the `settings` checks just above: it still needs `test-support` from
|
|
# `agent`, `editor`, `language`, `language_model`, `lsp`, `project`, and
|
|
# `settings` (via `SettingsStore::update_user_settings`, which has no
|
|
# production-capable equivalent for mutating already-loaded settings
|
|
# content) for the same harness this script used to document against
|
|
# `benchmarks`. That is tracked debt toward eventually having no benchmark
|
|
# depend on `test-support` at all, not a gap this script hides — confirm the
|
|
# package still exists and builds rather than silently skipping it.
|
|
if ! cargo tree --offline --package edit_file_tool_benchmarks >/dev/null; then
|
|
echo "edit_file_tool_benchmarks package is missing or fails to resolve"
|
|
exit 1
|
|
fi
|