Commit ed8c5501 authored by Dmitriy Vyukov's avatar Dmitriy Vyukov

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
parent b4f370ca
......@@ -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
......@@ -222,13 +252,14 @@ type netFD struct {
closing bool
// immutable until Close
sysfd syscall.Handle
family int
sotype int
isConnected bool
net string
laddr Addr
raddr Addr
sysfd syscall.Handle
family int
sotype int
isConnected bool
skipSyncNotif bool
net string
laddr Addr
raddr Addr
rop operation // read operation
wop operation // write operation
......@@ -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.
......
This diff is collapsed.
This diff is collapsed.
......@@ -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
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment