From: Patrick Steinhardt <ps@pks.im>
To: git@vger.kernel.org
Subject: [PATCH 9/9] builtin/cat-file: use bitmaps to efficiently filter by object type
Date: Fri, 21 Feb 2025 08:47:34 +0100 [thread overview]
Message-ID: <20250221-pks-cat-file-object-type-filter-v1-9-0852530888e2@pks.im> (raw)
In-Reply-To: <20250221-pks-cat-file-object-type-filter-v1-0-0852530888e2@pks.im>
While it is now possible to filter objects by type, this mechanism is
for now mostly a convenience. Most importantly, we still have to iterate
through the whole packfile to find all objects of a specific type. This
can be prohibitively expensive depending on the size of the packfiles.
It isn't really possible to do better than this when only considering a
packfile itself, as the order of objects is not fixed. But when we have
a packfile with a corresponding bitmap, either because the packfile
itself has one or because the multi-pack index has a bitmap for it, then
we can use these bitmaps to improve the runtime.
While bitmaps are typically used to compute reachability of objects,
they also contain one bitmap per object type encodes which object has
what type. So instead of reading through the whole packfile(s), we can
use the bitmaps and iterate through the type-specific bitmap. Typically,
only a subset of packfiles will have a bitmap. But this isn't really
much of a problem: we can use bitmaps when available, and then use the
non-bitmap walk for every packfile that isn't covered by one.
Overall, this leads to quite a significant speedup depending on how many
objects of a certain type exist. The following benchmarks have been
executed in the Chromium repository, which has a 50GB packfile with
almost 25 million objects:
Benchmark 1: git cat-file --batch-check --batch-all-objects --unordered --buffer --no-objects-filter
Time (mean ± σ): 82.806 s ± 6.363 s [User: 30.956 s, System: 8.264 s]
Range (min … max): 73.936 s … 89.690 s 10 runs
Benchmark 2: git cat-file --batch-check --batch-all-objects --unordered --buffer --objects-filter=object:type=tag
Time (mean ± σ): 20.8 ms ± 1.3 ms [User: 6.1 ms, System: 14.5 ms]
Range (min … max): 18.2 ms … 23.6 ms 127 runs
Benchmark 3: git cat-file --batch-check --batch-all-objects --unordered --buffer --objects-filter=object:type=commit
Time (mean ± σ): 1.551 s ± 0.008 s [User: 1.401 s, System: 0.147 s]
Range (min … max): 1.541 s … 1.566 s 10 runs
Benchmark 4: git cat-file --batch-check --batch-all-objects --unordered --buffer --objects-filter=object:type=tree
Time (mean ± σ): 11.169 s ± 0.046 s [User: 10.076 s, System: 1.063 s]
Range (min … max): 11.114 s … 11.245 s 10 runs
Benchmark 5: git cat-file --batch-check --batch-all-objects --unordered --buffer --objects-filter=object:type=blob
Time (mean ± σ): 67.342 s ± 3.368 s [User: 20.318 s, System: 7.787 s]
Range (min … max): 62.836 s … 73.618 s 10 runs
Benchmark 6: git cat-file --batch-check --batch-all-objects --unordered --buffer --objects-filter=blob:none
Time (mean ± σ): 13.032 s ± 0.072 s [User: 11.638 s, System: 1.368 s]
Range (min … max): 12.960 s … 13.199 s 10 runs
Summary
git cat-file --batch-check --batch-all-objects --unordered --buffer --objects-filter=object:type=tag
74.75 ± 4.61 times faster than git cat-file --batch-check --batch-all-objects --unordered --buffer --objects-filter=object:type=commit
538.17 ± 33.17 times faster than git cat-file --batch-check --batch-all-objects --unordered --buffer --objects-filter=object:type=tree
627.98 ± 38.77 times faster than git cat-file --batch-check --batch-all-objects --unordered --buffer --objects-filter=blob:none
3244.93 ± 257.23 times faster than git cat-file --batch-check --batch-all-objects --unordered --buffer --objects-filter=object:type=blob
3990.07 ± 392.72 times faster than git cat-file --batch-check --batch-all-objects --unordered --buffer --no-objects-filter
The first benchmark is mostly equivalent in runtime compared to all the
others without the bitmap-optimization introduced in this commit. What
is noticeable in the benchmarks is that we're I/O-bound, not CPU-bound,
as can be seen from the user/system runtimes, which is often way lower
than the overall benchmarked runtime.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
builtin/cat-file.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 50 insertions(+), 5 deletions(-)
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 25d5429e391..9021fd52f30 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -21,6 +21,7 @@
#include "streaming.h"
#include "oid-array.h"
#include "packfile.h"
+#include "pack-bitmap.h"
#include "object-file.h"
#include "object-name.h"
#include "object-store-ll.h"
@@ -805,7 +806,20 @@ static int batch_one_object_packed(const struct object_id *oid,
payload->payload);
}
-static void batch_each_object(for_each_object_fn callback,
+static int batch_one_object_bitmapped(const struct object_id *oid,
+ enum object_type type UNUSED,
+ int flags UNUSED,
+ uint32_t hash UNUSED,
+ struct packed_git *pack,
+ off_t offset,
+ void *_payload)
+{
+ struct for_each_object_payload *payload = _payload;
+ return payload->callback(oid, pack, offset, payload->payload);
+}
+
+static void batch_each_object(struct batch_options *opt,
+ for_each_object_fn callback,
unsigned flags,
void *_payload)
{
@@ -813,9 +827,40 @@ static void batch_each_object(for_each_object_fn callback,
.callback = callback,
.payload = _payload,
};
+ struct bitmap_index *bitmap = prepare_bitmap_git(the_repository);
+
for_each_loose_object(batch_one_object_loose, &payload, 0);
- for_each_packed_object(the_repository, batch_one_object_packed,
- &payload, flags);
+
+ if (bitmap &&
+ (opt->objects_filter.choice == LOFC_OBJECT_TYPE ||
+ opt->objects_filter.choice == LOFC_BLOB_NONE)) {
+ struct packed_git *pack;
+
+ if (opt->objects_filter.choice == LOFC_OBJECT_TYPE) {
+ for_each_bitmapped_object(bitmap, opt->objects_filter.object_type,
+ batch_one_object_bitmapped, &payload);
+ } else {
+ for_each_bitmapped_object(bitmap, OBJ_COMMIT,
+ batch_one_object_bitmapped, &payload);
+ for_each_bitmapped_object(bitmap, OBJ_TAG,
+ batch_one_object_bitmapped, &payload);
+ for_each_bitmapped_object(bitmap, OBJ_TREE,
+ batch_one_object_bitmapped, &payload);
+ }
+
+ for (pack = get_all_packs(the_repository); pack; pack = pack->next) {
+ if (bitmap_index_contains_pack(bitmap, pack) ||
+ open_pack_index(pack))
+ continue;
+ for_each_object_in_pack(pack, batch_one_object_packed,
+ &payload, flags);
+ }
+ } else {
+ for_each_packed_object(the_repository, batch_one_object_packed,
+ &payload, flags);
+ }
+
+ free_bitmap_index(bitmap);
}
static int batch_objects(struct batch_options *opt)
@@ -872,14 +917,14 @@ static int batch_objects(struct batch_options *opt)
cb.seen = &seen;
- batch_each_object(batch_unordered_object,
+ batch_each_object(opt, batch_unordered_object,
FOR_EACH_OBJECT_PACK_ORDER, &cb);
oidset_clear(&seen);
} else {
struct oid_array sa = OID_ARRAY_INIT;
- batch_each_object(collect_object, 0, &sa);
+ batch_each_object(opt, collect_object, 0, &sa);
oid_array_for_each_unique(&sa, batch_object_cb, &cb);
oid_array_clear(&sa);
--
2.48.1.683.gf705b3209c.dirty
next prev parent reply other threads:[~2025-02-21 7:47 UTC|newest]
Thread overview: 72+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-21 7:47 [PATCH 0/9] builtin/cat-file: allow filtering objects in batch mode Patrick Steinhardt
2025-02-21 7:47 ` [PATCH 1/9] builtin/cat-file: rename variable that tracks usage Patrick Steinhardt
2025-02-21 7:47 ` [PATCH 2/9] builtin/cat-file: wire up an option to filter objects Patrick Steinhardt
2025-02-26 15:20 ` Toon Claes
2025-02-28 10:51 ` Patrick Steinhardt
2025-02-28 17:44 ` Junio C Hamano
2025-03-03 10:40 ` Patrick Steinhardt
2025-02-27 11:20 ` Karthik Nayak
2025-02-21 7:47 ` [PATCH 3/9] builtin/cat-file: support "blob:none" objects filter Patrick Steinhardt
2025-02-26 15:22 ` Toon Claes
2025-02-27 11:26 ` Karthik Nayak
2025-02-21 7:47 ` [PATCH 4/9] builtin/cat-file: support "blob:limit=" " Patrick Steinhardt
2025-02-21 7:47 ` [PATCH 5/9] builtin/cat-file: support "object:type=" " Patrick Steinhardt
2025-02-26 15:23 ` Toon Claes
2025-02-28 10:51 ` Patrick Steinhardt
2025-02-21 7:47 ` [PATCH 6/9] pack-bitmap: expose function to iterate over bitmapped objects Patrick Steinhardt
2025-02-24 18:05 ` Junio C Hamano
2025-02-25 6:59 ` Patrick Steinhardt
2025-02-25 16:59 ` Junio C Hamano
2025-02-27 23:26 ` Taylor Blau
2025-02-28 10:54 ` Patrick Steinhardt
2025-02-27 23:23 ` Taylor Blau
2025-02-27 23:32 ` Junio C Hamano
2025-02-27 23:39 ` Taylor Blau
2025-02-21 7:47 ` [PATCH 7/9] pack-bitmap: introduce function to check whether a pack is bitmapped Patrick Steinhardt
2025-02-27 23:33 ` Taylor Blau
2025-02-21 7:47 ` [PATCH 8/9] builtin/cat-file: deduplicate logic to iterate over all objects Patrick Steinhardt
2025-02-21 7:47 ` Patrick Steinhardt [this message]
2025-02-27 11:38 ` [PATCH 9/9] builtin/cat-file: use bitmaps to efficiently filter by object type Karthik Nayak
2025-02-27 23:48 ` Taylor Blau
2025-03-27 9:43 ` [PATCH v2 00/10] builtin/cat-file: allow filtering objects in batch mode Patrick Steinhardt
2025-03-27 9:43 ` [PATCH v2 01/10] builtin/cat-file: rename variable that tracks usage Patrick Steinhardt
2025-04-01 9:51 ` Karthik Nayak
2025-04-02 11:13 ` Patrick Steinhardt
2025-04-07 20:25 ` Junio C Hamano
2025-03-27 9:43 ` [PATCH v2 02/10] builtin/cat-file: wire up an option to filter objects Patrick Steinhardt
2025-04-01 11:45 ` Toon Claes
2025-04-02 11:13 ` Patrick Steinhardt
2025-04-01 12:05 ` Karthik Nayak
2025-04-02 11:13 ` Patrick Steinhardt
2025-03-27 9:43 ` [PATCH v2 03/10] builtin/cat-file: support "blob:none" objects filter Patrick Steinhardt
2025-04-01 12:22 ` Karthik Nayak
2025-04-01 12:31 ` Karthik Nayak
2025-04-02 11:13 ` Patrick Steinhardt
2025-03-27 9:43 ` [PATCH v2 04/10] builtin/cat-file: support "blob:limit=" " Patrick Steinhardt
2025-03-27 9:44 ` [PATCH v2 05/10] builtin/cat-file: support "object:type=" " Patrick Steinhardt
2025-03-27 9:44 ` [PATCH v2 06/10] pack-bitmap: allow passing payloads to `show_reachable_fn()` Patrick Steinhardt
2025-04-01 12:17 ` Toon Claes
2025-04-02 11:13 ` Patrick Steinhardt
2025-03-27 9:44 ` [PATCH v2 07/10] pack-bitmap: add function to iterate over filtered bitmapped objects Patrick Steinhardt
2025-03-27 9:44 ` [PATCH v2 08/10] pack-bitmap: introduce function to check whether a pack is bitmapped Patrick Steinhardt
2025-04-01 11:46 ` Toon Claes
2025-04-02 11:13 ` Patrick Steinhardt
2025-03-27 9:44 ` [PATCH v2 09/10] builtin/cat-file: deduplicate logic to iterate over all objects Patrick Steinhardt
2025-04-01 12:13 ` Toon Claes
2025-04-02 11:13 ` Patrick Steinhardt
2025-04-03 18:24 ` Toon Claes
2025-03-27 9:44 ` [PATCH v2 10/10] builtin/cat-file: use bitmaps to efficiently filter by object type Patrick Steinhardt
2025-04-02 11:13 ` [PATCH v3 00/11] builtin/cat-file: allow filtering objects in batch mode Patrick Steinhardt
2025-04-02 11:13 ` [PATCH v3 01/11] builtin/cat-file: rename variable that tracks usage Patrick Steinhardt
2025-04-02 11:13 ` [PATCH v3 02/11] builtin/cat-file: introduce function to report object status Patrick Steinhardt
2025-04-02 11:13 ` [PATCH v3 03/11] builtin/cat-file: wire up an option to filter objects Patrick Steinhardt
2025-04-02 11:13 ` [PATCH v3 04/11] builtin/cat-file: support "blob:none" objects filter Patrick Steinhardt
2025-04-02 11:13 ` [PATCH v3 05/11] builtin/cat-file: support "blob:limit=" " Patrick Steinhardt
2025-04-02 11:13 ` [PATCH v3 06/11] builtin/cat-file: support "object:type=" " Patrick Steinhardt
2025-04-02 11:13 ` [PATCH v3 07/11] pack-bitmap: allow passing payloads to `show_reachable_fn()` Patrick Steinhardt
2025-04-02 11:13 ` [PATCH v3 08/11] pack-bitmap: add function to iterate over filtered bitmapped objects Patrick Steinhardt
2025-04-02 11:13 ` [PATCH v3 09/11] pack-bitmap: introduce function to check whether a pack is bitmapped Patrick Steinhardt
2025-04-02 11:13 ` [PATCH v3 10/11] builtin/cat-file: deduplicate logic to iterate over all objects Patrick Steinhardt
2025-04-02 11:13 ` [PATCH v3 11/11] builtin/cat-file: use bitmaps to efficiently filter by object type Patrick Steinhardt
2025-04-03 8:17 ` [PATCH v3 00/11] builtin/cat-file: allow filtering objects in batch mode Karthik Nayak
2025-04-08 0:32 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250221-pks-cat-file-object-type-filter-v1-9-0852530888e2@pks.im \
--to=ps@pks.im \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).