git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Trac+Git: rev-list with pathspec performance?

From
SBStephen Bash <bash@genarts.com>
Date
Oct 4, 2010, 20:21 UTC
Message-ID
<27777603.436995.1286223710787.JavaMail.root@mail.hq.genarts.com>
In-Reply-To
<13399611.436896.1286218134223.JavaMail.root@mail.hq.genarts.com>
Hi all-
I'm trying to improve the performance of Trac [1], the GitPlugin for Trac[2], and Git.  Trac is being extremely sluggish while browsing source, and profiling revealed the majority of the time was the GitPlugin calling git rev-list.  When I directly entered the rev-list calls from the shell, I found Git itself was performing slower than I would expect...
The bottleneck is while Trac is populating the "last change to file" column in the source browser (see the "rev" column of [3] for an *cough* SVN *cough* example).  This concept of "find the last change to a file" was discussed a few weeks ago [4], but unlike that thread, the GitPlugin is simply calling
   git rev-list --max-count=1 branchName -- fileName
for each file in the current directory.  For files modified recently this is very fast (thousandths of a second), but for older files rev-list takes a long time to come up with an answer (~2-3 seconds on our server).  
I created a script [5] that reproduces the rev-list behavior with 10k commits (ours is about 17k) and 500 files (we peaked at just under 600 in the root of our repo -- that's been cleaned up in the current version, but the history is still there).  On our system the test script fast case is:
   real 0m0.003s, user 0m0.000s, sys 0m0.010s
The slow case is
   real 0m1.072s, user 0m1.050s, sys 0m0.000s
If I naively profile Git I find the worst time offender is tree_entry_interesting with over 10 million calls in the slow case.  That seems high (even every commit, every file would be 500*10000=5 million), but I don't know anything about the actual search algorithm.
Is there anything obvious I can do about this performance bottleneck or is it just the nature of our repository?  Is there potentially a bug in how rev-list works with a pathspec?  Is there a more efficient way to obtain the last commit that changed each file in a directory?  (A hack I'm currently testing is just always return the current commit when Trac asks for the last change... that speeds things up but changes the user experience)

Thanks, Stephen

References: [1] http://trac.edgewall.org [2] http://trac-hacks.org/wiki/GitPlugin [3] http://trac.edgewall.org/browser/trunk [4] http://article.gmane.org/gmane.comp.version-control.git/150183/ [5] #!/bin/bash

git init big-repo
cd big-repo
touch foo
touch bar
for ii in {1..500}
do
   # create some files for background noise
   touch $ii
done
git add .
git commit -qm "initial import"
for ii in {1..10000}
do
   echo "Creating commit $ii"
   echo $ii >> foo
   git add foo
   git commit -qm "simple change $ii"
   if [ $(( $ii % 250 )) == 0 ]
   then
      echo "Running git gc ($ii)"
      git gc --quiet
   fi
done

# Fast case (last change is close to HEAD) echo "git rev-list --max-count=1 HEAD -- foo ..." time git rev-list --max-count=1 HEAD -- foo

# Slow case (last change is long before HEAD) echo "git rev-list --max-count=1 HEAD -- bar ..." time git rev-list --max-count=1 HEAD -- bar

cd ..
#rm -rf big-repo
Next: Jonathan Nieder
Message 1 of 6 in “Trac+Git: rev-list with pathspec performance?”
  1. Stephen BashOct 4, 2010
  2. Jonathan NiederOct 4, 2010
  3. Jakub NarebskiOct 5, 2010
  4. Stephen BashOct 6, 2010
  5. Stephen BashOct 7, 2010
  6. Jakub NarebskiOct 7, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.