From 4fb900e9ca1f08c57b074e7bf6a7eab90b92c898 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Sun, 3 Mar 2019 17:02:14 -0800 Subject: [PATCH] internal/poll: copy and use errnoErr to avoid allocations MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Converting a syscall.Errno to an interface is a significant source of allocations in os/exec. Elsewhere in the tree, we have pre-allocated errors for common errno values. Use the same trick here. This CL makes yet another copy of this code. The problem is that there isn't really a great place to share it. The existing copies are in: cmd/vendor/golang.org/x/sys/unix cmd/vendor/golang.org/x/sys/windows cmd/vendor/golang.org/x/sys/windows/registry internal/syscall/windows internal/syscall/windows/registry syscall internal/poll can't import from cmd/vendor, and cmd/vendor can't import from internal/*, so we can ignore cmd/vendor. We could put the unix version in internal/syscall/unix and then have a platform-independent wrapper in internal/syscall. But syscall couldn't use it; internal/syscall/* depends on syscall. So that only allows code re-use with internal/syscall/windows/*. We could create a new very low level internal package, internal/errno. But syscall couldn't use it, because it has to import syscall to get access to syscall.Errno. So that only allows code re-use with internal/syscall/windows/*. It's not clear that that any of these options pulls its weight. The obvious and "correct" place for this is syscall. But we can't export syscall's version, because package syscall is frozen. So just copy the code. There's not much of it. name old alloc/op new alloc/op delta ExecHostname-8 6.15kB ± 0% 6.13kB ± 0% -0.38% (p=0.000 n=20+19) name old allocs/op new allocs/op delta ExecHostname-8 34.0 ± 0% 31.0 ± 0% -8.82% (p=0.000 n=20+20) Fixes #30535 Change-Id: Idd31c7cced6e15387acc698ffc011e1b7b479903 Reviewed-on: https://go-review.googlesource.com/c/164971 Run-TryBot: Josh Bleecher Snyder Reviewed-by: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/internal/poll/errno_unix.go | 33 ++++++++++++++++++++++++++++ src/internal/poll/errno_windows.go | 31 ++++++++++++++++++++++++++ src/internal/poll/fd_poll_runtime.go | 2 +- 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/internal/poll/errno_unix.go create mode 100644 src/internal/poll/errno_windows.go diff --git a/src/internal/poll/errno_unix.go b/src/internal/poll/errno_unix.go new file mode 100644 index 0000000000..0b23fc3210 --- /dev/null +++ b/src/internal/poll/errno_unix.go @@ -0,0 +1,33 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris + +package poll + +import "syscall" + +// Do the interface allocations only once for common +// Errno values. +var ( + errEAGAIN error = syscall.EAGAIN + errEINVAL error = syscall.EINVAL + errENOENT error = syscall.ENOENT +) + +// errnoErr returns common boxed Errno values, to prevent +// allocations at runtime. +func errnoErr(e syscall.Errno) error { + switch e { + case 0: + return nil + case syscall.EAGAIN: + return errEAGAIN + case syscall.EINVAL: + return errEINVAL + case syscall.ENOENT: + return errENOENT + } + return e +} diff --git a/src/internal/poll/errno_windows.go b/src/internal/poll/errno_windows.go new file mode 100644 index 0000000000..e3bddb4bb2 --- /dev/null +++ b/src/internal/poll/errno_windows.go @@ -0,0 +1,31 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build windows + +package poll + +import "syscall" + +// Do the interface allocations only once for common +// Errno values. + +var ( + errERROR_IO_PENDING error = syscall.Errno(syscall.ERROR_IO_PENDING) +) + +// ErrnoErr returns common boxed Errno values, to prevent +// allocations at runtime. +func errnoErr(e syscall.Errno) error { + switch e { + case 0: + return nil + case syscall.ERROR_IO_PENDING: + return errERROR_IO_PENDING + } + // TODO: add more here, after collecting data on the common + // error values see on Windows. (perhaps when running + // all.bat?) + return e +} diff --git a/src/internal/poll/fd_poll_runtime.go b/src/internal/poll/fd_poll_runtime.go index 687f702556..2932615d85 100644 --- a/src/internal/poll/fd_poll_runtime.go +++ b/src/internal/poll/fd_poll_runtime.go @@ -42,7 +42,7 @@ func (pd *pollDesc) init(fd *FD) error { runtime_pollUnblock(ctx) runtime_pollClose(ctx) } - return syscall.Errno(errno) + return errnoErr(syscall.Errno(errno)) } pd.runtimeCtx = ctx return nil -- 2.50.0