Index: configure.in
===================================================================
RCS file: /cvs/gnome/glib/configure.in,v
retrieving revision 1.440
diff -u -p -r1.440 configure.in
--- configure.in	31 Mar 2005 06:22:18 -0000	1.440
+++ configure.in	3 Apr 2005 13:24:44 -0000
@@ -814,6 +814,15 @@ AC_CHECK_FUNCS(lstat strerror strsignal 
 AC_FUNC_VSNPRINTF_C99
 AC_FUNC_PRINTF_UNIX98
 
+AC_ARG_ENABLE(memalign,
+	      [AC_HELP_STRING([--enable-memalign],
+	                      [use posix_memalign() to speed up memchunks, if available [default=yes]])],
+              enable_memalign="$enableval",
+	      enable_memalign="yes")
+if test "x$enable_memalign" = "xyes" ; then
+  AC_CHECK_FUNCS(posix_memalign)
+fi
+
 #
 # Check whether to use an included printf
 #
Index: glib/gmem.c
===================================================================
RCS file: /cvs/gnome/glib/glib/gmem.c,v
retrieving revision 1.47
diff -u -p -r1.47 gmem.c
--- glib/gmem.c	22 Mar 2005 04:09:16 -0000	1.47
+++ glib/gmem.c	3 Apr 2005 13:24:45 -0000
@@ -30,6 +30,7 @@
 
 #include "config.h"
 
+#define _GNU_SOURCE
 #include <stdlib.h>
 #include <string.h>
 #include <signal.h>
@@ -637,23 +638,39 @@ struct _GMemChunk
   gint num_marked_areas;     /* the number of areas marked for deletion */
   guint atom_size;           /* the size of an atom */
   gulong area_size;          /* the size of a memory area */
+  guint area_shift;          /* 2^area_shift == area_size */
   GMemArea *mem_area;        /* the current memory area */
   GMemArea *mem_areas;       /* a list of all the mem areas owned by this chunk */
   GMemArea *free_mem_area;   /* the free area...which is about to be destroyed */
   GFreeAtom *free_atoms;     /* the free atoms list */
+#ifndef HAVE_POSIX_MEMALIGN
   GTree *mem_tree;           /* tree of mem areas sorted by memory address */
+#endif
   GMemChunk *next;           /* pointer to the next chunk */
   GMemChunk *prev;           /* pointer to the previous chunk */
 };
 
 
 #ifndef DISABLE_MEM_POOLS
-static gulong g_mem_chunk_compute_size (gulong    size,
-					gulong    min_size) G_GNUC_CONST;
+static void   g_mem_chunk_compute_size (GMemChunk *chunk,
+                                        gulong     size,
+					gulong     min_size);
+static inline GMemArea *g_mem_chunk_area_find (GMemChunk *mem_chunk,
+                                               gpointer mem) G_GNUC_CONST;
+
+static inline GMemArea *g_mem_chunk_area_alloc (GMemChunk *mem_chunk);
+static inline void g_mem_chunk_remove_area (GMemChunk *mem_chunk,
+                                            GMemArea *area);
+static inline void g_mem_chunk_add_area (GMemChunk *mem_chunk,
+                                         GMemArea *area);
+
+#ifndef HAVE_POSIX_MEMALIGN
 static gint   g_mem_chunk_area_compare (GMemArea *a,
 					GMemArea *b);
-static gint   g_mem_chunk_area_search  (GMemArea *a,
-					gchar    *addr);
+#define g_mem_chunk_area_free(area) g_free (area)
+#else
+#define g_mem_chunk_area_free(area) free (area)
+#endif
 
 /* here we can't use StaticMutexes, as they depend upon a working
  * g_malloc, the same holds true for StaticPrivate
@@ -686,19 +703,21 @@ g_mem_chunk_new (const gchar  *name,
   mem_chunk->mem_area = NULL;
   mem_chunk->free_mem_area = NULL;
   mem_chunk->free_atoms = NULL;
-  mem_chunk->mem_tree = NULL;
   mem_chunk->mem_areas = NULL;
   mem_chunk->atom_size = atom_size;
-  
+
+#ifndef HAVE_POSIX_MEMALIGN
   if (mem_chunk->type == G_ALLOC_AND_FREE)
     mem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare);
+  else
+      mem_chunk->mem_tree = NULL;
+#endif
   
   if (mem_chunk->atom_size % G_MEM_ALIGN)
     mem_chunk->atom_size += G_MEM_ALIGN - (mem_chunk->atom_size % G_MEM_ALIGN);
 
   rarea_size = area_size + sizeof (GMemArea) - MEM_AREA_SIZE;
-  rarea_size = g_mem_chunk_compute_size (rarea_size, atom_size + sizeof (GMemArea) - MEM_AREA_SIZE);
-  mem_chunk->area_size = rarea_size - (sizeof (GMemArea) - MEM_AREA_SIZE);
+  g_mem_chunk_compute_size (mem_chunk, rarea_size, atom_size + sizeof (GMemArea) - MEM_AREA_SIZE);
 
   g_mutex_lock (mem_chunks_lock);
   mem_chunk->next = mem_chunks;
@@ -728,7 +747,7 @@ g_mem_chunk_destroy (GMemChunk *mem_chun
     {
       temp_area = mem_areas;
       mem_areas = mem_areas->next;
-      g_free (temp_area);
+      g_mem_chunk_area_free (temp_area);
     }
   
   g_mutex_lock (mem_chunks_lock);
@@ -740,10 +759,12 @@ g_mem_chunk_destroy (GMemChunk *mem_chun
   if (mem_chunk == mem_chunks)
     mem_chunks = mem_chunks->next;
   g_mutex_unlock (mem_chunks_lock);
-  
+
+#ifndef HAVE_POSIX_MEMALIGN
   if (mem_chunk->type == G_ALLOC_AND_FREE)
     g_tree_destroy (mem_chunk->mem_tree);  
-
+#endif
+  
   g_free (mem_chunk);
 
   LEAVE_MEM_CHUNK_ROUTINE ();
@@ -770,9 +791,7 @@ g_mem_chunk_alloc (GMemChunk *mem_chunk)
       mem_chunk->free_atoms = mem_chunk->free_atoms->next;
       
       /* Determine which area this piece of memory is allocated from */
-      temp_area = g_tree_search (mem_chunk->mem_tree,
-				 (GCompareFunc) g_mem_chunk_area_search,
-				 mem);
+      temp_area = g_mem_chunk_area_find (mem_chunk, mem);
       
       /* If the area has been marked, then it is being destroyed.
        *  (ie marked to be destroyed).
@@ -806,10 +825,8 @@ g_mem_chunk_alloc (GMemChunk *mem_chunk)
                     temp_area->prev->next = temp_area->next;
                   if (temp_area == mem_chunk->mem_areas)
                     mem_chunk->mem_areas = mem_chunk->mem_areas->next;
-		  
-		  if (mem_chunk->type == G_ALLOC_AND_FREE)
-		    g_tree_remove (mem_chunk->mem_tree, temp_area);
-                  g_free (temp_area);
+
+                  g_mem_chunk_remove_area (mem_chunk, temp_area);
                 }
               else
                 mem_chunk->free_mem_area = temp_area;
@@ -843,15 +860,7 @@ g_mem_chunk_alloc (GMemChunk *mem_chunk)
         }
       else
         {
-#ifdef ENABLE_GC_FRIENDLY
-	  mem_chunk->mem_area = (GMemArea*) g_malloc0 (sizeof (GMemArea) -
-						       MEM_AREA_SIZE +
-						       mem_chunk->area_size); 
-#else /* !ENABLE_GC_FRIENDLY */
-	  mem_chunk->mem_area = (GMemArea*) g_malloc (sizeof (GMemArea) -
-						      MEM_AREA_SIZE +
-						      mem_chunk->area_size);
-#endif /* ENABLE_GC_FRIENDLY */
+          mem_chunk->mem_area = g_mem_chunk_area_alloc (mem_chunk);
 	  
 	  mem_chunk->num_mem_areas += 1;
 	  mem_chunk->mem_area->next = mem_chunk->mem_areas;
@@ -860,9 +869,8 @@ g_mem_chunk_alloc (GMemChunk *mem_chunk)
 	  if (mem_chunk->mem_areas)
 	    mem_chunk->mem_areas->prev = mem_chunk->mem_area;
 	  mem_chunk->mem_areas = mem_chunk->mem_area;
-	  
-	  if (mem_chunk->type == G_ALLOC_AND_FREE)
-	    g_tree_insert (mem_chunk->mem_tree, mem_chunk->mem_area, mem_chunk->mem_area);
+
+	  g_mem_chunk_add_area (mem_chunk, mem_chunk->mem_area);
         }
       
       mem_chunk->mem_area->index = 0;
@@ -924,11 +932,8 @@ g_mem_chunk_free (GMemChunk *mem_chunk,
       free_atom = (GFreeAtom*) mem;
       free_atom->next = mem_chunk->free_atoms;
       mem_chunk->free_atoms = free_atom;
-      
-      temp_area = g_tree_search (mem_chunk->mem_tree,
-				 (GCompareFunc) g_mem_chunk_area_search,
-				 mem);
-      
+      temp_area = g_mem_chunk_area_find (mem_chunk, mem);
+
       temp_area->allocated -= 1;
       
       if (temp_area->allocated == 0)
@@ -963,9 +968,7 @@ g_mem_chunk_clean (GMemChunk *mem_chunk)
 	{
 	  mem = (gpointer) temp_free_atom;
 	  
-	  mem_area = g_tree_search (mem_chunk->mem_tree,
-				    (GCompareFunc) g_mem_chunk_area_search,
-				    mem);
+	  mem_area = g_mem_chunk_area_find (mem_chunk, mem);
 	  
           /* If this mem area is marked for destruction then delete the
 	   *  area and list node and decrement the free mem.
@@ -992,10 +995,8 @@ g_mem_chunk_clean (GMemChunk *mem_chunk)
 		    mem_chunk->mem_areas = mem_chunk->mem_areas->next;
 		  if (mem_area == mem_chunk->mem_area)
 		    mem_chunk->mem_area = NULL;
-		  
-		  if (mem_chunk->type == G_ALLOC_AND_FREE)
-		    g_tree_remove (mem_chunk->mem_tree, mem_area);
-		  g_free (mem_area);
+
+                  g_mem_chunk_remove_area (mem_chunk, mem_area);
 		}
 	    }
 	  else
@@ -1027,16 +1028,18 @@ g_mem_chunk_reset (GMemChunk *mem_chunk)
     {
       temp_area = mem_areas;
       mem_areas = mem_areas->next;
-      g_free (temp_area);
+      g_mem_chunk_area_free (temp_area);
     }
   
   mem_chunk->free_atoms = NULL;
-  
+
+#ifndef HAVE_POSIX_MEMALIGN
   if (mem_chunk->mem_tree)
     {
       g_tree_destroy (mem_chunk->mem_tree);
       mem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare);
     }
+#endif
 
   LEAVE_MEM_CHUNK_ROUTINE ();
 }
@@ -1107,26 +1110,69 @@ g_blow_chunks (void)
     }
 }
 
-static gulong
-g_mem_chunk_compute_size (gulong size,
+static void
+g_mem_chunk_compute_size (GMemChunk *mem_chunk,
+                          gulong size,
 			  gulong min_size)
 {
   gulong power_of_2;
   gulong lower, upper;
+  guint shift;
   
   power_of_2 = 16;
-  while (power_of_2 < size)
+  for (shift = 4; power_of_2 < size; shift++)
     power_of_2 <<= 1;
   
   lower = power_of_2 >> 1;
   upper = power_of_2;
   
   if (size - lower < upper - size && lower >= min_size)
-    return lower;
+    mem_chunk->area_size = lower;
   else
-    return upper;
+    mem_chunk->area_size = upper;
+  mem_chunk->area_shift = shift;
+  
+  mem_chunk->area_size -= (sizeof (GMemArea) - MEM_AREA_SIZE);
+}
+
+#ifdef HAVE_POSIX_MEMALIGN
+
+static GMemArea *
+g_mem_chunk_area_find (GMemChunk *mem_chunk,
+                       gpointer mem)
+{
+  return (GMemArea *)(((gulong)mem & (~0UL << mem_chunk->area_shift)));
+}
+
+static GMemArea *
+g_mem_chunk_area_alloc (GMemChunk *mem_chunk)
+{
+  GMemArea *area;
+  int retval;
+  
+  retval = posix_memalign (&area, 1 << mem_chunk->area_shift,
+                           sizeof (GMemArea) - MEM_AREA_SIZE +
+                           mem_chunk->area_size);
+  g_assert (retval == 0);
+
+  return area;
+}
+
+static void
+g_mem_chunk_remove_area (GMemChunk *mem_chunk,
+                         GMemArea *area)
+{
+  free (area);
+}
+
+static void
+g_mem_chunk_add_area (GMemChunk *mem_chunk,
+                      GMemArea *area)
+{
 }
 
+#else /* no posix_memalign() */
+
 static gint
 g_mem_chunk_area_compare (GMemArea *a,
 			  GMemArea *b)
@@ -1150,6 +1196,46 @@ g_mem_chunk_area_search (GMemArea *a,
     }
   return -1;
 }
+
+static GMemArea *
+g_mem_chunk_area_find (GMemChunk *mem_chunk,
+                       gpointer mem)
+{
+  return g_tree_search (mem_chunk->mem_tree,
+                        (GCompareFunc) g_mem_chunk_area_search,
+                        mem);
+}
+
+static GMemArea *
+g_mem_chunk_area_alloc (GMemChunk *mem_chunk)
+{
+#ifdef ENABLE_GC_FRIENDLY
+  return (GMemArea*) g_malloc0 (sizeof (GMemArea) - MEM_AREA_SIZE +
+                                mem_chunk->area_size);
+#else /* !ENABLE_GC_FRIENDLY */
+  return (GMemArea*) g_malloc (sizeof (GMemArea) - MEM_AREA_SIZE +
+                               mem_chunk->area_size);
+#endif /* ENABLE_GC_FRIENDLY */
+}
+
+static void
+g_mem_chunk_remove_area (GMemChunk *mem_chunk,
+                         GMemArea *area)
+{
+  if (mem_chunk->type == G_ALLOC_AND_FREE)
+    g_tree_remove (mem_chunk->mem_tree, area);
+  g_free (area);
+}
+
+static void
+g_mem_chunk_add_area (GMemChunk *mem_chunk,
+                      GMemArea *area)
+{
+  if (mem_chunk->type == G_ALLOC_AND_FREE)
+    g_tree_insert (mem_chunk->mem_tree, area, area);
+}
+
+#endif      
 
 #else /* DISABLE_MEM_POOLS */
 
Index: tests/Makefile.am
===================================================================
RCS file: /cvs/gnome/glib/tests/Makefile.am,v
retrieving revision 1.68
diff -u -p -r1.68 Makefile.am
--- tests/Makefile.am	8 Feb 2005 15:14:31 -0000	1.68
+++ tests/Makefile.am	3 Apr 2005 13:24:45 -0000
@@ -49,7 +49,7 @@ endif
 if ENABLE_TIMELOOP
 timeloop = timeloop timeloop-closure
 endif
-noinst_PROGRAMS = testglib testgdate testgdateparser unicode-normalize unicode-collate $(timeloop)
+noinst_PROGRAMS = testglib testgdate testgdateparser unicode-normalize unicode-collate $(timeloop) memchunk-speed
 testglib_LDADD = $(libglib)
 patterntest_LDADD = $(libglib)
 testgdate_LDADD = $(libglib)
@@ -157,6 +157,7 @@ unicode_encoding_LDADD = $(progs_ldadd)
 unicode_caseconv_LDADD = $(progs_ldadd)
 utf8_validate_LDADD = $(progs_ldadd)
 uri_test_LDADD = $(progs_ldadd)
+memchunk_speed_LDADD = $(progs_ldadd)
 
 lib_LTLIBRARIES = libmoduletestplugin_a.la libmoduletestplugin_b.la
 
Index: tests/memchunk-speed.c
===================================================================
RCS file: tests/memchunk-speed.c
diff -N tests/memchunk-speed.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/memchunk-speed.c	3 Apr 2005 13:24:45 -0000
@@ -0,0 +1,74 @@
+#include "glib.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#define NUM (1000L * 1000L * 10L)
+#define ATOM_SIZE 8
+#define AREA_SIZE ATOM_SIZE * 1024
+#define MAX_AT_A_TIME 10
+
+int main (int argc, char *argv[])
+{
+  int j, count;
+  long i;
+  GPtrArray *atoms;
+  GTimer *timer = g_timer_new ();
+  
+  atoms = g_ptr_array_sized_new (MAX_AT_A_TIME * 100);
+
+  printf ("timing %ld random malloc()/free() calls...", NUM);
+  g_timer_start (timer);
+  for (i = 0; i < NUM; i += count)
+  {
+    count = g_random_int_range (1, MAX_AT_A_TIME);
+    if (atoms->len == 0 || g_random_int () % 2)
+    {
+      for (j = 0; j < count; j++)
+        g_ptr_array_add (atoms, malloc (ATOM_SIZE));
+    }
+    else
+    {
+      if (count > atoms->len)
+        count = atoms->len;
+      for (j = 0; j < count; j++)
+        free (g_ptr_array_remove_index_fast (atoms,
+                                             g_random_int() % atoms->len));
+    }
+  }
+  g_timer_stop (timer);
+  printf ("%g seconds\n", g_timer_elapsed (timer, NULL));
+  while (atoms->len > 0)
+    free (g_ptr_array_remove_index_fast (atoms, 0));
+
+  GMemChunk *memchunk = g_mem_chunk_new ("test memory",
+                                         ATOM_SIZE, AREA_SIZE,
+                                         G_ALLOC_AND_FREE);
+
+  printf ("timing %ld random memchunk alloc()/free() calls...", NUM);
+  g_timer_start (timer);
+  
+  for (i = 0; i < NUM; i += count)
+  {
+    count = g_random_int_range (1, MAX_AT_A_TIME);
+    if (atoms->len == 0 || g_random_int () % 2)
+    {
+      for (j = 0; j < count; j++)
+        g_ptr_array_add (atoms, g_mem_chunk_alloc (memchunk));
+    }
+    else
+    {
+      if (count > atoms->len)
+        count = atoms->len;
+      for (j = 0; j < count; j++)
+        g_mem_chunk_free (memchunk,
+                          g_ptr_array_remove_index_fast (atoms,
+                                                         g_random_int() % atoms->len));
+    }
+  }
+  printf ("%g seconds\n", g_timer_elapsed (timer, NULL));
+
+  g_free (timer);
+  
+  return 0;
+}
