perf(ermitegit): re-route the readers with the numbers of ermite-git 5228465
- commit
- 7b4c45664e9be3bb8985fcd5fe272d59e4f0e8a0
- author
- brice · · 2026-10-11 01:51 UTC
- parent
- 127d960
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +112 -38
M internal/adapters/ermitegit/ermitegit.go +3 -3
| @@ -23,9 +23,9 @@ | |||
| 23 | 23 | // commit-graph and notice a repository that stopped being supported: at once | |
| 24 | 24 | // when ermite itself wrote (the push and the maintenance tell it through | |
| 25 | 25 | // Refresh), and as a safety net at most once per Config.RefreshEvery for each | |
| 26 | - | // repository while it is read, by one reader at a time. A stat-based Refresh | |
| 27 | - | // is 20 µs and 34 allocations, too much to pay on every read of a method that | |
| 28 | - | // itself costs 20 µs. | |
| 26 | + | // repository while it is read, by one reader at a time. A Refresh | |
| 27 | + | // stats the files of the repository, too much to pay on every read of a | |
| 28 | + | // method that itself costs 2 µs. | |
| 29 | 29 | // | |
| 30 | 30 | // Memory: the cache of open repositories is bounded (LRU) and drops the ones | |
| 31 | 31 | // idle longer than Config.IdleTTL; each repository holds at most | |
| @@ -23,9 +23,9 @@ | |||||
| 23 | // commit-graph and notice a repository that stopped being supported: at once | 23 | // commit-graph and notice a repository that stopped being supported: at once | ||
| 24 | // when ermite itself wrote (the push and the maintenance tell it through | 24 | // when ermite itself wrote (the push and the maintenance tell it through | ||
| 25 | // Refresh), and as a safety net at most once per Config.RefreshEvery for each | 25 | // Refresh), and as a safety net at most once per Config.RefreshEvery for each | ||
| 26 | - | // repository while it is read, by one reader at a time. A stat-based Refresh | 26 | + | // repository while it is read, by one reader at a time. A Refresh |
| 27 | - | // is 20 µs and 34 allocations, too much to pay on every read of a method that | 27 | + | // stats the files of the repository, too much to pay on every read of a |
| 28 | - | // itself costs 20 µs. | 28 | + | // method that itself costs 2 µs. |
| 29 | // | 29 | // | ||
| 30 | // Memory: the cache of open repositories is bounded (LRU) and drops the ones | 30 | // Memory: the cache of open repositories is bounded (LRU) and drops the ones | ||
| 31 | // idle longer than Config.IdleTTL; each repository holds at most | 31 | // idle longer than Config.IdleTTL; each repository holds at most | ||
M internal/adapters/ermitegit/routes.go +109 -35
| @@ -4,47 +4,121 @@ package ermitegit | |||
| 4 | 4 | ||
| 5 | 5 | // DefaultRoutes returns the routes of production. | |
| 6 | 6 | // | |
| 7 | - | // A method is routed to ermite-git only when it passes the shared conformance | |
| 8 | - | // table (TestConformance, TestCompareWithCLI) and its benchmark beats the CLI | |
| 9 | - | // adapter in time AND in allocations, on the generated fixture and on lazygit | |
| 10 | - | // (BenchmarkRepoReader, ERMITE_GIT_BENCH_REPO). A method that does not stays | |
| 11 | - | // on the CLI, with the numbers that decided it. GetCommit is not routable: the | |
| 7 | + | // The rule: a method is routed to ermite-git only when it passes the shared | |
| 8 | + | // conformance table (TestConformance, TestCompareWithCLI) and its benchmark | |
| 9 | + | // beats the CLI adapter in time, in bytes AND in allocations per call, warm | |
| 10 | + | // AND cold, on the generated fixture AND on lazygit (BenchmarkRepoReader, | |
| 11 | + | // ERMITE_GIT_BENCH_REPO). Where a method has several shapes, every shape must | |
| 12 | + | // win: the constants GetTree, GetTreeLastCommits, ResolveRevisionAbbrev and | |
| 13 | + | // ListCommitsPath cover directories of any size and files of any history. A | |
| 14 | + | // method that does not win stays on the CLI. GetCommit is not routable: the | |
| 12 | 15 | // diff stays on git. | |
| 13 | 16 | // | |
| 14 | - | // The numbers are the median of three runs of `go test -bench RepoReader | |
| 15 | - | // -benchmem` on an AMD Ryzen 9 7900X3D, git 2.56, ermite-git ea9bcf1, as | |
| 16 | - | // "time / allocations per call", CLI against ermite-git. The fixture has 220 | |
| 17 | - | // commits, 8 directories of 40 files and a 10 MiB blob; lazygit has 7,550 | |
| 18 | - | // commits. Only the allocations of the Go process are counted, which favours | |
| 19 | - | // the CLI (its work happens in git processes). | |
| 17 | + | // Warm is a repository that is open; cold closes it before every call, the | |
| 18 | + | // price of the first read after the idle TTL, an eviction or a restart (a | |
| 19 | + | // cold ermite-git call opens the packs and the commit-graph: about 65 µs and | |
| 20 | + | // 130 allocations before the call itself). The CLI keeps nothing open, so its | |
| 21 | + | // cold run is its warm run. Only the allocations of the Go process are | |
| 22 | + | // counted, which favours the CLI (its work happens in git processes). The | |
| 23 | + | // parallel runs (b.RunParallel) were also made: they agree with the warm runs | |
| 24 | + | // and widen the time gap. | |
| 20 | 25 | // | |
| 21 | - | // fixture lazygit | |
| 22 | - | // ListRefs 900 µs/126 → 29 µs/89 900 µs/89 → 20 µs/43 win | |
| 23 | - | // ResolveRevision branch 24 µs/19 → 5 µs/14 26 µs/19 → 5 µs/14 win | |
| 24 | - | // ResolveRevision full id 10 µs/22 → 2 µs/6 9 µs/22 → 2 µs/6 win | |
| 25 | - | // ResolveRevision abbrev 65 µs/31 → 12 µs/33 65 µs/31 → 13 µs/33 allocs +2 | |
| 26 | - | // ResolveRefPath 108 µs/59 → 20 µs/72 159 µs/79 → 28 µs/101 allocs +13 | |
| 27 | - | // GetTree dir 736 µs/141 → 26 µs/51 1.3 ms/1059 → 3.5 ms/2634 loses on lazygit | |
| 28 | - | // GetTree root 717 µs/114 → 14 µs/36 812 µs/167 → 50 µs/78 win | |
| 29 | - | // GetTree root+last 4.0 ms/1022 → 73 µs/139 20 ms/3084 → 6.2 ms/4470 allocs +45% | |
| 30 | - | // GetTree dir+last 5.3 ms/1452 → 176 µs/247 196 ms/17143 → 11 ms/8058 win | |
| 31 | - | // OpenBlob small 46 µs/25 → 17 µs/28 53 µs/25 → 29 µs/57 allocs +2.3x | |
| 32 | - | // OpenBlob 10 MiB 21 ms/64 → 49 ms/28 3.4 ms/64 → 5.6 ms/140 loses (inflate speed) | |
| 33 | - | // ListCommits page 1 1.0 ms/404 → 59 µs/149 1.3 ms/415 → 368 µs/265 win | |
| 34 | - | // ListCommits skip 5000 1.0 ms/404 → 74 µs/149 2.0 ms/404 → 433 µs/153 win | |
| 35 | - | // ListCommits -- file 1.6 ms/138 → 453 µs/355 12.7 ms/117 → 6.1 ms/6870 allocs +58x | |
| 36 | - | // ListCommits -- dir 1.3 ms/403 → 202 µs/239 6.6 ms/403 → 2.0 ms/1988 allocs +5x | |
| 26 | + | // The numbers are the median of six runs of `go test -bench RepoReader | |
| 27 | + | // -benchmem -benchtime 500ms` on an AMD Ryzen 9 7900X3D, git 2.56, ermite-git | |
| 28 | + | // 5228465, as "time bytes allocations per call", CLI against ermite-git (K and | |
| 29 | + | // M are KiB and MiB). The fixture has 220 commits, 8 directories of 40 files | |
| 30 | + | // and a 10 MiB blob; lazygit has 7,550 commits. "loses" names what the | |
| 31 | + | // library does not win: t time, b bytes, a allocations. | |
| 37 | 32 | // | |
| 38 | - | // Where a method has several shapes, every shape must win to be routed: the | |
| 39 | - | // constants GetTree, GetTreeLastCommits and ListCommitsPath cover directories | |
| 40 | - | // of any size and files of any history. The losses in allocations come from | |
| 41 | - | // the inflate of tree and commit objects (compress/zlib allocates an adler32 | |
| 42 | - | // digest and the flate tables on every Reset): once the library avoids that, | |
| 43 | - | // re-run the benchmark and flip the constants it wins. | |
| 33 | + | // shape repo mode cli ermite-git verdict | |
| 34 | + | // ListRefs fixture warm 905µs 116.3K 125 24µs 19.0K 73 win | |
| 35 | + | // ListRefs fixture cold 904µs 116.3K 125 88µs 35.2K 203 loses a | |
| 36 | + | // ListRefs lazygit warm 901µs 105.2K 88 15µs 2.2K 27 win | |
| 37 | + | // ListRefs lazygit cold 908µs 105.4K 88 88µs 14.2K 163 loses a | |
| 38 | + | // ResolveRevision/branch fixture warm 22µs 0.9K 19 4µs 0.4K 8 win | |
| 39 | + | // ResolveRevision/branch fixture cold 22µs 0.9K 19 68µs 16.6K 138 loses tba | |
| 40 | + | // ResolveRevision/branch lazygit warm 22µs 1.0K 19 4µs 0.5K 8 win | |
| 41 | + | // ResolveRevision/branch lazygit cold 23µs 1.0K 19 72µs 12.4K 144 loses tba | |
| 42 | + | // ResolveRevision/fullid fixture warm 9µs 1.3K 22 2µs 0.4K 6 win | |
| 43 | + | // ResolveRevision/fullid fixture cold 9µs 1.3K 22 65µs 16.6K 136 loses tba | |
| 44 | + | // ResolveRevision/fullid lazygit warm 9µs 1.3K 22 2µs 0.4K 6 win | |
| 45 | + | // ResolveRevision/fullid lazygit cold 9µs 1.3K 22 70µs 12.3K 142 loses tba | |
| 46 | + | // ResolveRevision/abbrev fixture warm 63µs 1.5K 31 9µs 0.7K 11 win | |
| 47 | + | // ResolveRevision/abbrev fixture cold 64µs 1.5K 31 71µs 16.8K 141 loses tba | |
| 48 | + | // ResolveRevision/abbrev lazygit warm 63µs 1.5K 31 9µs 0.6K 11 win | |
| 49 | + | // ResolveRevision/abbrev lazygit cold 63µs 1.5K 31 76µs 12.6K 147 loses tba | |
| 50 | + | // ResolveRefPath fixture warm 104µs 2.4K 59 15µs 0.8K 22 win | |
| 51 | + | // ResolveRefPath fixture cold 105µs 2.4K 59 78µs 17.0K 152 loses ba | |
| 52 | + | // ResolveRefPath lazygit warm 150µs 4.1K 79 22µs 1.4K 29 win | |
| 53 | + | // ResolveRefPath lazygit cold 148µs 4.1K 79 89µs 13.4K 165 loses ba | |
| 54 | + | // GetTree/root fixture warm 717µs 108.4K 114 13µs 5.8K 24 win | |
| 55 | + | // GetTree/root fixture cold 725µs 108.4K 114 78µs 22.4K 154 loses a | |
| 56 | + | // GetTree/root lazygit warm 827µs 121.4K 167 29µs 18.2K 56 win | |
| 57 | + | // GetTree/root lazygit cold 831µs 121.5K 167 376µs 1.6M 200 loses ba | |
| 58 | + | // GetTree/dir fixture warm 742µs 109.5K 141 16µs 9.2K 26 win | |
| 59 | + | // GetTree/dir fixture cold 745µs 109.5K 141 109µs 75.8K 158 loses a | |
| 60 | + | // GetTree/dir lazygit warm 1.4ms 267.9K 1058 193µs 318.4K 73 loses b | |
| 61 | + | // GetTree/dir lazygit cold 1.4ms 268.0K 1058 4.2ms 2.0M 2490 loses tba | |
| 62 | + | // GetTree/root+last fixture warm 4.0ms 1.2M 1023 70µs 108.3K 107 win | |
| 63 | + | // GetTree/root+last fixture cold 4.0ms 1.2M 1024 165µs 127.8K 249 win | |
| 64 | + | // GetTree/root+last lazygit warm 20.2ms 3.8M 3072 6.1ms 367.0K 510 win | |
| 65 | + | // GetTree/root+last lazygit cold 20.3ms 3.8M 3073 8.5ms 3.4M 4204 loses a | |
| 66 | + | // GetTree/dir+last fixture warm 5.3ms 1.8M 1454 190µs 166.1K 142 win | |
| 67 | + | // GetTree/dir+last fixture cold 5.4ms 1.8M 1455 316µs 247.6K 323 win | |
| 68 | + | // GetTree/dir+last lazygit warm 195.2ms 20.5M 17116 7.9ms 1.5M 855 win | |
| 69 | + | // GetTree/dir+last lazygit cold 195.9ms 20.5M 17107 14.8ms 5.1M 6989 win | |
| 70 | + | // OpenBlob/small fixture warm 46µs 6.1K 25 17µs 5.8K 14 win | |
| 71 | + | // OpenBlob/small fixture cold 47µs 6.1K 25 87µs 27.7K 147 loses tba | |
| 72 | + | // OpenBlob/small lazygit warm 51µs 5.4K 25 29µs 7.0K 42 loses ba | |
| 73 | + | // OpenBlob/small lazygit cold 50µs 5.4K 25 131µs 25.1K 184 loses tba | |
| 74 | + | // OpenBlob/largest fixture warm 21.4ms 69.7K 64 52.5ms 9.0K 13 loses t | |
| 75 | + | // OpenBlob/largest fixture cold 21.6ms 70.0K 64 51.4ms 26.2K 143 loses ta | |
| 76 | + | // OpenBlob/largest lazygit warm 3.3ms 69.9K 64 5.7ms 16.3K 123 loses ta | |
| 77 | + | // OpenBlob/largest lazygit cold 3.3ms 69.9K 64 5.8ms 31.6K 283 loses ta | |
| 78 | + | // ListCommits/page1 fixture warm 1.0ms 122.5K 404 61µs 19.1K 108 win | |
| 79 | + | // ListCommits/page1 fixture cold 1.0ms 122.5K 404 134µs 36.9K 244 win | |
| 80 | + | // ListCommits/page1 lazygit warm 1.3ms 157.2K 415 361µs 120.1K 224 win | |
| 81 | + | // ListCommits/page1 lazygit cold 1.3ms 157.2K 415 503µs 136.2K 377 win | |
| 82 | + | // ListCommits/deep fixture warm 1.0ms 122.1K 404 71µs 19.3K 108 win | |
| 83 | + | // ListCommits/deep fixture cold 1.0ms 122.1K 404 136µs 36.1K 238 win | |
| 84 | + | // ListCommits/deep lazygit warm 2.0ms 123.2K 404 424µs 23.9K 112 win | |
| 85 | + | // ListCommits/deep lazygit cold 2.0ms 123.2K 404 544µs 36.3K 248 win | |
| 86 | + | // ListCommits/path fixture warm 1.6ms 108.8K 138 443µs 25.4K 42 win | |
| 87 | + | // ListCommits/path fixture cold 1.6ms 108.9K 138 594µs 93.6K 360 loses a | |
| 88 | + | // ListCommits/path lazygit warm 12.9ms 108.7K 118 6.0ms 29.2K 58 win | |
| 89 | + | // ListCommits/path lazygit cold 12.8ms 107.7K 118 9.5ms 2.4M 6498 loses ba | |
| 90 | + | // ListCommits/dirpath fixture warm 1.3ms 123.0K 403 199µs 33.8K 113 win | |
| 91 | + | // ListCommits/dirpath fixture cold 1.3ms 123.0K 403 277µs 55.4K 268 win | |
| 92 | + | // ListCommits/dirpath lazygit warm 6.7ms 127.8K 403 2.0ms 50.2K 181 win | |
| 93 | + | // ListCommits/dirpath lazygit cold 6.7ms 127.8K 403 3.3ms 887.1K 2019 loses ba | |
| 94 | + | // | |
| 95 | + | // What decides the routes, with ermite-git 5228465 (zlib reader with a reused | |
| 96 | + | // adler32, header-size cache, Refresh and LookupRefID without allocations): | |
| 97 | + | // | |
| 98 | + | // - The warm runs all win but GetTree of a large directory on lazygit (time | |
| 99 | + | // is won since the zlib change, bytes are not) and OpenBlob, whose | |
| 100 | + | // allocations come from the inflate of a small blob and whose time is | |
| 101 | + | // lost for a 10 MiB blob (inflate speed: 52 ms against 21 ms). | |
| 102 | + | // - The cold runs lose in allocations for every method that does little | |
| 103 | + | // work after the open (ListRefs, GetTree, ResolveRefPath: 150 to 200 | |
| 104 | + | // against 60 to 140), and in time too for the ones that cost a few | |
| 105 | + | // microseconds warm (ResolveRevision: 65 µs against 9 to 63 µs). | |
| 106 | + | // - Only the history of a revision (ListCommits page 1 and deep) wins every | |
| 107 | + | // line, so it is the only method routed. GetTree dir+last also wins every | |
| 108 | + | // line, but GetTreeLastCommits covers GetTree root+last too, which loses | |
| 109 | + | // cold allocations on lazygit (4204 against 3073): it is the nearest | |
| 110 | + | // miss, and the first to flip once opening a repository allocates less. | |
| 111 | + | // - OpenBlob by size: below 1 MiB the small blob loses cold and, on lazygit, | |
| 112 | + | // warm bytes and allocations; above, it loses time. No size makes it win, | |
| 113 | + | // so there is no size-based route. | |
| 114 | + | // | |
| 115 | + | // Once opening a repository allocates less, re-run the benchmark and flip the | |
| 116 | + | // constants it wins: ListRefs, ResolveRefPath and ResolveRevision win warm by 4 | |
| 117 | + | // to 60 times in time. | |
| 44 | 118 | func DefaultRoutes() Routes { | |
| 45 | 119 | return Routes{ | |
| 46 | - | ListRefs: ErmiteGit, | |
| 47 | - | ResolveRevision: ErmiteGit, | |
| 120 | + | ListRefs: CLI, | |
| 121 | + | ResolveRevision: CLI, | |
| 48 | 122 | ResolveRevisionAbbrev: CLI, | |
| 49 | 123 | ResolveRefPath: CLI, | |
| 50 | 124 | GetTree: CLI, | |
| @@ -4,47 +4,121 @@ package ermitegit | |||||
| 4 | 4 | ||||
| 5 | // DefaultRoutes returns the routes of production. | 5 | // DefaultRoutes returns the routes of production. | ||
| 6 | // | 6 | // | ||
| 7 | - | // A method is routed to ermite-git only when it passes the shared conformance | 7 | + | // The rule: a method is routed to ermite-git only when it passes the shared |
| 8 | - | // table (TestConformance, TestCompareWithCLI) and its benchmark beats the CLI | 8 | + | // conformance table (TestConformance, TestCompareWithCLI) and its benchmark |
| 9 | - | // adapter in time AND in allocations, on the generated fixture and on lazygit | 9 | + | // beats the CLI adapter in time, in bytes AND in allocations per call, warm |
| 10 | - | // (BenchmarkRepoReader, ERMITE_GIT_BENCH_REPO). A method that does not stays | 10 | + | // AND cold, on the generated fixture AND on lazygit (BenchmarkRepoReader, |
| 11 | - | // on the CLI, with the numbers that decided it. GetCommit is not routable: the | 11 | + | // ERMITE_GIT_BENCH_REPO). Where a method has several shapes, every shape must |
| 12 | + | // win: the constants GetTree, GetTreeLastCommits, ResolveRevisionAbbrev and | |||
| 13 | + | // ListCommitsPath cover directories of any size and files of any history. A | |||
| 14 | + | // method that does not win stays on the CLI. GetCommit is not routable: the | |||
| 12 | // diff stays on git. | 15 | // diff stays on git. | ||
| 13 | // | 16 | // | ||
| 14 | - | // The numbers are the median of three runs of `go test -bench RepoReader | 17 | + | // Warm is a repository that is open; cold closes it before every call, the |
| 15 | - | // -benchmem` on an AMD Ryzen 9 7900X3D, git 2.56, ermite-git ea9bcf1, as | 18 | + | // price of the first read after the idle TTL, an eviction or a restart (a |
| 16 | - | // "time / allocations per call", CLI against ermite-git. The fixture has 220 | 19 | + | // cold ermite-git call opens the packs and the commit-graph: about 65 µs and |
| 17 | - | // commits, 8 directories of 40 files and a 10 MiB blob; lazygit has 7,550 | 20 | + | // 130 allocations before the call itself). The CLI keeps nothing open, so its |
| 18 | - | // commits. Only the allocations of the Go process are counted, which favours | 21 | + | // cold run is its warm run. Only the allocations of the Go process are |
| 19 | - | // the CLI (its work happens in git processes). | 22 | + | // counted, which favours the CLI (its work happens in git processes). The |
| 23 | + | // parallel runs (b.RunParallel) were also made: they agree with the warm runs | |||
| 24 | + | // and widen the time gap. | |||
| 20 | // | 25 | // | ||
| 21 | - | // fixture lazygit | 26 | + | // The numbers are the median of six runs of `go test -bench RepoReader |
| 22 | - | // ListRefs 900 µs/126 → 29 µs/89 900 µs/89 → 20 µs/43 win | 27 | + | // -benchmem -benchtime 500ms` on an AMD Ryzen 9 7900X3D, git 2.56, ermite-git |
| 23 | - | // ResolveRevision branch 24 µs/19 → 5 µs/14 26 µs/19 → 5 µs/14 win | 28 | + | // 5228465, as "time bytes allocations per call", CLI against ermite-git (K and |
| 24 | - | // ResolveRevision full id 10 µs/22 → 2 µs/6 9 µs/22 → 2 µs/6 win | 29 | + | // M are KiB and MiB). The fixture has 220 commits, 8 directories of 40 files |
| 25 | - | // ResolveRevision abbrev 65 µs/31 → 12 µs/33 65 µs/31 → 13 µs/33 allocs +2 | 30 | + | // and a 10 MiB blob; lazygit has 7,550 commits. "loses" names what the |
| 26 | - | // ResolveRefPath 108 µs/59 → 20 µs/72 159 µs/79 → 28 µs/101 allocs +13 | 31 | + | // library does not win: t time, b bytes, a allocations. |
| 27 | - | // GetTree dir 736 µs/141 → 26 µs/51 1.3 ms/1059 → 3.5 ms/2634 loses on lazygit | |||
| 28 | - | // GetTree root 717 µs/114 → 14 µs/36 812 µs/167 → 50 µs/78 win | |||
| 29 | - | // GetTree root+last 4.0 ms/1022 → 73 µs/139 20 ms/3084 → 6.2 ms/4470 allocs +45% | |||
| 30 | - | // GetTree dir+last 5.3 ms/1452 → 176 µs/247 196 ms/17143 → 11 ms/8058 win | |||
| 31 | - | // OpenBlob small 46 µs/25 → 17 µs/28 53 µs/25 → 29 µs/57 allocs +2.3x | |||
| 32 | - | // OpenBlob 10 MiB 21 ms/64 → 49 ms/28 3.4 ms/64 → 5.6 ms/140 loses (inflate speed) | |||
| 33 | - | // ListCommits page 1 1.0 ms/404 → 59 µs/149 1.3 ms/415 → 368 µs/265 win | |||
| 34 | - | // ListCommits skip 5000 1.0 ms/404 → 74 µs/149 2.0 ms/404 → 433 µs/153 win | |||
| 35 | - | // ListCommits -- file 1.6 ms/138 → 453 µs/355 12.7 ms/117 → 6.1 ms/6870 allocs +58x | |||
| 36 | - | // ListCommits -- dir 1.3 ms/403 → 202 µs/239 6.6 ms/403 → 2.0 ms/1988 allocs +5x | |||
| 37 | // | 32 | // | ||
| 38 | - | // Where a method has several shapes, every shape must win to be routed: the | 33 | + | // shape repo mode cli ermite-git verdict |
| 39 | - | // constants GetTree, GetTreeLastCommits and ListCommitsPath cover directories | 34 | + | // ListRefs fixture warm 905µs 116.3K 125 24µs 19.0K 73 win |
| 40 | - | // of any size and files of any history. The losses in allocations come from | 35 | + | // ListRefs fixture cold 904µs 116.3K 125 88µs 35.2K 203 loses a |
| 41 | - | // the inflate of tree and commit objects (compress/zlib allocates an adler32 | 36 | + | // ListRefs lazygit warm 901µs 105.2K 88 15µs 2.2K 27 win |
| 42 | - | // digest and the flate tables on every Reset): once the library avoids that, | 37 | + | // ListRefs lazygit cold 908µs 105.4K 88 88µs 14.2K 163 loses a |
| 43 | - | // re-run the benchmark and flip the constants it wins. | 38 | + | // ResolveRevision/branch fixture warm 22µs 0.9K 19 4µs 0.4K 8 win |
| 39 | + | // ResolveRevision/branch fixture cold 22µs 0.9K 19 68µs 16.6K 138 loses tba | |||
| 40 | + | // ResolveRevision/branch lazygit warm 22µs 1.0K 19 4µs 0.5K 8 win | |||
| 41 | + | // ResolveRevision/branch lazygit cold 23µs 1.0K 19 72µs 12.4K 144 loses tba | |||
| 42 | + | // ResolveRevision/fullid fixture warm 9µs 1.3K 22 2µs 0.4K 6 win | |||
| 43 | + | // ResolveRevision/fullid fixture cold 9µs 1.3K 22 65µs 16.6K 136 loses tba | |||
| 44 | + | // ResolveRevision/fullid lazygit warm 9µs 1.3K 22 2µs 0.4K 6 win | |||
| 45 | + | // ResolveRevision/fullid lazygit cold 9µs 1.3K 22 70µs 12.3K 142 loses tba | |||
| 46 | + | // ResolveRevision/abbrev fixture warm 63µs 1.5K 31 9µs 0.7K 11 win | |||
| 47 | + | // ResolveRevision/abbrev fixture cold 64µs 1.5K 31 71µs 16.8K 141 loses tba | |||
| 48 | + | // ResolveRevision/abbrev lazygit warm 63µs 1.5K 31 9µs 0.6K 11 win | |||
| 49 | + | // ResolveRevision/abbrev lazygit cold 63µs 1.5K 31 76µs 12.6K 147 loses tba | |||
| 50 | + | // ResolveRefPath fixture warm 104µs 2.4K 59 15µs 0.8K 22 win | |||
| 51 | + | // ResolveRefPath fixture cold 105µs 2.4K 59 78µs 17.0K 152 loses ba | |||
| 52 | + | // ResolveRefPath lazygit warm 150µs 4.1K 79 22µs 1.4K 29 win | |||
| 53 | + | // ResolveRefPath lazygit cold 148µs 4.1K 79 89µs 13.4K 165 loses ba | |||
| 54 | + | // GetTree/root fixture warm 717µs 108.4K 114 13µs 5.8K 24 win | |||
| 55 | + | // GetTree/root fixture cold 725µs 108.4K 114 78µs 22.4K 154 loses a | |||
| 56 | + | // GetTree/root lazygit warm 827µs 121.4K 167 29µs 18.2K 56 win | |||
| 57 | + | // GetTree/root lazygit cold 831µs 121.5K 167 376µs 1.6M 200 loses ba | |||
| 58 | + | // GetTree/dir fixture warm 742µs 109.5K 141 16µs 9.2K 26 win | |||
| 59 | + | // GetTree/dir fixture cold 745µs 109.5K 141 109µs 75.8K 158 loses a | |||
| 60 | + | // GetTree/dir lazygit warm 1.4ms 267.9K 1058 193µs 318.4K 73 loses b | |||
| 61 | + | // GetTree/dir lazygit cold 1.4ms 268.0K 1058 4.2ms 2.0M 2490 loses tba | |||
| 62 | + | // GetTree/root+last fixture warm 4.0ms 1.2M 1023 70µs 108.3K 107 win | |||
| 63 | + | // GetTree/root+last fixture cold 4.0ms 1.2M 1024 165µs 127.8K 249 win | |||
| 64 | + | // GetTree/root+last lazygit warm 20.2ms 3.8M 3072 6.1ms 367.0K 510 win | |||
| 65 | + | // GetTree/root+last lazygit cold 20.3ms 3.8M 3073 8.5ms 3.4M 4204 loses a | |||
| 66 | + | // GetTree/dir+last fixture warm 5.3ms 1.8M 1454 190µs 166.1K 142 win | |||
| 67 | + | // GetTree/dir+last fixture cold 5.4ms 1.8M 1455 316µs 247.6K 323 win | |||
| 68 | + | // GetTree/dir+last lazygit warm 195.2ms 20.5M 17116 7.9ms 1.5M 855 win | |||
| 69 | + | // GetTree/dir+last lazygit cold 195.9ms 20.5M 17107 14.8ms 5.1M 6989 win | |||
| 70 | + | // OpenBlob/small fixture warm 46µs 6.1K 25 17µs 5.8K 14 win | |||
| 71 | + | // OpenBlob/small fixture cold 47µs 6.1K 25 87µs 27.7K 147 loses tba | |||
| 72 | + | // OpenBlob/small lazygit warm 51µs 5.4K 25 29µs 7.0K 42 loses ba | |||
| 73 | + | // OpenBlob/small lazygit cold 50µs 5.4K 25 131µs 25.1K 184 loses tba | |||
| 74 | + | // OpenBlob/largest fixture warm 21.4ms 69.7K 64 52.5ms 9.0K 13 loses t | |||
| 75 | + | // OpenBlob/largest fixture cold 21.6ms 70.0K 64 51.4ms 26.2K 143 loses ta | |||
| 76 | + | // OpenBlob/largest lazygit warm 3.3ms 69.9K 64 5.7ms 16.3K 123 loses ta | |||
| 77 | + | // OpenBlob/largest lazygit cold 3.3ms 69.9K 64 5.8ms 31.6K 283 loses ta | |||
| 78 | + | // ListCommits/page1 fixture warm 1.0ms 122.5K 404 61µs 19.1K 108 win | |||
| 79 | + | // ListCommits/page1 fixture cold 1.0ms 122.5K 404 134µs 36.9K 244 win | |||
| 80 | + | // ListCommits/page1 lazygit warm 1.3ms 157.2K 415 361µs 120.1K 224 win | |||
| 81 | + | // ListCommits/page1 lazygit cold 1.3ms 157.2K 415 503µs 136.2K 377 win | |||
| 82 | + | // ListCommits/deep fixture warm 1.0ms 122.1K 404 71µs 19.3K 108 win | |||
| 83 | + | // ListCommits/deep fixture cold 1.0ms 122.1K 404 136µs 36.1K 238 win | |||
| 84 | + | // ListCommits/deep lazygit warm 2.0ms 123.2K 404 424µs 23.9K 112 win | |||
| 85 | + | // ListCommits/deep lazygit cold 2.0ms 123.2K 404 544µs 36.3K 248 win | |||
| 86 | + | // ListCommits/path fixture warm 1.6ms 108.8K 138 443µs 25.4K 42 win | |||
| 87 | + | // ListCommits/path fixture cold 1.6ms 108.9K 138 594µs 93.6K 360 loses a | |||
| 88 | + | // ListCommits/path lazygit warm 12.9ms 108.7K 118 6.0ms 29.2K 58 win | |||
| 89 | + | // ListCommits/path lazygit cold 12.8ms 107.7K 118 9.5ms 2.4M 6498 loses ba | |||
| 90 | + | // ListCommits/dirpath fixture warm 1.3ms 123.0K 403 199µs 33.8K 113 win | |||
| 91 | + | // ListCommits/dirpath fixture cold 1.3ms 123.0K 403 277µs 55.4K 268 win | |||
| 92 | + | // ListCommits/dirpath lazygit warm 6.7ms 127.8K 403 2.0ms 50.2K 181 win | |||
| 93 | + | // ListCommits/dirpath lazygit cold 6.7ms 127.8K 403 3.3ms 887.1K 2019 loses ba | |||
| 94 | + | // | |||
| 95 | + | // What decides the routes, with ermite-git 5228465 (zlib reader with a reused | |||
| 96 | + | // adler32, header-size cache, Refresh and LookupRefID without allocations): | |||
| 97 | + | // | |||
| 98 | + | // - The warm runs all win but GetTree of a large directory on lazygit (time | |||
| 99 | + | // is won since the zlib change, bytes are not) and OpenBlob, whose | |||
| 100 | + | // allocations come from the inflate of a small blob and whose time is | |||
| 101 | + | // lost for a 10 MiB blob (inflate speed: 52 ms against 21 ms). | |||
| 102 | + | // - The cold runs lose in allocations for every method that does little | |||
| 103 | + | // work after the open (ListRefs, GetTree, ResolveRefPath: 150 to 200 | |||
| 104 | + | // against 60 to 140), and in time too for the ones that cost a few | |||
| 105 | + | // microseconds warm (ResolveRevision: 65 µs against 9 to 63 µs). | |||
| 106 | + | // - Only the history of a revision (ListCommits page 1 and deep) wins every | |||
| 107 | + | // line, so it is the only method routed. GetTree dir+last also wins every | |||
| 108 | + | // line, but GetTreeLastCommits covers GetTree root+last too, which loses | |||
| 109 | + | // cold allocations on lazygit (4204 against 3073): it is the nearest | |||
| 110 | + | // miss, and the first to flip once opening a repository allocates less. | |||
| 111 | + | // - OpenBlob by size: below 1 MiB the small blob loses cold and, on lazygit, | |||
| 112 | + | // warm bytes and allocations; above, it loses time. No size makes it win, | |||
| 113 | + | // so there is no size-based route. | |||
| 114 | + | // | |||
| 115 | + | // Once opening a repository allocates less, re-run the benchmark and flip the | |||
| 116 | + | // constants it wins: ListRefs, ResolveRefPath and ResolveRevision win warm by 4 | |||
| 117 | + | // to 60 times in time. | |||
| 44 | func DefaultRoutes() Routes { | 118 | func DefaultRoutes() Routes { | ||
| 45 | return Routes{ | 119 | return Routes{ | ||
| 46 | - | ListRefs: ErmiteGit, | 120 | + | ListRefs: CLI, |
| 47 | - | ResolveRevision: ErmiteGit, | 121 | + | ResolveRevision: CLI, |
| 48 | ResolveRevisionAbbrev: CLI, | 122 | ResolveRevisionAbbrev: CLI, | ||
| 49 | ResolveRefPath: CLI, | 123 | ResolveRefPath: CLI, | ||
| 50 | GetTree: CLI, | 124 | GetTree: CLI, | ||