1
0
mirror of https://github.com/golang/go synced 2024-11-05 15:26:15 -07:00

syscall: simplify and optimize environment block creation on Windows

createEnvBlock currently allocates multiple times: at least one to
convert the slice of strings into a NULL separated slice of bytes, and
then again to encode it as UTF-16. The logic to do so is also quite
complex.

This CL simplifies the logic by allocating only once by encoding the
slice of strings into UTF-16 directly using utf16.AppendRune.

goos: windows
goarch: amd64
pkg: syscall
cpu: Intel(R) Core(TM) i7-10850H CPU @ 2.70GHz
                  │   old.txt    │               new.txt               │
                  │    sec/op    │   sec/op     vs base                │
CreateEnvBlock-12   37.92µ ± 24%   21.36µ ± 8%  -43.66% (p=0.000 n=10)

                  │    old.txt    │               new.txt                │
                  │     B/op      │     B/op      vs base                │
CreateEnvBlock-12   109.12Ki ± 0%   26.62Ki ± 0%  -75.60% (p=0.000 n=10)

                  │  old.txt   │              new.txt               │
                  │ allocs/op  │ allocs/op   vs base                │
CreateEnvBlock-12   4.000 ± 0%   1.000 ± 0%  -75.00% (p=0.000 n=10)

Change-Id: If35f62c3926b486d5253a9ae23a33b979b2f02c2
Reviewed-on: https://go-review.googlesource.com/c/go/+/531355
Reviewed-by: Bryan Mills <bcmills@google.com>
Run-TryBot: Quim Muntal <quimmuntal@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
qmuntal 2023-09-27 11:53:30 +02:00 committed by Quim Muntal
parent 6e866fea2b
commit 5351bcf822

View File

@ -118,11 +118,11 @@ func makeCmdLine(args []string) string {
// terminated strings followed by a nil. // terminated strings followed by a nil.
// Last bytes are two UCS-2 NULs, or four NUL bytes. // Last bytes are two UCS-2 NULs, or four NUL bytes.
// If any string contains a NUL, it returns (nil, EINVAL). // If any string contains a NUL, it returns (nil, EINVAL).
func createEnvBlock(envv []string) (*uint16, error) { func createEnvBlock(envv []string) ([]uint16, error) {
if len(envv) == 0 { if len(envv) == 0 {
return &utf16.Encode([]rune("\x00\x00"))[0], nil return utf16.Encode([]rune("\x00\x00")), nil
} }
length := 0 var length int
for _, s := range envv { for _, s := range envv {
if bytealg.IndexByteString(s, 0) != -1 { if bytealg.IndexByteString(s, 0) != -1 {
return nil, EINVAL return nil, EINVAL
@ -131,17 +131,15 @@ func createEnvBlock(envv []string) (*uint16, error) {
} }
length += 1 length += 1
b := make([]byte, length) b := make([]uint16, 0, length)
i := 0
for _, s := range envv { for _, s := range envv {
l := len(s) for _, c := range s {
copy(b[i:i+l], []byte(s)) b = utf16.AppendRune(b, c)
copy(b[i+l:i+l+1], []byte{0}) }
i = i + l + 1 b = utf16.AppendRune(b, 0)
} }
copy(b[i:i+1], []byte{0}) b = utf16.AppendRune(b, 0)
return b, nil
return &utf16.Encode([]rune(string(b)))[0], nil
} }
func CloseOnExec(fd Handle) { func CloseOnExec(fd Handle) {
@ -387,9 +385,9 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
pi := new(ProcessInformation) pi := new(ProcessInformation)
flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT | _EXTENDED_STARTUPINFO_PRESENT flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT | _EXTENDED_STARTUPINFO_PRESENT
if sys.Token != 0 { if sys.Token != 0 {
err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, envBlock, dirp, &si.StartupInfo, pi) err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, &envBlock[0], dirp, &si.StartupInfo, pi)
} else { } else {
err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, envBlock, dirp, &si.StartupInfo, pi) err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, willInheritHandles, flags, &envBlock[0], dirp, &si.StartupInfo, pi)
} }
if err != nil { if err != nil {
return 0, 0, err return 0, 0, err