-
Notifications
You must be signed in to change notification settings - Fork 18k
os/user: user.Current() too slow on Windows #68312
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Related Issues
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.) |
cc @golang/windows |
I think we will need a proposal for an alternate API. See https://go.dev/s/proposal. |
Is it possible to adjust glog code to use something different from Alex |
It seems that the problem relies on the fact that user.Current() tries to make network calls to deal with active directory and domain lookup. I think a new alternate api would be a "local only" version of
Looks like kubernetes/klog (a fork of golang/glog) already applies a hack to bypass this https://github.com/kubernetes/klog/pull/123/files#diff-d01d6fd256d313607b4da3fdc0147234f5c8c4326b18044201af6da8a69ae36aR63-R84. |
Change https://go.dev/cl/597255 mentions this issue: |
I've taken a stab at this in https://go-review.googlesource.com/c/go/+/597255. It replaces the offending slow API calls with GetUserNameExW, which should be faster for the current user. @philwo could you give it a try? You can test test it compiling the Go toolchain at that CL by following these steps:
(Replace step 3 arguments with whatever build args you are using to build your app). |
Hi @qmuntal, Wow, thank you so much for quickly finding & implementing this fix. I've tested it on the corporate Windows machine that showed the performance issues. Your CL is a huge improvement for me in all cases. First, I compared that the output of Then I compared the performance:
So impressive! 🚀 For comparison, I also benchmarked the problematic workaround that some people use, which is to rely on the %USERNAME% environment variable on Windows. The performance as measured by the above benchmark is the same, so I can't think of a good reason to keep using %USERNAME%. I think this will not only result in an ecosystem-wide startup time improvement of Go tools running on Windows that were affected by this, but if we can get folks to revert their workarounds that depend on %USERNAME%, it will improve security as well, because...
😅 Thanks, |
Glad that it helped 😸, thanks for testing it. I'm afraid it is too late to merge the fix into go1.23 release branch, unless the @golang/release team thinks it worth the risk. |
Change https://go.dev/cl/604395 mentions this issue: |
This reverts CL 597255. Reason for revert: Broke windows/arm64 Fixes #68822. Updates #68312. Change-Id: I43efabad43c74045888bb62bd27522aeaba0a64c Reviewed-on: https://go-review.googlesource.com/c/go/+/604555 Reviewed-by: Ian Lance Taylor <iant@google.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reopen due to CL 604555. I'll prepare a CL with another attempt soon. |
Change https://go.dev/cl/604555 mentions this issue: |
Change https://go.dev/cl/605135 mentions this issue: |
Update #21867. Update #68312. Update #68647. Change-Id: Ic41d6747c5a54ba28c1292258aa4d318ccb9fe40 Reviewed-on: https://go-review.googlesource.com/c/go/+/604395 Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
@qmuntal
https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getusernamea#parameters |
Why 257? 257 is too large for an average user name. We start with 50 and grow only if 50 is not large enough. Alex |
i missed this part of the function docs, that
https://learn.microsoft.com/en-us/windows/win32/api/secext/nf-secext-getusernameexa#parameters |
Go version
go version go1.22.4 windows/amd64
Output of
go env
in your module/workspace:What did you do?
I ran various tools that are part of Chromium's build tooling and are written in Go (reproxy, Siso), which have a mysterious startup overhead on my corporate Windows machine when I'm logged in via SSH, sometimes between 30s - 120s.
I traced it down to all of them depending on glog, which calls
user.Current()
in its init function.user.Current()
on corporate Windows (joined to a domain) makes a network call to figure out the display name of the current user, which is part of theuser.User
struct returned by the function.None of the callers that I inspected actually need the display name, they only wanted to know the username and/or the home directory of the user. However, there is no lightweight API available in the Go standard library that would allow callers to only get the username without the display name.
Here's a minimal repro example: https://go.dev/play/p/ODg6zPl1M1p
I found some other reports about this in the past as well:
user.Current()
on Windows to stop making these network calls, because they don't work inside a container with Nano Server.What did you see happen?
The provided example takes ~500ms in the best case on corporate Windows for me, but between 30s - 120s when anything goes wrong with the network call to Active Directory triggered by
user.Current()
's call to TranslateAccountName or NetUserGetInfo, which is unfortunately regularly the case (and currently for yet unknown reasons always when logged in to the machine via SSH instead of Remote Desktop).Here's an example where I added timing measurements to the calls in the code:
What did you expect to see?
user.Current()
should returns within single-digit milliseconds, like on macOS and Linux.The text was updated successfully, but these errors were encountered: