From 7bb4b2cefe79b397a555f17cdbf72bc70a835499 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 30 Sep 2001 01:33:28 +0000 Subject: [PATCH] Added a fast non-blocking memchunk implementation, it's about 20x faster than a mutex based implementation. Original commit message from CVS: Added a fast non-blocking memchunk implementation, it's about 20x faster than a mutex based implementation. --- test/memchunk/Makefile.am | 7 +++ test/memchunk/gmemchunktest.c | 78 +++++++++++++++++++++++++++ test/memchunk/gstmemchunk.c | 96 +++++++++++++++++++++++++++++++++ test/memchunk/gstmemchunk.h | 30 +++++++++++ test/memchunk/gstmemchunktest.c | 73 +++++++++++++++++++++++++ 5 files changed, 284 insertions(+) create mode 100644 test/memchunk/Makefile.am create mode 100644 test/memchunk/gmemchunktest.c create mode 100644 test/memchunk/gstmemchunk.c create mode 100644 test/memchunk/gstmemchunk.h create mode 100644 test/memchunk/gstmemchunktest.c diff --git a/test/memchunk/Makefile.am b/test/memchunk/Makefile.am new file mode 100644 index 0000000000..3c8e0231f1 --- /dev/null +++ b/test/memchunk/Makefile.am @@ -0,0 +1,7 @@ +noinst_PROGRAMS = gmemchunktest gstmemchunktest + +gmemchunktest_SOURCES = gmemchunktest.c +gstmemchunktest_SOURCES = gstmemchunktest.c gstmemchunk.c gstmemchunk.h + +LIBS += $(GST_LIBS) +CFLAGS += $(GST_CFLAGS) diff --git a/test/memchunk/gmemchunktest.c b/test/memchunk/gmemchunktest.c new file mode 100644 index 0000000000..b3301f13dd --- /dev/null +++ b/test/memchunk/gmemchunktest.c @@ -0,0 +1,78 @@ +#include + +#define MAX_THREADS 100 + +static GMemChunk *_chunks; +static GMutex *_lock; + +static gint num_allocs; +static gint num_threads; + +static gpointer +alloc_chunk (void) +{ + gpointer ret; + g_mutex_lock (_lock); + ret = g_mem_chunk_alloc (_chunks); + g_mutex_unlock (_lock); + + return ret; +} + +static void +free_chunk (gpointer chunk) +{ + g_mutex_lock (_lock); + g_mem_chunk_free (_chunks, chunk); + g_mutex_unlock (_lock); +} + + +void* +run_test (void *threadid) +{ + gint i; + gpointer chunk; + sleep(1); + + for (i = 0; i \n", argv[0]); + exit (-1); + } + + num_threads = atoi (argv[1]); + num_allocs = atoi (argv[2]); + + _chunks = g_mem_chunk_new ("test", 32, 32 * 16, G_ALLOC_AND_FREE); + _lock = g_mutex_new (); + + for(t=0; t < num_threads; t++) { + rc = pthread_create (&threads[t], NULL, run_test, (void *)t); + if (rc) { + printf ("ERROR: return code from pthread_create() is %d\n", rc); + printf ("Code %d= %s\n", rc, strerror(rc)); + exit (-1); + } + } + printf ("main(): Created %d threads.\n", t); + + pthread_exit (NULL); + g_mem_chunk_info(); +} diff --git a/test/memchunk/gstmemchunk.c b/test/memchunk/gstmemchunk.c new file mode 100644 index 0000000000..33389e5ca7 --- /dev/null +++ b/test/memchunk/gstmemchunk.c @@ -0,0 +1,96 @@ +#include "gstmemchunk.h" + +#ifdef __SMP__ +#define CHUNK_LOCK "lock ; " +#else +#define CHUNK_LOCK "" +#endif + +static void +setup_area (guint8 *area, gint chunk_size, gulong area_size) +{ + gint i; + g_print ("setup area at %p, real area_size %lu, chunk size %d\n", area, area_size, chunk_size); + + for (i = 0; i < area_size; i += chunk_size) { + guint8 *next; + + next = area + chunk_size; + + ((GstMemChunkElement *)area)->link = (gpointer)(next); + + area = next; + } +} + + +GstMemChunk * +gst_mem_chunk_new (gchar * name, gint atom_size, gulong area_size, gint type) +{ + GstMemChunk *mem_chunk; + gint chunk_size; + + g_print ("create: atom size %d, area_size %lu\n", atom_size, area_size); + + chunk_size = atom_size + sizeof (gpointer); + area_size = (area_size/atom_size) * chunk_size; + + g_print ("chunk size %d, real area_size %lu\n", chunk_size, area_size); + + mem_chunk = g_malloc (sizeof (GstMemChunk)); + + mem_chunk->free = g_malloc0 (area_size); + mem_chunk->cnt = 0; + mem_chunk->atom_size = atom_size; + mem_chunk->chunk_size = chunk_size; + mem_chunk->area_size = area_size; + + setup_area ((guint8 *)mem_chunk->free, chunk_size, area_size); + + return mem_chunk; +} + +gpointer +gst_mem_chunk_alloc (GstMemChunk *mem_chunk) +{ + guint8 *chunk = NULL; + + g_return_val_if_fail (mem_chunk != NULL, NULL); + + __asm__ __volatile__ ("testl %%eax, %%eax \n\t" + "jz 20f \n" + "10:\t" + "movl (%%eax), %%ebx \n\t" + "movl %%edx, %%ecx \n\t" + "incl %%ecx \n\t" + CHUNK_LOCK "cmpxchg8b %1 \n\t" + "jz 20f \n\t" + "testl %%eax, %%eax \n\t" + "jnz 10b \n" + "20:\t":"=a" (chunk):"m" (*mem_chunk), + "a" (mem_chunk->free), "d" (mem_chunk->cnt):"ecx", + "ebx"); + + if (chunk) + chunk += sizeof (gpointer); + else { + g_print ("empty\n"); + exit (-1); + } + + return (gpointer) chunk; +} + +void +gst_mem_chunk_free (GstMemChunk *mem_chunk, gpointer mem) +{ + guint8 *chunk = ((guint8 *)mem) - sizeof (gpointer); + + g_return_if_fail (mem_chunk != NULL); + g_return_if_fail (mem != NULL); + + __asm__ __volatile__ ( "1:\t" + "movl %2, (%1) \n" + CHUNK_LOCK "cmpxchg %1, %0 \n\t" + "jnz 1b \n\t"::"m" (*mem_chunk), "r" (chunk), "a" (mem_chunk->free)); +} diff --git a/test/memchunk/gstmemchunk.h b/test/memchunk/gstmemchunk.h new file mode 100644 index 0000000000..49fd0c67b9 --- /dev/null +++ b/test/memchunk/gstmemchunk.h @@ -0,0 +1,30 @@ + +#include + +typedef struct _GstMemChunk GstMemChunk; +typedef struct _GstMemChunkElement GstMemChunkElement; + +struct _GstMemChunkElement +{ + GstMemChunkElement *link; /* next cell in the lifo */ + // data is here +}; + +struct _GstMemChunk +{ + volatile GstMemChunkElement *free; /* the first free element */ + volatile unsigned long cnt; /* used to avoid ABA problem */ + + gulong area_size; + gulong chunk_size; + gulong atom_size; +}; + +GstMemChunk* gst_mem_chunk_new (gchar *name, + gint atom_size, + gulong area_size, + gint type); + +gpointer gst_mem_chunk_alloc (GstMemChunk *mem_chunk); +void gst_mem_chunk_free (GstMemChunk *mem_chunk, + gpointer mem); diff --git a/test/memchunk/gstmemchunktest.c b/test/memchunk/gstmemchunktest.c new file mode 100644 index 0000000000..420709ab67 --- /dev/null +++ b/test/memchunk/gstmemchunktest.c @@ -0,0 +1,73 @@ +#include +#include "gstmemchunk.h" + +#define MAX_THREADS 100 + +static GstMemChunk *_chunks; + +static gint num_allocs; +static gint num_threads; + +static gpointer +alloc_chunk (void) +{ + gpointer ret; + ret = gst_mem_chunk_alloc (_chunks); + + return ret; +} + +static void +free_chunk (gpointer chunk) +{ + gst_mem_chunk_free (_chunks, chunk); +} + + +void* +run_test (void *threadid) +{ + gint i; + gpointer chunk; + sleep(1); + + for (i = 0; i \n", argv[0]); + exit (-1); + } + + num_threads = atoi (argv[1]); + num_allocs = atoi (argv[2]); + + _chunks = gst_mem_chunk_new ("test", 32, 32 * 16, G_ALLOC_AND_FREE); + + for(t=0; t < num_threads; t++) { + rc = pthread_create (&threads[t], NULL, run_test, (void *)t); + if (rc) { + printf ("ERROR: return code from pthread_create() is %d\n", rc); + printf ("Code %d= %s\n", rc, strerror(rc)); + exit (-1); + } + } + printf ("main(): Created %d threads.\n", t); + + pthread_exit (NULL); + g_mem_chunk_info(); +}