git/list[1] front-page[2] threads[3] people[4] search[5] about
 

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

From
Jeff King <peff@peff.net>
Date
May 19, 2017, 06:12 UTC
Message-ID
<20170519061212.5xrkqydzl32l24ck@sigill.intra.peff.net>
In-Reply-To
<20170517140417.kwzznw4su36k6pxv@sigill.intra.peff.net>

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>
---
The "something like this" patch I sent earlier just cached the value of
HEAD in a global for the length of the program. This is a bit nicer, in
that it ties the cache to the atom we are filling in. But since that's
also stored in a program global, the end effect is the same. :) I think
it's still worth doing it this way, though, as we might one day push the
used_atom stuff into some kind of ref_filter_context struct, and then
this would Just Work.

I did take a look at de-globalifying used_atom and friends, but it gets pretty nasty pushing it all through the callstack. Since there's no immediate benefit, I don't think it's really worth pursuing for now.

 ref-filter.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/ref-filter.c b/ref-filter.c
index 1fc5e9970..82ca411d0 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -93,6 +93,7 @@ static struct used_atom {
 			unsigned int length;
 		} objectname;
 		struct refname_atom refname;
+		char *head;
 	} u;
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
@@ -287,6 +288,12 @@ static void if_atom_parser(struct used_atom *atom, const char *arg)
 	}
 }
 
+static void head_atom_parser(struct used_atom *atom, const char *arg)
+{
+	unsigned char unused[GIT_SHA1_RAWSZ];
+
+	atom->u.head = resolve_refdup("HEAD", RESOLVE_REF_READING, unused, NULL);
+}
 
 static struct {
 	const char *name;
@@ -325,7 +332,7 @@ static struct {
 	{ "push", FIELD_STR, remote_ref_atom_parser },
 	{ "symref", FIELD_STR, refname_atom_parser },
 	{ "flag" },
-	{ "HEAD" },
+	{ "HEAD", FIELD_STR, head_atom_parser },
 	{ "color", FIELD_STR, color_atom_parser },
 	{ "align", FIELD_STR, align_atom_parser },
 	{ "end" },
@@ -1369,12 +1376,7 @@ static void populate_value(struct ref_array_item *ref)
 		} else if (!deref && grab_objectname(name, ref->objectname, v, atom)) {
 			continue;
 		} else if (!strcmp(name, "HEAD")) {
-			const char *head;
-			unsigned char sha1[20];
-
-			head = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
-						  sha1, NULL);
-			if (head && !strcmp(ref->refname, head))
+			if (atom->u.head && !strcmp(ref->refname, atom->u.head))
 				v->s = "*";
 			else
 				v->s = " ";
-- 
2.13.0.219.g63f6bc368
Previous: Jeff King
Message 3 of 3 in “Performance regression in `git branch` due to ref-filter usage”
  1. Michael HaggertyMay 17, 2017
  2. Jeff KingMay 17, 2017
  3. ref-filter: resolve HEAD when parsing %(HEAD) atomJeff King, May 19, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.