read-cache.c: optimize reading index format v4

Index format v4 requires some more computation to assemble a path based on a previous one. The current code is not very efficient because - it doubles memory copy, we assemble the final path in a temporary first before putting it back to a cache_entry - strbuf_remove() in expand_name_field() is not exactly a good fit for stripping a part at the end, _setlen() would do the same job and is much cheaper. - the open-coded loop to find the end of the string in expand_name_field() can't beat an optimized strlen() This patch avoids the temporary buffer and writes directly to the new cache_entry, which addresses the first two points. The last point could also be avoided if the total string length fits in the first 12 bits of ce_flags, if not we fall back to strlen(). Running "test-tool read-cache 100" on webkit.git (275k files), reading v2 only takes 4.226 seconds, while v4 takes 5.711 seconds, 35% more time. The patch reduces read time on v4 to 4.319 seconds. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Sep 26, 2018 at 15:54 UTC 252d079cbd27ca442d94535e3979145eceaf082b
1 file changed +60 -68
read-cache.c
+60 -68
@@ -1713,63 +1713,24 @@ int read_index(struct index_state *istate)
1713 return read_index_from(istate, get_index_file(), get_git_dir());
1714 }
1715
1716 -static struct cache_entry *cache_entry_from_ondisk(struct mem_pool *mem_pool,
1717 - struct ondisk_cache_entry *ondisk,
1718 - unsigned int flags,
1719 - const char *name,
1720 - size_t len)
1721 -{
1722 - struct cache_entry *ce = mem_pool__ce_alloc(mem_pool, len);
1723 -
1724 - ce->ce_stat_data.sd_ctime.sec = get_be32(&ondisk->ctime.sec);
1725 - ce->ce_stat_data.sd_mtime.sec = get_be32(&ondisk->mtime.sec);
1726 - ce->ce_stat_data.sd_ctime.nsec = get_be32(&ondisk->ctime.nsec);
1727 - ce->ce_stat_data.sd_mtime.nsec = get_be32(&ondisk->mtime.nsec);
1728 - ce->ce_stat_data.sd_dev = get_be32(&ondisk->dev);
1729 - ce->ce_stat_data.sd_ino = get_be32(&ondisk->ino);
1730 - ce->ce_mode = get_be32(&ondisk->mode);
1731 - ce->ce_stat_data.sd_uid = get_be32(&ondisk->uid);
1732 - ce->ce_stat_data.sd_gid = get_be32(&ondisk->gid);
1733 - ce->ce_stat_data.sd_size = get_be32(&ondisk->size);
1734 - ce->ce_flags = flags & ~CE_NAMEMASK;
1735 - ce->ce_namelen = len;
1736 - ce->index = 0;
1737 - hashcpy(ce->oid.hash, ondisk->sha1);
1738 - memcpy(ce->name, name, len);
1739 - ce->name[len] = '\0';
1740 - return ce;
1741 -}
1742 -
1743 -/*
1744 - * Adjacent cache entries tend to share the leading paths, so it makes
1745 - * sense to only store the differences in later entries. In the v4
1746 - * on-disk format of the index, each on-disk cache entry stores the
1747 - * number of bytes to be stripped from the end of the previous name,
1748 - * and the bytes to append to the result, to come up with its name.
1749 - */
1750 -static unsigned long expand_name_field(struct strbuf *name, const char *cp_)
1751 -{
1752 - const unsigned char *ep, *cp = (const unsigned char *)cp_;
1753 - size_t len = decode_varint(&cp);
1754 -
1755 - if (name->len < len)
1756 - die("malformed name field in the index");
1757 - strbuf_remove(name, name->len - len, len);
1758 - for (ep = cp; *ep; ep++)
1759 - ; /* find the end */
1760 - strbuf_add(name, cp, ep - cp);
1761 - return (const char *)ep + 1 - cp_;
1762 -}
1763 -
1764 -static struct cache_entry *create_from_disk(struct mem_pool *mem_pool,
1716 +static struct cache_entry *create_from_disk(struct index_state *istate,
1717 struct ondisk_cache_entry *ondisk,
1718 unsigned long *ent_size,
1767 - struct strbuf *previous_name)
1719 + const struct cache_entry *previous_ce)
1720 {
1721 struct cache_entry *ce;
1722 size_t len;
1723 const char *name;
1724 unsigned int flags;
1725 + size_t copy_len;
1726 + /*
1727 + * Adjacent cache entries tend to share the leading paths, so it makes
1728 + * sense to only store the differences in later entries. In the v4
1729 + * on-disk format of the index, each on-disk cache entry stores the
1730 + * number of bytes to be stripped from the end of the previous name,
1731 + * and the bytes to append to the result, to come up with its name.
1732 + */
1733 + int expand_name_field = istate->version == 4;
1734
1735 /* On-disk flags are just 16 bits */
1736 flags = get_be16(&ondisk->flags);
@@ -1789,21 +1750,54 @@ static struct cache_entry *create_from_disk(struct mem_pool *mem_pool,
1750 else
1751 name = ondisk->name;
1752
1792 - if (!previous_name) {
1793 - /* v3 and earlier */
1794 - if (len == CE_NAMEMASK)
1795 - len = strlen(name);
1796 - ce = cache_entry_from_ondisk(mem_pool, ondisk, flags, name, len);
1753 + if (expand_name_field) {
1754 + const unsigned char *cp = (const unsigned char *)name;
1755 + size_t strip_len, previous_len;
1756
1798 - *ent_size = ondisk_ce_size(ce);
1799 - } else {
1800 - unsigned long consumed;
1801 - consumed = expand_name_field(previous_name, name);
1802 - ce = cache_entry_from_ondisk(mem_pool, ondisk, flags,
1803 - previous_name->buf,
1804 - previous_name->len);
1757 + previous_len = previous_ce ? previous_ce->ce_namelen : 0;
1758 + strip_len = decode_varint(&cp);
1759 + if (previous_len < strip_len) {
1760 + if (previous_ce)
1761 + die(_("malformed name field in the index, near path '%s'"),
1762 + previous_ce->name);
1763 + else
1764 + die(_("malformed name field in the index in the first path"));
1765 + }
1766 + copy_len = previous_len - strip_len;
1767 + name = (const char *)cp;
1768 + }
1769 +
1770 + if (len == CE_NAMEMASK) {
1771 + len = strlen(name);
1772 + if (expand_name_field)
1773 + len += copy_len;
1774 + }
1775 +
1776 + ce = mem_pool__ce_alloc(istate->ce_mem_pool, len);
1777 +
1778 + ce->ce_stat_data.sd_ctime.sec = get_be32(&ondisk->ctime.sec);
1779 + ce->ce_stat_data.sd_mtime.sec = get_be32(&ondisk->mtime.sec);
1780 + ce->ce_stat_data.sd_ctime.nsec = get_be32(&ondisk->ctime.nsec);
1781 + ce->ce_stat_data.sd_mtime.nsec = get_be32(&ondisk->mtime.nsec);
1782 + ce->ce_stat_data.sd_dev = get_be32(&ondisk->dev);
1783 + ce->ce_stat_data.sd_ino = get_be32(&ondisk->ino);
1784 + ce->ce_mode = get_be32(&ondisk->mode);
1785 + ce->ce_stat_data.sd_uid = get_be32(&ondisk->uid);
1786 + ce->ce_stat_data.sd_gid = get_be32(&ondisk->gid);
1787 + ce->ce_stat_data.sd_size = get_be32(&ondisk->size);
1788 + ce->ce_flags = flags & ~CE_NAMEMASK;
1789 + ce->ce_namelen = len;
1790 + ce->index = 0;
1791 + hashcpy(ce->oid.hash, ondisk->sha1);
1792
1806 - *ent_size = (name - ((char *)ondisk)) + consumed;
1793 + if (expand_name_field) {
1794 + if (copy_len)
1795 + memcpy(ce->name, previous_ce->name, copy_len);
1796 + memcpy(ce->name + copy_len, name, len + 1 - copy_len);
1797 + *ent_size = (name - ((char *)ondisk)) + len + 1 - copy_len;
1798 + } else {
1799 + memcpy(ce->name, name, len + 1);
1800 + *ent_size = ondisk_ce_size(ce);
1801 }
1802 return ce;
1803 }
@@ -1898,7 +1892,7 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
1892 struct cache_header *hdr;
1893 void *mmap;
1894 size_t mmap_size;
1901 - struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
1895 + const struct cache_entry *previous_ce = NULL;
1896
1897 if (istate->initialized)
1898 return istate->cache_nr;
@@ -1936,11 +1930,9 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
1930 istate->initialized = 1;
1931
1932 if (istate->version == 4) {
1939 - previous_name = &previous_name_buf;
1933 mem_pool_init(&istate->ce_mem_pool,
1934 estimate_cache_size_from_compressed(istate->cache_nr));
1935 } else {
1943 - previous_name = NULL;
1936 mem_pool_init(&istate->ce_mem_pool,
1937 estimate_cache_size(mmap_size, istate->cache_nr));
1938 }
@@ -1952,12 +1944,12 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
1944 unsigned long consumed;
1945
1946 disk_ce = (struct ondisk_cache_entry *)((char *)mmap + src_offset);
1955 - ce = create_from_disk(istate->ce_mem_pool, disk_ce, &consumed, previous_name);
1947 + ce = create_from_disk(istate, disk_ce, &consumed, previous_ce);
1948 set_index_entry(istate, i, ce);
1949
1950 src_offset += consumed;
1951 + previous_ce = ce;
1952 }
1960 - strbuf_release(&previous_name_buf);
1953 istate->timestamp.sec = st.st_mtime;
1954 istate->timestamp.nsec = ST_MTIME_NSEC(st);
1955