2002-11-20 22:53:24

by Manfred Spraul

[permalink] [raw]
Subject: [RFC] 6 sys_poll/sys_select performance patches

// $Header$
// Kernel Version:
// VERSION = 2
// PATCHLEVEL = 5
// SUBLEVEL = 48
// EXTRAVERSION =
--- 2.5/fs/select.c 2002-11-20 23:25:46.000000000 +0100
+++ build-2.5/fs/select.c 2002-11-20 23:21:51.000000000 +0100
@@ -225,13 +225,16 @@
return retval;
}

-static int scan_select_entries(fd_set_bits *fds, struct poll_table_entry *entries, int size, int *prev)
+static int scan_entries(struct poll_table_entry *entries, int size, void **prev,
+ int (*actor)(void *priv, void *handle, unsigned long mask), void *priv)
{
- int i;
int retval = 0;
+ int i;
+
for (i=0;i<size;i++) {
unsigned long mask;
- int fd;
+ void *handle;
+
if (!entries[i].woken)
continue;
entries[i].woken = 0;
@@ -239,18 +242,51 @@
/* drivers are permitted to use multiple waitqueues, but we must
* not double-account that in the return value
*/
- fd = (int)entries[i].handle;
- if (fd == *prev)
+ handle = entries[i].handle;
+ if (handle == *prev)
continue;
- *prev = fd;
+ *prev = handle;
mask = DEFAULT_POLLMASK;
if (entries[i].filp->f_op && entries[i].filp->f_op->poll)
mask = entries[i].filp->f_op->poll(entries[i].filp, NULL);
- retval += parse_mask(fds, mask, fd/__NFDBITS, BIT(fd));
+ retval += actor(priv, handle, mask);
+
}
return retval;
}

+static int wait_for_events(struct poll_wqueues *wait, long *timeout,
+ int (*actor)(void *priv, void *handle, unsigned long mask), void *priv)
+{
+ int count = 0;
+ for (;;) {
+ struct poll_table_page *pg;
+ void *prev;
+ if (count || !(*timeout) || signal_pending(current))
+ break;
+ count = wait->error;
+ if (count)
+ break;
+ *timeout = schedule_timeout(*timeout);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ prev = NULL;
+ count = scan_entries(wait->internal, wait->nr, &prev, actor, priv);
+ pg = wait->table;
+ while (pg) {
+ count += scan_entries(pg->entries, pg->entry-pg->entries, &prev, actor, priv);
+ pg = pg->next;
+ }
+ }
+ return count;
+}
+
+static int select_actor(void *priv, void *handle, unsigned long mask)
+{
+ int fd = (int)handle;
+ return parse_mask(priv, mask, fd/__NFDBITS, BIT(fd));
+}
+
int do_select(int n, fd_set_bits *fds, long *timeout)
{
struct poll_wqueues table;
@@ -294,27 +330,8 @@
if (retval)
wait = NULL;
}
- /* step two: now scan through the wait queues, that's faster
- * than the bit lookup */
- for (;;) {
- struct poll_table_page *pg;
- int prev;
- if (retval || !__timeout || signal_pending(current))
- break;
- if(table.error) {
- retval = table.error;
- break;
- }
- __timeout = schedule_timeout(__timeout);
- set_current_state(TASK_INTERRUPTIBLE);
- prev = -1;
- retval = scan_select_entries(fds, table.internal, table.nr, &prev);
- pg = table.table;
- while (pg) {
- retval += scan_select_entries(fds, pg->entries, pg->entry-pg->entries, &prev);
- pg = pg->next;
- }
- }
+ if (!retval && __timeout)
+ retval = wait_for_events(&table, &__timeout, select_actor, fds);
current->state = TASK_RUNNING;

poll_freewait(&table);
@@ -487,36 +504,16 @@
}
}

-static int scan_poll_entries(struct poll_table_entry *entries, int size, void **prev)
+int poll_actor(void *priv, void *handle, unsigned long mask)
{
- int retval = 0;
- int i;
-
- for (i=0;i<size;i++) {
- unsigned long mask;
- struct pollfd *fdp;
+ struct pollfd *fdp = handle;

- if (!entries[i].woken)
- continue;
- entries[i].woken = 0;
- mb();
- /* drivers are permitted to use multiple waitqueues, but we must
- * not double-account that in the return value
- */
- fdp = entries[i].handle;
- if (fdp == *prev)
- continue;
- *prev = fdp;
- mask = DEFAULT_POLLMASK;
- if (entries[i].filp->f_op && entries[i].filp->f_op->poll)
- mask = entries[i].filp->f_op->poll(entries[i].filp, NULL);
- mask &= fdp->events | POLLERR | POLLHUP;
- if (mask) {
- retval++;
- fdp->revents = mask;
- }
+ mask &= fdp->events | POLLERR | POLLHUP;
+ if (mask) {
+ fdp->revents = mask;
+ return 1;
}
- return retval;
+ return 0;
}

static int do_poll(unsigned int nfds, struct poll_list *list,
@@ -535,27 +532,8 @@
do_pollfd( walk->len, walk->entries, &pt, &count);
walk = walk->next;
}
- pt = NULL;
- for (;;) {
- struct poll_table_page *pg;
- void *prev;
-
- if (count || !timeout || signal_pending(current))
- break;
- count = wait->error;
- if (count)
- break;
- timeout = schedule_timeout(timeout);
-
- set_current_state(TASK_INTERRUPTIBLE);
- prev = NULL;
- count = scan_poll_entries(wait->internal, wait->nr, &prev);
- pg = wait->table;
- while (pg) {
- count += scan_poll_entries(pg->entries, pg->entry-pg->entries, &prev);
- pg = pg->next;
- }
- }
+ if (!count && timeout)
+ count = wait_for_events(wait, &timeout, poll_actor, NULL);
current->state = TASK_RUNNING;
return count;
}


Attachments:
patch-poll-1-wqalloc (4.18 kB)
patch-poll-2-selectalloc (1.57 kB)
patch-poll-3-alloc (5.08 kB)
patch-poll-4-fast-select (5.65 kB)
patch-poll-5-fast-poll (3.67 kB)
patch-poll-6-merge (4.71 kB)
Download all attachments

2002-11-21 00:21:37

by Davide Libenzi

[permalink] [raw]
Subject: Re: [RFC] 6 sys_poll/sys_select performance patches

On Thu, 21 Nov 2002, Manfred Spraul wrote:

> Attached are 6 patches that try to improve the performance of sys_poll
> and sys_select:
>
> - avoid dynamic memory allocations, stack storage is sufficient for most
> callers and faster.
> - use the wakeup callbacks and use that info to speed up the 2nd scan
> for new events.
>
> What do you think? Are there any apps/tests/benchmarks that stress
> sys_poll or sys_select?

You can try Ben's pipetest ...



- Davide


2002-11-21 02:06:14

by Hanna Linder

[permalink] [raw]
Subject: Re: [RFC] 6 sys_poll/sys_select performance patches

--On Wednesday, November 20, 2002 04:29:16 PM -0800 Davide Libenzi
<[email protected]> wrote:

>> What do you think? Are there any apps/tests/benchmarks that stress
>> sys_poll or sys_select?
>
> You can try Ben's pipetest ...

The pointer for which can be found (with detailed testing instructions)
at: http://lse.sf.net/epoll

Hanna