Skip to content

Commit e681f00

Browse files
codexByron
authored andcommitted
test(perf): track native repository reads and required fallbacks
Extend the existing `pyperf` journey with submodule inventory, tree/index revision paths and modes, and raw commit/tree readback. Fresh public wrappers on the retained `Repo` join the separate benchmark CI job, result-parity checks and per-measurement reporting. Read existing signed objects without rewriting them, and keep opening/discovery separate from the already-open journey. Each new read has a zero-CLI ceiling backed by Gix APIs. The expanded warm journey records CLI/Gix launch counts of 43/1; submodule inventory is 11/0, revision paths 8/0 and object readback 1/0. Opening/discovery retain their real fallback requirements: 9/1 and 11/3. A Python substitute must not be used to lower those ceilings. Update the coverage overview for the expanded workload. This measurement-only commit reduces backend CLI launches by zero. Its purpose is to make genuine conversions and remaining fallbacks visible and enforceable as GixPython gains capabilities. Validation: 13 counter/comparison tests passed with Gix first and CLI second (0.05s each). All 14 untimed result digests match and corrected CLI ceilings pass. Repository-wide Ruff lint/format, `mypy` (47 files), `basedpyright` (zero errors/warnings) and `git diff --check` passed. Fresh full-suite and timed measurements are recorded separately in the following journal commit.
1 parent 95c6d9a commit e681f00

4 files changed

Lines changed: 36 additions & 4 deletions

File tree

‎doc/gix-backend.md‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ counter is 30,899 because the import-time Git probe precedes pytest session
120120
accounting. The same run recorded 21,409 fallback decisions. These totals
121121
include explicit CLI tests and fixture commands, including non-Git commands
122122
passed directly to `Git.execute`; they are a local baseline, not a count of
123-
only fallback calls. The fixed warm benchmark instead isolates a user journey:
124-
23 CLI launches versus one Gix launch, opening nine versus one, and nested
123+
only fallback calls. The expanded warm benchmark instead isolates a user journey:
124+
43 CLI launches versus one Gix launch, opening nine versus one, and nested
125125
discovery eleven versus three after restoring the reference-format fallback
126126
and sharing successful version checks.
127127
The historical full-suite counts above predate this correction. A constant
@@ -198,14 +198,19 @@ environment metadata.
198198
### Existing-repository benchmark
199199

200200
[`test/performance/README.md`](../test/performance/README.md) describes the
201-
`pyperf` harness and fixed GitPython 3.1.45 fixture. It measures eight public-API
201+
`pyperf` harness and fixed GitPython 3.1.45 fixture. It measures eleven public-API
202202
operations and their complete journey on one already-open `git.Repo`, plus
203203
separate direct opening and discovery from `git/objects`. Fresh high-level
204204
wrappers preserve the cost of actual operations; imports, fixture preparation
205205
and parity preflight are outside timing. Native repository refresh remains
206206
inside operation timing, so these measurements include the cost of keeping
207207
retained state current.
208208

209+
Submodule inventory, revision path/mode lookup and raw commit/tree readback
210+
extend the already-open journey, each with a zero-CLI ceiling. The readback
211+
measurement reads existing bytes, including the signed fixture commit, without
212+
rewriting objects. Historical tables below retain their original workloads.
213+
209214
At `244e418da6cc43de129cbe2908d11be4c5ad457a`, using official GixPython
210215
0.1.0 and the same existing CPython 3.12.14/macOS arm64 interpreter for both
211216
installations, with Git 2.54.0 (Apple Git-157), six worker processes with three values each produced the

‎test/performance/README.md‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Backend benchmark
22

33
`bench_repository.py` uses `pyperf` to measure a complete read-only journey and
4-
eight named operations against an existing repository, plus separate direct
4+
eleven named operations against an existing repository, plus separate direct
55
opening and nested-directory discovery measurements. It keeps one `Repo`
66
instance open per worker, but creates fresh commit/tree/index wrappers per
77
invocation so their cached properties cannot turn the measurement into a no-op.
@@ -61,6 +61,12 @@ at least one parent, a root `README.md` and a `git/objects` directory for the
6161
nested discovery measurement. The harness never prepares or
6262
mutates that worktree, and ignores ambient Git environment/config overrides.
6363

64+
The journey also enumerates submodules, resolves tree/index revisions with
65+
their paths and modes, and reads raw commit/tree bytes through the object
66+
database. The last operation covers serialization readback without rewriting
67+
objects; the pinned fixture's signed commit remains intact. These three
68+
measurements have zero-CLI ceilings and join the existing CI job automatically.
69+
6470
Add a function returning JSON-compatible results to `MEASUREMENTS` in
6571
`bench_repository.py`. It automatically becomes a separate benchmark and part
6672
of the journey and parity checks. Include supported and fallback operations;

‎test/performance/bench_repository.py‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,21 @@ def index(repo):
4444
return sorted([path, stage, entry.mode, entry.hexsha] for (path, stage), entry in repo.index.entries.items())
4545

4646

47+
def submodules(repo):
48+
return [[module.name, module.path, module.hexsha, module.url, module.branch_path] for module in repo.submodules]
49+
50+
51+
def revision_paths(repo):
52+
objects = [repo.rev_parse(revision) for revision in ("HEAD:README.md", "HEAD:git", ":README.md")]
53+
return [[obj.hexsha, obj.path, obj.mode] for obj in objects]
54+
55+
56+
def object_readback(repo):
57+
commit = repo.commit("HEAD")
58+
# Read the same bytes used by serialization, without writing objects or stripping signatures.
59+
return [sha256(obj.data_stream.read()).hexdigest() for obj in (commit, commit.tree)]
60+
61+
4762
def graph(repo):
4863
tip, parent = repo.commit("HEAD"), repo.commit("HEAD~1")
4964
return {
@@ -81,6 +96,9 @@ def worktree(repo):
8196
"history_25": history,
8297
"browse_tree_and_blob": browse,
8398
"read_index": index,
99+
"submodule_inventory": submodules,
100+
"revision_paths": revision_paths,
101+
"object_readback": object_readback,
84102
"revision_graph": graph,
85103
"diff_and_stats": changes,
86104
"patch_diff": patch,

‎test/performance/cli-budget.json‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
"history_25": 0,
77
"browse_tree_and_blob": 0,
88
"read_index": 0,
9+
"submodule_inventory": 0,
10+
"revision_paths": 0,
11+
"object_readback": 0,
912
"revision_graph": 0,
1013
"diff_and_stats": 0,
1114
"patch_diff": 1,

0 commit comments

Comments
 (0)