Skip to content

Commit 854349e

Browse files
committed
os/user: speed up Current on Windows
[This is a roll-forward of CL 597255, which had to be rolled back because it broke the windows-arm64 builder, whose current user display name is unavailable. This new CL fixes the issue by reintroducing the historical behavior of falling back to the user name instead of returning an error]. user.Current is slow on Windows sessions connected to an Active Directory domain. This is because it uses Windows APIs that do RPC calls to the domain controller, such as TranslateAccountW and NetUserGetInfo. This change speeds up user.Current by using the GetUserNameEx API instead, which is already optimized for retrieving the current user name in different formats. These are the improvements I see with the new implementation: goos: windows goarch: amd64 pkg: os/user cpu: Intel(R) Core(TM) i7-10850H CPU @ 2.70GHz │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ Current-12 501.8µ ± 7% 118.6µ ± 11% -76.36% (p=0.000 n=10) │ old.txt │ new.txt │ │ B/op │ B/op vs base │ Current-12 888.0 ± 0% 832.0 ± 0% -6.31% (p=0.000 n=10) │ old.txt │ new.txt │ │ allocs/op │ allocs/op vs base │ Current-12 15.00 ± 0% 11.00 ± 0% -26.67% (p=0.000 n=10) Updates #5298 Fixes #21867 Fixes #68312 Cq-Include-Trybots: luci.golang.try:gotip-windows-amd64-longtest,gotip-windows-arm64 Change-Id: Ib7f77086d389cccb9d91cb77ea688d438a0ee5fd Reviewed-on: https://go-review.googlesource.com/c/go/+/605135 Reviewed-by: Dmitri Shuralyov <[email protected]> Reviewed-by: Mauri de Souza Meneguzzo <[email protected]> Reviewed-by: Alex Brainman <[email protected]> Reviewed-by: Cherry Mui <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent fd985d2 commit 854349e

File tree

3 files changed

+36
-4
lines changed

3 files changed

+36
-4
lines changed

src/internal/syscall/windows/security_windows.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,22 @@ type UserInfo4 struct {
156156
//
157157
//go:linkname GetSystemDirectory
158158
func GetSystemDirectory() string // Implemented in runtime package.
159+
160+
// GetUserName retrieves the user name of the current thread
161+
// in the specified format.
162+
func GetUserName(format uint32) (string, error) {
163+
n := uint32(50)
164+
for {
165+
b := make([]uint16, n)
166+
e := syscall.GetUserNameEx(format, &b[0], &n)
167+
if e == nil {
168+
return syscall.UTF16ToString(b[:n]), nil
169+
}
170+
if e != syscall.ERROR_MORE_DATA {
171+
return "", e
172+
}
173+
if n <= uint32(len(b)) {
174+
return "", e
175+
}
176+
}
177+
}

src/os/user/lookup_windows.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,12 +232,24 @@ func current() (*User, error) {
232232
if e != nil {
233233
return e
234234
}
235-
username, domain, e := lookupUsernameAndDomain(u.User.Sid)
235+
username, e := windows.GetUserName(syscall.NameSamCompatible)
236236
if e != nil {
237237
return e
238238
}
239-
usr, e = newUser(uid, gid, dir, username, domain)
240-
return e
239+
displayName, e := windows.GetUserName(syscall.NameDisplay)
240+
if e != nil {
241+
// Historically, the username is used as fallback
242+
// when the display name can't be retrieved.
243+
displayName = username
244+
}
245+
usr = &User{
246+
Uid: uid,
247+
Gid: gid,
248+
Username: username,
249+
Name: displayName,
250+
HomeDir: dir,
251+
}
252+
return nil
241253
})
242254
return usr, err
243255
}

src/os/user/user_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ func TestCurrent(t *testing.T) {
4545
}
4646

4747
func BenchmarkCurrent(b *testing.B) {
48+
// Benchmark current instead of Current because Current caches the result.
4849
for i := 0; i < b.N; i++ {
49-
Current()
50+
current()
5051
}
5152
}
5253

0 commit comments

Comments
 (0)