]> Cypherpunks repositories - gostls13.git/commitdiff
syscall: cache Errno.Error() on Windows
authorJake Bailey <jacob.b.bailey@gmail.com>
Mon, 24 Mar 2025 23:01:06 +0000 (16:01 -0700)
committerGopher Robot <gobot@golang.org>
Wed, 30 Apr 2025 15:41:56 +0000 (08:41 -0700)
Windows is unlike the other OSs and depends on a syscall for most
errors. This can be costly; cache the returned string for later reuse.

This helps test caching, since errors are written out as string to the
test ID, which are often PathErrors wrapping Errnos.

For now, only cache ERROR_FILE_NOT_FOUND and ERROR_PATH_NOT_FOUND.

goos: windows
goarch: amd64
pkg: syscall
cpu: Intel(R) Core(TM) i9-10900K CPU @ 3.70GHz
               │    old.txt    │               new.txt               │
               │    sec/op     │   sec/op     vs base                │
ErrnoString-20   1788.00n ± 1%   11.08n ± 1%  -99.38% (p=0.000 n=10)

               │  old.txt   │              new.txt               │
               │    B/op    │   B/op     vs base                 │
ErrnoString-20   48.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)

               │  old.txt   │               new.txt               │
               │ allocs/op  │ allocs/op   vs base                 │
ErrnoString-20   1.000 ± 0%   0.000 ± 0%  -100.00% (p=0.000 n=10)

For #72992

Change-Id: I9a0910fa6538772ffc64ef7670b44059a2c7d18c
Reviewed-on: https://go-review.googlesource.com/c/go/+/667495
Reviewed-by: Carlos Amedee <carlos@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Reviewed-by: Quim Muntal <quimmuntal@gmail.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Auto-Submit: Carlos Amedee <carlos@golang.org>

src/syscall/syscall_windows.go
src/syscall/syscall_windows_test.go

index c4782031a41be215efc82019e5a61d5da0251504..f7fca07301b0756fa9f45b60b31515dcf64a7059 100644 (file)
@@ -138,12 +138,32 @@ func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf
        return formatMessage(flags, uintptr(msgsrc), msgid, langid, buf, args)
 }
 
+var errnoErrorCache sync.Map
+
 func (e Errno) Error() string {
        // deal with special go errors
        idx := int(e - APPLICATION_ERROR)
        if 0 <= idx && idx < len(errors) {
                return errors[idx]
        }
+
+       cache := false
+       switch e {
+       case ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND:
+               if cached, ok := errnoErrorCache.Load(e); ok {
+                       return cached.(string)
+               }
+               cache = true
+       }
+
+       result := e.error()
+       if cache {
+               errnoErrorCache.Store(e, result)
+       }
+       return result
+}
+
+func (e Errno) error() string {
        // ask windows for the remaining errors
        var flags uint32 = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_IGNORE_INSERTS
        b := make([]uint16, 300)
index 882a279692cc9165f1c3f5d2135363465601b5bf..5e6ba9dbed7a9dc837e2eb75d1349b601f7d1ccd 100644 (file)
@@ -299,3 +299,10 @@ func FuzzUTF16FromString(f *testing.F) {
                }
        })
 }
+
+func BenchmarkErrnoString(b *testing.B) {
+       b.ReportAllocs()
+       for b.Loop() {
+               _ = syscall.Errno(2).Error()
+       }
+}