t/perf: add pack-objects filter and path-walk benchmark

Add p5315-pack-objects-filter.sh to measure the performance of 'git pack-objects --revs --all' under different filter and traversal combinations: * no filter (baseline) * --filter=blob:none (blobless) * --filter=sparse:oid=<oid> (cone-mode sparse) Each filter scenario is tested both with and without --path-walk, producing paired measurements that show the impact of the path-walk traversal for each filter type as we integrate the --path-walk feature with different --filter options. It currently has no integration so falls back to the standard revision walk. Thus, there are no significant differences in the current results other than a full repack (and even then, the --path-walk feature is not incredibly different for the default Git repository): Test HEAD ----------------------------------------------------- 5315.2: repack (no filter) 27.91 5315.3: repack size (no filter) 250.7M 5315.4: repack (no filter, --path-walk) 34.92 5315.5: repack size (no filter, --path-walk) 220.0M 5315.6: repack (blob:none) 13.63 5315.7: repack size (blob:none) 137.6M 5315.8: repack (blob:none, --path-walk) 13.48 5315.9: repack size (blob:none, --path-walk) 137.7M 5315.10: repack (sparse:oid) 72.67 5315.11: repack size (sparse:oid) 187.4M 5315.12: repack (sparse:oid, --path-walk) 72.47 5315.13: repack size (sparse:oid, --path-walk) 187.4M The sparse filter definition is built automatically by sampling depth-2 directories from the test repository, making the test work on any repo passed via GIT_PERF_LARGE_REPO. For repos that lack depth-2 directories, a single top-level directory is used; for flat repos, the sparse tests are skipped via prerequisite. Signed-off-by: Derrick Stolee <stolee@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed May 22, 2026 at 18:24 UTC 5406b62b21e4c24cd2b0ca698b5fb95b4a5816ca
1 file changed +129
t/perf/p5315-pack-objects-filter.sh new
+129
@@ -0,0 +1,129 @@
1 +#!/bin/sh
2 +
3 +test_description='Tests pack-objects performance with filters and --path-walk'
4 +. ./perf-lib.sh
5 +
6 +test_perf_large_repo
7 +
8 +test_expect_success 'setup filter inputs' '
9 + # Sample a few depth-2 directories from the test repo to build
10 + # a cone-mode sparse-checkout definition. The sampling picks
11 + # directories at evenly-spaced positions so the choice is stable
12 + # and scales to repos of any shape.
13 +
14 + git ls-tree -d HEAD >top-entries &&
15 + grep "^040000" top-entries |
16 + awk "{print \$4;}" >top-dirs &&
17 + top_nr=$(wc -l <top-dirs) &&
18 +
19 + while read tdir
20 + do
21 + git ls-tree -d --format="$tdir/%(path)" "HEAD:$tdir" || return 1
22 + done <top-dirs >depth2-dirs &&
23 +
24 + d2_nr=$(wc -l <depth2-dirs) &&
25 +
26 + if test "$d2_nr" -ge 2
27 + then
28 + # Pick two directories from evenly-spaced positions.
29 + first=$(sed -n "1p" depth2-dirs) &&
30 + mid=$(sed -n "$((d2_nr / 2 + 1))p" depth2-dirs) &&
31 +
32 + p1=$(dirname "$first") &&
33 + p2=$(dirname "$mid") &&
34 +
35 + # Build cone-mode sparse-checkout patterns.
36 + {
37 + echo "/*" &&
38 + echo "!/*/" &&
39 + echo "/$p1/" &&
40 + echo "!/$p1/*/" &&
41 + if test "$p1" != "$p2"
42 + then
43 + echo "/$p2/" &&
44 + echo "!/$p2/*/"
45 + fi &&
46 + echo "/$first/" &&
47 + if test "$first" != "$mid"
48 + then
49 + echo "/$mid/"
50 + fi
51 + } >sparse-patterns &&
52 +
53 + git hash-object -w sparse-patterns >sparse-oid &&
54 + echo "Sparse cone: $first $mid" &&
55 + cat sparse-patterns &&
56 + test_set_prereq SPARSE_OID
57 + elif test "$top_nr" -ge 1
58 + then
59 + # Fallback: use a single top-level directory.
60 + first=$(sed -n "1p" top-dirs) &&
61 + {
62 + echo "/*" &&
63 + echo "!/*/" &&
64 + echo "/$first/"
65 + } >sparse-patterns &&
66 +
67 + git hash-object -w sparse-patterns >sparse-oid &&
68 + echo "Sparse cone: $first" &&
69 + cat sparse-patterns &&
70 + test_set_prereq SPARSE_OID
71 + fi
72 +'
73 +
74 +test_perf 'repack (no filter)' '
75 + git pack-objects --stdout --no-reuse-delta --revs --all </dev/null >pk
76 +'
77 +
78 +test_size 'repack size (no filter)' '
79 + test_file_size pk
80 +'
81 +
82 +test_perf 'repack (no filter, --path-walk)' '
83 + git pack-objects --stdout --no-reuse-delta --revs --all --path-walk </dev/null >pk
84 +'
85 +
86 +test_size 'repack size (no filter, --path-walk)' '
87 + test_file_size pk
88 +'
89 +
90 +test_perf 'repack (blob:none)' '
91 + git pack-objects --stdout --no-reuse-delta --revs --all --filter=blob:none </dev/null >pk
92 +'
93 +
94 +test_size 'repack size (blob:none)' '
95 + test_file_size pk
96 +'
97 +
98 +test_perf 'repack (blob:none, --path-walk)' '
99 + git pack-objects --stdout --no-reuse-delta --revs --all --path-walk \
100 + --filter=blob:none </dev/null >pk
101 +'
102 +
103 +test_size 'repack size (blob:none, --path-walk)' '
104 + test_file_size pk
105 +'
106 +
107 +test_perf 'repack (sparse:oid)' \
108 + --prereq SPARSE_OID '
109 + git pack-objects --stdout --no-reuse-delta --revs --all \
110 + --filter=sparse:oid=$(cat sparse-oid) </dev/null >pk
111 +'
112 +
113 +test_size 'repack size (sparse:oid)' \
114 + --prereq SPARSE_OID '
115 + test_file_size pk
116 +'
117 +
118 +test_perf 'repack (sparse:oid, --path-walk)' \
119 + --prereq SPARSE_OID '
120 + git pack-objects --stdout --no-reuse-delta --revs --all --path-walk \
121 + --filter=sparse:oid=$(cat sparse-oid) </dev/null >pk
122 +'
123 +
124 +test_size 'repack size (sparse:oid, --path-walk)' \
125 + --prereq SPARSE_OID '
126 + test_file_size pk
127 +'
128 +
129 +test_done