ref-filter: resolve HEAD when parsing %(HEAD) atom

If the user asks to display (or sort by) the %(HEAD) atom, ref-filter has to compare each refname to the value of HEAD. We do so by resolving HEAD fresh when calling populate_value() on each ref. If there are a large number of refs, this can have a measurable impact on runtime. Instead, let's resolve HEAD once when we realize we need the %(HEAD) atom, allowing us to do a simple string comparison for each ref. On a repository with 3000 branches (high, but an actual example found in the wild) this drops the best-of-five time to run "git branch >/dev/null" from 59ms to 48ms (~20% savings). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed May 19, 2017 at 02:12 UTC 613a0e52ea11c4496e3e154de192486a18eac2e4
1 file changed +9 -7
ref-filter.c
+9 -7
@@ -92,6 +92,7 @@ static struct used_atom {
92 unsigned int length;
93 } objectname;
94 struct refname_atom refname;
95 + char *head;
96 } u;
97 } *used_atom;
98 static int used_atom_cnt, need_tagged, need_symref;
@@ -286,6 +287,12 @@ static void if_atom_parser(struct used_atom *atom, const char *arg)
287 }
288 }
289
290 +static void head_atom_parser(struct used_atom *atom, const char *arg)
291 +{
292 + unsigned char unused[GIT_SHA1_RAWSZ];
293 +
294 + atom->u.head = resolve_refdup("HEAD", RESOLVE_REF_READING, unused, NULL);
295 +}
296
297 static struct {
298 const char *name;
@@ -324,7 +331,7 @@ static struct {
331 { "push", FIELD_STR, remote_ref_atom_parser },
332 { "symref", FIELD_STR, refname_atom_parser },
333 { "flag" },
327 - { "HEAD" },
334 + { "HEAD", FIELD_STR, head_atom_parser },
335 { "color", FIELD_STR, color_atom_parser },
336 { "align", FIELD_STR, align_atom_parser },
337 { "end" },
@@ -1366,12 +1373,7 @@ static void populate_value(struct ref_array_item *ref)
1373 } else if (!deref && grab_objectname(name, ref->objectname, v, atom)) {
1374 continue;
1375 } else if (!strcmp(name, "HEAD")) {
1369 - const char *head;
1370 - unsigned char sha1[20];
1371 -
1372 - head = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
1373 - sha1, NULL);
1374 - if (head && !strcmp(ref->refname, head))
1376 + if (atom->u.head && !strcmp(ref->refname, atom->u.head))
1377 v->s = "*";
1378 else
1379 v->s = " ";