From: git@jeffhostetler.com
To: git@vger.kernel.org
Cc: gitster@pobox.com, peff@peff.net,
Jeff Hostetler <jeffhost@microsoft.com>
Subject: [PATCH v9 3/3] read-cache: speed up add_index_entry during checkout
Date: Tue, 11 Apr 2017 19:17:02 +0000 [thread overview]
Message-ID: <20170411191702.20134-4-git@jeffhostetler.com> (raw)
In-Reply-To: <20170411191702.20134-1-git@jeffhostetler.com>
From: Jeff Hostetler <jeffhost@microsoft.com>
Teach add_index_entry_with_check() and has_dir_name()
to see if the path of the new item is greater than the
last path in the index array before attempting to search
for it.
During checkout, merge_working_tree() populates the new
index in sorted order, so this change will save at least 2
binary lookups per file. This preserves the original
behavior but simply checks the last element before starting
the search.
This helps performance on very large repositories.
This can be seen using p0006-read-tree-checkout.sh and the
artificial repository created by t/perf/repos/many-files.sh
with parameters (5, 10, 9). (1M files in index.)
Test HEAD^ HEAD
----------------------------------------------------------------------------------------------------------
0006.2: read-tree br_base br_ballast (1000001) 4.15(2.72+1.41) 3.21(1.97+1.22) -22.7%
0006.3: switch between br_base br_ballast (1000001) 8.11(5.57+2.28) 6.77(4.36+2.14) -16.5%
0006.4: switch between br_ballast br_ballast_plus_1 (1000001) 13.52(8.68+4.35) 11.80(7.38+3.96) -12.7%
0006.5: switch between aliases (1000001) 13.59(8.75+4.43) 11.85(7.49+3.87) -12.8%
On linux.git, results are:
Test HEAD^ HEAD
------------------------------------------------------------------------------------------------------
0006.2: read-tree br_base br_ballast (57994) 0.24(0.22+0.01) 0.20(0.17+0.02) -16.7%
0006.3: switch between br_base br_ballast (57994) 9.91(5.82+2.79) 10.26(5.92+2.77) +3.5%
0006.4: switch between br_ballast br_ballast_plus_1 (57994) 0.59(0.44+0.16) 0.50(0.34+0.18) -15.3%
0006.5: switch between aliases (57994) 0.62(0.48+0.16) 0.50(0.35+0.16) -19.4%
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
---
read-cache.c | 46 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 44 insertions(+), 2 deletions(-)
diff --git a/read-cache.c b/read-cache.c
index 97f13a1..a8ef823 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -918,9 +918,24 @@ static int has_dir_name(struct index_state *istate,
int stage = ce_stage(ce);
const char *name = ce->name;
const char *slash = name + ce_namelen(ce);
+ size_t len_eq_last;
+ int cmp_last = 0;
+
+ if (istate->cache_nr > 0) {
+ /*
+ * Compare the entry's full path with the last path in the index.
+ * If it sorts AFTER the last entry in the index and they have no
+ * common prefix, then there cannot be any F/D name conflicts.
+ */
+ cmp_last = strcmp_offset(name,
+ istate->cache[istate->cache_nr-1]->name,
+ &len_eq_last);
+ if (cmp_last > 0 && len_eq_last == 0)
+ return retval;
+ }
for (;;) {
- int len;
+ size_t len;
for (;;) {
if (*--slash == '/')
@@ -930,6 +945,24 @@ static int has_dir_name(struct index_state *istate,
}
len = slash - name;
+ if (cmp_last > 0) {
+ /*
+ * If this part of the directory prefix (including the trailing
+ * slash) already appears in the path of the last entry in the
+ * index, then we cannot also have a file with this prefix (or
+ * any parent directory prefix).
+ */
+ if (len+1 <= len_eq_last)
+ return retval;
+ /*
+ * If this part of the directory prefix (excluding the trailing
+ * slash) is longer than the known equal portions, then this part
+ * of the prefix cannot collide with a file. Go on to the parent.
+ */
+ if (len > len_eq_last)
+ continue;
+ }
+
pos = index_name_stage_pos(istate, name, len, stage);
if (pos >= 0) {
/*
@@ -1021,7 +1054,16 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
if (!(option & ADD_CACHE_KEEP_CACHE_TREE))
cache_tree_invalidate_path(istate, ce->name);
- pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce));
+
+ /*
+ * If this entry's path sorts after the last entry in the index,
+ * we can avoid searching for it.
+ */
+ if (istate->cache_nr > 0 &&
+ strcmp(ce->name, istate->cache[istate->cache_nr - 1]->name) > 0)
+ pos = -istate->cache_nr - 1;
+ else
+ pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce));
/* existing match? Just replace it. */
if (pos >= 0) {
--
2.9.3
next prev parent reply other threads:[~2017-04-11 19:17 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-04-11 19:16 [PATCH v9 0/3] read-cache: speed up add_index_entry git
2017-04-11 19:17 ` [PATCH v9 1/3] read-cache: add strcmp_offset function git
2017-04-11 19:17 ` [PATCH v9 2/3] p0006-read-tree-checkout: perf test to time read-tree git
2017-04-11 19:17 ` git [this message]
2017-04-12 3:12 ` [PATCH v9 3/3] read-cache: speed up add_index_entry during checkout Junio C Hamano
2017-04-14 13:06 ` Jeff Hostetler
2017-04-11 19:26 ` [PATCH v9 0/3] read-cache: speed up add_index_entry Jeff King
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=20170411191702.20134-4-git@jeffhostetler.com \
--to=git@jeffhostetler.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=jeffhost@microsoft.com \
--cc=peff@peff.net \
/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).