Hello,

the attached patch modifies the allocator (and pool) to allow for
order-0 nodes/allocations (2^0, one page, 4K on most CPUs).

The pools are still created with order-1 (two pages) by default, but
one can use the new apr_pool_order_set(order) function at any time
(preferable init time) to default to different order (max 9).

This change requires to recycle single pages in slot 0
(allocator->free[0]) and thus to move the sink slot at MAX_INDEX (for
non-fitting nodes).

Also, since the page is now relevant outside APR_ALLOCATOR_USES_MMAP
scope, _SC_PAGESIZE is always determined at init time and gives
dynamic BOUNDARY_INDEX/BOUNDARY_SIZE for runtime (only when
_SC_PAGESIZE is defined still, otherwise 4K is the default).

Pros/cons?


Regards,
Yann.
Index: include/apr_pools.h
===================================================================
--- include/apr_pools.h	(revision 1784277)
+++ include/apr_pools.h	(working copy)
@@ -171,6 +171,13 @@ APR_DECLARE(apr_status_t) apr_pool_initialize(void
  */
 APR_DECLARE(void) apr_pool_terminate(void);
 
+/**
+ * Setup the order (power of two number of pages to allocate) when creating
+ * a pool.
+ * @param order The order to set
+ * @return APR_SUCCESS, or APR_EINVAL if @a order is too high (e.g. 10)
+ */
+APR_DECLARE(apr_status_t) apr_pool_order_set(unsigned int order);
 
 /*
  * Pool creation/destruction
Index: memory/unix/apr_pools.c
===================================================================
--- memory/unix/apr_pools.c	(revision 1784277)
+++ memory/unix/apr_pools.c	(working copy)
@@ -63,23 +63,30 @@ int apr_running_on_valgrind = 0;
  */
 
 /*
- * XXX: This is not optimal when using --enable-allocator-uses-mmap on
- * XXX: machines with large pagesize, but currently the sink is assumed
- * XXX: to be index 0, so MIN_ALLOC must be at least two pages.
+ * Allocate at least MIN_ALLOC (one boundary/page) bytes.
+ * Recycle up to MAX_INDEX in slots, larger indexes go to
+ * the sink slot at MAX_INDEX.
  */
-#define MIN_ALLOC (2 * BOUNDARY_SIZE)
-#define MAX_INDEX   20
+#define MIN_ALLOC BOUNDARY_SIZE
+#define MAX_INDEX 20
 
-#if APR_ALLOCATOR_USES_MMAP && defined(_SC_PAGESIZE)
+/*
+ * Determines the boundary/page size.
+ */
+#if defined(_SC_PAGESIZE)
 static unsigned int boundary_index;
 static unsigned int boundary_size;
 #define BOUNDARY_INDEX  boundary_index
 #define BOUNDARY_SIZE   boundary_size
-#else
-#define BOUNDARY_INDEX 12
-#define BOUNDARY_SIZE (1 << BOUNDARY_INDEX)
+#else  /* Assume 4K pages */
+#define BOUNDARY_INDEX  12
+#define BOUNDARY_SIZE   (1 << BOUNDARY_INDEX)
 #endif
 
+#define POOL_ORDER_MAX  9
+static unsigned int     pool_order = 1;
+#define POOL_SIZE       (BOUNDARY_SIZE << pool_order)
+
 #if APR_ALLOCATOR_GUARD_PAGES
 #if defined(_SC_PAGESIZE)
 #define GUARDPAGE_SIZE boundary_size
@@ -126,16 +133,17 @@ struct apr_allocator_t {
 #endif /* APR_HAS_THREADS */
     apr_pool_t         *owner;
     /**
-     * Lists of free nodes. Slot 0 is used for oversized nodes,
-     * and the slots 1..MAX_INDEX-1 contain nodes of sizes
+     * Lists of free nodes. Slot MAX_INDEX is used for oversized nodes,
+     * and the slots 0..MAX_INDEX-1 contain nodes of sizes
      * (i+1) * BOUNDARY_SIZE. Example for BOUNDARY_INDEX == 12:
-     * slot  0: nodes larger than 81920
+     * slot  0: size  4096
      * slot  1: size  8192
      * slot  2: size 12288
      * ...
      * slot 19: size 81920
+     * slot 20: nodes larger than 81920
      */
-    apr_memnode_t      *free[MAX_INDEX];
+    apr_memnode_t      *free[MAX_INDEX + 1];
 };
 
 #define SIZEOF_ALLOCATOR_T  APR_ALIGN_DEFAULT(sizeof(apr_allocator_t))
@@ -167,7 +175,7 @@ APR_DECLARE(void) apr_allocator_destroy(apr_alloca
     apr_uint32_t index;
     apr_memnode_t *node, **ref;
 
-    for (index = 0; index < MAX_INDEX; index++) {
+    for (index = 0; index <= MAX_INDEX; index++) {
         ref = &allocator->free[index];
         while ((node = *ref) != NULL) {
             *ref = node->next;
@@ -328,10 +336,10 @@ apr_memnode_t *allocator_alloc(apr_allocator_t *al
 #endif /* APR_HAS_THREADS */
     }
 
-    /* If we found nothing, seek the sink (at index 0), if
+    /* If we found nothing, seek the sink (at index MAX_INDEX), if
      * it is not empty.
      */
-    else if (allocator->free[0]) {
+    else if (allocator->free[MAX_INDEX]) {
 #if APR_HAS_THREADS
         if (allocator->mutex)
             apr_thread_mutex_lock(allocator->mutex);
@@ -340,7 +348,7 @@ apr_memnode_t *allocator_alloc(apr_allocator_t *al
         /* Walk the free list to see if there are
          * any nodes on it of the requested size
          */
-        ref = &allocator->free[0];
+        ref = &allocator->free[MAX_INDEX];
         while ((node = *ref) != NULL && index > node->index)
             ref = &node->next;
 
@@ -445,10 +453,10 @@ void allocator_free(apr_allocator_t *allocator, ap
         }
         else {
             /* This node is too large to keep in a specific size bucket,
-             * just add it to the sink (at index 0).
+             * just add it to the sink (at index MAX_INDEX).
              */
-            node->next = allocator->free[0];
-            allocator->free[0] = node;
+            node->next = allocator->free[MAX_INDEX];
+            allocator->free[MAX_INDEX] = node;
             if (current_free_index >= index + 1)
                 current_free_index -= index + 1;
             else
@@ -622,6 +630,15 @@ static void free_proc_chain(struct process_chain *
 static void pool_destroy_debug(apr_pool_t *pool, const char *file_line);
 #endif
 
+APR_DECLARE(apr_status_t) apr_pool_order_set(unsigned int order)
+{
+    if (order > POOL_ORDER_MAX) {
+        return APR_EINVAL;
+    }
+    pool_order = order;
+    return APR_SUCCESS;
+}
+
 #if !APR_POOL_DEBUG
 /*
  * Initialization
@@ -638,7 +655,7 @@ APR_DECLARE(apr_status_t) apr_pool_initialize(void
     apr_running_on_valgrind = RUNNING_ON_VALGRIND;
 #endif
 
-#if APR_ALLOCATOR_USES_MMAP && defined(_SC_PAGESIZE)
+#if defined(_SC_PAGESIZE)
     boundary_size = sysconf(_SC_PAGESIZE);
     boundary_index = 12;
     while ( (1 << boundary_index) < boundary_size)
@@ -1050,7 +1067,7 @@ APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_p
         allocator = parent->allocator;
 
     if ((node = allocator_alloc(allocator,
-                                MIN_ALLOC - APR_MEMNODE_T_SIZE)) == NULL) {
+                                POOL_SIZE - APR_MEMNODE_T_SIZE)) == NULL) {
         if (abort_fn)
             abort_fn(APR_ENOMEM);
 
@@ -1144,7 +1161,7 @@ APR_DECLARE(apr_status_t) apr_pool_create_unmanage
             return APR_ENOMEM;
         }
         if ((node = allocator_alloc(pool_allocator,
-                                   MIN_ALLOC - APR_MEMNODE_T_SIZE)) == NULL) {
+                                    POOL_SIZE - APR_MEMNODE_T_SIZE)) == NULL) {
             if (abort_fn)
                 abort_fn(APR_ENOMEM);
 
@@ -1152,7 +1169,7 @@ APR_DECLARE(apr_status_t) apr_pool_create_unmanage
         }
     }
     else if ((node = allocator_alloc(pool_allocator,
-                                     MIN_ALLOC - APR_MEMNODE_T_SIZE)) == NULL) {
+                                     POOL_SIZE - APR_MEMNODE_T_SIZE)) == NULL) {
         if (abort_fn)
             abort_fn(APR_ENOMEM);
 
@@ -1634,7 +1651,7 @@ APR_DECLARE(apr_status_t) apr_pool_initialize(void
     if (apr_pools_initialized++)
         return APR_SUCCESS;
 
-#if APR_ALLOCATOR_USES_MMAP && defined(_SC_PAGESIZE)
+#if defined(_SC_PAGESIZE)
     boundary_size = sysconf(_SC_PAGESIZE);
     boundary_index = 12;
     while ( (1 << boundary_index) < boundary_size)

Reply via email to