Commit bed3229b by Shawn O. Pearce

Precompute the fanout decoding and the oid offset in a pack-*.idx

The fanout table is fairly commonly accessed, we need to read it
twice for each object we lookup in any given pack file.  Most of
the processors running Git are running in little-endian mode, as
they are variants of the x86 platform, so reading the fanout is
a costly operation as we need to convert from network byte order
to local byte order.  By decoding the fanout table into a malloc
obtained buffer we can save these 2 decode operations per lookup
and make search go more quickly.

This also cleans up the initialization of the search functions
by cutting out a few instructions, saving a small amount of time.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
parent a7c60cfc
...@@ -46,6 +46,8 @@ struct git_pack { ...@@ -46,6 +46,8 @@ struct git_pack {
/** The .idx file, mapped into memory. */ /** The .idx file, mapped into memory. */
git_file idx_fd; git_file idx_fd;
gitfo_map idx_map; gitfo_map idx_map;
uint32_t *im_fanout;
unsigned char *im_oid;
uint32_t *im_crc; uint32_t *im_crc;
uint32_t *im_offset32; uint32_t *im_offset32;
uint32_t *im_offset64; uint32_t *im_offset64;
...@@ -520,11 +522,10 @@ static int pack_openidx_map(git_pack *p) ...@@ -520,11 +522,10 @@ static int pack_openidx_map(git_pack *p)
static int idxv1_search(off_t *out, git_pack *p, const git_oid *id) static int idxv1_search(off_t *out, git_pack *p, const git_oid *id)
{ {
unsigned char *data = p->idx_map.data; unsigned char *data = p->im_oid;
size_t lo = id->id[0] ? decode32(data + ((id->id[0]-1) << 2)) : 0; size_t lo = id->id[0] ? p->im_fanout[id->id[0] - 1] : 0;
size_t hi = decode32(data + (id->id[0] << 2)); size_t hi = p->im_fanout[id->id[0]];
data += 1024;
do { do {
size_t mid = (lo + hi) >> 1; size_t mid = (lo + hi) >> 1;
size_t pos = 24 * mid; size_t pos = 24 * mid;
...@@ -542,30 +543,42 @@ static int idxv1_search(off_t *out, git_pack *p, const git_oid *id) ...@@ -542,30 +543,42 @@ static int idxv1_search(off_t *out, git_pack *p, const git_oid *id)
static int pack_openidx_v1(git_pack *p) static int pack_openidx_v1(git_pack *p)
{ {
uint32_t *fanout = p->idx_map.data; uint32_t *src_fanout = p->idx_map.data;
uint32_t *im_fanout;
size_t expsz; size_t expsz;
int j; int j;
if (!(im_fanout = git__malloc(sizeof(*im_fanout) * 256)))
return GIT_ERROR;
im_fanout[0] = decode32(&src_fanout[0]);
for (j = 1; j < 256; j++) { for (j = 1; j < 256; j++) {
if (decode32(&fanout[j]) < decode32(&fanout[j - 1])) im_fanout[j] = decode32(&src_fanout[j]);
if (im_fanout[j] < im_fanout[j - 1]) {
free(im_fanout);
return GIT_ERROR; return GIT_ERROR;
} }
p->obj_cnt = decode32(&fanout[255]); }
p->obj_cnt = im_fanout[255];
expsz = 4 * 256 + 24 * p->obj_cnt + 2 * 20; expsz = 4 * 256 + 24 * p->obj_cnt + 2 * 20;
if (expsz != p->idx_map.len) if (expsz != p->idx_map.len) {
free(im_fanout);
return GIT_ERROR; return GIT_ERROR;
}
p->idx_search = idxv1_search; p->idx_search = idxv1_search;
p->im_fanout = im_fanout;
p->im_oid = (unsigned char*)(src_fanout + 256);
return GIT_SUCCESS; return GIT_SUCCESS;
} }
static int idxv2_search(off_t *out, git_pack *p, const git_oid *id) static int idxv2_search(off_t *out, git_pack *p, const git_oid *id)
{ {
unsigned char *data = ((unsigned char*)p->idx_map.data) + 8; unsigned char *data = p->im_oid;
size_t lo = id->id[0] ? decode32(data + ((id->id[0]-1) << 2)) : 0; size_t lo = id->id[0] ? p->im_fanout[id->id[0] - 1] : 0;
size_t hi = decode32(data + (id->id[0] << 2)); size_t hi = p->im_fanout[id->id[0]];
data += 1024;
do { do {
size_t mid = (lo + hi) >> 1; size_t mid = (lo + hi) >> 1;
size_t pos = 20 * mid; size_t pos = 20 * mid;
...@@ -587,17 +600,28 @@ static int idxv2_search(off_t *out, git_pack *p, const git_oid *id) ...@@ -587,17 +600,28 @@ static int idxv2_search(off_t *out, git_pack *p, const git_oid *id)
static int pack_openidx_v2(git_pack *p) static int pack_openidx_v2(git_pack *p)
{ {
void *data = ((unsigned char*)p->idx_map.data) + 8; unsigned char *data = p->idx_map.data;
uint32_t *fanout = data; uint32_t *src_fanout = (uint32_t*)(data + 8);
uint32_t *im_fanout;
int j; int j;
if (!(im_fanout = git__malloc(sizeof(*im_fanout) * 256)))
return GIT_ERROR;
im_fanout[0] = decode32(&src_fanout[0]);
for (j = 1; j < 256; j++) { for (j = 1; j < 256; j++) {
if (decode32(&fanout[j]) < decode32(&fanout[j - 1])) im_fanout[j] = decode32(&src_fanout[j]);
if (im_fanout[j] < im_fanout[j - 1]) {
free(im_fanout);
return GIT_ERROR; return GIT_ERROR;
} }
p->obj_cnt = decode32(&fanout[255]); }
p->obj_cnt = im_fanout[255];
p->idx_search = idxv2_search; p->idx_search = idxv2_search;
p->im_crc = (uint32_t*)(data + 1024 + (20 * p->obj_cnt)); p->im_fanout = im_fanout;
p->im_oid = (unsigned char*)(src_fanout + 256);
p->im_crc = (uint32_t*)(p->im_oid + 20 * p->obj_cnt);
p->im_offset32 = p->im_crc + p->obj_cnt; p->im_offset32 = p->im_crc + p->obj_cnt;
p->im_offset64 = p->im_offset32 + p->obj_cnt; p->im_offset64 = p->im_offset32 + p->obj_cnt;
return GIT_SUCCESS; return GIT_SUCCESS;
...@@ -661,6 +685,7 @@ static void pack_dec(git_pack *p) ...@@ -661,6 +685,7 @@ static void pack_dec(git_pack *p)
if (p->idx_search) { if (p->idx_search) {
gitfo_free_map(&p->idx_map); gitfo_free_map(&p->idx_map);
gitfo_close(p->idx_fd); gitfo_close(p->idx_fd);
free(p->im_fanout);
} }
gitlck_free(&p->lock); gitlck_free(&p->lock);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment