mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
dmz: use sendfile(2) when cloning /proc/self/exe
This results in a 5-20% speedup of dmz.CloneBinary(), depending on the machine. io.Copy: goos: linux goarch: amd64 pkg: github.com/opencontainers/runc/libcontainer/dmz cpu: Intel(R) Core(TM) i5-10210U CPU @ 1.60GHz BenchmarkCloneBinary BenchmarkCloneBinary-8 139 8075074 ns/op PASS ok github.com/opencontainers/runc/libcontainer/dmz 2.286s unix.Sendfile: goos: linux goarch: amd64 pkg: github.com/opencontainers/runc/libcontainer/dmz cpu: Intel(R) Core(TM) i5-10210U CPU @ 1.60GHz BenchmarkCloneBinary BenchmarkCloneBinary-8 192 6382121 ns/op PASS ok github.com/opencontainers/runc/libcontainer/dmz 2.415s Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
This commit is contained in:
@@ -5,6 +5,7 @@ package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
@@ -174,3 +175,42 @@ func ExecutableMemfd(comment string, flags int) (*os.File, error) {
|
||||
}
|
||||
return os.NewFile(uintptr(memfd), "/memfd:"+comment), nil
|
||||
}
|
||||
|
||||
// Copy is like io.Copy except it uses sendfile(2) if the source and sink are
|
||||
// both (*os.File) as an optimisation to make copies faster.
|
||||
func Copy(dst io.Writer, src io.Reader) (copied int64, err error) {
|
||||
dstFile, _ := dst.(*os.File)
|
||||
srcFile, _ := src.(*os.File)
|
||||
|
||||
if dstFile != nil && srcFile != nil {
|
||||
fi, err := srcFile.Stat()
|
||||
if err != nil {
|
||||
goto fallback
|
||||
}
|
||||
size := fi.Size()
|
||||
for size > 0 {
|
||||
n, err := unix.Sendfile(int(dstFile.Fd()), int(srcFile.Fd()), nil, int(size))
|
||||
if n > 0 {
|
||||
size -= int64(n)
|
||||
copied += int64(n)
|
||||
}
|
||||
if err == unix.EINTR {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
if copied == 0 {
|
||||
// If we haven't copied anything so far, we can safely just
|
||||
// fallback to io.Copy. We could always do the fallback but
|
||||
// it's safer to error out in the case of a partial copy
|
||||
// followed by an error (which should never happen).
|
||||
goto fallback
|
||||
}
|
||||
return copied, fmt.Errorf("partial sendfile copy: %w", err)
|
||||
}
|
||||
}
|
||||
return copied, nil
|
||||
}
|
||||
|
||||
fallback:
|
||||
return io.Copy(dst, src)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user