mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-04 15:36:35 +00:00
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.
This commit is contained in:
parent
81a7a06c20
commit
7bb4b2cefe
5 changed files with 284 additions and 0 deletions
7
test/memchunk/Makefile.am
Normal file
7
test/memchunk/Makefile.am
Normal file
|
@ -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)
|
78
test/memchunk/gmemchunktest.c
Normal file
78
test/memchunk/gmemchunktest.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
#include <gst/gst.h>
|
||||
|
||||
#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<num_allocs; i++) {
|
||||
chunk = alloc_chunk ();
|
||||
free_chunk (chunk);
|
||||
}
|
||||
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
|
||||
gint
|
||||
main (gint argc, gchar *argv[])
|
||||
{
|
||||
pthread_t threads[MAX_THREADS];
|
||||
int rc, t;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
if (argc != 3) {
|
||||
g_print ("usage: %s <num_threads> <num_allocs>\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();
|
||||
}
|
96
test/memchunk/gstmemchunk.c
Normal file
96
test/memchunk/gstmemchunk.c
Normal file
|
@ -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));
|
||||
}
|
30
test/memchunk/gstmemchunk.h
Normal file
30
test/memchunk/gstmemchunk.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
|
||||
#include <gst/gst.h>
|
||||
|
||||
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);
|
73
test/memchunk/gstmemchunktest.c
Normal file
73
test/memchunk/gstmemchunktest.c
Normal file
|
@ -0,0 +1,73 @@
|
|||
#include <gst/gst.h>
|
||||
#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<num_allocs; i++) {
|
||||
chunk = alloc_chunk ();
|
||||
free_chunk (chunk);
|
||||
}
|
||||
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
|
||||
gint
|
||||
main (gint argc, gchar *argv[])
|
||||
{
|
||||
pthread_t threads[MAX_THREADS];
|
||||
int rc, t;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
if (argc != 3) {
|
||||
g_print ("usage: %s <num_threads> <num_allocs>\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();
|
||||
}
|
Loading…
Reference in a new issue