On Sat, Dec 29, 2012 at 04:05:58AM -0500, Jeff King wrote:

> On Sat, Dec 29, 2012 at 12:27:47AM -0500, Jeff King wrote:
> 
> > > I think I tried the partial decompression for commit header and it did
> > > not help much (or I misremember it, not so sure).
> > 
> > I'll see if I can dig up the reference, as it was something I was going
> > to look at next.
> 
> I tried the simple patch below, but it actually made things slower!  I'm
> assuming it is because the streaming setup is not micro-optimized very
> well. A custom read_sha1_until_blank_line() could probably do better.

Something like the patch below, which does speed things up. But not
nearly as much as I'd hoped:

  [before]
  $ best-of-five git rev-list --count --all
  real    0m4.197s
  user    0m4.112s
  sys     0m0.072s

  [after]
  $ best-of-five git rev-list --count --all
  real    0m3.782s
  user    0m3.708s
  sys     0m0.064s

Only about a 10% speedup (versus ~75% with uncompressed commits).

---
diff --git a/cache.h b/cache.h
index 18fdd18..a494d3b 100644
--- a/cache.h
+++ b/cache.h
@@ -724,6 +724,7 @@ int offset_1st_component(const char *path);
 
 /* object replacement */
 #define READ_SHA1_FILE_REPLACE 1
+#define READ_SHA1_FILE_HEADER 2
 extern void *read_sha1_file_extended(const unsigned char *sha1, enum 
object_type *type, unsigned long *size, unsigned flag);
 static inline void *read_sha1_file(const unsigned char *sha1, enum object_type 
*type, unsigned long *size)
 {
@@ -1059,7 +1060,7 @@ extern int is_pack_valid(struct packed_git *);
 extern off_t nth_packed_object_offset(const struct packed_git *, uint32_t);
 extern off_t find_pack_entry_one(const unsigned char *, struct packed_git *);
 extern int is_pack_valid(struct packed_git *);
-extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, 
unsigned long *);
+extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, 
unsigned long *, int);
 extern unsigned long unpack_object_header_buffer(const unsigned char *buf, 
unsigned long len, enum object_type *type, unsigned long *sizep);
 extern unsigned long get_size_from_delta(struct packed_git *, struct 
pack_window **, off_t);
 extern int unpack_object_header(struct packed_git *, struct pack_window **, 
off_t *, unsigned long *);
diff --git a/commit.c b/commit.c
index e8eb0ae..0a088dc 100644
--- a/commit.c
+++ b/commit.c
@@ -312,12 +312,13 @@ int parse_commit(struct commit *item)
        void *buffer;
        unsigned long size;
        int ret;
+       int flags = save_commit_buffer ? 0 : READ_SHA1_FILE_HEADER;
 
        if (!item)
                return -1;
        if (item->object.parsed)
                return 0;
-       buffer = read_sha1_file(item->object.sha1, &type, &size);
+       buffer = read_sha1_file_extended(item->object.sha1, &type, &size, 
flags);
        if (!buffer)
                return error("Could not read %s",
                             sha1_to_hex(item->object.sha1));
diff --git a/fast-import.c b/fast-import.c
index c2a814e..a140d57 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -1303,7 +1303,7 @@ static void *gfi_unpack_entry(
                 */
                p->pack_size = pack_size + 20;
        }
-       return unpack_entry(p, oe->idx.offset, &type, sizep);
+       return unpack_entry(p, oe->idx.offset, &type, sizep, 0);
 }
 
 static const char *get_mode(const char *str, uint16_t *modep)
diff --git a/pack-check.c b/pack-check.c
index 63a595c..e4a43c0 100644
--- a/pack-check.c
+++ b/pack-check.c
@@ -116,7 +116,7 @@ static int verify_packfile(struct packed_git *p,
                                            sha1_to_hex(entries[i].sha1),
                                            p->pack_name, (uintmax_t)offset);
                }
-               data = unpack_entry(p, entries[i].offset, &type, &size);
+               data = unpack_entry(p, entries[i].offset, &type, &size, 0);
                if (!data)
                        err = error("cannot unpack %s from %s at offset 
%"PRIuMAX"",
                                    sha1_to_hex(entries[i].sha1), p->pack_name,
diff --git a/sha1_file.c b/sha1_file.c
index 40b2329..1f1f31a 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1469,16 +1469,19 @@ static void *unpack_sha1_file(void *map, unsigned long 
mapsize, enum object_type
        return *hdr ? -1 : type_from_string(type);
 }
 
-static void *unpack_sha1_file(void *map, unsigned long mapsize, enum 
object_type *type, unsigned long *size, const unsigned char *sha1)
+static void *unpack_sha1_file(void *map, unsigned long mapsize, enum 
object_type *type, unsigned long *size, const unsigned char *sha1, int 
stop_at_blank)
 {
        int ret;
        git_zstream stream;
-       char hdr[8192];
+       char hdr[512];
 
        ret = unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr));
        if (ret < Z_OK || (*type = parse_sha1_header(hdr, size)) < 0)
                return NULL;
-
+       if (stop_at_blank && strstr(hdr, "\n\n")) {
+               *size = strlen(hdr);
+               return xstrdup(hdr);
+       }
        return unpack_sha1_rest(&stream, hdr, *size, sha1);
 }
 
@@ -1667,8 +1670,11 @@ static void *unpack_compressed_entry(struct packed_git 
*p,
 static void *unpack_compressed_entry(struct packed_git *p,
                                    struct pack_window **w_curs,
                                    off_t curpos,
-                                   unsigned long size)
+                                   unsigned long *sizep,
+                                   int stop_at_blank)
 {
+       static const int chunk_size = 256;
+       unsigned long size = *sizep;
        int st;
        git_zstream stream;
        unsigned char *buffer, *in;
@@ -1676,15 +1682,27 @@ static void *unpack_compressed_entry(struct packed_git 
*p,
        buffer = xmallocz(size);
        memset(&stream, 0, sizeof(stream));
        stream.next_out = buffer;
-       stream.avail_out = size + 1;
+
+       if (stop_at_blank)
+               stream.avail_out = chunk_size;
+       else
+               stream.avail_out = size + 1;
 
        git_inflate_init(&stream);
        do {
                in = use_pack(p, w_curs, curpos, &stream.avail_in);
                stream.next_in = in;
                st = git_inflate(&stream, Z_FINISH);
-               if (!stream.avail_out)
-                       break; /* the payload is larger than it should be */
+               if (!stream.avail_out) {
+                       if (!stop_at_blank)
+                               break; /* the payload is larger than it should 
be */
+                       if (memmem(buffer, chunk_size, "\n\n", 2)) {
+                               git_inflate_end(&stream);
+                               *sizep = chunk_size;
+                               return buffer;
+                       }
+                       stream.avail_out = size + 1 - chunk_size;
+               }
                curpos += stream.next_in - in;
        } while (st == Z_OK || st == Z_BUF_ERROR);
        git_inflate_end(&stream);
@@ -1731,7 +1749,8 @@ static void *cache_or_unpack_entry(struct packed_git *p, 
off_t base_offset,
 }
 
 static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset,
-       unsigned long *base_size, enum object_type *type, int keep_cache)
+       unsigned long *base_size, enum object_type *type, int keep_cache,
+       int stop_at_blank)
 {
        void *ret;
        unsigned long hash = pack_entry_hash(p, base_offset);
@@ -1739,9 +1758,9 @@ static void *cache_or_unpack_entry(struct packed_git *p, 
off_t base_offset,
 
        ret = ent->data;
        if (!ret || ent->p != p || ent->base_offset != base_offset)
-               return unpack_entry(p, base_offset, type, base_size);
+               return unpack_entry(p, base_offset, type, base_size, 
stop_at_blank);
 
-       if (!keep_cache) {
+       if (!stop_at_blank && !keep_cache) {
                ent->data = NULL;
                ent->lru.next->prev = ent->lru.prev;
                ent->lru.prev->next = ent->lru.next;
@@ -1810,7 +1829,7 @@ static void *read_object(const unsigned char *sha1, enum 
object_type *type,
 }
 
 static void *read_object(const unsigned char *sha1, enum object_type *type,
-                        unsigned long *size);
+                        unsigned long *size, int stop_at_blank);
 
 static void *unpack_delta_entry(struct packed_git *p,
                                struct pack_window **w_curs,
@@ -1832,7 +1851,7 @@ static void *unpack_delta_entry(struct packed_git *p,
                return NULL;
        }
        unuse_pack(w_curs);
-       base = cache_or_unpack_entry(p, base_offset, &base_size, type, 0);
+       base = cache_or_unpack_entry(p, base_offset, &base_size, type, 0, 0);
        if (!base) {
                /*
                 * We're probably in deep shit, but let's try to fetch
@@ -1851,12 +1870,12 @@ static void *unpack_delta_entry(struct packed_git *p,
                      sha1_to_hex(base_sha1), (uintmax_t)base_offset,
                      p->pack_name);
                mark_bad_packed_object(p, base_sha1);
-               base = read_object(base_sha1, type, &base_size);
+               base = read_object(base_sha1, type, &base_size, 0);
                if (!base)
                        return NULL;
        }
 
-       delta_data = unpack_compressed_entry(p, w_curs, curpos, delta_size);
+       delta_data = unpack_compressed_entry(p, w_curs, curpos, &delta_size, 0);
        if (!delta_data) {
                error("failed to unpack compressed delta "
                      "at offset %"PRIuMAX" from %s",
@@ -1895,7 +1914,8 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
 int do_check_packed_object_crc;
 
 void *unpack_entry(struct packed_git *p, off_t obj_offset,
-                  enum object_type *type, unsigned long *sizep)
+                  enum object_type *type, unsigned long *sizep,
+                  int stop_at_blank)
 {
        struct pack_window *w_curs = NULL;
        off_t curpos = obj_offset;
@@ -1929,7 +1949,8 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
        case OBJ_TREE:
        case OBJ_BLOB:
        case OBJ_TAG:
-               data = unpack_compressed_entry(p, &w_curs, curpos, *sizep);
+               data = unpack_compressed_entry(p, &w_curs, curpos, sizep,
+                                              stop_at_blank);
                break;
        default:
                data = NULL;
@@ -2208,14 +2229,15 @@ static void *read_packed_sha1(const unsigned char *sha1,
 }
 
 static void *read_packed_sha1(const unsigned char *sha1,
-                             enum object_type *type, unsigned long *size)
+                             enum object_type *type, unsigned long *size,
+                             int stop_at_blank)
 {
        struct pack_entry e;
        void *data;
 
        if (!find_pack_entry(sha1, &e))
                return NULL;
-       data = cache_or_unpack_entry(e.p, e.offset, size, type, 1);
+       data = cache_or_unpack_entry(e.p, e.offset, size, type, 1, 
stop_at_blank);
        if (!data) {
                /*
                 * We're probably in deep shit, but let's try to fetch
@@ -2226,7 +2248,7 @@ static void *read_packed_sha1(const unsigned char *sha1,
                error("failed to read object %s at offset %"PRIuMAX" from %s",
                      sha1_to_hex(sha1), (uintmax_t)e.offset, e.p->pack_name);
                mark_bad_packed_object(e.p, sha1);
-               data = read_object(sha1, type, size);
+               data = read_object(sha1, type, size, stop_at_blank);
        }
        return data;
 }
@@ -2255,7 +2277,7 @@ static void *read_object(const unsigned char *sha1, enum 
object_type *type,
 }
 
 static void *read_object(const unsigned char *sha1, enum object_type *type,
-                        unsigned long *size)
+                        unsigned long *size, int stop_at_blank)
 {
        unsigned long mapsize;
        void *map, *buf;
@@ -2268,17 +2290,18 @@ static void *read_object(const unsigned char *sha1, 
enum object_type *type,
                return xmemdupz(co->buf, co->size);
        }
 
-       buf = read_packed_sha1(sha1, type, size);
+       buf = read_packed_sha1(sha1, type, size, stop_at_blank);
        if (buf)
                return buf;
        map = map_sha1_file(sha1, &mapsize);
        if (map) {
-               buf = unpack_sha1_file(map, mapsize, type, size, sha1);
+               buf = unpack_sha1_file(map, mapsize, type, size, sha1,
+                                      stop_at_blank);
                munmap(map, mapsize);
                return buf;
        }
        reprepare_packed_git();
-       return read_packed_sha1(sha1, type, size);
+       return read_packed_sha1(sha1, type, size, stop_at_blank);
 }
 
 /*
@@ -2296,9 +2319,10 @@ void *read_sha1_file_extended(const unsigned char *sha1,
        const struct packed_git *p;
        const unsigned char *repl = (flag & READ_SHA1_FILE_REPLACE)
                ? lookup_replace_object(sha1) : sha1;
+       int stop_at_blank = !!(flag & READ_SHA1_FILE_HEADER);
 
        errno = 0;
-       data = read_object(repl, type, size);
+       data = read_object(repl, type, size, stop_at_blank);
        if (data)
                return data;
 
@@ -2597,7 +2621,7 @@ int force_object_loose(const unsigned char *sha1, time_t 
mtime)
 
        if (has_loose_object(sha1))
                return 0;
-       buf = read_packed_sha1(sha1, &type, &len);
+       buf = read_packed_sha1(sha1, &type, &len, 0);
        if (!buf)
                return error("cannot read sha1_file for %s", sha1_to_hex(sha1));
        hdrlen = sprintf(hdr, "%s %lu", typename(type), len) + 1;
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to