Fossil Forum

danshearer 2 days, 11 hours ago

Post: Big wins in fossil caching

I found some fixes that appear to give between 20% and 70% speedups for each of fossil rebuild, fossil test-integrity and fossil export, depending on command, workload and system size. If you'd like to contribute to the tuning by trying out numbers on your systems, you can try this:

  • check out the branch cache-speedups and build it
  • cd cache-speedups ; cp /src/path/sqlite.fossil .
  • run cache-speedups/export.sh, rebuild.sh and test-integrity.sh

These print time results, based on three numbers at the top of each script. I get the best results from the middle number in each case, but if people try with different repos and systems there will probably be different sweet spots to report.

If someone has resources to spare, it would be great to try importing the gcc compiler collection and then running these scripts on it. This repo is my personal rule of thumb for maximum comfortable Fossil repo size.

What's going on here

I need Fossil to be faster, because I do a lot of correctness and performance testing when running LMDB and encryption backends and the test cycles seem to take forever :) So I considered caching. We had some wins in libfossil by looking at caching, which ended up finding a cache design that wasn't working at all, which was an even bigger win. libfossil often copies Fossil, and in this case I wondered about those same hardcoded values. Along the way I noticed that we don't switch on SQLite caching at all at least in one important case.

This branch has two small patches:

  1. Call PRAGMA cache_size in src/db.c. With feedback from these test scripts we can find a sensible default, and then make it a global setting.

  2. Set the maximum number of items and the maximum size of the artifact cache in src/content.c. The maximum size just needs to be high enough to be out of the way, we are really just varying the number of items in the test scripts, and it makes a big difference.

Item 1 will probably quickly become a committable long-term fix.

Item 2 brings up lots of questions about caching. Perhaps we could choose better hard-coded numbers and commit them immediately (say for the next Fossil release or something), and then improve the cache design over time. For example, it's an LRU but it always sits around the maximum cache size, never growing or shrinking. The reason its a good idea in the first place is because Fossil stores artifacts as deltas against other artifacts, so it makes sense that content_get() caches as it walks back up the tree. But why just every 8th artifact? These design questions require a deep understanding of how Fossil works, which I don't have. And there is considerable overlap with parts of libfossil, so there's probably some cross-checking work that can happen between the projects on this.

Discuss!

--
Dan Shearer
[email protected] / https://shearer.org

stephan 2 days, 11 hours ago

But why just every 8th artifact?

Funnily enough... i had the same question when adding the content cache to libfossil (it was, for years, just a useless placeholder saying "fossil does this, do we need to?").

After much experimentation i got best results, overall, with that every-8th-artifact approach. Why, i have no idea, but it works well in practice. As proof i offer only this comment from libfossil's counterpart of content_get():

        /*
           2021-03-24: in a debug build, running:

           f-parseparty -t c -c -q

           (i.e.: parse and crosslink all checkin artifacts)

           on the libfossil repo with 2003 checkins takes:

           10.5s without this cache
           5.2s with this cache

           We shave another 0.5s if we always cache instead of using
           this mysterious (mx-n)%8 heuristic.

           Later testing with f-rebuild gives much different results:
           the (mx-n)%8 heuristic provides the best results of the
           variations tested, including always caching.
        */

Shrug.

danshearer 2 days, 9 hours ago

After much experimentation i got best results, overall, with that every-8th-artifact approach.

Did you experiment with repos having different average chain lengths? The Fossil and SQLite repos have deep chains, and GCC almost certainly even deeper, but many do not. By "chain" I mean how many deltas are applied to a given base artifact. I suspect this might be where numbers other than 8 could be optimal.

--
Dan Shearer
[email protected] / https://shearer.org

stephan 2 days, 8 hours ago

Did you experiment with repos having ...

No - only that one repo in its then-current state. At the time i don't recall having been conscious of how deep delta chains got but have since seen chains 500+ long. (Which, frankly, surprised me - my expectation was to see a full "snapshot" copy retained every Nth levels (20? 50?) if for no other reason than mpg does that with "reference frames".)

danshearer 22 hours, 17 minutes ago

Turns out the artifact cache fix also helps fossil git export by a large amount. Unsurprising, but it only just occurred to me to test.

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button