index-pack usage of mmap() is unacceptably slower on many OSes other than Linux

It was reported by Randal L. Schwartz <merlyn@stonehenge.com> that
indexing the Linux repository ~150MB pack takes about an hour on OS x
while it's a minute on Linux.  It seems that the OS X mmap()
implementation is more than 2 orders of magnitude slower than the Linux
one.

Linus proposed a patch replacing mmap() with pread() bringing index-pack
performance on OS X in line with the Linux one.  The performances on
Linux also improved by a small margin.

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
Nicolas Pitre 2006-12-19 10:53:08 -05:00 committed by Junio C Hamano
parent 313ce8cee6
commit 6d2fa7f1b4

View file

@ -1,3 +1,8 @@
#define _XOPEN_SOURCE 600
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>
#include "cache.h" #include "cache.h"
#include "delta.h" #include "delta.h"
#include "pack.h" #include "pack.h"
@ -6,8 +11,6 @@
#include "commit.h" #include "commit.h"
#include "tag.h" #include "tag.h"
#include "tree.h" #include "tree.h"
#include <sys/time.h>
#include <signal.h>
static const char index_pack_usage[] = static const char index_pack_usage[] =
"git-index-pack [-v] [-o <index-file>] [{ ---keep | --keep=<msg> }] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }"; "git-index-pack [-v] [-o <index-file>] [{ ---keep | --keep=<msg> }] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
@ -87,7 +90,7 @@ static unsigned display_progress(unsigned n, unsigned total, unsigned last_pc)
static unsigned char input_buffer[4096]; static unsigned char input_buffer[4096];
static unsigned long input_offset, input_len, consumed_bytes; static unsigned long input_offset, input_len, consumed_bytes;
static SHA_CTX input_ctx; static SHA_CTX input_ctx;
static int input_fd, output_fd, mmap_fd; static int input_fd, output_fd, pack_fd;
/* Discard current buffer used content. */ /* Discard current buffer used content. */
static void flush(void) static void flush(void)
@ -148,14 +151,14 @@ static const char *open_pack_file(const char *pack_name)
output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600); output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600);
if (output_fd < 0) if (output_fd < 0)
die("unable to create %s: %s\n", pack_name, strerror(errno)); die("unable to create %s: %s\n", pack_name, strerror(errno));
mmap_fd = output_fd; pack_fd = output_fd;
} else { } else {
input_fd = open(pack_name, O_RDONLY); input_fd = open(pack_name, O_RDONLY);
if (input_fd < 0) if (input_fd < 0)
die("cannot open packfile '%s': %s", die("cannot open packfile '%s': %s",
pack_name, strerror(errno)); pack_name, strerror(errno));
output_fd = -1; output_fd = -1;
mmap_fd = input_fd; pack_fd = input_fd;
} }
SHA1_Init(&input_ctx); SHA1_Init(&input_ctx);
return pack_name; return pack_name;
@ -279,27 +282,25 @@ static void *get_data_from_pack(struct object_entry *obj)
{ {
unsigned long from = obj[0].offset + obj[0].hdr_size; unsigned long from = obj[0].offset + obj[0].hdr_size;
unsigned long len = obj[1].offset - from; unsigned long len = obj[1].offset - from;
unsigned pg_offset = from % getpagesize(); unsigned char *src, *data;
unsigned char *map, *data;
z_stream stream; z_stream stream;
int st; int st;
map = mmap(NULL, len + pg_offset, PROT_READ, MAP_PRIVATE, src = xmalloc(len);
mmap_fd, from - pg_offset); if (pread(pack_fd, src, len, from) != len)
if (map == MAP_FAILED) die("cannot pread pack file: %s", strerror(errno));
die("cannot mmap pack file: %s", strerror(errno));
data = xmalloc(obj->size); data = xmalloc(obj->size);
memset(&stream, 0, sizeof(stream)); memset(&stream, 0, sizeof(stream));
stream.next_out = data; stream.next_out = data;
stream.avail_out = obj->size; stream.avail_out = obj->size;
stream.next_in = map + pg_offset; stream.next_in = src;
stream.avail_in = len; stream.avail_in = len;
inflateInit(&stream); inflateInit(&stream);
while ((st = inflate(&stream, Z_FINISH)) == Z_OK); while ((st = inflate(&stream, Z_FINISH)) == Z_OK);
inflateEnd(&stream); inflateEnd(&stream);
if (st != Z_STREAM_END || stream.total_out != obj->size) if (st != Z_STREAM_END || stream.total_out != obj->size)
die("serious inflate inconsistency"); die("serious inflate inconsistency");
munmap(map, len + pg_offset); free(src);
return data; return data;
} }