epoll: use ilist:generic_list instead of ilist:ilist

ilist:generic_list works faster than ilist:ilist.

Here is a beanchmark test to measure performance of epoll_wait, when readyList
isn't empty. It shows about 30% better performance with these changes.

Benchmark           Time(ns)        CPU(ns)     Iterations
Before:
BM_EpollAllEvents      46725          46899          14286

After:
BM_EpollAllEvents      33167          33300          18919
PiperOrigin-RevId: 240185278
Change-Id: I3e33f9b214db13ab840b91613400525de5b58d18
This commit is contained in:
Andrei Vagin
2019-03-25 11:41:50 -07:00
committed by Shentubot
parent b81bfd6013
commit ddc05e3053
3 changed files with 28 additions and 18 deletions
+14 -1
View File
@@ -1,17 +1,30 @@
package(licenses = ["notice"])
load("//tools/go_generics:defs.bzl", "go_template_instance")
load("//tools/go_stateify:defs.bzl", "go_library", "go_test")
go_template_instance(
name = "epoll_list",
out = "epoll_list.go",
package = "epoll",
prefix = "pollEntry",
template = "//pkg/ilist:generic_list",
types = {
"Element": "*pollEntry",
"Linker": "*pollEntry",
},
)
go_library(
name = "epoll",
srcs = [
"epoll.go",
"epoll_list.go",
"epoll_state.go",
],
importpath = "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/epoll",
visibility = ["//pkg/sentry:internal"],
deps = [
"//pkg/ilist",
"//pkg/refs",
"//pkg/sentry/context",
"//pkg/sentry/fs",
+8 -9
View File
@@ -21,7 +21,6 @@ import (
"sync"
"syscall"
"gvisor.googlesource.com/gvisor/pkg/ilist"
"gvisor.googlesource.com/gvisor/pkg/refs"
"gvisor.googlesource.com/gvisor/pkg/sentry/context"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs"
@@ -70,7 +69,7 @@ type FileIdentifier struct {
//
// +stateify savable
type pollEntry struct {
ilist.Entry
pollEntryEntry
file *refs.WeakRef `state:"manual"`
id FileIdentifier `state:"wait"`
userData [2]int32
@@ -84,7 +83,7 @@ type pollEntry struct {
// struct, while state framework currently does not support such
// in-struct pointers. Instead, EventPoll will properly set this field
// in its loading logic.
curList *ilist.List `state:"nosave"`
curList *pollEntryList `state:"nosave"`
}
// WeakRefGone implements refs.WeakRefUser.WeakRefGone.
@@ -133,9 +132,9 @@ type EventPoll struct {
// disabledList -- when the entry is disabled. This happens when
// a one-shot entry gets delivered via readEvents().
listsMu sync.Mutex `state:"nosave"`
readyList ilist.List
waitingList ilist.List
disabledList ilist.List
readyList pollEntryList
waitingList pollEntryList
disabledList pollEntryList
}
// cycleMu is used to serialize all the cycle checks. This is only used when
@@ -189,7 +188,7 @@ func (e *EventPoll) eventsAvailable() bool {
e.listsMu.Lock()
for it := e.readyList.Front(); it != nil; {
entry := it.(*pollEntry)
entry := it
it = it.Next()
// If the entry is ready, we know 'e' has at least one entry
@@ -225,14 +224,14 @@ func (e *EventPoll) Readiness(mask waiter.EventMask) waiter.EventMask {
// ReadEvents returns up to max available events.
func (e *EventPoll) ReadEvents(max int) []Event {
var local ilist.List
var local pollEntryList
var ret []Event
e.listsMu.Lock()
// Go through all entries we believe may be ready.
for it := e.readyList.Front(); it != nil && len(ret) < max; {
entry := it.(*pollEntry)
entry := it
it = it.Next()
// Check the entry's readiness. It it's not really ready, we
+6 -8
View File
@@ -15,7 +15,6 @@
package epoll
import (
"gvisor.googlesource.com/gvisor/pkg/ilist"
"gvisor.googlesource.com/gvisor/pkg/refs"
"gvisor.googlesource.com/gvisor/pkg/waiter"
)
@@ -33,18 +32,17 @@ func (e *EventPoll) afterLoad() {
e.listsMu.Lock()
defer e.listsMu.Unlock()
for _, ls := range []*ilist.List{&e.waitingList, &e.readyList, &e.disabledList} {
for _, ls := range []*pollEntryList{&e.waitingList, &e.readyList, &e.disabledList} {
for it := ls.Front(); it != nil; it = it.Next() {
it.(*pollEntry).curList = ls
it.curList = ls
}
}
for it := e.waitingList.Front(); it != nil; it = it.Next() {
p := it.(*pollEntry)
if p.id.File.Readiness(p.mask) != 0 {
e.waitingList.Remove(p)
e.readyList.PushBack(p)
p.curList = &e.readyList
if it.id.File.Readiness(it.mask) != 0 {
e.waitingList.Remove(it)
e.readyList.PushBack(it)
it.curList = &e.readyList
e.Notify(waiter.EventIn)
}
}