diff options
author | Carlos Martín Nieto <cmn@dwim.me> | 2014-05-08 22:31:59 +0200 |
---|---|---|
committer | Carlos Martín Nieto <cmn@dwim.me> | 2014-05-08 22:40:13 +0200 |
commit | 2dde1e0c1c398708d6a84763015e690f23cc7511 (patch) | |
tree | 46a0560de9c30a121597f208f6b5a9e4c7a4f3f7 | |
parent | ed476c236b8328c31acb150ee69eaf00c821b9e3 (diff) | |
download | libgit2-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.c | 23 |
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; |