Commit add8c8db authored by Ian Lance Taylor's avatar Ian Lance Taylor

net: Use preallocated buffer for epoll.

Reduces rpc test "mallocs per rpc round trip" by 4.

Gains ~8% on a localhost client/server RPC test.

R=rsc
CC=golang-dev
https://golang.org/cl/4284056
parent 8c4a2ae6
...@@ -22,6 +22,15 @@ type pollster struct { ...@@ -22,6 +22,15 @@ type pollster struct {
// Events we're already waiting for // Events we're already waiting for
// Must hold pollServer lock // Must hold pollServer lock
events map[int]uint32 events map[int]uint32
// An event buffer for EpollWait.
// Used without a lock, may only be used by WaitFD.
waitEventBuf [10]syscall.EpollEvent
waitEvents []syscall.EpollEvent
// An event buffer for EpollCtl, to avoid a malloc.
// Must hold pollServer lock.
ctlEvent syscall.EpollEvent
} }
func newpollster() (p *pollster, err os.Error) { func newpollster() (p *pollster, err os.Error) {
...@@ -30,7 +39,7 @@ func newpollster() (p *pollster, err os.Error) { ...@@ -30,7 +39,7 @@ func newpollster() (p *pollster, err os.Error) {
// The arg to epoll_create is a hint to the kernel // The arg to epoll_create is a hint to the kernel
// about the number of FDs we will care about. // about the number of FDs we will care about.
// We don't know. // We don't know, and since 2.6.8 the kernel ignores it anyhow.
if p.epfd, e = syscall.EpollCreate(16); e != 0 { if p.epfd, e = syscall.EpollCreate(16); e != 0 {
return nil, os.NewSyscallError("epoll_create", e) return nil, os.NewSyscallError("epoll_create", e)
} }
...@@ -41,17 +50,16 @@ func newpollster() (p *pollster, err os.Error) { ...@@ -41,17 +50,16 @@ func newpollster() (p *pollster, err os.Error) {
func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error { func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
// pollServer is locked. // pollServer is locked.
var ev syscall.EpollEvent
var already bool var already bool
ev.Fd = int32(fd) p.ctlEvent.Fd = int32(fd)
ev.Events, already = p.events[fd] p.ctlEvent.Events, already = p.events[fd]
if !repeat { if !repeat {
ev.Events |= syscall.EPOLLONESHOT p.ctlEvent.Events |= syscall.EPOLLONESHOT
} }
if mode == 'r' { if mode == 'r' {
ev.Events |= readFlags p.ctlEvent.Events |= readFlags
} else { } else {
ev.Events |= writeFlags p.ctlEvent.Events |= writeFlags
} }
var op int var op int
...@@ -60,10 +68,10 @@ func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error { ...@@ -60,10 +68,10 @@ func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
} else { } else {
op = syscall.EPOLL_CTL_ADD op = syscall.EPOLL_CTL_ADD
} }
if e := syscall.EpollCtl(p.epfd, op, fd, &ev); e != 0 { if e := syscall.EpollCtl(p.epfd, op, fd, &p.ctlEvent); e != 0 {
return os.NewSyscallError("epoll_ctl", e) return os.NewSyscallError("epoll_ctl", e)
} }
p.events[fd] = ev.Events p.events[fd] = p.ctlEvent.Events
return nil return nil
} }
...@@ -87,10 +95,9 @@ func (p *pollster) StopWaiting(fd int, bits uint) { ...@@ -87,10 +95,9 @@ func (p *pollster) StopWaiting(fd int, bits uint) {
// event in the kernel. Otherwise, delete it. // event in the kernel. Otherwise, delete it.
events &= ^uint32(bits) events &= ^uint32(bits)
if int32(events)&^syscall.EPOLLONESHOT != 0 { if int32(events)&^syscall.EPOLLONESHOT != 0 {
var ev syscall.EpollEvent p.ctlEvent.Fd = int32(fd)
ev.Fd = int32(fd) p.ctlEvent.Events = events
ev.Events = events if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &p.ctlEvent); e != 0 {
if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &ev); e != 0 {
print("Epoll modify fd=", fd, ": ", os.Errno(e).String(), "\n") print("Epoll modify fd=", fd, ": ", os.Errno(e).String(), "\n")
} }
p.events[fd] = events p.events[fd] = events
...@@ -113,28 +120,31 @@ func (p *pollster) DelFD(fd int, mode int) { ...@@ -113,28 +120,31 @@ func (p *pollster) DelFD(fd int, mode int) {
} }
func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) { func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) {
s.Unlock() for len(p.waitEvents) == 0 {
var msec int = -1
// Get an event. if nsec > 0 {
var evarray [1]syscall.EpollEvent msec = int((nsec + 1e6 - 1) / 1e6)
ev := &evarray[0] }
var msec int = -1
if nsec > 0 {
msec = int((nsec + 1e6 - 1) / 1e6)
}
n, e := syscall.EpollWait(p.epfd, evarray[0:], msec)
for e == syscall.EAGAIN || e == syscall.EINTR {
n, e = syscall.EpollWait(p.epfd, evarray[0:], msec)
}
s.Lock() s.Unlock()
n, e := syscall.EpollWait(p.epfd, p.waitEventBuf[0:], msec)
s.Lock()
if e != 0 { if e != 0 {
return -1, 0, os.NewSyscallError("epoll_wait", e) if e == syscall.EAGAIN || e == syscall.EINTR {
} continue
if n == 0 { }
return -1, 0, nil return -1, 0, os.NewSyscallError("epoll_wait", e)
}
if n == 0 {
return -1, 0, nil
}
p.waitEvents = p.waitEventBuf[0:n]
} }
ev := &p.waitEvents[0]
p.waitEvents = p.waitEvents[1:]
fd = int(ev.Fd) fd = int(ev.Fd)
if ev.Events&writeFlags != 0 { if ev.Events&writeFlags != 0 {
......
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