mirror of
https://github.com/golang/go
synced 2024-09-25 15:10:11 -06:00
net: use SetFileCompletionNotificationModes on windows if available
This allows to skip GetQueuedCompletionStatus if an IO operation completes synchronously. benchmark old ns/op new ns/op delta BenchmarkTCP4Persistent 27669 25863 -6.53% BenchmarkTCP4Persistent-2 18173 15908 -12.46% BenchmarkTCP4Persistent-4 10390 9766 -6.01% R=golang-dev, mikioh.mikioh, alex.brainman CC=golang-dev https://golang.org/cl/12409044
This commit is contained in:
parent
b4f370ca57
commit
ed8c5501c7
@ -27,7 +27,11 @@ var initErr error
|
||||
// package uses CancelIoEx API, if present, otherwise it fallback
|
||||
// to CancelIo.
|
||||
|
||||
var canCancelIO bool // determines if CancelIoEx API is present
|
||||
var (
|
||||
canCancelIO bool // determines if CancelIoEx API is present
|
||||
skipSyncNotif bool
|
||||
hasLoadSetFileCompletionNotificationModes bool
|
||||
)
|
||||
|
||||
func sysInit() {
|
||||
var d syscall.WSAData
|
||||
@ -40,6 +44,27 @@ func sysInit() {
|
||||
lookupPort = newLookupPort
|
||||
lookupIP = newLookupIP
|
||||
}
|
||||
|
||||
hasLoadSetFileCompletionNotificationModes = syscall.LoadSetFileCompletionNotificationModes() == nil
|
||||
if hasLoadSetFileCompletionNotificationModes {
|
||||
// It's not safe to use FILE_SKIP_COMPLETION_PORT_ON_SUCCESS if non IFS providers are installed:
|
||||
// http://support.microsoft.com/kb/2568167
|
||||
skipSyncNotif = true
|
||||
protos := [2]int32{syscall.IPPROTO_TCP, 0}
|
||||
var buf [32]syscall.WSAProtocolInfo
|
||||
len := uint32(unsafe.Sizeof(buf))
|
||||
n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len)
|
||||
if err != nil {
|
||||
skipSyncNotif = false
|
||||
} else {
|
||||
for i := int32(0); i < n; i++ {
|
||||
if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 {
|
||||
skipSyncNotif = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func closesocket(s syscall.Handle) error {
|
||||
@ -148,7 +173,12 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
|
||||
}
|
||||
switch err {
|
||||
case nil:
|
||||
// IO completed immediately, but we need to get our completion message anyway.
|
||||
// IO completed immediately
|
||||
if o.fd.skipSyncNotif {
|
||||
// No completion message will follow, so return immediately.
|
||||
return int(o.qty), nil
|
||||
}
|
||||
// Need to get our completion message anyway.
|
||||
case syscall.ERROR_IO_PENDING:
|
||||
// IO started, and we have to wait for its completion.
|
||||
err = nil
|
||||
@ -226,6 +256,7 @@ type netFD struct {
|
||||
family int
|
||||
sotype int
|
||||
isConnected bool
|
||||
skipSyncNotif bool
|
||||
net string
|
||||
laddr Addr
|
||||
raddr Addr
|
||||
@ -249,6 +280,19 @@ func (fd *netFD) init() error {
|
||||
if err := fd.pd.Init(fd); err != nil {
|
||||
return err
|
||||
}
|
||||
if hasLoadSetFileCompletionNotificationModes {
|
||||
// We do not use events, so we can skip them always.
|
||||
flags := uint8(syscall.FILE_SKIP_SET_EVENT_ON_HANDLE)
|
||||
// It's not safe to skip completion notifications for UDP:
|
||||
// http://blogs.technet.com/b/winserverperformance/archive/2008/06/26/designing-applications-for-high-performance-part-iii.aspx
|
||||
if skipSyncNotif && fd.net == "tcp" {
|
||||
flags |= syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
|
||||
}
|
||||
err := syscall.SetFileCompletionNotificationModes(fd.sysfd, flags)
|
||||
if err == nil && flags&syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS != 0 {
|
||||
fd.skipSyncNotif = true
|
||||
}
|
||||
}
|
||||
fd.rop.mode = 'r'
|
||||
fd.wop.mode = 'w'
|
||||
fd.rop.fd = fd
|
||||
|
@ -508,6 +508,10 @@ func LoadCancelIoEx() error {
|
||||
return procCancelIoEx.Find()
|
||||
}
|
||||
|
||||
func LoadSetFileCompletionNotificationModes() error {
|
||||
return procSetFileCompletionNotificationModes.Find()
|
||||
}
|
||||
|
||||
// net api calls
|
||||
|
||||
const socket_error = uintptr(^uint32(0))
|
||||
@ -541,6 +545,8 @@ const socket_error = uintptr(^uint32(0))
|
||||
//sys FreeAddrInfoW(addrinfo *AddrinfoW) = ws2_32.FreeAddrInfoW
|
||||
//sys GetIfEntry(pIfRow *MibIfRow) (errcode error) = iphlpapi.GetIfEntry
|
||||
//sys GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) = iphlpapi.GetAdaptersInfo
|
||||
//sys SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) = kernel32.SetFileCompletionNotificationModes
|
||||
//sys WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) [failretval==-1] = ws2_32.WSAEnumProtocolsW
|
||||
|
||||
// For testing: clients can set this flag to force
|
||||
// creation of IPv6 sockets to return EAFNOSUPPORT.
|
||||
|
@ -137,6 +137,8 @@ var (
|
||||
procFreeAddrInfoW = modws2_32.NewProc("FreeAddrInfoW")
|
||||
procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
|
||||
procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
|
||||
procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
|
||||
procWSAEnumProtocolsW = modws2_32.NewProc("WSAEnumProtocolsW")
|
||||
procTranslateNameW = modsecur32.NewProc("TranslateNameW")
|
||||
procGetUserNameExW = modsecur32.NewProc("GetUserNameExW")
|
||||
procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo")
|
||||
@ -1582,6 +1584,31 @@ func GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) {
|
||||
return
|
||||
}
|
||||
|
||||
func SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) {
|
||||
r1, _, e1 := Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(handle), uintptr(flags), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) {
|
||||
r0, _, e1 := Syscall(procWSAEnumProtocolsW.Addr(), 3, uintptr(unsafe.Pointer(protocols)), uintptr(unsafe.Pointer(protocolBuffer)), uintptr(unsafe.Pointer(bufferLength)))
|
||||
n = int32(r0)
|
||||
if n == -1 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) {
|
||||
r1, _, e1 := Syscall6(procTranslateNameW.Addr(), 5, uintptr(unsafe.Pointer(accName)), uintptr(accNameFormat), uintptr(desiredNameFormat), uintptr(unsafe.Pointer(translatedName)), uintptr(unsafe.Pointer(nSize)), 0)
|
||||
if r1&0xff == 0 {
|
||||
|
@ -137,6 +137,8 @@ var (
|
||||
procFreeAddrInfoW = modws2_32.NewProc("FreeAddrInfoW")
|
||||
procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
|
||||
procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
|
||||
procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
|
||||
procWSAEnumProtocolsW = modws2_32.NewProc("WSAEnumProtocolsW")
|
||||
procTranslateNameW = modsecur32.NewProc("TranslateNameW")
|
||||
procGetUserNameExW = modsecur32.NewProc("GetUserNameExW")
|
||||
procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo")
|
||||
@ -1582,6 +1584,31 @@ func GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) {
|
||||
return
|
||||
}
|
||||
|
||||
func SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) {
|
||||
r1, _, e1 := Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(handle), uintptr(flags), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) {
|
||||
r0, _, e1 := Syscall(procWSAEnumProtocolsW.Addr(), 3, uintptr(unsafe.Pointer(protocols)), uintptr(unsafe.Pointer(protocolBuffer)), uintptr(unsafe.Pointer(bufferLength)))
|
||||
n = int32(r0)
|
||||
if n == -1 {
|
||||
if e1 != 0 {
|
||||
err = error(e1)
|
||||
} else {
|
||||
err = EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) {
|
||||
r1, _, e1 := Syscall6(procTranslateNameW.Addr(), 5, uintptr(unsafe.Pointer(accName)), uintptr(accNameFormat), uintptr(desiredNameFormat), uintptr(unsafe.Pointer(translatedName)), uintptr(unsafe.Pointer(nSize)), 0)
|
||||
if r1&0xff == 0 {
|
||||
|
@ -964,3 +964,69 @@ var WSAID_CONNECTEX = GUID{
|
||||
0x4660,
|
||||
[8]byte{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e},
|
||||
}
|
||||
|
||||
const (
|
||||
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
|
||||
FILE_SKIP_SET_EVENT_ON_HANDLE = 2
|
||||
)
|
||||
|
||||
const (
|
||||
WSAPROTOCOL_LEN = 255
|
||||
MAX_PROTOCOL_CHAIN = 7
|
||||
BASE_PROTOCOL = 1
|
||||
LAYERED_PROTOCOL = 0
|
||||
|
||||
XP1_CONNECTIONLESS = 0x00000001
|
||||
XP1_GUARANTEED_DELIVERY = 0x00000002
|
||||
XP1_GUARANTEED_ORDER = 0x00000004
|
||||
XP1_MESSAGE_ORIENTED = 0x00000008
|
||||
XP1_PSEUDO_STREAM = 0x00000010
|
||||
XP1_GRACEFUL_CLOSE = 0x00000020
|
||||
XP1_EXPEDITED_DATA = 0x00000040
|
||||
XP1_CONNECT_DATA = 0x00000080
|
||||
XP1_DISCONNECT_DATA = 0x00000100
|
||||
XP1_SUPPORT_BROADCAST = 0x00000200
|
||||
XP1_SUPPORT_MULTIPOINT = 0x00000400
|
||||
XP1_MULTIPOINT_CONTROL_PLANE = 0x00000800
|
||||
XP1_MULTIPOINT_DATA_PLANE = 0x00001000
|
||||
XP1_QOS_SUPPORTED = 0x00002000
|
||||
XP1_UNI_SEND = 0x00008000
|
||||
XP1_UNI_RECV = 0x00010000
|
||||
XP1_IFS_HANDLES = 0x00020000
|
||||
XP1_PARTIAL_MESSAGE = 0x00040000
|
||||
XP1_SAN_SUPPORT_SDP = 0x00080000
|
||||
|
||||
PFL_MULTIPLE_PROTO_ENTRIES = 0x00000001
|
||||
PFL_RECOMMENDED_PROTO_ENTRY = 0x00000002
|
||||
PFL_HIDDEN = 0x00000004
|
||||
PFL_MATCHES_PROTOCOL_ZERO = 0x00000008
|
||||
PFL_NETWORKDIRECT_PROVIDER = 0x00000010
|
||||
)
|
||||
|
||||
type WSAProtocolInfo struct {
|
||||
ServiceFlags1 uint32
|
||||
ServiceFlags2 uint32
|
||||
ServiceFlags3 uint32
|
||||
ServiceFlags4 uint32
|
||||
ProviderFlags uint32
|
||||
ProviderId GUID
|
||||
CatalogEntryId uint32
|
||||
ProtocolChain WSAProtocolChain
|
||||
Version int32
|
||||
AddressFamily int32
|
||||
MaxSockAddr int32
|
||||
MinSockAddr int32
|
||||
SocketType int32
|
||||
Protocol int32
|
||||
ProtocolMaxOffset int32
|
||||
NetworkByteOrder int32
|
||||
SecurityScheme int32
|
||||
MessageSize uint32
|
||||
ProviderReserved uint32
|
||||
ProtocolName [WSAPROTOCOL_LEN + 1]uint16
|
||||
}
|
||||
|
||||
type WSAProtocolChain struct {
|
||||
ChainLen int32
|
||||
ChainEntries [MAX_PROTOCOL_CHAIN]uint32
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user