summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2014-05-08 22:31:59 +0200
committerCarlos Martín Nieto <cmn@dwim.me>2014-05-08 22:40:13 +0200
commit2dde1e0c1c398708d6a84763015e690f23cc7511 (patch)
tree46a0560de9c30a121597f208f6b5a9e4c7a4f3f7
parented476c236b8328c31acb150ee69eaf00c821b9e3 (diff)
downloadlibgit2-cmn/indexer-vector-handling.tar.gz
indexer: avoid memory movescmn/indexer-vector-handling
Our vector does a move of the rest of the array when we remove an item. Doing this repeatedly can be expensive, and we do this a lot in the indexer. Instead, set the value to NULL and skip those entries. perf reported around 30% of `index-pack` time was going into memmove. With this change, that goes away and we spent most of the time hashing and inflating data.
-rw-r--r--src/indexer.c23
1 files changed, 15 insertions, 8 deletions
diff --git a/src/indexer.c b/src/indexer.c
index adf5ceaa7..3c8415c7c 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -717,6 +717,9 @@ static int fix_thin_pack(git_indexer *idx, git_transfer_progress *stats)
/* Loop until we find the first REF delta */
git_vector_foreach(&idx->deltas, i, delta) {
+ if (!delta)
+ continue;
+
curpos = delta->delta_off;
error = git_packfile_unpack_header(&size, &type, &idx->pack->mwf, &w, &curpos);
git_mwindow_close(&w);
@@ -756,13 +759,18 @@ static int resolve_deltas(git_indexer *idx, git_transfer_progress *stats)
{
unsigned int i;
struct delta_info *delta;
- int progressed = 0, progress_cb_result;
+ int progressed = 0, non_null = 0, progress_cb_result;
while (idx->deltas.length > 0) {
progressed = 0;
+ non_null = 0;
git_vector_foreach(&idx->deltas, i, delta) {
git_rawobj obj;
+ if (!delta)
+ continue;
+
+ non_null = 1;
idx->off = delta->delta_off;
if (git_packfile_unpack(&obj, idx->pack, &idx->off) < 0)
continue;
@@ -777,16 +785,15 @@ static int resolve_deltas(git_indexer *idx, git_transfer_progress *stats)
if ((progress_cb_result = do_progress_callback(idx, stats)) < 0)
return progress_cb_result;
- /*
- * Remove this delta from the list and
- * decrease i so we don't skip over the next
- * delta.
- */
- git_vector_remove(&idx->deltas, i);
+ /* remove from the list */
+ git_vector_set(NULL, &idx->deltas, i, NULL);
git__free(delta);
- i--;
}
+ /* if none were actually set, we're done */
+ if (!non_null)
+ break;
+
if (!progressed && (fix_thin_pack(idx, stats) < 0)) {
giterr_set(GITERR_INDEXER, "missing delta bases");
return -1;