[gegl] buffer: in gegl-tile-alloc, keep a spare empty block



commit 54d1ef723ecded5e2c7987f43d0278c4f216ed29
Author: Ell <ell_se yahoo com>
Date:   Sun Apr 26 14:20:56 2020 +0300

    buffer: in gegl-tile-alloc, keep a spare empty block
    
    In gegl-tile-alloc, when all tiles in a block are freed, keep a
    single empty block around at any given time as a spare, and reuse
    the block when a new one is required.  This avoids frequent block
    allocation and freeing when a single (or few) tiles on the edge of
    a block are repeadtedly allocated/freed.

 gegl/buffer/gegl-tile-alloc.c | 202 ++++++++++++++++++++++++++++--------------
 gegl/buffer/gegl-tile-alloc.h |   3 +
 gegl/gegl-init.c              |   3 +
 3 files changed, 143 insertions(+), 65 deletions(-)
---
diff --git a/gegl/buffer/gegl-tile-alloc.c b/gegl/buffer/gegl-tile-alloc.c
index c7cf44ec3..e1a0d4a9b 100644
--- a/gegl/buffer/gegl-tile-alloc.c
+++ b/gegl/buffer/gegl-tile-alloc.c
@@ -81,6 +81,7 @@ static GeglTileBlock         * gegl_tile_block_new        (GeglTileBlock * volat
                                                            gsize                      size);
 static void                    gegl_tile_block_free       (GeglTileBlock             *block,
                                                            GeglTileBlock            **head_block);
+static void                    gegl_tile_block_free_mem   (GeglTileBlock             *block);
 
 static inline gpointer         gegl_tile_buffer_to_data   (GeglTileBuffer            *buffer);
 static inline GeglTileBuffer * gegl_tile_buffer_from_data (gpointer                   data);
@@ -93,6 +94,7 @@ static gpointer                gegl_tile_alloc_fallback   (gsize
 static const gint     gegl_tile_divisors[] = {1, 3, 5};
 static GeglTileBlock *gegl_tile_blocks[G_N_ELEMENTS (gegl_tile_divisors)]
                                       [GEGL_TILE_MAX_SIZE_LOG2];
+static GeglTileBlock *gegl_tile_empty_block;
 static gint           gegl_tile_n_blocks;
 static gint           gegl_tile_max_n_blocks;
 
@@ -138,66 +140,99 @@ static GeglTileBlock *
 gegl_tile_block_new (GeglTileBlock * volatile *block_ptr,
                      gsize                     size)
 {
-  GeglTileBlock   *block;
-  GeglTileBuffer  *buffer;
-  GeglTileBuffer **next_buffer;
-  gsize            block_size;
-  gsize            buffer_size;
-  gsize            n_buffers;
-  gint             n_blocks;
-  gint             i;
+  GeglTileBlock *block;
+  gsize          block_size;
+  gsize          buffer_size;
+  gsize          n_buffers;
+  gboolean       init_block = TRUE;
 
   buffer_size = GEGL_TILE_BUFFER_DATA_OFFSET + GEGL_ALIGN (size);
 
-  block_size  = floor (gegl_buffer_config ()->tile_cache_size *
-                       GEGL_TILE_BLOCK_SIZE_RATIO);
-  block_size -= block_size % buffer_size;
+  do
+    {
+      block = gegl_tile_empty_block;
+    }
+  while (block &&
+         ! g_atomic_pointer_compare_and_exchange (&gegl_tile_empty_block,
+                                                  block, NULL));
 
-  n_buffers = block_size / buffer_size;
-  n_buffers = MIN (n_buffers, GEGL_TILE_BLOCK_MAX_BUFFERS);
+  if (block && block->size - GEGL_TILE_BLOCK_BUFFER_OFFSET < buffer_size)
+    {
+      gegl_tile_block_free_mem (block);
 
-  if (n_buffers <= 1)
-    return NULL;
+      block = NULL;
+    }
 
-  block_size = n_buffers * buffer_size;
+  if (block)
+    {
+      block_size = block->size;
 
-  block = gegl_try_malloc (GEGL_TILE_BLOCK_BUFFER_OFFSET + block_size);
+      n_buffers = (block_size - GEGL_TILE_BLOCK_BUFFER_OFFSET) / buffer_size;
 
-  if (! block)
-    return NULL;
+      if (block->block_ptr == block_ptr)
+        init_block = FALSE;
+    }
+  else
+    {
+      gint n_blocks;
 
-  block->block_ptr   = block_ptr;
-  block->size        = GEGL_TILE_BLOCK_BUFFER_OFFSET + block_size;
+      block_size  = floor (gegl_buffer_config ()->tile_cache_size *
+                           GEGL_TILE_BLOCK_SIZE_RATIO);
+      block_size -= block_size % buffer_size;
 
-  block->head        = (GeglTileBuffer *) ((guint8 *) block +
-                                           GEGL_TILE_BLOCK_BUFFER_OFFSET);
-  block->n_allocated = 0;
+      n_buffers = block_size / buffer_size;
+      n_buffers = MIN (n_buffers, GEGL_TILE_BLOCK_MAX_BUFFERS);
 
-  block->prev        = NULL;
-  block->next        = NULL;
+      if (n_buffers <= 1)
+        return NULL;
 
-  buffer = block->head;
+      block_size = GEGL_TILE_BLOCK_BUFFER_OFFSET + n_buffers * buffer_size;
 
-  for (i = n_buffers; i; i--)
-    {
-      buffer->block = block;
+      block = gegl_try_malloc (block_size);
 
-      next_buffer = gegl_tile_buffer_to_data (buffer);
+      if (! block)
+        return NULL;
 
-      if (i > 1)
-        buffer = (GeglTileBuffer *) ((guint8 *) buffer + buffer_size);
-      else
-        buffer = NULL;
+      n_blocks = g_atomic_int_add (&gegl_tile_n_blocks, +1) + 1;
+
+      if (n_blocks % GEGL_TILE_BLOCKS_PER_TRIM == 0)
+        gegl_tile_max_n_blocks = MAX (gegl_tile_max_n_blocks, n_blocks);
 
-      *next_buffer = buffer;
+      g_atomic_pointer_add (&gegl_tile_alloc_total, +block_size);
     }
 
-  n_blocks = g_atomic_int_add (&gegl_tile_n_blocks, +1) + 1;
+  if (init_block)
+    {
+      GeglTileBuffer  *buffer;
+      GeglTileBuffer **next_buffer;
+      gint             i;
+
+      block->block_ptr   = block_ptr;
+      block->size        = block_size;
 
-  if (n_blocks % GEGL_TILE_BLOCKS_PER_TRIM == 0)
-    gegl_tile_max_n_blocks = MAX (gegl_tile_max_n_blocks, n_blocks);
+      block->head        = (GeglTileBuffer *) ((guint8 *) block +
+                                               GEGL_TILE_BLOCK_BUFFER_OFFSET);
+      block->n_allocated = 0;
 
-  g_atomic_pointer_add (&gegl_tile_alloc_total, +block->size);
+      block->prev        = NULL;
+      block->next        = NULL;
+
+      buffer = block->head;
+
+      for (i = n_buffers; i; i--)
+        {
+          buffer->block = block;
+
+          next_buffer = gegl_tile_buffer_to_data (buffer);
+
+          if (i > 1)
+            buffer = (GeglTileBuffer *) ((guint8 *) buffer + buffer_size);
+          else
+            buffer = NULL;
+
+          *next_buffer = buffer;
+        }
+    }
 
   return block;
 }
@@ -206,9 +241,6 @@ static void
 gegl_tile_block_free (GeglTileBlock  *block,
                       GeglTileBlock **head_block)
 {
-  guintptr block_size = block->size;
-  gint     n_blocks;
-
   if (block->prev)
     block->prev->next = block->next;
   else
@@ -217,6 +249,27 @@ gegl_tile_block_free (GeglTileBlock  *block,
   if (block->next)
     block->next->prev = block->prev;
 
+  if (! gegl_tile_empty_block)
+    {
+      block->prev = NULL;
+      block->next = NULL;
+
+      if (g_atomic_pointer_compare_and_exchange (&gegl_tile_empty_block,
+                                                 NULL, block))
+        {
+          return;
+        }
+    }
+
+  gegl_tile_block_free_mem (block);
+}
+
+static void
+gegl_tile_block_free_mem (GeglTileBlock *block)
+{
+  guintptr block_size = block->size;
+  gint     n_blocks;
+
   gegl_free (block);
 
   n_blocks = g_atomic_int_add (&gegl_tile_n_blocks, -1) - 1;
@@ -276,6 +329,28 @@ gegl_tile_alloc_enabled (void)
 
 /*  public functions  */
 
+void
+gegl_tile_alloc_init (void)
+{
+}
+
+void
+gegl_tile_alloc_cleanup (void)
+{
+  GeglTileBlock *block;
+
+  do
+    {
+      block = gegl_tile_empty_block;
+    }
+  while (block &&
+         ! g_atomic_pointer_compare_and_exchange (&gegl_tile_empty_block,
+                                                  block, NULL));
+
+  if (block)
+    gegl_tile_block_free_mem (block);
+}
+
 gpointer
 gegl_tile_alloc (gsize size)
 {
@@ -364,10 +439,11 @@ gegl_tile_alloc0 (gsize size)
 void
 gegl_tile_free (gpointer ptr)
 {
-  GeglTileBlock * volatile *block_ptr;
-  GeglTileBlock            *block;
-  GeglTileBlock            *head_block;
-  GeglTileBuffer           *buffer;
+  GeglTileBlock * volatile  *block_ptr;
+  GeglTileBlock             *block;
+  GeglTileBlock             *head_block;
+  GeglTileBuffer            *buffer;
+  GeglTileBuffer           **next_buffer;
 
   if (! ptr)
     return;
@@ -395,30 +471,26 @@ gegl_tile_free (gpointer ptr)
 
   block->n_allocated--;
 
-  if (block->n_allocated == 0)
-    {
-      gegl_tile_block_free (block, &head_block);
-    }
-  else
-    {
-      GeglTileBuffer **next_buffer = gegl_tile_buffer_to_data (buffer);
-
-      *next_buffer = block->head;
+  next_buffer = gegl_tile_buffer_to_data (buffer);
 
-      if (! block->head)
-        {
-          block->prev = NULL;
-          block->next = head_block;
+  *next_buffer = block->head;
 
-          if (head_block)
-            head_block->prev = block;
+  if (! block->head)
+    {
+      block->prev = NULL;
+      block->next = head_block;
 
-          head_block = block;
-        }
+      if (head_block)
+        head_block->prev = block;
 
-      block->head = buffer;
+      head_block = block;
     }
 
+  block->head = buffer;
+
+  if (block->n_allocated == 0)
+    gegl_tile_block_free (block, &head_block);
+
   g_atomic_pointer_set (block_ptr, head_block);
 }
 
diff --git a/gegl/buffer/gegl-tile-alloc.h b/gegl/buffer/gegl-tile-alloc.h
index 78cb02c08..6fcfe18e2 100644
--- a/gegl/buffer/gegl-tile-alloc.h
+++ b/gegl/buffer/gegl-tile-alloc.h
@@ -20,6 +20,9 @@
 #define __GEGL_TILE_ALLOC_H__
 
 
+void       gegl_tile_alloc_init      (void);
+void       gegl_tile_alloc_cleanup   (void);
+
 /* the buffer returned by gegl_tile_alloc() and gegl_tile_alloc0() is
  * guaranteed to have room for two `int`s in front of the buffer.
  */
diff --git a/gegl/gegl-init.c b/gegl/gegl-init.c
index 739349939..6482f952c 100644
--- a/gegl/gegl-init.c
+++ b/gegl/gegl-init.c
@@ -75,6 +75,7 @@ guint gegl_debug_flags = 0;
 #include "buffer/gegl-buffer-iterator-private.h"
 #include "buffer/gegl-buffer-swap-private.h"
 #include "buffer/gegl-compression.h"
+#include "buffer/gegl-tile-alloc.h"
 #include "buffer/gegl-tile-backend-ram.h"
 #include "buffer/gegl-tile-backend-file.h"
 #include "gegl-config.h"
@@ -409,6 +410,7 @@ gegl_exit (void)
   gegl_random_cleanup ();
   gegl_parallel_cleanup ();
   gegl_buffer_swap_cleanup ();
+  gegl_tile_alloc_cleanup ();
   gegl_cl_cleanup ();
 
   gegl_temp_buffer_free ();
@@ -599,6 +601,7 @@ gegl_post_parse_hook (GOptionContext *context,
 
   GEGL_INSTRUMENT_START();
 
+  gegl_tile_alloc_init ();
   gegl_buffer_swap_init ();
   gegl_parallel_init ();
   gegl_compression_init ();


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]