diff options
author | Davidlohr Bueso <dave@stgolabs.net> | 2017-09-08 19:15:18 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-08 21:26:49 -0400 |
commit | b2ac2ea6296e7dd779168eb085b09d0fab9d1294 (patch) | |
tree | 8fefe90ed4da5ac94000fd160d42c5c39a225670 /fs/eventpoll.c | |
parent | 410bd5ecb276593e7ec1552014083215d4a43c3a (diff) |
fs/epoll: use faster rb_first_cached()
... such that we can avoid the tree walks to get the node with the
smallest key. Semantically the same, as the previously used rb_first(),
but O(1). The main overhead is the extra footprint for the cached rb_node
pointer, which should not matter for epoll.
Link: http://lkml.kernel.org/r/20170719014603.19029-15-dave@stgolabs.net
Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Jan Kara <jack@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/eventpoll.c')
-rw-r--r-- | fs/eventpoll.c | 30 |
1 files changed, 16 insertions, 14 deletions
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index adbe328b957c..2fabd19cdeea 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c | |||
@@ -205,7 +205,7 @@ struct eventpoll { | |||
205 | struct list_head rdllist; | 205 | struct list_head rdllist; |
206 | 206 | ||
207 | /* RB tree root used to store monitored fd structs */ | 207 | /* RB tree root used to store monitored fd structs */ |
208 | struct rb_root rbr; | 208 | struct rb_root_cached rbr; |
209 | 209 | ||
210 | /* | 210 | /* |
211 | * This is a single linked list that chains all the "struct epitem" that | 211 | * This is a single linked list that chains all the "struct epitem" that |
@@ -796,7 +796,7 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi) | |||
796 | list_del_rcu(&epi->fllink); | 796 | list_del_rcu(&epi->fllink); |
797 | spin_unlock(&file->f_lock); | 797 | spin_unlock(&file->f_lock); |
798 | 798 | ||
799 | rb_erase(&epi->rbn, &ep->rbr); | 799 | rb_erase_cached(&epi->rbn, &ep->rbr); |
800 | 800 | ||
801 | spin_lock_irqsave(&ep->lock, flags); | 801 | spin_lock_irqsave(&ep->lock, flags); |
802 | if (ep_is_linked(&epi->rdllink)) | 802 | if (ep_is_linked(&epi->rdllink)) |
@@ -840,7 +840,7 @@ static void ep_free(struct eventpoll *ep) | |||
840 | /* | 840 | /* |
841 | * Walks through the whole tree by unregistering poll callbacks. | 841 | * Walks through the whole tree by unregistering poll callbacks. |
842 | */ | 842 | */ |
843 | for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) { | 843 | for (rbp = rb_first_cached(&ep->rbr); rbp; rbp = rb_next(rbp)) { |
844 | epi = rb_entry(rbp, struct epitem, rbn); | 844 | epi = rb_entry(rbp, struct epitem, rbn); |
845 | 845 | ||
846 | ep_unregister_pollwait(ep, epi); | 846 | ep_unregister_pollwait(ep, epi); |
@@ -856,7 +856,7 @@ static void ep_free(struct eventpoll *ep) | |||
856 | * a lockdep warning. | 856 | * a lockdep warning. |
857 | */ | 857 | */ |
858 | mutex_lock(&ep->mtx); | 858 | mutex_lock(&ep->mtx); |
859 | while ((rbp = rb_first(&ep->rbr)) != NULL) { | 859 | while ((rbp = rb_first_cached(&ep->rbr)) != NULL) { |
860 | epi = rb_entry(rbp, struct epitem, rbn); | 860 | epi = rb_entry(rbp, struct epitem, rbn); |
861 | ep_remove(ep, epi); | 861 | ep_remove(ep, epi); |
862 | cond_resched(); | 862 | cond_resched(); |
@@ -963,7 +963,7 @@ static void ep_show_fdinfo(struct seq_file *m, struct file *f) | |||
963 | struct rb_node *rbp; | 963 | struct rb_node *rbp; |
964 | 964 | ||
965 | mutex_lock(&ep->mtx); | 965 | mutex_lock(&ep->mtx); |
966 | for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) { | 966 | for (rbp = rb_first_cached(&ep->rbr); rbp; rbp = rb_next(rbp)) { |
967 | struct epitem *epi = rb_entry(rbp, struct epitem, rbn); | 967 | struct epitem *epi = rb_entry(rbp, struct epitem, rbn); |
968 | struct inode *inode = file_inode(epi->ffd.file); | 968 | struct inode *inode = file_inode(epi->ffd.file); |
969 | 969 | ||
@@ -1040,7 +1040,7 @@ static int ep_alloc(struct eventpoll **pep) | |||
1040 | init_waitqueue_head(&ep->wq); | 1040 | init_waitqueue_head(&ep->wq); |
1041 | init_waitqueue_head(&ep->poll_wait); | 1041 | init_waitqueue_head(&ep->poll_wait); |
1042 | INIT_LIST_HEAD(&ep->rdllist); | 1042 | INIT_LIST_HEAD(&ep->rdllist); |
1043 | ep->rbr = RB_ROOT; | 1043 | ep->rbr = RB_ROOT_CACHED; |
1044 | ep->ovflist = EP_UNACTIVE_PTR; | 1044 | ep->ovflist = EP_UNACTIVE_PTR; |
1045 | ep->user = user; | 1045 | ep->user = user; |
1046 | 1046 | ||
@@ -1066,7 +1066,7 @@ static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd) | |||
1066 | struct epoll_filefd ffd; | 1066 | struct epoll_filefd ffd; |
1067 | 1067 | ||
1068 | ep_set_ffd(&ffd, file, fd); | 1068 | ep_set_ffd(&ffd, file, fd); |
1069 | for (rbp = ep->rbr.rb_node; rbp; ) { | 1069 | for (rbp = ep->rbr.rb_root.rb_node; rbp; ) { |
1070 | epi = rb_entry(rbp, struct epitem, rbn); | 1070 | epi = rb_entry(rbp, struct epitem, rbn); |
1071 | kcmp = ep_cmp_ffd(&ffd, &epi->ffd); | 1071 | kcmp = ep_cmp_ffd(&ffd, &epi->ffd); |
1072 | if (kcmp > 0) | 1072 | if (kcmp > 0) |
@@ -1088,7 +1088,7 @@ static struct epitem *ep_find_tfd(struct eventpoll *ep, int tfd, unsigned long t | |||
1088 | struct rb_node *rbp; | 1088 | struct rb_node *rbp; |
1089 | struct epitem *epi; | 1089 | struct epitem *epi; |
1090 | 1090 | ||
1091 | for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) { | 1091 | for (rbp = rb_first_cached(&ep->rbr); rbp; rbp = rb_next(rbp)) { |
1092 | epi = rb_entry(rbp, struct epitem, rbn); | 1092 | epi = rb_entry(rbp, struct epitem, rbn); |
1093 | if (epi->ffd.fd == tfd) { | 1093 | if (epi->ffd.fd == tfd) { |
1094 | if (toff == 0) | 1094 | if (toff == 0) |
@@ -1273,20 +1273,22 @@ static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead, | |||
1273 | static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi) | 1273 | static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi) |
1274 | { | 1274 | { |
1275 | int kcmp; | 1275 | int kcmp; |
1276 | struct rb_node **p = &ep->rbr.rb_node, *parent = NULL; | 1276 | struct rb_node **p = &ep->rbr.rb_root.rb_node, *parent = NULL; |
1277 | struct epitem *epic; | 1277 | struct epitem *epic; |
1278 | bool leftmost = true; | ||
1278 | 1279 | ||
1279 | while (*p) { | 1280 | while (*p) { |
1280 | parent = *p; | 1281 | parent = *p; |
1281 | epic = rb_entry(parent, struct epitem, rbn); | 1282 | epic = rb_entry(parent, struct epitem, rbn); |
1282 | kcmp = ep_cmp_ffd(&epi->ffd, &epic->ffd); | 1283 | kcmp = ep_cmp_ffd(&epi->ffd, &epic->ffd); |
1283 | if (kcmp > 0) | 1284 | if (kcmp > 0) { |
1284 | p = &parent->rb_right; | 1285 | p = &parent->rb_right; |
1285 | else | 1286 | leftmost = false; |
1287 | } else | ||
1286 | p = &parent->rb_left; | 1288 | p = &parent->rb_left; |
1287 | } | 1289 | } |
1288 | rb_link_node(&epi->rbn, parent, p); | 1290 | rb_link_node(&epi->rbn, parent, p); |
1289 | rb_insert_color(&epi->rbn, &ep->rbr); | 1291 | rb_insert_color_cached(&epi->rbn, &ep->rbr, leftmost); |
1290 | } | 1292 | } |
1291 | 1293 | ||
1292 | 1294 | ||
@@ -1530,7 +1532,7 @@ error_remove_epi: | |||
1530 | list_del_rcu(&epi->fllink); | 1532 | list_del_rcu(&epi->fllink); |
1531 | spin_unlock(&tfile->f_lock); | 1533 | spin_unlock(&tfile->f_lock); |
1532 | 1534 | ||
1533 | rb_erase(&epi->rbn, &ep->rbr); | 1535 | rb_erase_cached(&epi->rbn, &ep->rbr); |
1534 | 1536 | ||
1535 | error_unregister: | 1537 | error_unregister: |
1536 | ep_unregister_pollwait(ep, epi); | 1538 | ep_unregister_pollwait(ep, epi); |
@@ -1878,7 +1880,7 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests) | |||
1878 | mutex_lock_nested(&ep->mtx, call_nests + 1); | 1880 | mutex_lock_nested(&ep->mtx, call_nests + 1); |
1879 | ep->visited = 1; | 1881 | ep->visited = 1; |
1880 | list_add(&ep->visited_list_link, &visited_list); | 1882 | list_add(&ep->visited_list_link, &visited_list); |
1881 | for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) { | 1883 | for (rbp = rb_first_cached(&ep->rbr); rbp; rbp = rb_next(rbp)) { |
1882 | epi = rb_entry(rbp, struct epitem, rbn); | 1884 | epi = rb_entry(rbp, struct epitem, rbn); |
1883 | if (unlikely(is_file_epoll(epi->ffd.file))) { | 1885 | if (unlikely(is_file_epoll(epi->ffd.file))) { |
1884 | ep_tovisit = epi->ffd.file->private_data; | 1886 | ep_tovisit = epi->ffd.file->private_data; |