aboutsummaryrefslogtreecommitdiff
path: root/src/internal
diff options
context:
space:
mode:
authorqmuntal <quimmuntal@gmail.com>2022-11-22 18:46:35 +0100
committerQuim Muntal <quimmuntal@gmail.com>2023-01-24 13:26:00 +0000
commit1951857ec07c1d491e1836770a647d3902934a67 (patch)
treec6d132e27692470402908a581ae3b3c893ff7366 /src/internal
parent7b5a34418cd32ec4d2c0f7d6e4c7e6fe7585a17f (diff)
downloadgo-1951857ec07c1d491e1836770a647d3902934a67.tar.xz
os: use handle based APIs to read directories on windows
This CL updates File.readdir() on windows so it uses GetFileInformationByHandleEx with FILE_ID_BOTH_DIR_INFO instead of Find* APIs. The former is more performant because it allows us to buffer IO calls and reduces the number of system calls, passing from 1 per file to 1 every ~100 files (depending on the size of the file name and the size of the buffer). This change improve performance of File.ReadDir by 20-30%. name old time/op new time/op delta ReadDir-12 562µs ±14% 385µs ± 9% -31.60% (p=0.000 n=9+9) name old alloc/op new alloc/op delta ReadDir-12 29.7kB ± 0% 29.5kB ± 0% -0.88% (p=0.000 n=8+10) name old allocs/op new allocs/op delta ReadDir-12 399 ± 0% 397 ± 0% -0.50% (p=0.000 n=10+10) This change also speeds up calls to os.SameFile when using FileStats returned from File.readdir(), as their file ID can be inferred while reading the directory. Change-Id: Id56a338ee66c39656b564105cac131099218fb5d Reviewed-on: https://go-review.googlesource.com/c/go/+/452995 TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Damien Neil <dneil@google.com> Reviewed-by: Alex Brainman <alex.brainman@gmail.com> Run-TryBot: Quim Muntal <quimmuntal@gmail.com> Reviewed-by: Bryan Mills <bcmills@google.com>
Diffstat (limited to 'src/internal')
-rw-r--r--src/internal/syscall/windows/syscall_windows.go20
-rw-r--r--src/internal/syscall/windows/zsyscall_windows.go73
2 files changed, 61 insertions, 32 deletions
diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go
index 8ace2a27e7..311d083f45 100644
--- a/src/internal/syscall/windows/syscall_windows.go
+++ b/src/internal/syscall/windows/syscall_windows.go
@@ -367,3 +367,23 @@ func LoadGetFinalPathNameByHandle() error {
//sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock
//sys RtlGenRandom(buf []byte) (err error) = advapi32.SystemFunction036
+
+type FILE_ID_BOTH_DIR_INFO struct {
+ NextEntryOffset uint32
+ FileIndex uint32
+ CreationTime syscall.Filetime
+ LastAccessTime syscall.Filetime
+ LastWriteTime syscall.Filetime
+ ChangeTime syscall.Filetime
+ EndOfFile uint64
+ AllocationSize uint64
+ FileAttributes uint32
+ FileNameLength uint32
+ EaSize uint32
+ ShortNameLength uint32
+ ShortName [12]uint16
+ FileID uint64
+ FileName [1]uint16
+}
+
+//sys GetVolumeInformationByHandle(file syscall.Handle, volumeNameBuffer *uint16, volumeNameSize uint32, volumeNameSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemNameBuffer *uint16, fileSystemNameSize uint32) (err error) = GetVolumeInformationByHandleW
diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go
index afd64e318e..fd2f255b9b 100644
--- a/src/internal/syscall/windows/zsyscall_windows.go
+++ b/src/internal/syscall/windows/zsyscall_windows.go
@@ -45,38 +45,39 @@ var (
moduserenv = syscall.NewLazyDLL(sysdll.Add("userenv.dll"))
modws2_32 = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll"))
- procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges")
- procDuplicateTokenEx = modadvapi32.NewProc("DuplicateTokenEx")
- procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
- procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
- procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken")
- procRevertToSelf = modadvapi32.NewProc("RevertToSelf")
- procSetTokenInformation = modadvapi32.NewProc("SetTokenInformation")
- procSystemFunction036 = modadvapi32.NewProc("SystemFunction036")
- procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
- procGetACP = modkernel32.NewProc("GetACP")
- procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW")
- procGetConsoleCP = modkernel32.NewProc("GetConsoleCP")
- procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
- procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx")
- procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW")
- procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW")
- procLockFileEx = modkernel32.NewProc("LockFileEx")
- procModule32FirstW = modkernel32.NewProc("Module32FirstW")
- procModule32NextW = modkernel32.NewProc("Module32NextW")
- procMoveFileExW = modkernel32.NewProc("MoveFileExW")
- procMultiByteToWideChar = modkernel32.NewProc("MultiByteToWideChar")
- procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle")
- procUnlockFileEx = modkernel32.NewProc("UnlockFileEx")
- procVirtualQuery = modkernel32.NewProc("VirtualQuery")
- procNetShareAdd = modnetapi32.NewProc("NetShareAdd")
- procNetShareDel = modnetapi32.NewProc("NetShareDel")
- procNetUserGetLocalGroups = modnetapi32.NewProc("NetUserGetLocalGroups")
- procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
- procCreateEnvironmentBlock = moduserenv.NewProc("CreateEnvironmentBlock")
- procDestroyEnvironmentBlock = moduserenv.NewProc("DestroyEnvironmentBlock")
- procGetProfilesDirectoryW = moduserenv.NewProc("GetProfilesDirectoryW")
- procWSASocketW = modws2_32.NewProc("WSASocketW")
+ procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges")
+ procDuplicateTokenEx = modadvapi32.NewProc("DuplicateTokenEx")
+ procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
+ procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
+ procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken")
+ procRevertToSelf = modadvapi32.NewProc("RevertToSelf")
+ procSetTokenInformation = modadvapi32.NewProc("SetTokenInformation")
+ procSystemFunction036 = modadvapi32.NewProc("SystemFunction036")
+ procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
+ procGetACP = modkernel32.NewProc("GetACP")
+ procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW")
+ procGetConsoleCP = modkernel32.NewProc("GetConsoleCP")
+ procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
+ procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx")
+ procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW")
+ procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW")
+ procGetVolumeInformationByHandleW = modkernel32.NewProc("GetVolumeInformationByHandleW")
+ procLockFileEx = modkernel32.NewProc("LockFileEx")
+ procModule32FirstW = modkernel32.NewProc("Module32FirstW")
+ procModule32NextW = modkernel32.NewProc("Module32NextW")
+ procMoveFileExW = modkernel32.NewProc("MoveFileExW")
+ procMultiByteToWideChar = modkernel32.NewProc("MultiByteToWideChar")
+ procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle")
+ procUnlockFileEx = modkernel32.NewProc("UnlockFileEx")
+ procVirtualQuery = modkernel32.NewProc("VirtualQuery")
+ procNetShareAdd = modnetapi32.NewProc("NetShareAdd")
+ procNetShareDel = modnetapi32.NewProc("NetShareDel")
+ procNetUserGetLocalGroups = modnetapi32.NewProc("NetUserGetLocalGroups")
+ procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
+ procCreateEnvironmentBlock = moduserenv.NewProc("CreateEnvironmentBlock")
+ procDestroyEnvironmentBlock = moduserenv.NewProc("DestroyEnvironmentBlock")
+ procGetProfilesDirectoryW = moduserenv.NewProc("GetProfilesDirectoryW")
+ procWSASocketW = modws2_32.NewProc("WSASocketW")
)
func adjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) (ret uint32, err error) {
@@ -219,6 +220,14 @@ func GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32,
return
}
+func GetVolumeInformationByHandle(file syscall.Handle, volumeNameBuffer *uint16, volumeNameSize uint32, volumeNameSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemNameBuffer *uint16, fileSystemNameSize uint32) (err error) {
+ r1, _, e1 := syscall.Syscall9(procGetVolumeInformationByHandleW.Addr(), 8, uintptr(file), uintptr(unsafe.Pointer(volumeNameBuffer)), uintptr(volumeNameSize), uintptr(unsafe.Pointer(volumeNameSerialNumber)), uintptr(unsafe.Pointer(maximumComponentLength)), uintptr(unsafe.Pointer(fileSystemFlags)), uintptr(unsafe.Pointer(fileSystemNameBuffer)), uintptr(fileSystemNameSize), 0)
+ if r1 == 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
func LockFileEx(file syscall.Handle, flags uint32, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) {
r1, _, e1 := syscall.Syscall6(procLockFileEx.Addr(), 6, uintptr(file), uintptr(flags), uintptr(reserved), uintptr(bytesLow), uintptr(bytesHigh), uintptr(unsafe.Pointer(overlapped)))
if r1 == 0 {