# Poor performance of git describe in big repos

33 messages from 2013-05-30 to 2013-06-03. Participants: Alex Bennée, Ramkumar Ramachandra, John Keeping, Duy Nguyen, Thomas Rast, Antoine Pelisse, Jeff King, Junio C Hamano.
Thread: https://gitlist.dev/t/33984

## Alex Bennée, 2013-05-30 10:38

Subject: Poor performance of git describe in big repos
Message-ID: <CAJ-05NPQLVFhtb9KMLNLc5MqguBYM1=gKEVrrtT3kSMiZKma_g@mail.gmail.com>
URL: https://gitlist.dev/e/CAJ-05NPQLVFhtb9KMLNLc5MqguBYM1%3DgKEVrrtT3kSMiZKma_g%40mail.gmail.com

```
Hi,

I'm a fairly heavy user of the magit Emacs extension for interacting
with my git repos. However I've noticed there are some cases where lag
is very high. By analysing strace output of emacs calling git I found
two commands that where particularly problematic when interrogating
the repo:

11:00 ajb@sloy/x86_64 [work.git] >time /usr/bin/git --no-pager
describe --long --tags
ajb-build-test-5224-10-gfa296e6

real    0m5.016s
user    0m4.364s
sys     0m0.444s

11:34 ajb@sloy/x86_64 [work.git] >time /usr/bin/git --no-pager
describe --contains HEAD
fatal: cannot describe 'fa296e61f549a1252a65a13b2f734d7afbc7e88e'

real    0m4.805s
user    0m4.388s
sys     0m0.400s

Running with first command with the --debug flag on gives:

11:34 ajb@sloy/x86_64 [work.git] >time /usr/bin/git --no-pager
describe --long --tags --debug
searching to describe HEAD
 lightweight       10 ajb-build-test-5224
 lightweight       41 ajb-build-test-5222
 annotated        146 vnms-2-1-36-32
 annotated        155 vnms-2-1-36-31
 annotated        174 vnms-2-1-36-30
 annotated        183 vnms-2-1-36-29
 lightweight      188 vnms-2-1-36-28
 annotated        193 vnms-2-1-36-27
 annotated        206 vnms-2-1-36-26
 annotated        215 vectastar-4-2-83-5
traversed 223 commits
more than 10 tags found; listed 10 most recent
gave up search at 2b69df72d47be8440e3ce4cee91b9b7ceaf8b77c
ajb-build-test-5224-10-gfa296e6

real    0m4.817s
user    0m4.320s
sys     0m0.464s

Which has only traversed 223 before coming to a decision. This seems
like a very low number of commits given the time it's spent doing
this.

One factor might be the size of my repo (.git is around 2.4G). Could
this just be due to computational cost of searching through large
packs to walk the commit chain? Is there any way to make this easier
for git to do?


-- 
Alex, homepage: http://www.bennee.com/~alex/

```

## Ramkumar Ramachandra, 2013-05-30 11:33

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CALkWK0ndKMZRuWgdg6djqPUGxbDAqZPcv2q0qPrv_2b=1NEM5g@mail.gmail.com>
URL: https://gitlist.dev/e/CALkWK0ndKMZRuWgdg6djqPUGxbDAqZPcv2q0qPrv_2b%3D1NEM5g%40mail.gmail.com
In-Reply-To: <CAJ-05NPQLVFhtb9KMLNLc5MqguBYM1=gKEVrrtT3kSMiZKma_g@mail.gmail.com>

```
Alex Bennée wrote:
>>time /usr/bin/git --no-pager
> traversed 223 commits
>
> real    0m4.817s
> user    0m4.320s
> sys     0m0.464s

I'm quite clueless about why it is taking this long: I think it's IO
because there's nothing to compute?  I really can't trace anything
unless you can reproduce it on a public repository.  On linux.git with
my rotating hard disk:

$ time git describe --debug --long --tags HEAD~10000
searching to describe HEAD~10000
 annotated       5445 v2.6.33
 annotated       5660 v2.6.33-rc8
 annotated       5884 v2.6.33-rc7
 annotated       6140 v2.6.33-rc6
 annotated       6467 v2.6.33-rc5
 annotated       6999 v2.6.33-rc4
 annotated       7430 v2.6.33-rc3
 annotated       7746 v2.6.33-rc2
 annotated       8212 v2.6.33-rc1
 annotated      13854 v2.6.32
traversed 18895 commits
more than 10 tags found; listed 10 most recent
gave up search at 648f4e3e50c4793d9dbf9a09afa193631f76fa26
v2.6.33-5445-ge7c84ee

real    0m0.509s
user    0m0.470s
sys     0m0.037s

18k+ commits traversed in half a second here, so I really don't know
what is going on.

```

## John Keeping, 2013-05-30 11:48

Subject: Re: Poor performance of git describe in big repos
Message-ID: <20130530114808.GD17475@serenity.lan>
URL: https://gitlist.dev/e/20130530114808.GD17475%40serenity.lan
In-Reply-To: <CAJ-05NPQLVFhtb9KMLNLc5MqguBYM1=gKEVrrtT3kSMiZKma_g@mail.gmail.com>

```
On Thu, May 30, 2013 at 11:38:32AM +0100, Alex Bennée wrote:
> One factor might be the size of my repo (.git is around 2.4G). Could
> this just be due to computational cost of searching through large
> packs to walk the commit chain? Is there any way to make this easier
> for git to do?

What does "git count-objects -v" say for your repository?

You may find that performance improves if you repack with "git gc
--aggressive".

```

## Alex Bennée, 2013-05-30 12:29

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CAJ-05NM9EhikDBP0izqWrnLbZW6RcHq_cH-20YTE08SZw5fjqA@mail.gmail.com>
URL: https://gitlist.dev/e/CAJ-05NM9EhikDBP0izqWrnLbZW6RcHq_cH-20YTE08SZw5fjqA%40mail.gmail.com
In-Reply-To: <20130530114808.GD17475@serenity.lan>

```
The repo is a fairly hairy one as it includes two historically
un-related but content related repos which I'm the process of
cherry-picking stuff across.

11:58 ajb@sloy/x86_64 [work.git] >git count-objects -v
count: 493
size: 4572
in-pack: 399307
packs: 1
size-pack: 1930755
prune-packable: 0
garbage: 0
size-garbage: 0

This was after a repack which did have slight negative effect on
performance. The pack file is:

13:27 ajb@sloy/x86_64 [work.git] >ls -lh ./.git/objects/pack/*
-r--r--r-- 1 ajb cvs  11M May 30 11:56
./.git/objects/pack/pack-a9ba133a6f25ffa74c3c407e09ab030f8745b201.idx
-r--r--r-- 1 ajb cvs 1.9G May 30 11:56
./.git/objects/pack/pack-a9ba133a6f25ffa74c3c407e09ab030f8745b201.pack

I ran perf on it and the top items in the report where:

 41.58%   git  libcrypto.so.1.0.0  [.] 0x6ae73
 33.96%   git  libz.so.1.2.3.4     [.] 0xe0ec
 10.39%   git  libz.so.1.2.3.4     [.] adler32
  2.03%   git  [kernel.kallsyms]   [k] clear_page_c

So I'm guessing it's spending a lot of non-cache efficient time
un-packing and processing the deltas?

--
Alex.

On 30 May 2013 12:48, John Keeping <john@keeping.me.uk> wrote:
> On Thu, May 30, 2013 at 11:38:32AM +0100, Alex Bennée wrote:
>> One factor might be the size of my repo (.git is around 2.4G). Could
>> this just be due to computational cost of searching through large
>> packs to walk the commit chain? Is there any way to make this easier
>> for git to do?
>
> What does "git count-objects -v" say for your repository?
>
> You may find that performance improves if you repack with "git gc
> --aggressive".



-- 
Alex, homepage: http://www.bennee.com/~alex/

```

## Alex Bennée, 2013-05-30 13:09

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CAJ-05NNAeLUfyk8+NU8PmjKqfTcZ1NT_NPAk3M1QROtzsQKJ8g@mail.gmail.com>
URL: https://gitlist.dev/e/CAJ-05NNAeLUfyk8%2BNU8PmjKqfTcZ1NT_NPAk3M1QROtzsQKJ8g%40mail.gmail.com
In-Reply-To: <CALkWK0ndKMZRuWgdg6djqPUGxbDAqZPcv2q0qPrv_2b=1NEM5g@mail.gmail.com>

```
It looks like it's a file caching effect combined with my repo being
more pathalogical in size and contents. Note run 1 (cold) vs run 2 on
the linux file tree:

13:52 ajb@sloy/x86_64 [linux.git] >time git describe --debug --long
--tags HEAD~10000
searching to describe HEAD~10000
 annotated         57 v2.6.34-rc2
 annotated       1688 v2.6.34-rc1
 annotated       7932 v2.6.33
 annotated       8157 v2.6.33-rc8
 annotated       8381 v2.6.33-rc7
 annotated       8637 v2.6.33-rc6
 annotated       8964 v2.6.33-rc5
 annotated       9493 v2.6.33-rc4
 annotated       9912 v2.6.33-rc3
 annotated      10202 v2.6.33-rc2
traversed 10547 commits
more than 10 tags found; listed 10 most recent
gave up search at 55639353a0035052d9ea6cfe4dde0ac7fcbb2c9f
v2.6.34-rc2-57-gef5da59

real    0m7.332s
user    0m0.308s
sys     0m0.244s
14:03 ajb@sloy/x86_64 [linux.git] >time git describe --debug --long
--tags HEAD~10000
searching to describe HEAD~10000
 annotated         57 v2.6.34-rc2
 annotated       1688 v2.6.34-rc1
 annotated       7932 v2.6.33
 annotated       8157 v2.6.33-rc8
 annotated       8381 v2.6.33-rc7
 annotated       8637 v2.6.33-rc6
 annotated       8964 v2.6.33-rc5
 annotated       9493 v2.6.33-rc4
 annotated       9912 v2.6.33-rc3
 annotated      10202 v2.6.33-rc2
traversed 10547 commits
more than 10 tags found; listed 10 most recent
gave up search at 55639353a0035052d9ea6cfe4dde0ac7fcbb2c9f
v2.6.34-rc2-57-gef5da59

real    0m0.298s
user    0m0.244s
sys     0m0.036s

Although the perf profile looks subtly different.

First through the linux tree:

 22.35%   git  libz.so.1.2.3.4    [.] inflate
 18.56%   git  libz.so.1.2.3.4    [.] inflate_fast
 17.48%   git  libz.so.1.2.3.4    [.] inflate_table
  7.84%   git  git                [.] hashcmp
  3.93%   git  git                [.] get_sha1_hex
  3.46%   git  libz.so.1.2.3.4    [.] adler32

And through my "special" repo:

 41.58%   git  libcrypto.so.1.0.0  [.] sha1_block_data_order_ssse3
 33.62%   git  libz.so.1.2.3.4     [.] inflate_fast
 10.39%   git  libz.so.1.2.3.4     [.] adler32
  2.03%   git  [kernel.kallsyms]   [k] clear_page_c

 I'm not sure why libcrypto features so highly in the results


 --
 Alex.

On 30 May 2013 12:33, Ramkumar Ramachandra <artagnon@gmail.com> wrote:
> Alex Bennée wrote:
>>>time /usr/bin/git --no-pager
>> traversed 223 commits
>>
>> real    0m4.817s
>> user    0m4.320s
>> sys     0m0.464s
>
> I'm quite clueless about why it is taking this long: I think it's IO
> because there's nothing to compute?  I really can't trace anything
> unless you can reproduce it on a public repository.  On linux.git with
> my rotating hard disk:
>
> $ time git describe --debug --long --tags HEAD~10000
> searching to describe HEAD~10000
>  annotated       5445 v2.6.33
>  annotated       5660 v2.6.33-rc8
>  annotated       5884 v2.6.33-rc7
>  annotated       6140 v2.6.33-rc6
>  annotated       6467 v2.6.33-rc5
>  annotated       6999 v2.6.33-rc4
>  annotated       7430 v2.6.33-rc3
>  annotated       7746 v2.6.33-rc2
>  annotated       8212 v2.6.33-rc1
>  annotated      13854 v2.6.32
> traversed 18895 commits
> more than 10 tags found; listed 10 most recent
> gave up search at 648f4e3e50c4793d9dbf9a09afa193631f76fa26
> v2.6.33-5445-ge7c84ee
>
> real    0m0.509s
> user    0m0.470s
> sys     0m0.037s
>
> 18k+ commits traversed in half a second here, so I really don't know
> what is going on.



-- 
Alex, homepage: http://www.bennee.com/~alex/

```

## Alex Bennée, 2013-05-30 13:16

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CAJ-05NOyQu7pfY7jwKTJ2ZS_h9pBtnyeMAxJVzjC7R0kVoLUBw@mail.gmail.com>
URL: https://gitlist.dev/e/CAJ-05NOyQu7pfY7jwKTJ2ZS_h9pBtnyeMAxJVzjC7R0kVoLUBw%40mail.gmail.com
In-Reply-To: <20130530114808.GD17475@serenity.lan>

```
> You may find that performance improves if you repack with "git gc
--aggressive".

It seems that increases the time to get to where it wants to:

14:12 ajb@sloy/x86_64 [work.git] >time /usr/bin/git --no-pager
describe --long --tags --debug
searching to describe HEAD
 lightweight       10 ajb-build-test-5224
 lightweight       41 ajb-build-test-5222
 annotated        146 vnms-2-1-36-32
 annotated        155 vnms-2-1-36-31
 annotated        174 vnms-2-1-36-30
 annotated        183 vnms-2-1-36-29
 lightweight      188 vnms-2-1-36-28
 annotated        193 vnms-2-1-36-27
 annotated        206 vnms-2-1-36-26
 annotated        215 vectastar-4-2-83-5
traversed 223 commits
more than 10 tags found; listed 10 most recent
gave up search at 2b69df72d47be8440e3ce4cee91b9b7ceaf8b77c
ajb-build-test-5224-10-gfa296e6

real    0m14.658s
user    0m12.845s
sys     0m1.776s

On 30 May 2013 12:48, John Keeping <john@keeping.me.uk> wrote:
> On Thu, May 30, 2013 at 11:38:32AM +0100, Alex Bennée wrote:
>> One factor might be the size of my repo (.git is around 2.4G). Could
>> this just be due to computational cost of searching through large
>> packs to walk the commit chain? Is there any way to make this easier
>> for git to do?
>
> What does "git count-objects -v" say for your repository?
>
> You may find that performance improves if you repack with "git gc
> --aggressive".



-- 
Alex, homepage: http://www.bennee.com/~alex/

```

## Duy Nguyen, 2013-05-30 13:20

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CACsJy8A1oEezNeFjXTrQ=+gJ6nxDheFYTU0xtiSRt0aOOvE=Vw@mail.gmail.com>
URL: https://gitlist.dev/e/CACsJy8A1oEezNeFjXTrQ%3D%2BgJ6nxDheFYTU0xtiSRt0aOOvE%3DVw%40mail.gmail.com
In-Reply-To: <CAJ-05NM9EhikDBP0izqWrnLbZW6RcHq_cH-20YTE08SZw5fjqA@mail.gmail.com>

```
On Thu, May 30, 2013 at 7:29 PM, Alex Bennée <kernel-hacker@bennee.com> wrote:
> I ran perf on it and the top items in the report where:
>
>  41.58%   git  libcrypto.so.1.0.0  [.] 0x6ae73
>  33.96%   git  libz.so.1.2.3.4     [.] 0xe0ec
>  10.39%   git  libz.so.1.2.3.4     [.] adler32
>   2.03%   git  [kernel.kallsyms]   [k] clear_page_c
>
> So I'm guessing it's spending a lot of non-cache efficient time
> un-packing and processing the deltas?

If I'm not mistaken, commits are never deltified. They are usually
small and packed close together for better I/O patterns. If you really
just read hundreds of commits, it can't take that long. Maybe some
code paths accidentally open a tree, a blob or something..

Can you try setting core.logpackaccess to a path on and rerun
describe? Jugding from the code (I never actually tried it), it'll
create a file at the given path with the accessed pack offsets. You
can check what offset corresponds to what object with verify-pack -v.
--
Duy

```

## Duy Nguyen, 2013-05-30 13:45

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CACsJy8AuhbwkjGjeQRYe1XZFsAntNdpKYxBM9aeMwF3HpB16Ow@mail.gmail.com>
URL: https://gitlist.dev/e/CACsJy8AuhbwkjGjeQRYe1XZFsAntNdpKYxBM9aeMwF3HpB16Ow%40mail.gmail.com
In-Reply-To: <CAJ-05NPacjAEC99Ntd9eMnTD9_PMMYFob-_tAx5CeSB79TkRSg@mail.gmail.com>

```
On Thu, May 30, 2013 at 8:34 PM, Alex Bennée <kernel-hacker@bennee.com> wrote:
> From the following run:
>
>
> 14:31 ajb@sloy/x86_64 [work.git] >time /usr/bin/git --no-pager
> describe --long --tags
> ajb-build-test-5224-11-g9660048
>
> real    0m14.720s
> user    0m12.985s
> sys     0m1.700s
> 14:31 ajb@sloy/x86_64 [work.git] >wc -l /tmp/log-pack.txt
> 1610 /tmp/log-pack.txt
>
> The pack has been "tuned" with a gc --aggressive. Assuming the numbers
> are offsets into the pack it looks fairly random access until the last
> 100 or so.
>
> [snipped]

Thanks. Can you share "verify-pack -v" output of
pack-a9ba133a6f25ffa74c3c407e09ab030f8745b201.pack? I think you need
to put it somewhere on Internet temporarily as it's likely to exceed
git@vger limits.
--
Duy

```

## Alex Bennée, 2013-05-30 14:02

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CAJ-05NNB7b5Bgc4B5OUOta+Q08+fgKf_NzuG44z8_teqWgnctQ@mail.gmail.com>
URL: https://gitlist.dev/e/CAJ-05NNB7b5Bgc4B5OUOta%2BQ08%2BfgKf_NzuG44z8_teqWgnctQ%40mail.gmail.com
In-Reply-To: <CACsJy8AuhbwkjGjeQRYe1XZFsAntNdpKYxBM9aeMwF3HpB16Ow@mail.gmail.com>

```
On 30 May 2013 14:45, Duy Nguyen <pclouds@gmail.com> wrote:
> On Thu, May 30, 2013 at 8:34 PM, Alex Bennée <kernel-hacker@bennee.com> wrote:
> <snip>
> Thanks. Can you share "verify-pack -v" output of
> pack-a9ba133a6f25ffa74c3c407e09ab030f8745b201.pack? I think you need
> to put it somewhere on Internet temporarily as it's likely to exceed
> git@vger limits.
> --
> Duy

http://www.bennee.com/~alex/stuff/git-pack-access.tar.bz2

--
Alex, homepage: http://www.bennee.com/~alex/

```

## Ramkumar Ramachandra, 2013-05-30 14:32

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CALkWK0=bgM+fYcVEwjHHF8k2Q8wMmjdbM5bxXdPH6s9StDH_Ng@mail.gmail.com>
URL: https://gitlist.dev/e/CALkWK0%3DbgM%2BfYcVEwjHHF8k2Q8wMmjdbM5bxXdPH6s9StDH_Ng%40mail.gmail.com
In-Reply-To: <CAJ-05NNAeLUfyk8+NU8PmjKqfTcZ1NT_NPAk3M1QROtzsQKJ8g@mail.gmail.com>

```
Alex Bennée wrote:
> And through my "special" repo:
>
>  41.58%   git  libcrypto.so.1.0.0  [.] sha1_block_data_order_ssse3
>  33.62%   git  libz.so.1.2.3.4     [.] inflate_fast
>  10.39%   git  libz.so.1.2.3.4     [.] adler32
>   2.03%   git  [kernel.kallsyms]   [k] clear_page_c
>
>  I'm not sure why libcrypto features so highly in the results

While Duy churns on the delta chain, let me try to make a (rather
crude) observation:

What does it mean for libcrypto to be so high in your perf report?
sha1_block_data_order is ultimately by object.c:parse_object.  While
it indicates that deltas are taking a long time to apply (or are
somehow not optimally organized for IO), I think it indicates either:

1. Your history is very deep and there are an unusually high number of
deltas for each blob.  What are the total number of commits?

2. You have have huge (binary) files checked into your repository.  Do
you?  If so, why isn't the code in streaming.c kicking in?

```

## Alex Bennée, 2013-05-30 15:01

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CAJ-05NMt6h=JFLLCP+LASKMcToENhF=BSsk1dPML0024hJTwTw@mail.gmail.com>
URL: https://gitlist.dev/e/CAJ-05NMt6h%3DJFLLCP%2BLASKMcToENhF%3DBSsk1dPML0024hJTwTw%40mail.gmail.com
In-Reply-To: <CALkWK0=bgM+fYcVEwjHHF8k2Q8wMmjdbM5bxXdPH6s9StDH_Ng@mail.gmail.com>

```
On 30 May 2013 15:32, Ramkumar Ramachandra <artagnon@gmail.com> wrote:
> Alex Bennée wrote:
>> And through my "special" repo:
>>
>>  41.58%   git  libcrypto.so.1.0.0  [.] sha1_block_data_order_ssse3
>>  33.62%   git  libz.so.1.2.3.4     [.] inflate_fast
>>  10.39%   git  libz.so.1.2.3.4     [.] adler32
>>   2.03%   git  [kernel.kallsyms]   [k] clear_page_c
>>
>>  I'm not sure why libcrypto features so highly in the results
>
> While Duy churns on the delta chain, let me try to make a (rather
> crude) observation:
>
> What does it mean for libcrypto to be so high in your perf report?
> sha1_block_data_order is ultimately by object.c:parse_object.  While
> it indicates that deltas are taking a long time to apply (or are
> somehow not optimally organized for IO), I think it indicates either:
>
> 1. Your history is very deep and there are an unusually high number of
> deltas for each blob.  What are the total number of commits?

Well the history does en-compose about 10 years of product development
and has a high number of files in the repo (including about 3 copies of
the kernel - sans upstream history).

15:50 ajb@sloy/x86_64 [work.git] >time git log --pretty=oneline | wc -l
24648

real    0m0.434s
user    0m0.388s
sys     0m0.112s

Although it doesn't take too long to walk the whole mainline history
(obviously ignoring all the other branches).

15:52 ajb@sloy/x86_64 [work.git] >git count-objects -v -H
count: 581
size: 5.09 MiB
in-pack: 399307
packs: 1
size-pack: 1.49 GiB
prune-packable: 0
garbage: 0
size-garbage: 0 bytes

It is a pick repo. The gc --aggressive nearly took out my machine keeping
around 4gb resident for most of the half hour and using nearly 8gb of VM.

Of course most of the history is not needed for day to day stuff. Maybe
if I split the pack files up it wouldn't be quite such a strain to work
through them?

> 2. You have have huge (binary) files checked into your repository.  Do
> you?  If so, why isn't the code in streaming.c kicking in?

We do have some binary blobs in the repository (mainly DSP and FPGA images)
although not a huge number:

15:58 ajb@sloy/x86_64 [work.git] >time git log --pretty=oneline -- xxx
xxx/xxxxxx/*.out ./xxx/xxx/*.out ./xxx/xxxxxxx/*.out | wc -l
234

real    0m0.590s
user    0m0.552s
sys     0m0.040s

How can I tell if streaming is kicking in or now?


-- 
Alex, homepage: http://www.bennee.com/~alex/

```

## Ramkumar Ramachandra, 2013-05-30 15:17

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CALkWK0=6xg8X7ZLXoaTk_ZgRnhgXWsftsTzr6JAWFBJvmVOgFw@mail.gmail.com>
URL: https://gitlist.dev/e/CALkWK0%3D6xg8X7ZLXoaTk_ZgRnhgXWsftsTzr6JAWFBJvmVOgFw%40mail.gmail.com
In-Reply-To: <CAJ-05NMt6h=JFLLCP+LASKMcToENhF=BSsk1dPML0024hJTwTw@mail.gmail.com>

```
Alex Bennée wrote:
> 15:50 ajb@sloy/x86_64 [work.git] >time git log --pretty=oneline | wc -l
> 24648
>
> real    0m0.434s
> user    0m0.388s
> sys     0m0.112s
>
> Although it doesn't take too long to walk the whole mainline history
> (obviously ignoring all the other branches).

Damn, non-starter.  linux.git has 361k+ commits in mainline history.

Nit: use git rev-list --count HEAD next time.

> 15:52 ajb@sloy/x86_64 [work.git] >git count-objects -v -H
> count: 581
> size: 5.09 MiB
> in-pack: 399307
> packs: 1
> size-pack: 1.49 GiB
> prune-packable: 0
> garbage: 0
> size-garbage: 0 bytes

linux.git has 2.9m+ in-pack.  The pack-size is much lower at about
800+ MiB, but I don't think 1.49 GiB is a problem in itself.  Looking
forward to your big-files report to see why it's so big.

> It is a pick repo. The gc --aggressive nearly took out my machine keeping
> around 4gb resident for most of the half hour and using nearly 8gb of VM.
>
> Of course most of the history is not needed for day to day stuff. Maybe
> if I split the pack files up it wouldn't be quite such a strain to work
> through them?

Really out of my depth here, sorry.  Let's see what Duy (or the
others) have to say.

>> 2. You have have huge (binary) files checked into your repository.  Do
>> you?  If so, why isn't the code in streaming.c kicking in?
>
> We do have some binary blobs in the repository (mainly DSP and FPGA images)
> although not a huge number:
>
> 15:58 ajb@sloy/x86_64 [work.git] >time git log --pretty=oneline -- xxx
> xxx/xxxxxx/*.out ./xxx/xxx/*.out ./xxx/xxxxxxx/*.out | wc -l
> 234
>
> real    0m0.590s
> user    0m0.552s
> sys     0m0.040s

log is streaming, and is not a good measure: it doesn't even walk the
entire commit graph.  How big are these files?

> How can I tell if streaming is kicking in or now?

I use callgrind (and kcachegrind to visualize).  Can you post
callgrind output?  It will be helpful in figuring out where exactly
git is spending time.

```

## Thomas Rast, 2013-05-30 15:33

Subject: Re: Poor performance of git describe in big repos
Message-ID: <87ehcoeb3t.fsf@linux-k42r.v.cablecom.net>
URL: https://gitlist.dev/e/87ehcoeb3t.fsf%40linux-k42r.v.cablecom.net
In-Reply-To: <CAJ-05NNAeLUfyk8+NU8PmjKqfTcZ1NT_NPAk3M1QROtzsQKJ8g@mail.gmail.com>

```
Alex Bennée <kernel-hacker@bennee.com> writes:

>  41.58%   git  libcrypto.so.1.0.0  [.] sha1_block_data_order_ssse3
>  33.62%   git  libz.so.1.2.3.4     [.] inflate_fast
>  10.39%   git  libz.so.1.2.3.4     [.] adler32
>   2.03%   git  [kernel.kallsyms]   [k] clear_page_c

Do you have any large blobs in the repo that are referenced directly by
a tag?

Because this just so happens to exactly reproduce your symptoms:

  # in a random git.git
  $ time git describe --debug
  [...]
  real    0m0.390s
  user    0m0.037s
  sys     0m0.011s
  $ git tag big1 $(dd if=/dev/urandom bs=1M count=512 | git hash-object -w --stdin)
  512+0 records in
  512+0 records out
  536870912 bytes (537 MB) copied, 45.5088 s, 11.8 MB/s
  $ time git describe --debug
  [...]
  real    0m1.875s
  user    0m1.738s
  sys     0m0.129s
  $ git tag big2 $(dd if=/dev/urandom bs=1M count=512 | git hash-object -w --stdin)
  512+0 records in
  512+0 records out
  536870912 bytes (537 MB) copied, 44.972 s, 11.9 MB/s
  $ time git describe --debugsuche zur Beschreibung von HEAD
  [...]
  real    0m3.620s
  user    0m3.357s
  sys     0m0.248s

(I actually ran the git-describe invocations more than once to ensure
that they are again cache-hot.)

git-describe should probably be fixed to avoid loading blobs, though I'm
not sure off hand if we have any infrastructure to infer the type of a
loose object without inflating it.  (This could probably be added by
inflating only the first block.)  We do have this for packed objects, so
at least for packed repos there's a speedup to be had.

-- 
Thomas Rast
trast@{inf,student}.ethz.ch

```

## Alex Bennée, 2013-05-30 16:01

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CAJ-05NOjVhb+3Cab7uQE8K3VE0Q2GhqR3FE=WzJZvSn8Djt6tw@mail.gmail.com>
URL: https://gitlist.dev/e/CAJ-05NOjVhb%2B3Cab7uQE8K3VE0Q2GhqR3FE%3DWzJZvSn8Djt6tw%40mail.gmail.com
In-Reply-To: <87ehcoeb3t.fsf@linux-k42r.v.cablecom.net>

```
On 30 May 2013 16:33, Thomas Rast <trast@inf.ethz.ch> wrote:
> Alex Bennée <kernel-hacker@bennee.com> writes:
>
>>  41.58%   git  libcrypto.so.1.0.0  [.] sha1_block_data_order_ssse3
>>  33.62%   git  libz.so.1.2.3.4     [.] inflate_fast
>>  10.39%   git  libz.so.1.2.3.4     [.] adler32
>>   2.03%   git  [kernel.kallsyms]   [k] clear_page_c
>
> Do you have any large blobs in the repo that are referenced directly by
> a tag?

Most probably. I've certainly done a bunch of releases (which are tagged) were
the last thing that was updated was an FPGA image.

> Because this just so happens to exactly reproduce your symptoms:
>
>   # in a random git.git
>   $ time git describe --debug
>   [...]
>   real    0m0.390s
>   user    0m0.037s
>   sys     0m0.011s
>   $ git tag big1 $(dd if=/dev/urandom bs=1M count=512 | git hash-object -w --stdin)
>   512+0 records in
>   512+0 records out
>   536870912 bytes (537 MB) copied, 45.5088 s, 11.8 MB/s
>   $ time git describe --debug
>   [...]
>   real    0m1.875s
>   user    0m1.738s
>   sys     0m0.129s
>   $ git tag big2 $(dd if=/dev/urandom bs=1M count=512 | git hash-object -w --stdin)
>   512+0 records in
>   512+0 records out
>   536870912 bytes (537 MB) copied, 44.972 s, 11.9 MB/s
>   $ time git describe --debugsuche zur Beschreibung von HEAD
>   [...]
>   real    0m3.620s
>   user    0m3.357s
>   sys     0m0.248s
>
> (I actually ran the git-describe invocations more than once to ensure
> that they are again cache-hot.)

That looks pretty promising as a replication.

> git-describe should probably be fixed to avoid loading blobs, though I'm
> not sure off hand if we have any infrastructure to infer the type of a
> loose object without inflating it.  (This could probably be added by
> inflating only the first block.)  We do have this for packed objects, so
> at least for packed repos there's a speedup to be had.

Will it be loading the blob for every commit it traverses or just ones that hit
a tag? Why does it need to load the blob at all? Surely the commit
tree state doesn't
need to be walked down?

>
> --
> Thomas Rast
> trast@{inf,student}.ethz.ch



-- 
Alex, homepage: http://www.bennee.com/~alex/

```

## Thomas Rast, 2013-05-30 16:21

Subject: Re: Poor performance of git describe in big repos
Message-ID: <87ip20bfq4.fsf@linux-k42r.v.cablecom.net>
URL: https://gitlist.dev/e/87ip20bfq4.fsf%40linux-k42r.v.cablecom.net
In-Reply-To: <CAJ-05NOjVhb+3Cab7uQE8K3VE0Q2GhqR3FE=WzJZvSn8Djt6tw@mail.gmail.com>

```
Alex Bennée <kernel-hacker@bennee.com> writes:

> On 30 May 2013 16:33, Thomas Rast <trast@inf.ethz.ch> wrote:
>> Alex Bennée <kernel-hacker@bennee.com> writes:
>>
>>>  41.58%   git  libcrypto.so.1.0.0  [.] sha1_block_data_order_ssse3
>>>  33.62%   git  libz.so.1.2.3.4     [.] inflate_fast
>>>  10.39%   git  libz.so.1.2.3.4     [.] adler32
>>>   2.03%   git  [kernel.kallsyms]   [k] clear_page_c
>>
>> Do you have any large blobs in the repo that are referenced directly by
>> a tag?
>
> Most probably. I've certainly done a bunch of releases (which are tagged) were
> the last thing that was updated was an FPGA image.
[...]
>> git-describe should probably be fixed to avoid loading blobs, though I'm
>> not sure off hand if we have any infrastructure to infer the type of a
>> loose object without inflating it.  (This could probably be added by
>> inflating only the first block.)  We do have this for packed objects, so
>> at least for packed repos there's a speedup to be had.
>
> Will it be loading the blob for every commit it traverses or just ones that hit
> a tag? Why does it need to load the blob at all? Surely the commit
> tree state doesn't
> need to be walked down?

No, my theory is that you tagged *the blobs*.  Git supports this.

git-describe needs to look at the commit (if any) obtained by peeling
each tag (i.e. dereferencing tags until it reaches a non-tag).  So to do
that, it resolves the tag's referent and loads it.  Usually this will be
a commit, in which case it is marked as reached by the tag.

As my example shows, it also resolves tags' referents if they refer to
non-commits, in particular, it will decompress large blobs that are
(directly) referenced by a tag.

Note that while annotated tags provide the type information themselves,
e.g.

  $ git cat-file tag junio-gpg-pub
  object fe113d3f96636710600c6b02d5fd421fa7e87dd6
  type blob
  tag junio-gpg-pub
  [...]

unannotated tags are simply refs, so it is not enough to just look at
the tag objects' referent type.

I had a brief look around sha1_file.c, in particular sha1_object_info,
and it turns out we lack the "deflate only early part" logic as I
suspected.  So that'll have to be fixed first.  After that I *think* it
should automatically carry over into the tag readers.

-- 
Thomas Rast
trast@{inf,student}.ethz.ch

```

## Thomas Rast, 2013-05-30 16:44

Subject: Re: Poor performance of git describe in big repos
Message-ID: <87bo7sbeoc.fsf@linux-k42r.v.cablecom.net>
URL: https://gitlist.dev/e/87bo7sbeoc.fsf%40linux-k42r.v.cablecom.net
In-Reply-To: <87ip20bfq4.fsf@linux-k42r.v.cablecom.net>

```
Thomas Rast <trast@inf.ethz.ch> writes:

> I had a brief look around sha1_file.c, in particular sha1_object_info,
> and it turns out we lack the "deflate only early part" logic as I
> suspected.  So that'll have to be fixed first.  After that I *think* it
> should automatically carry over into the tag readers.

Strike that, I'm wrong.  sha1_object_info is fast even for these big
loose objects.

The culprit, according to some callgrind investigation, is
lookup_commit_reference_gently() [for the unannotated case] or
deref_tag() [annotated case] calling parse_object().

-- 
Thomas Rast
trast@{inf,student}.ethz.ch

```

## Antoine Pelisse, 2013-05-30 19:01

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CALWbr2xd4k_P6KUQOcRJotWj3=DfJNnhL4rsGSw0yE+53gdyWw@mail.gmail.com>
URL: https://gitlist.dev/e/CALWbr2xd4k_P6KUQOcRJotWj3%3DDfJNnhL4rsGSw0yE%2B53gdyWw%40mail.gmail.com
In-Reply-To: <87bo7sbeoc.fsf@linux-k42r.v.cablecom.net>

```
> The culprit, according to some callgrind investigation, is
> lookup_commit_reference_gently() [for the unannotated case] or
> deref_tag() [annotated case] calling parse_object().

Using the scenario you described earlier, I think it ends-up spending
most of its time in check_sha1_signature (both deref_tag and
lookup_commit_reference_gently() go there) with 20% inflating, 80% in
SHA1_Update(). Not much we can do about that, can we ?

```

## John Keeping, 2013-05-30 19:30

Subject: Re: Poor performance of git describe in big repos
Message-ID: <20130530193046.GG17475@serenity.lan>
URL: https://gitlist.dev/e/20130530193046.GG17475%40serenity.lan
In-Reply-To: <87ip20bfq4.fsf@linux-k42r.v.cablecom.net>

```
On Thu, May 30, 2013 at 06:21:55PM +0200, Thomas Rast wrote:
> Alex Bennée <kernel-hacker@bennee.com> writes:
> 
> > On 30 May 2013 16:33, Thomas Rast <trast@inf.ethz.ch> wrote:
> >> Alex Bennée <kernel-hacker@bennee.com> writes:
> >>
> >>>  41.58%   git  libcrypto.so.1.0.0  [.] sha1_block_data_order_ssse3
> >>>  33.62%   git  libz.so.1.2.3.4     [.] inflate_fast
> >>>  10.39%   git  libz.so.1.2.3.4     [.] adler32
> >>>   2.03%   git  [kernel.kallsyms]   [k] clear_page_c
> >>
> >> Do you have any large blobs in the repo that are referenced directly by
> >> a tag?
> >
> > Most probably. I've certainly done a bunch of releases (which are tagged) were
> > the last thing that was updated was an FPGA image.
> [...]
> >> git-describe should probably be fixed to avoid loading blobs, though I'm
> >> not sure off hand if we have any infrastructure to infer the type of a
> >> loose object without inflating it.  (This could probably be added by
> >> inflating only the first block.)  We do have this for packed objects, so
> >> at least for packed repos there's a speedup to be had.
> >
> > Will it be loading the blob for every commit it traverses or just ones that hit
> > a tag? Why does it need to load the blob at all? Surely the commit
> > tree state doesn't
> > need to be walked down?
> 
> No, my theory is that you tagged *the blobs*.  Git supports this.

You can see if that is the case by doing something like this:

    eval $(git for-each-ref --shell --format '
        test $(git cat-file -t %(objectname)^{}) = commit ||
        echo %(refname);')

That will print out the name of any ref that doesn't point at a commit.

```

## Alex Bennée, 2013-05-31 08:14

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CAJ-05NOEuxOVy7LFp_XRa_08G-Mj0x7q+RiR=u71-iyfOXpHow@mail.gmail.com>
URL: https://gitlist.dev/e/CAJ-05NOEuxOVy7LFp_XRa_08G-Mj0x7q%2BRiR%3Du71-iyfOXpHow%40mail.gmail.com
In-Reply-To: <20130530193046.GG17475@serenity.lan>

```
On 30 May 2013 20:30, John Keeping <john@keeping.me.uk> wrote:
> On Thu, May 30, 2013 at 06:21:55PM +0200, Thomas Rast wrote:
>> Alex Bennée <kernel-hacker@bennee.com> writes:
>>
>> > On 30 May 2013 16:33, Thomas Rast <trast@inf.ethz.ch> wrote:
>> >> Alex Bennée <kernel-hacker@bennee.com> writes:
> <snip>
>> > Will it be loading the blob for every commit it traverses or just ones that hit
>> > a tag? Why does it need to load the blob at all? Surely the commit
>> > tree state doesn't
>> > need to be walked down?
>>
>> No, my theory is that you tagged *the blobs*.  Git supports this.

Wait is this the difference between annotated and non-annotated tags?
I thought a non-annotated just acted like references to a particular
tree state?

>
> You can see if that is the case by doing something like this:
>
>     eval $(git for-each-ref --shell --format '
>         test $(git cat-file -t %(objectname)^{}) = commit ||
>         echo %(refname);')
>
> That will print out the name of any ref that doesn't point at a
> commit.

Hmm that didn't seem to work. But looking at the output by hand I
certainly have a mix of tags that are commits vs tags:


09:08 ajb@sloy/x86_64 [work.git] >git for-each-ref | grep "refs/tags"
| grep "commit" | wc -l
1345
09:12 ajb@sloy/x86_64 [work.git] >git for-each-ref | grep "refs/tags"
| grep -v "commit" | wc -l
66

Unfortunately I can't just delete those tags as they do refer to known
releases which we obviously care about. If I delete the tags on my
local repo and test for a speed increase can I re-create them as
annotated tag objects?

-- 
Alex, homepage: http://www.bennee.com/~alex/

```

## Thomas Rast, 2013-05-31 08:24

Subject: Re: Poor performance of git describe in big repos
Message-ID: <87obbr5zg3.fsf@linux-k42r.v.cablecom.net>
URL: https://gitlist.dev/e/87obbr5zg3.fsf%40linux-k42r.v.cablecom.net
In-Reply-To: <CAJ-05NOEuxOVy7LFp_XRa_08G-Mj0x7q+RiR=u71-iyfOXpHow@mail.gmail.com>

```
Alex Bennée <kernel-hacker@bennee.com> writes:

> On 30 May 2013 20:30, John Keeping <john@keeping.me.uk> wrote:
>> On Thu, May 30, 2013 at 06:21:55PM +0200, Thomas Rast wrote:
>>> Alex Bennée <kernel-hacker@bennee.com> writes:
>>>
>>> > On 30 May 2013 16:33, Thomas Rast <trast@inf.ethz.ch> wrote:
>>> >> Alex Bennée <kernel-hacker@bennee.com> writes:
>> <snip>
>>> > Will it be loading the blob for every commit it traverses or just ones that hit
>>> > a tag? Why does it need to load the blob at all? Surely the commit
>>> > tree state doesn't
>>> > need to be walked down?
>>>
>>> No, my theory is that you tagged *the blobs*.  Git supports this.
>
> Wait is this the difference between annotated and non-annotated tags?
> I thought a non-annotated just acted like references to a particular
> tree state?

A tag is just a ref.  It can point at anything, in particular also a
blob (= some file *contents*).

An annotated tag is just a tag pointing at a "tag object".  A tag object
contains tagger name/email/date, a reference to an object, and a tag
message.

The slowness I found relates to having tags that point at blobs directly
(unannotated).

>> You can see if that is the case by doing something like this:
>>
>>     eval $(git for-each-ref --shell --format '
>>         test $(git cat-file -t %(objectname)^{}) = commit ||
>>         echo %(refname);')
>>
>> That will print out the name of any ref that doesn't point at a
>> commit.
>
> Hmm that didn't seem to work. But looking at the output by hand I
> certainly have a mix of tags that are commits vs tags:
>
>
> 09:08 ajb@sloy/x86_64 [work.git] >git for-each-ref | grep "refs/tags"
> | grep "commit" | wc -l
> 1345
> 09:12 ajb@sloy/x86_64 [work.git] >git for-each-ref | grep "refs/tags"
> | grep -v "commit" | wc -l
> 66
>
> Unfortunately I can't just delete those tags as they do refer to known
> releases which we obviously care about. If I delete the tags on my
> local repo and test for a speed increase can I re-create them as
> annotated tag objects?

I would be more interested in this:

  git for-each-ref | grep ' blob'

and

  (git for-each-ref | grep ' blob' | cut -d\  -f1 | xargs -n1 git cat-file blob) | wc -c

The first tells you if you have any refs pointing at blobs.  The second
computes their total unpacked size.  My theory is that the second yields
some large number (hundreds of megabytes at least).

It would be nice if you checked, because if there turn out to be big
blobs, we have all the pieces and just need to assemble the best
solution.  Otherwise, there's something else going on and the problem
remains open.

-- 
Thomas Rast
trast@{inf,student}.ethz.ch

```

## John Keeping, 2013-05-31 08:32

Subject: Re: Poor performance of git describe in big repos
Message-ID: <20130531083252.GA1072@serenity.lan>
URL: https://gitlist.dev/e/20130531083252.GA1072%40serenity.lan
In-Reply-To: <CAJ-05NOEuxOVy7LFp_XRa_08G-Mj0x7q+RiR=u71-iyfOXpHow@mail.gmail.com>

```
On Fri, May 31, 2013 at 09:14:49AM +0100, Alex Bennée wrote:
> On 30 May 2013 20:30, John Keeping <john@keeping.me.uk> wrote:
> > On Thu, May 30, 2013 at 06:21:55PM +0200, Thomas Rast wrote:
> >> Alex Bennée <kernel-hacker@bennee.com> writes:
> >>
> >> > On 30 May 2013 16:33, Thomas Rast <trast@inf.ethz.ch> wrote:
> >> >> Alex Bennée <kernel-hacker@bennee.com> writes:
> > <snip>
> >> > Will it be loading the blob for every commit it traverses or just ones that hit
> >> > a tag? Why does it need to load the blob at all? Surely the commit
> >> > tree state doesn't
> >> > need to be walked down?
> >>
> >> No, my theory is that you tagged *the blobs*.  Git supports this.
> 
> Wait is this the difference between annotated and non-annotated tags?
> I thought a non-annotated just acted like references to a particular
> tree state?

No, this is something slightly different.  In Git there are four types
of object: tag, commit, tree and blob.  When you have a heavyweight tag,
the tag reference points at a tag object (which in turn points at
another object).  With a lightweight tag, the tag reference typically
points at a commit object.

However, there is no restriction that says that a tag object must point
to a commit or that a lightweight tag must point at a commit - it is
equally possible to point directly at a tree or a blob (although a lot
less common).

Thomas is suggesting that you might have a tag that does not point at a
commit but instead points to a blob object.

> > You can see if that is the case by doing something like this:
> >
> >     eval $(git for-each-ref --shell --format '
> >         test $(git cat-file -t %(objectname)^{}) = commit ||
> >         echo %(refname);')
> >
> > That will print out the name of any ref that doesn't point at a
> > commit.
> 
> Hmm that didn't seem to work.

You mean there was no output?  In that case it's likely that all your
references do indeed point at commits.

>                               But looking at the output by hand I
> certainly have a mix of tags that are commits vs tags:
> 
> 
> 09:08 ajb@sloy/x86_64 [work.git] >git for-each-ref | grep "refs/tags"
> | grep "commit" | wc -l
> 1345
> 09:12 ajb@sloy/x86_64 [work.git] >git for-each-ref | grep "refs/tags"
> | grep -v "commit" | wc -l
> 66

This means that you have 1345 lightweight tags and 66 heavyweight tags,
assuming that all of the lines that don't say "commit" do say "tag".

By the way, I don't remember if you said which version of Git you're
using.  If it's an older version then it's possible that something has
changed.

```

## Alex Bennée, 2013-05-31 08:40

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CAJ-05NOdg5TvjzEMrXaPgogU5z5W6kywZhD-82eTUmvE9Hp=Lw@mail.gmail.com>
URL: https://gitlist.dev/e/CAJ-05NOdg5TvjzEMrXaPgogU5z5W6kywZhD-82eTUmvE9Hp%3DLw%40mail.gmail.com
In-Reply-To: <87obbr5zg3.fsf@linux-k42r.v.cablecom.net>

```
On 31 May 2013 09:24, Thomas Rast <trast@inf.ethz.ch> wrote:
> Alex Bennée <kernel-hacker@bennee.com> writes:
>> On 30 May 2013 20:30, John Keeping <john@keeping.me.uk> wrote:
>>> On Thu, May 30, 2013 at 06:21:55PM +0200, Thomas Rast wrote:
>>>> Alex Bennée <kernel-hacker@bennee.com> writes:
>>>> > On 30 May 2013 16:33, Thomas Rast <trast@inf.ethz.ch> wrote:
> <snip>
>>>> No, my theory is that you tagged *the blobs*.  Git supports this.
>>
>> Wait is this the difference between annotated and non-annotated tags?
>> I thought a non-annotated just acted like references to a particular
>> tree state?
>
> A tag is just a ref.  It can point at anything, in particular also a
> blob (= some file *contents*).
>
> An annotated tag is just a tag pointing at a "tag object".  A tag object
> contains tagger name/email/date, a reference to an object, and a tag
> message.
>
> The slowness I found relates to having tags that point at blobs directly
> (unannotated).

I think you are right. I was brave (well I assumed the tags would come
back from the upstream repo) and ran:

git for-each-ref | grep "refs/tags" | grep "commit" | cut -d '/' -f 3
| xargs git tag -d

And boom:

09:19 ajb@sloy/x86_64 [work.git] >time /usr/bin/git --no-pager
describe --long --tags
ajb-build-test-5225-2-gdc0b771

real    0m0.009s
user    0m0.008s
sys     0m0.000s

Which is much better performance. So it does look like unannotated
tags pointing at binary blobs is the failure case.

<snip>
>
> I would be more interested in this:
>
>   git for-each-ref | grep ' blob'

Hmmm that gives nothing. All the refs are either tag or commit

> and
>
>   (git for-each-ref | grep ' blob' | cut -d\  -f1 | xargs -n1 git
>cat-file blob) | wc -c

However I have some big commits it seems:

09:37 ajb@sloy/x86_64 [work.git] >(git for-each-ref | grep ' commit' |
cut -d\  -f1 | xargs -n1 git cat-file commit) | wc -c
1147231984

>
> The first tells you if you have any refs pointing at blobs.  The second
> computes their total unpacked size.  My theory is that the second yields
> some large number (hundreds of megabytes at least).
>
> It would be nice if you checked, because if there turn out to be big
> blobs, we have all the pieces and just need to assemble the best
> solution.  Otherwise, there's something else going on and the problem
> remains open.

If you want any other numbers I'm only too happy to help. Sorry I
can't share the repo though...

-- 
Alex, homepage: http://www.bennee.com/~alex/

```

## Thomas Rast, 2013-05-31 08:46

Subject: Re: Poor performance of git describe in big repos
Message-ID: <87y5av4jvj.fsf@linux-k42r.v.cablecom.net>
URL: https://gitlist.dev/e/87y5av4jvj.fsf%40linux-k42r.v.cablecom.net
In-Reply-To: <CAJ-05NOdg5TvjzEMrXaPgogU5z5W6kywZhD-82eTUmvE9Hp=Lw@mail.gmail.com>

```
Alex Bennée <kernel-hacker@bennee.com> writes:

> I think you are right. I was brave (well I assumed the tags would come
> back from the upstream repo) and ran:
>
> git for-each-ref | grep "refs/tags" | grep "commit" | cut -d '/' -f 3
> | xargs git tag -d

So that deleted all unannotated tags pointing at commits, and then it
was fast.  Curious.

> However I have some big commits it seems:
>
> 09:37 ajb@sloy/x86_64 [work.git] >(git for-each-ref | grep ' commit' |
> cut -d\  -f1 | xargs -n1 git cat-file commit) | wc -c
> 1147231984

How many unique entries are there in that list, i.e., what does

  git for-each-ref | grep ' commit' | cut -d\  -f1 | sort -u | wc -l

say?  Perhaps you can also find the biggest commit, e.g. like so:

  git for-each-ref | grep ' commit' | cut -d\  -f1 |
  while read sha; do git cat-file commit $sha | wc -c; done |
  sort -n

However, if that turns out to be the culprit, it's not fixable
currently[1].  Having commits with insanely long messages is just, well,
insane.


[1]  unless we do a major rework of the loading infrastructure, so that
we can teach it to load only the beginning of a commit as long as we are
only interested in parents and such

-- 
Thomas Rast
trast@{inf,student}.ethz.ch

```

## Alex Bennée, 2013-05-31 08:49

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CAJ-05NNgVPukJchskVv9oL7-9p+txC0g_SXfHne-mwF327Q_3Q@mail.gmail.com>
URL: https://gitlist.dev/e/CAJ-05NNgVPukJchskVv9oL7-9p%2BtxC0g_SXfHne-mwF327Q_3Q%40mail.gmail.com
In-Reply-To: <20130531083252.GA1072@serenity.lan>

```
On 31 May 2013 09:32, John Keeping <john@keeping.me.uk> wrote:
> On Fri, May 31, 2013 at 09:14:49AM +0100, Alex Bennée wrote:
>> On 30 May 2013 20:30, John Keeping <john@keeping.me.uk> wrote:
>> > On Thu, May 30, 2013 at 06:21:55PM +0200, Thomas Rast wrote:
>> >> Alex Bennée <kernel-hacker@bennee.com> writes:
>> >>
>> >> > On 30 May 2013 16:33, Thomas Rast <trast@inf.ethz.ch> wrote:
>> >> >> Alex Bennée <kernel-hacker@bennee.com> writes:
>> > <snip>
>> >> > Will it be loading the blob for every commit it traverses or just ones that hit
>> >> > a tag? Why does it need to load the blob at all? Surely the commit
>> >> > tree state doesn't
>> >> > need to be walked down?
>> >>
>> >> No, my theory is that you tagged *the blobs*.  Git supports this.
>>
>> Wait is this the difference between annotated and non-annotated tags?
>> I thought a non-annotated just acted like references to a particular
>> tree state?
>
> No, this is something slightly different.  In Git there are four types
> of object: tag, commit, tree and blob.  When you have a heavyweight tag,
> the tag reference points at a tag object (which in turn points at
> another object).  With a lightweight tag, the tag reference typically
> points at a commit object.

I think this is the case in my repo.

> However, there is no restriction that says that a tag object must point
> to a commit or that a lightweight tag must point at a commit - it is
> equally possible to point directly at a tree or a blob (although a lot
> less common).
>
> Thomas is suggesting that you might have a tag that does not point at a
> commit but instead points to a blob object.

It's looking like I just have some very heavy commits. One data point
I probably should have mentioned at the beginning is this was a
converted CVS repo and I'm wondering if some of the artifacts that
introduced has contributed to this.

>> > You can see if that is the case by doing something like this:
>> >
>> >     eval $(git for-each-ref --shell --format '
>> >         test $(git cat-file -t %(objectname)^{}) = commit ||
>> >         echo %(refname);')
>> >
>> > That will print out the name of any ref that doesn't point at a
>> > commit.
>>
>> Hmm that didn't seem to work.
>
> You mean there was no output?  In that case it's likely that all your
> references do indeed point at commits.

Correct.

>
>>                               But looking at the output by hand I
>> certainly have a mix of tags that are commits vs tags:
>>
>>
>> 09:08 ajb@sloy/x86_64 [work.git] >git for-each-ref | grep "refs/tags"
>> | grep "commit" | wc -l
>> 1345
>> 09:12 ajb@sloy/x86_64 [work.git] >git for-each-ref | grep "refs/tags"
>> | grep -v "commit" | wc -l
>> 66
>
> This means that you have 1345 lightweight tags and 66 heavyweight tags,
> assuming that all of the lines that don't say "commit" do say "tag".

Yep all commits and tags, nothing else

> By the way, I don't remember if you said which version of Git you're
> using.  If it's an older version then it's possible that something has
> changed.

I'm running the GIT stable PPA:

09:38 ajb@sloy/x86_64 [work.git] >git --version
git version 1.8.3

Although I have also tested with the latest git.git maint. I'm happy
to try master if it's likely to have changed.

-- 
Alex, homepage: http://www.bennee.com/~alex/

```

## John Keeping, 2013-05-31 08:59

Subject: Re: Poor performance of git describe in big repos
Message-ID: <20130531085959.GB1072@serenity.lan>
URL: https://gitlist.dev/e/20130531085959.GB1072%40serenity.lan
In-Reply-To: <CAJ-05NNgVPukJchskVv9oL7-9p+txC0g_SXfHne-mwF327Q_3Q@mail.gmail.com>

```
On Fri, May 31, 2013 at 09:49:57AM +0100, Alex Bennée wrote:
> On 31 May 2013 09:32, John Keeping <john@keeping.me.uk> wrote:
> > Thomas is suggesting that you might have a tag that does not point at a
> > commit but instead points to a blob object.
> 
> It's looking like I just have some very heavy commits. One data point
> I probably should have mentioned at the beginning is this was a
> converted CVS repo and I'm wondering if some of the artifacts that
> introduced has contributed to this.

You can try another for-each-ref invocation to see if that's the case:

    eval $(git for-each-ref --format 'printf "%s %s\n" \
        $(git cat-file -s %(objectname)) %(refname);') | sort -n

That will print the size of each object followed by the ref that points
to it, sorted by size.

> I'm running the GIT stable PPA:
> 
> 09:38 ajb@sloy/x86_64 [work.git] >git --version
> git version 1.8.3
> 
> Although I have also tested with the latest git.git maint. I'm happy
> to try master if it's likely to have changed.

master's still very close to 1.8.3 at the moment, so I don't think that
will make a difference.

```

## Alex Bennée, 2013-05-31 09:57

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CAJ-05NN8cARpPTnsCfHt3kY6gTnhZ=Vq55EzqxWBV_3ju-oczQ@mail.gmail.com>
URL: https://gitlist.dev/e/CAJ-05NN8cARpPTnsCfHt3kY6gTnhZ%3DVq55EzqxWBV_3ju-oczQ%40mail.gmail.com
In-Reply-To: <87y5av4jvj.fsf@linux-k42r.v.cablecom.net>

```
On 31 May 2013 09:46, Thomas Rast <trast@inf.ethz.ch> wrote:
> Alex Bennée <kernel-hacker@bennee.com> writes:
>
>> I think you are right. I was brave (well I assumed the tags would come
>> back from the upstream repo) and ran:
>>
>> git for-each-ref | grep "refs/tags" | grep "commit" | cut -d '/' -f 3
>> | xargs git tag -d
>
> So that deleted all unannotated tags pointing at commits, and then it
> was fast.  Curious.
>
>> However I have some big commits it seems:
>>
>> 09:37 ajb@sloy/x86_64 [work.git] >(git for-each-ref | grep ' commit' |
>> cut -d\  -f1 | xargs -n1 git cat-file commit) | wc -c
>> 1147231984
>
> How many unique entries are there in that list, i.e., what does
>
>   git for-each-ref | grep ' commit' | cut -d\  -f1 | sort -u | wc -l

09:49 ajb@sloy/x86_64 [work.git] >git for-each-ref | grep ' commit' |
cut -d\  -f1 | sort -u | wc -l
1508

> say?  Perhaps you can also find the biggest commit, e.g. like so:
>
>   git for-each-ref | grep ' commit' | cut -d\  -f1 |
>   while read sha; do git cat-file commit $sha | wc -c; done |
>   sort -n

Yeah there is a range from a few hundred bytes to a large number of 3M
commits. I guess I need to identify which commits they are and remove
the tags or convert them to annotated reference tags.

> However, if that turns out to be the culprit, it's not fixable
> currently[1].  Having commits with insanely long messages is just, well,
> insane.
>
>

> [1]  unless we do a major rework of the loading infrastructure, so that
> we can teach it to load only the beginning of a commit as long as we are
> only interested in parents and such

I'll do a bit of scripting to dig into the nature of these
uber-commits and try and work out how they cam about. I suspect they
are simply start of branch states in our broken and disparate history.

I'll get back to you once I've dug a little deeper.

>
> --
> Thomas Rast
> trast@{inf,student}.ethz.ch



-- 
Alex, homepage: http://www.bennee.com/~alex/

```

## Thomas Rast, 2013-05-31 10:27

Subject: Re: Poor performance of git describe in big repos
Message-ID: <87txlj30n4.fsf@linux-k42r.v.cablecom.net>
URL: https://gitlist.dev/e/87txlj30n4.fsf%40linux-k42r.v.cablecom.net
In-Reply-To: <87y5av4jvj.fsf@linux-k42r.v.cablecom.net>

```
Thomas Rast <trast@inf.ethz.ch> writes:

> However, if that turns out to be the culprit, it's not fixable
> currently[1].  Having commits with insanely long messages is just, well,
> insane.
>
> [1]  unless we do a major rework of the loading infrastructure, so that
> we can teach it to load only the beginning of a commit as long as we are
> only interested in parents and such

Actually, Peff, doesn't your commit parent/tree pointer caching give us
this for free?

-- 
Thomas Rast
trast@{inf,student}.ethz.ch

```

## Jeff King, 2013-05-31 16:17

Subject: Re: Poor performance of git describe in big repos
Message-ID: <20130531161710.GB1365@sigill.intra.peff.net>
URL: https://gitlist.dev/e/20130531161710.GB1365%40sigill.intra.peff.net
In-Reply-To: <87txlj30n4.fsf@linux-k42r.v.cablecom.net>

```
On Fri, May 31, 2013 at 12:27:11PM +0200, Thomas Rast wrote:

> Thomas Rast <trast@inf.ethz.ch> writes:
> 
> > However, if that turns out to be the culprit, it's not fixable
> > currently[1].  Having commits with insanely long messages is just, well,
> > insane.
> >
> > [1]  unless we do a major rework of the loading infrastructure, so that
> > we can teach it to load only the beginning of a commit as long as we are
> > only interested in parents and such
> 
> Actually, Peff, doesn't your commit parent/tree pointer caching give us
> this for free?

It does. You can test it from the "jk/metapacks" branch at
git://github.com/peff/git. After building, you'd need to do:

  $ git gc
  $ git metapack --all --commits

in the target repository. You can check that it's working because "git
rev-list --all --count" should be an order of magnitude faster. You may
need to add "save_commit_buffer = 0" in any commands you are checking,
though, as the optimization can only kick in if parse_commit does not
want to save the buffer as a side effect.

I also looked into trying to just read the beginning part of a commit[1],
but it turned out not to be all that much of an improvement.

-Peff

[1] http://article.gmane.org/gmane.comp.version-control.git/212301

```

## Alex Bennée, 2013-06-03 08:02

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CAJ-05NNgcj_pPer2Tw4HvKkVib7N1ZFo7rZOrR9z8NMV1WHQsQ@mail.gmail.com>
URL: https://gitlist.dev/e/CAJ-05NNgcj_pPer2Tw4HvKkVib7N1ZFo7rZOrR9z8NMV1WHQsQ%40mail.gmail.com
In-Reply-To: <CAJ-05NN8cARpPTnsCfHt3kY6gTnhZ=Vq55EzqxWBV_3ju-oczQ@mail.gmail.com>

```
On 31 May 2013 10:57, Alex Bennée <kernel-hacker@bennee.com> wrote:
> On 31 May 2013 09:46, Thomas Rast <trast@inf.ethz.ch> wrote:
>>
>> So that deleted all unannotated tags pointing at commits, and then it
>> was fast.  Curious.
>>
>> However, if that turns out to be the culprit, it's not fixable
>> currently[1].  Having commits with insanely long messages is just, well,
>> insane.
>>
>>
>> [1]  unless we do a major rework of the loading infrastructure, so that
>> we can teach it to load only the beginning of a commit as long as we are
>> only interested in parents and such
>
> I'll do a bit of scripting to dig into the nature of these
> uber-commits and try and work out how they cam about. I suspect they
> are simply start of branch states in our broken and disparate history.
>
> I'll get back to you once I've dug a little deeper.

So I wrote a little script [1] which I ran to remove all tags that did
not exist on any branches:

git-tag-cleaner.py -d no-branch

After a lot of churning:

17:26 ajb@sloy/x86_64 [work.git] >time /usr/bin/git --no-pager
describe --long --tags
ajb-build-test-5225-2-gdc0b771

real    0m0.799s
user    0m0.024s
sys     0m0.052s

So at least I can fix up my repo. All the big ones look at least as
though they were weird cvs2svn creations that exist to represent the
detached state of a strange CVS tag from the converted repository.
However it does raise one question.

Why is git attempting to parse a commit not on the DAG for the branch
I'm attempting to describe?

Anyway as I have a work around I'm going to do a slightly more
conservative clean of the repo with my script and move on.

[1] https://github.com/stsquad/git-tag-cleaner

-- 
Alex, homepage: http://www.bennee.com/~alex/

```

## Alex Bennée, 2013-06-03 08:39

Subject: Re: Poor performance of git describe in big repos
Message-ID: <CAJ-05NO2reGkboet1c2kYy0Y7xzkb9K45mTdCLq_AU7dp1OTNw@mail.gmail.com>
URL: https://gitlist.dev/e/CAJ-05NO2reGkboet1c2kYy0Y7xzkb9K45mTdCLq_AU7dp1OTNw%40mail.gmail.com
In-Reply-To: <20130531161710.GB1365@sigill.intra.peff.net>

```
On 31 May 2013 17:17, Jeff King <peff@peff.net> wrote:
> On Fri, May 31, 2013 at 12:27:11PM +0200, Thomas Rast wrote:
>
>> Thomas Rast <trast@inf.ethz.ch> writes:
>>
>> > However, if that turns out to be the culprit, it's not fixable
>> > currently[1].  Having commits with insanely long messages is just, well,
>> > insane.
>> >
>> > [1]  unless we do a major rework of the loading infrastructure, so that
>> > we can teach it to load only the beginning of a commit as long as we are
>> > only interested in parents and such
>>
>> Actually, Peff, doesn't your commit parent/tree pointer caching give us
>> this for free?
>
> It does. You can test it from the "jk/metapacks" branch at
> git://github.com/peff/git. After building, you'd need to do:
>
>   $ git gc
>   $ git metapack --all --commits
>
> in the target repository. You can check that it's working because "git
> rev-list --all --count" should be an order of magnitude faster. You may
> need to add "save_commit_buffer = 0" in any commands you are checking,
> though, as the optimization can only kick in if parse_commit does not
> want to save the buffer as a side effect.

Is this a command line argument? The tools don't seem to think so.

Anyway it seems to make a marginal difference to my case:

09:08 ajb@sloy/x86_64 [work.git] >time git --no-pager describe --long --tags
ajb-build-test-5225-2-gdc0b771

real    0m14.105s
user    0m12.409s
sys     0m1.660s
09:11 ajb@sloy/x86_64 [work.git] >git gc
Counting objects: 399436, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (110874/110874), done.
Writing objects: 100% (399436/399436), done.
Total 399436 (delta 281538), reused 398357 (delta 280493)
Checking connectivity: 399436, done.
09:12 ajb@sloy/x86_64 [work.git] >git metapack --all --commits
09:13 ajb@sloy/x86_64 [work.git] >time git --no-pager describe --long --tags
ajb-build-test-5225-2-gdc0b771

real    0m12.781s
user    0m11.669s
sys     0m1.080s
09:32 ajb@sloy/x86_64 [work.git] >time git --no-pager describe --long --tags
ajb-build-test-5225-2-gdc0b771

real    0m12.768s
user    0m11.817s
sys     0m0.908s
09:33 ajb@sloy/x86_64 [work.git] >time git --no-pager describe --long --tags
ajb-build-test-5225-2-gdc0b771

real    0m12.642s
user    0m11.705s
sys     0m0.904s


>
> I also looked into trying to just read the beginning part of a commit[1],
> but it turned out not to be all that much of an improvement.
>
> -Peff
>
> [1] http://article.gmane.org/gmane.comp.version-control.git/212301



-- 
Alex, homepage: http://www.bennee.com/~alex/

```

## Jeff King, 2013-06-03 14:49

Subject: Re: Poor performance of git describe in big repos
Message-ID: <20130603144907.GA5938@sigill.intra.peff.net>
URL: https://gitlist.dev/e/20130603144907.GA5938%40sigill.intra.peff.net
In-Reply-To: <CAJ-05NO2reGkboet1c2kYy0Y7xzkb9K45mTdCLq_AU7dp1OTNw@mail.gmail.com>

```
On Mon, Jun 03, 2013 at 09:39:21AM +0100, Alex Bennée wrote:

> > in the target repository. You can check that it's working because "git
> > rev-list --all --count" should be an order of magnitude faster. You may
> > need to add "save_commit_buffer = 0" in any commands you are checking,
> > though, as the optimization can only kick in if parse_commit does not
> > want to save the buffer as a side effect.
> 
> Is this a command line argument? The tools don't seem to think so.

If you mean the "save_commit_buffer = 0", no; I mean you would have to
insert it somewhere in builtin/$CMD.c, and then recompile. However,
git-describe already has it, so it should work.

> Anyway it seems to make a marginal difference to my case:

I get much better results:

  $ cd linux-2.6
  $ time git --no-pager describe --long --tags HEAD~800
  v3.5-6956-gaa0b3b2

  real    0m0.261s
  user    0m0.248s
  sys     0m0.012s

  $ git metapack --commits --all
  $ time git --no-pager describe --long --tags HEAD~800
  v3.5-6956-gaa0b3b2

  real    0m0.057s
  user    0m0.032s
  sys     0m0.024s

which implies that your time is being spent elsewhere. That topic
wouldn't avoid inflating tag objects from disk. Do you have really big
tag objects (or unannotated tags pointing to blobs)? What does:

  git for-each-ref --format='%(object)' refs/tags |
  git cat-file --batch-check |
  sort -k 3nr |
  head

say?

-Peff

```

## Junio C Hamano, 2013-06-03 16:32

Subject: Re: Poor performance of git describe in big repos
Message-ID: <7vfvwzi29f.fsf@alter.siamese.dyndns.org>
URL: https://gitlist.dev/e/7vfvwzi29f.fsf%40alter.siamese.dyndns.org
In-Reply-To: <CAJ-05NNgcj_pPer2Tw4HvKkVib7N1ZFo7rZOrR9z8NMV1WHQsQ@mail.gmail.com>

```
Alex Bennée <kernel-hacker@bennee.com> writes:

> Why is git attempting to parse a commit not on the DAG for the branch
> I'm attempting to describe?

I think that is because you need to parse the objects at the tip of
refs to see if they are on the DAG in the first place.

If there weren't any annotated tag, conceivably you could do without
parsing these objects.  You would:

 - First read the refs without parsing anything to learn the object
   name of the tips of refs;

 - Traverse the DAG, starting from the commit and notice when you
   see commits that are at the tips of refs you learned in the first
   step, arranging to stop when you found the "closest" tip.

But with annotated tags (and "git describe" is designed to be
primarily used with them; you would need "--tags" option to make it
notice unannotated tags), the object name you see sitting at the tip
will never appear during the DAG traversal.  You will only see
commits from the latter, so you would need to parse the tips to
learn what commits they refer to.

And of course, "then parse only annotated tags, without parsing
commits" would not work, because you wouldn't know what the object
is without looking at it ;-)

```

## Junio C Hamano, 2013-06-03 17:48

Subject: Re: Poor performance of git describe in big repos
Message-ID: <7v1u8jgk55.fsf@alter.siamese.dyndns.org>
URL: https://gitlist.dev/e/7v1u8jgk55.fsf%40alter.siamese.dyndns.org
In-Reply-To: <7vfvwzi29f.fsf@alter.siamese.dyndns.org>

```
Junio C Hamano <gitster@pobox.com> writes:

> Alex Bennée <kernel-hacker@bennee.com> writes:
>
>> Why is git attempting to parse a commit not on the DAG for the branch
>> I'm attempting to describe?
>
> I think that is because you need to parse the objects at the tip of
> refs to see if they are on the DAG in the first place.
>
> If there weren't any annotated tag, conceivably you could do without
> parsing these objects.  You would:
>
>  - First read the refs without parsing anything to learn the object
>    name of the tips of refs;
>
>  - Traverse the DAG, starting from the commit and notice when you
>    see commits that are at the tips of refs you learned in the first
>    step, arranging to stop when you found the "closest" tip.
>
> But with annotated tags (and "git describe" is designed to be
> primarily used with them; you would need "--tags" option to make it
> notice unannotated tags), the object name you see sitting at the tip
> will never appear during the DAG traversal.  You will only see
> commits from the latter, so you would need to parse the tips to
> learn what commits they refer to.
>
> And of course, "then parse only annotated tags, without parsing
> commits" would not work, because you wouldn't know what the object
> is without looking at it ;-)

Having said all that, with changes by Peff and Michael Haggerty
around f85354b5c7b8 (pack_one_ref(): use function peel_entry(),
2013-04-22), recent Git does not "parse" as many refs as it used to,
only to figure out what commit an annotated tag points at when your
refs are packed, so we may be a lot closer to the optimum than I
hinted by the above description.

```
