Andi Kleen writes:
> On Sun, Jun 04, 2000 at 05:24:11AM +0900, kumon@flab.fujitsu.co.jp wrote:
> > Some part of kmalloc/kfree overhead is come from do_select, and it is
> > easily eliminated using small array on a stack. Which I've already
> > posted. IMHO per CPU skb will not reduce the kmalloc overhead,
>
> Funny, Linux before 2.2 did that, but it was changed to allow fd set size
> extensions. There were actually patches that tried stack alloc and
> dynamic depending on the size, but they were rejected because of the
> complexity.
The attached patch allocates an array on a stack which can hold at least
64 fds. The array size is 48B for do_select and 32B for do_poll.
This adds almost no overhead and eliminates all kmalloc() from
do_select/do_poll of tipical cases.
Is it complex enough?
Yes, it contains weird magic number 64. But it is practical and
useful.
diff -rc linux-2.4.0-test1-smp/fs/select.c work/fs/select.c
*** linux-2.4.0-test1-smp/fs/select.c Sat Apr 22 04:53:45 2000
--- work/fs/select.c Thu Jun 1 15:46:36 2000
***************
*** 252,257 ****
--- 252,258 ----
*/
#define MAX_SELECT_SECONDS \
((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
+ #define MAX_SELECT_BITS_ON_STACK 64
asmlinkage long
sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
***************
*** 260,265 ****
--- 261,268 ----
char *bits;
long timeout;
int ret, size;
+ /* can hold MAX_SELECT_BITS_ON_STACK fds on stack */
+ char bits_on_stack[6 * FDS_BYTES(MAX_SELECT_BITS_ON_STACK)];
timeout = MAX_SCHEDULE_TIMEOUT;
if (tvp) {
***************
*** 294,302 ****
*/
ret = -ENOMEM;
size = FDS_BYTES(n);
! bits = kmalloc(6 * size, GFP_KERNEL);
! if (!bits)
! goto out_nofds;
fds.in = (unsigned long *) bits;
fds.out = (unsigned long *) (bits + size);
fds.ex = (unsigned long *) (bits + 2*size);
--- 297,308 ----
*/
ret = -ENOMEM;
size = FDS_BYTES(n);
! bits = bits_on_stack;
! if (6 * size > sizeof(bits_on_stack)) {
! bits = kmalloc(6 * size, GFP_KERNEL);
! if (!bits)
! goto out_nofds;
! }
fds.in = (unsigned long *) bits;
fds.out = (unsigned long *) (bits + size);
fds.ex = (unsigned long *) (bits + 2*size);
***************
*** 339,345 ****
set_fd_set(n, exp, fds.res_ex);
out:
! kfree(bits);
out_nofds:
return ret;
}
--- 345,352 ----
set_fd_set(n, exp, fds.res_ex);
out:
! if (bits != bits_on_stack)
! kfree(bits);
out_nofds:
return ret;
}
***************
*** 400,411 ****
--- 407,422 ----
return count;
}
+ #define MAX_POLL_FDS_ON_STACK 64
+
asmlinkage long sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout)
{
int i, j, fdcount, err;
struct pollfd **fds;
poll_table *wait = NULL;
int nchunks, nleft;
+ /* fds_on_stack can hold up to MAX_POLL_FDS_ON_STACK fds. */
+ struct pollfd *fds_on_stack[1 + (MAX_POLL_FDS_ON_STACK - 1) / POLLFD_PER_PAGE];
/* Do a sanity check on nfds ... */
if (nfds > current->files->max_fds)
***************
*** 426,438 ****
}
err = -ENOMEM;
! fds = NULL;
if (nfds != 0) {
! fds = (struct pollfd **)kmalloc(
! (1 + (nfds - 1) / POLLFD_PER_PAGE) * sizeof(struct pollfd *),
! GFP_KERNEL);
! if (fds == NULL)
! goto out;
}
nchunks = 0;
--- 437,450 ----
}
err = -ENOMEM;
! fds = fds_on_stack;
if (nfds != 0) {
! unsigned int pollfdsz = 1 + (nfds - 1) / POLLFD_PER_PAGE * sizeof(struct pollfd *);
! if (pollfdsz > sizeof(fds_on_stack)) {
! fds = (struct pollfd **)kmalloc(pollfdsz, GFP_KERNEL);
! if (fds == NULL)
! goto out;
! }
}
nchunks = 0;
***************
*** 480,486 ****
out_fds:
for (i=0; i < nchunks; i++)
free_page((unsigned long)(fds[i]));
! if (nfds != 0)
kfree(fds);
out:
free_wait(wait);
--- 492,498 ----
out_fds:
for (i=0; i < nchunks; i++)
free_page((unsigned long)(fds[i]));
! if (fds != fds_on_stack)
kfree(fds);
out:
free_wait(wait);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/
This archive was generated by hypermail 2b29 : Wed Jun 07 2000 - 21:00:18 EST