[PATCH 1/4] win32u: Add freelist cache allocator.

Jinoh Kang jinoh.kang.kr at gmail.com
Sun Mar 20 15:41:48 CDT 2022


Signed-off-by: Jinoh Kang <jinoh.kang.kr at gmail.com>
---
 dlls/win32u/Makefile.in     |   1 +
 dlls/win32u/alloc.c         | 173 ++++++++++++++++++++++++++++++++++++
 dlls/win32u/ntgdi_private.h |   4 +
 3 files changed, 178 insertions(+)
 create mode 100644 dlls/win32u/alloc.c

diff --git a/dlls/win32u/Makefile.in b/dlls/win32u/Makefile.in
index 2dea3682064..6c7eb383553 100644
--- a/dlls/win32u/Makefile.in
+++ b/dlls/win32u/Makefile.in
@@ -9,6 +9,7 @@ IMPORTS   = ntdll winecrt0
 EXTRADLLFLAGS = -nodefaultlibs -Wb,--syscall-table,1
 
 C_SRCS = \
+	alloc.c \
 	bitblt.c \
 	bitmap.c \
 	brush.c \
diff --git a/dlls/win32u/alloc.c b/dlls/win32u/alloc.c
new file mode 100644
index 00000000000..350f0ea0c87
--- /dev/null
+++ b/dlls/win32u/alloc.c
@@ -0,0 +1,173 @@
+/*
+ * simple freelist cache allocator
+ *
+ * Copyright 2022 Jinoh Kang
+ *
+ * This 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.
+ *
+ * This 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#if 0
+#pragma makedep unix
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <pthread.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "ntgdi_private.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(gdi);
+
+
+#define MEM_CACHE_NR_BUCKETS 1024
+#define MEM_CACHE_MIN_SIZE 16384
+#define MEM_CACHE_STEP 4096
+#ifdef _WIN64
+#define MEM_CACHE_THRESHOLD (32UL << 20)  /* 32MB */
+#else
+#define MEM_CACHE_THRESHOLD ( 8UL << 20)   /* 8MB */
+#endif
+
+static pthread_mutex_t mem_cache_lock = PTHREAD_MUTEX_INITIALIZER;
+static void **mem_cache_buckets[MEM_CACHE_NR_BUCKETS];
+static SIZE_T mem_cache_total_size;
+
+static SIZE_T get_bucket_index( SIZE_T size )
+{
+    if (size < MEM_CACHE_MIN_SIZE) return (SIZE_T)-1;
+    return (size - MEM_CACHE_MIN_SIZE + MEM_CACHE_STEP - 1) / MEM_CACHE_STEP;
+}
+
+static SIZE_T get_bucket_chunk_size( SIZE_T index )
+{
+    return index * MEM_CACHE_STEP + MEM_CACHE_MIN_SIZE;
+}
+
+static void *bucket_pop_chunk( SIZE_T i )
+{
+    SIZE_T real_size = get_bucket_chunk_size( i );
+    void *mem;
+
+    if (!(mem = mem_cache_buckets[i]))
+        return NULL;
+
+    assert(mem_cache_total_size >= real_size);
+    mem_cache_buckets[i] = *(void **)mem;
+    mem_cache_total_size -= real_size;
+    return mem;
+}
+
+static void bucket_push_chunk( SIZE_T i, void *mem )
+{
+    SIZE_T real_size = get_bucket_chunk_size( i );
+
+    mem_cache_total_size += real_size;
+    *(void **)mem = mem_cache_buckets[i];
+    mem_cache_buckets[i] = mem;
+}
+
+void *alloc_gdi_cache_memory( SIZE_T size, BOOL zero_mem )
+{
+    SIZE_T i, real_size = size;
+    SIZE_T real_bucket_i;
+    void *mem = NULL;
+
+    i = get_bucket_index( real_size );
+    if (i < MEM_CACHE_NR_BUCKETS)
+    {
+        real_size = get_bucket_chunk_size( i );
+        assert(real_size >= size);
+
+        pthread_mutex_lock( &mem_cache_lock );
+
+        real_bucket_i = i;
+        while (!(mem = bucket_pop_chunk( real_bucket_i )))
+        {
+            if (++real_bucket_i >= MEM_CACHE_NR_BUCKETS) break;
+        }
+
+        pthread_mutex_unlock( &mem_cache_lock );
+
+        if (mem)
+        {
+            if (i != real_bucket_i)
+            {
+                void *realloc_mem = realloc( mem, real_size );
+                if (realloc_mem)
+                    mem = realloc_mem;
+            }
+            if (zero_mem)
+                memset(mem, 0, size);
+        }
+        else TRACE("no cache for %lu\n", real_size);
+    }
+
+    if (!mem)
+    {
+        if (zero_mem)
+            mem = calloc( 1, real_size );
+        else
+            mem = malloc( real_size );
+    }
+
+    return mem;
+}
+
+void free_gdi_cache_memory( void *mem, SIZE_T size )
+{
+    SIZE_T i, real_size;
+    SIZE_T free_bucket_i;
+
+    i = get_bucket_index( size );
+    if (i < MEM_CACHE_NR_BUCKETS)
+    {
+        real_size = get_bucket_chunk_size( i );
+
+        pthread_mutex_lock( &mem_cache_lock );
+
+        free_bucket_i = 0;
+        while (real_size > MEM_CACHE_THRESHOLD - mem_cache_total_size)
+        {
+            void *old_mem = bucket_pop_chunk( free_bucket_i );
+            if (old_mem)
+            {
+                TRACE("pop cache %p (%lu)\n", old_mem, real_size);
+                free( old_mem );
+            }
+            if (++free_bucket_i >= MEM_CACHE_NR_BUCKETS) break;
+        }
+
+        if (real_size <= MEM_CACHE_THRESHOLD - mem_cache_total_size)
+        {
+            bucket_push_chunk( i, mem );
+            mem = NULL;
+        }
+        else
+        {
+            TRACE("discard memory %p (%lu)\n", mem, real_size);
+        }
+
+        pthread_mutex_unlock( &mem_cache_lock );
+    }
+
+    if (mem)
+        free( mem );
+}
diff --git a/dlls/win32u/ntgdi_private.h b/dlls/win32u/ntgdi_private.h
index 75cddc00fb3..5e5f6041865 100644
--- a/dlls/win32u/ntgdi_private.h
+++ b/dlls/win32u/ntgdi_private.h
@@ -427,6 +427,10 @@ extern HRGN create_polypolygon_region( const POINT *pts, const INT *count, INT n
 extern BOOL delete_dce( struct dce *dce ) DECLSPEC_HIDDEN;
 extern void update_dc( DC *dc ) DECLSPEC_HIDDEN;
 
+/* alloc.c */
+extern void *alloc_gdi_cache_memory( SIZE_T size, BOOL zero_mem ) DECLSPEC_HIDDEN;
+extern void free_gdi_cache_memory( void *mem, SIZE_T size ) DECLSPEC_HIDDEN;
+
 #define RGN_DEFAULT_RECTS 4
 typedef struct
 {
-- 
2.34.1




More information about the wine-devel mailing list