Re: [PATCH] 3 performance tweaks

From: kumon@flab.fujitsu.co.jp
Date: Wed May 24 2000 - 19:39:47 EST


Manfred Spraul writes:
> * Ingo has written a per-cpu slab. I'll wait until I have seen his
> patch.

I've already experimented my implementationo of per-cpu slab-cache.
By adding a limitted depth stack for each CPU in front of the slab
allocating logic . When a block is freed, it is put onto the stack
unless the depth is less than the limit, if it exceeds, the bottom of
the stack is returnd to slab allocating logic.

I used 32 entry stack and also limits the depth by the by cache amount
for the slab, in the experiment, the size limit is 32KB.

The result is very successfull, for the most of slab-types, the caches
hit more than 90% of the request, and also the Webbench gains about 5%
of speedup. Three are few slabs showing no cache gain, for example:
skbuf_head_cache, vm_area_struct.

skbuf_head_cache has alread had per-cpu cache in skb_head_pool in
skbuff.c, it also implement cache as stack, one difference is
skbuf_head_cache discard the newest data if the size exceeds the
limit.

vm_area_struct doesn't return slab by kmem_cache_free, the cache
mechanism is useless.

These behaviors suggest, the slab allocation needs extra information
such as NO_PER_CPU_CACHE, which can be informed at the cache creation
time.

The code is very ugly so I don't think I can submit it.

Also I found that most of size-32 slab is requested from select.c and
this data is used for only dynamic-sized array. Practically, number
of waiting fds is not so large, fixed sized array can eliminate
dynamic allocation.
The following patch implements it. But not so significant performance
gain is observed in practical applications.

diff -rc linux-2.3.99-pre8/fs/select.c work/fs/select.c
*** linux-2.3.99-pre8/fs/select.c Fri Apr 21 21:53:45 2000
--- work/fs/select.c Thu May 25 09:16:47 2000
***************
*** 252,257 ****
--- 252,258 ----
   */
  #define MAX_SELECT_SECONDS \
          ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
+ #define MAX_SELECT_AUTO_BITS 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_AUTO_BITS fds on stack */
+ char auto_bits[6 * FDS_BYTES(MAX_SELECT_AUTO_BITS)];
  
          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 = auto_bits;
! if (6 * size > sizeof(auto_bits)) {
! 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 != auto_bits)
! kfree(bits);
  out_nofds:
          return ret;
  }
***************
*** 400,411 ****
--- 407,422 ----
          return count;
  }
  
+ #define MAX_POLL_AUTO_FDS 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;
+ /* auto_fds can hold up to MAX_POLL_AUTO_FDS fds. */
+ struct pollfd *auto_fds[1 + (MAX_POLL_AUTO_FDS - 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 = auto_fds;
          if (nfds != 0) {
! unsigned int pollfdsz = 1 + (nfds - 1) / POLLFD_PER_PAGE * sizeof(struct pollfd *);
! if (pollfdsz > sizeof(auto_fds)) {
! 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 != auto_fds)
                  kfree(fds);
  out:
          free_wait(wait);

--
Computer Systems Laboratory, Fujitsu Labs.
kumon@flab.fujitsu.co.jp

- 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 May 31 2000 - 21:00:13 EST