load_ref_decorations(): avoid parsing non-tag objects

When we load the ref decorations, we parse the object pointed to by each
ref in order to get a "struct object". This is unnecessarily expensive;
we really only need the object struct, and don't even look at the parsed
contents. The exception is tags, which we do need to peel.

We can improve this by looking up the object type first (which is much
cheaper), and skipping the parse entirely for non-tags. This increases
the work slightly for annotated tags (which now do a type lookup _and_ a
parse), but decreases it a lot for other types. On balance, this seems
to be a good tradeoff.

In my git.git clone, with ~2k refs, most of which are branches, the time
to run "git log -1 --decorate" drops from 34ms to 11ms. Even on my
linux.git clone, which contains mostly tags and only a handful of
branches, the time drops from 30ms to 19ms. And on a more extreme
real-world case with ~220k refs, mostly non-tags, the time drops from
2.6s to 650ms.

That command is a lop-sided example, of course, because it does as
little non-loading work as possible. But it does show the absolute time
improvement. Even in something like a full "git log --decorate" on that
extreme repo, we'd still be saving 2s of CPU time.

Ideally we could push this even further, and avoid parsing even tags, by
relying on the packed-refs "peel" optimization (which we could do by
calling peel_iterated_oid() instead of peeling manually). But we can't
do that here. The packed-refs file only stores the bottom-layer of the
peel (so in a "tag->tag->commit" chain, it stores only the commit as the
peel result).  But the decoration code wants to peel the layers
individually, annotating the middle layers of the chain.

If the packed-refs file ever learns to store all of the peeled layers,
then we could switch to it. Or even if it stored a flag to indicate the
peel was not multi-layer (because most of them aren't), then we could
use it most of the time and fall back to a manual peel for the rare
cases.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jeff King 2021-06-22 13:06:48 -04:00 коммит произвёл Junio C Hamano
Родитель 7463064b28
Коммит 88473c8bae
1 изменённых файлов: 4 добавлений и 2 удалений

Просмотреть файл

@ -134,6 +134,7 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
int flags, void *cb_data) int flags, void *cb_data)
{ {
struct object *obj; struct object *obj;
enum object_type objtype;
enum decoration_type type = DECORATION_NONE; enum decoration_type type = DECORATION_NONE;
struct decoration_filter *filter = (struct decoration_filter *)cb_data; struct decoration_filter *filter = (struct decoration_filter *)cb_data;
@ -155,9 +156,10 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid,
return 0; return 0;
} }
obj = parse_object(the_repository, oid); objtype = oid_object_info(the_repository, oid, NULL);
if (!obj) if (objtype < 0)
return 0; return 0;
obj = lookup_object_by_type(the_repository, oid, objtype);
if (starts_with(refname, "refs/heads/")) if (starts_with(refname, "refs/heads/"))
type = DECORATION_REF_LOCAL; type = DECORATION_REF_LOCAL;