git/odb/pack: prevent unnecessary runtime.memmove
Running 'go tool pprof' in CPU mode while Git LFS is running a migration against a large repository shows that 4.73% percent of the CPU time is spent in a function called 'runtime.memmove'. This is the function called when append()-ing to a slice causes the slice to grow, and memory occupied by the existing slice must be moved into a different contiguous group. ``` $ go tool pprof $(which git-lfs) git-lfs-1504820145.pprof dot File: git-lfs Type: cpu Time: Sep 7, 2017 at 5:35pm (EDT) Duration: 35.17s, Total samples = 30.42s (86.49%) Entering interactive mode (type "help" for commands, "o" for options) (pprof) list runtime\.memmove Total: 30.42s ROUTINE ======================== runtime.memmove in ... 1.44s 1.44s (flat, cum) 4.73% of Total . . 30:// void runtime·memmove(void*, void*, uintptr) . . 31:TEXT runtime·memmove(SB), NOSPLIT, $0-24 . . 32: ... ``` The implementation of 'runtime.memmove' is [fairly complex][1] and takes a relatively long amount of time to execute. Unfortunately, the 'patch' function in package 'git/odb/pack' is one of the smaller contributors: ``` (pprof) tree runtime\.memmove ----------------------------------------------------------+------------- 0.01s 100% | git/odb/pack.patch 0 0% 4.73% 0.01s 0.033% | runtime.growslice 0.01s 100% | runtime.gcAssistAlloc ----------------------------------------------------------+------------- ``` That said, the delta instructions do hint at the size of the patched result of applying 'delta' to 'base', which we can use to eagerly allocate a contiguous block of memory for. [1]: https://github.com/golang/go/blob/go1.9/src/runtime/memmove_amd64.s
This commit is contained in:
parent
304707f25d
commit
f4f8e76a5d
@ -52,13 +52,13 @@ func patch(base, delta []byte) ([]byte, error) {
|
||||
return nil, errors.New("git/odb/pack: invalid delta data")
|
||||
}
|
||||
|
||||
var dest []byte
|
||||
|
||||
// The remainder of the delta header contains the destination size, and
|
||||
// moves the "pos" offset to the correct position to begin the set of
|
||||
// delta instructions.
|
||||
destSize, pos := patchDeltaHeader(delta, pos)
|
||||
|
||||
dest := make([]byte, 0, destSize)
|
||||
|
||||
for pos < len(delta) {
|
||||
c := int(delta[pos])
|
||||
pos += 1
|
||||
|
Loading…
Reference in New Issue
Block a user