This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

contribution to glibc


first i present myself, i am a computer scienc engineer.the reason for this email is to make two suggestion about the qsort function inside glibc.by reading the source code of glibc i noted that qsort could easily be made to use allocate half the size it is currently allocating to do merge sort.the modification to the file msort.c consists of a few lines.
the the idea came to me by reading the following website:


http://www.inf.fh-flensburg.de/lang/algorithmen/sortieren/merge/mergen.htm

the performance is also increased because less copying is done inside the function
msort_with_tmp().
the performance could be further inmproved by a simple modification to the function msort_with_tmp() by reducing the depth of the recursion; by treating the special case for n==2 in addition to the case n==1. this will eliminate the overhead of many function calls that do nothing.
i have tested my two suggestions on on different integer vectors and performance was increased between 8% and 25%.i have enclosed with this email both the patch and the modified file.


_________________________________________________________________
MSN Hotmail : créez votre adresse e-mail gratuite & à vie ! http://www.msn.fr/newhotmail/Default.asp?Ath=f
39c39,54
<   if (n <= 1)
---
>   if (n <= 2) {
>     if(n<=1)
>       return;
>     b1=b;
>     b2= (char *) b + s;
>     if ((*cmp) (b1, b2) > 0) {
>       if (s == OPSIZ && (b1 - (char *) 0) % OPSIZ == 0) {
>         *((op_t *) t) = *((op_t *) b1);
>         *((op_t *) b1) = *((op_t *) b2);
>         *((op_t *) b2) = *((op_t *) t);
>       } else {
>         memcpy (t, b1, s);
>         memcpy (b1, b2, s);
>         memcpy (b2, t, s);
>       };
>     };
40a56
>   };
46c62
< 
---
>   
49,50c65,67
< 
<   tmp = t;
---
>   memcpy (t, b, n1 * s);
>   b1=t;
>   tmp = b;
89d105
<   memcpy (b, t, (n - n2) * s);
99c115
<       void *buf = __alloca (size);
---
>       void *buf = __alloca (size/2);
124c140
< 	  phys_pages /= 4;
---
> 	  phys_pages /= 3;
137c153
<       if (size / pagesize > (size_t) phys_pages)
---
>       if (size / pagesize) > (size_t) phys_pages)
143c159
< 	  char *tmp = malloc (size);
---
> 	  char *tmp = malloc (size/2);

/* An alternative to qsort, with an identical interface.
   This file is part of the GNU C Library.
   Copyright (C) 1992,95-97,99,2000,01,02,04 Free Software Foundation, Inc.
   Written by Mike Haertel, September 1988.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */

#include <alloca.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <memcopy.h>
#include <errno.h>

static void msort_with_tmp (void *b, size_t n, size_t s,
			    __compar_fn_t cmp, char *t);

static void
msort_with_tmp (void *b, size_t n, size_t s, __compar_fn_t cmp,
		char *t)
{
  char *tmp;
  char *b1, *b2;
  size_t n1, n2;

  if (n <= 2) {
    if(n<=1)
      return;
    b1=b;
    b2= (char *) b + s;
    if ((*cmp) (b1, b2) > 0) {
      if (s == OPSIZ && (b1 - (char *) 0) % OPSIZ == 0) {
        *((op_t *) t) = *((op_t *) b1);
        *((op_t *) b1) = *((op_t *) b2);
        *((op_t *) b2) = *((op_t *) t);
      } else {
        memcpy (t, b1, s);
        memcpy (b1, b2, s);
        memcpy (b2, t, s);
      };
    };
    return;
  };

  n1 = n / 2;
  n2 = n - n1;
  b1 = b;
  b2 = (char *) b + (n1 * s);
  
  msort_with_tmp (b1, n1, s, cmp, t);
  msort_with_tmp (b2, n2, s, cmp, t);
  memcpy (t, b, n1 * s);
  b1=t;
  tmp = b;

  if (s == OPSIZ && (b1 - (char *) 0) % OPSIZ == 0)
    /* We are operating on aligned words.  Use direct word stores.  */
    while (n1 > 0 && n2 > 0)
      {
	if ((*cmp) (b1, b2) <= 0)
	  {
	    --n1;
	    *((op_t *) tmp) = *((op_t *) b1);
	    tmp += sizeof (op_t);
	    b1 += sizeof (op_t);
	  }
	else
	  {
	    --n2;
	    *((op_t *) tmp) = *((op_t *) b2);
	    tmp += sizeof (op_t);
	    b2 += sizeof (op_t);
	  }
      }
  else
    while (n1 > 0 && n2 > 0)
      {
	if ((*cmp) (b1, b2) <= 0)
	  {
	    tmp = (char *) __mempcpy (tmp, b1, s);
	    b1 += s;
	    --n1;
	  }
	else
	  {
	    tmp = (char *) __mempcpy (tmp, b2, s);
	    b2 += s;
	    --n2;
	  }
      }
  if (n1 > 0)
    memcpy (tmp, b1, n1 * s);
}

void
qsort (void *b, size_t n, size_t s, __compar_fn_t cmp)
{
  const size_t size = n * s;

  if (size < 1024)
    {
      void *buf = __alloca (size/2);

      /* The temporary array is small, so put it on the stack.  */
      msort_with_tmp (b, n, s, cmp, buf);
    }
  else
    {
      /* We should avoid allocating too much memory since this might
	 have to be backed up by swap space.  */
      static long int phys_pages;
      static int pagesize;

      if (phys_pages == 0)
	{
	  phys_pages = __sysconf (_SC_PHYS_PAGES);

	  if (phys_pages == -1)
	    /* Error while determining the memory size.  So let's
	       assume there is enough memory.  Otherwise the
	       implementer should provide a complete implementation of
	       the `sysconf' function.  */
	    phys_pages = (long int) (~0ul >> 1);

	  /* The following determines that we will never use more than
	     a quarter of the physical memory.  */
	  phys_pages /= 3;

	  pagesize = __sysconf (_SC_PAGESIZE);
	}

      /* Just a comment here.  We cannot compute
	   phys_pages * pagesize
	   and compare the needed amount of memory against this value.
	   The problem is that some systems might have more physical
	   memory then can be represented with a `size_t' value (when
	   measured in bytes.  */

      /* If the memory requirements are too high don't allocate memory.  */
      if (size / pagesize) > (size_t) phys_pages)
	_quicksort (b, n, s, cmp);
      else
	{
	  /* It's somewhat large, so malloc it.  */
	  int save = errno;
	  char *tmp = malloc (size/2);
	  if (tmp == NULL)
	    {
	      /* Couldn't get space, so use the slower algorithm
		 that doesn't need a temporary array.  */
	      __set_errno (save);
	      _quicksort (b, n, s, cmp);
	    }
	  else
	    {
	      __set_errno (save);
	      msort_with_tmp (b, n, s, cmp, tmp);
	      free (tmp);
	    }
	}
    }
}
libc_hidden_def (qsort)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]