put everything in tests/

Original commit message from CVS:
put everything in tests/
This commit is contained in:
Andy Wingo 2002-01-05 01:25:28 +00:00
parent e1bc025265
commit 1a4c7726aa
15 changed files with 1317 additions and 16 deletions

View file

@ -1,18 +1,8 @@
SUBDIRS = sched eos nego muxing
SUBDIRS = bufspeed memchunk muxing sched
if GST_DISABLE_LOADSAVE
GST_LOADSAVE_PROG =
else
GST_LOADSAVE_PROG = caps registry autoplug props tee autoplug2 capsconnect \
padfactory autoplug4
endif
noinst_PROGRAMS = lat
noinst_PROGRAMS = $(GST_LOADSAVE_PROG) init loadall simplefake states queue \
paranoia rip mp3encode case4 markup load autoplug3 \
incsched reaping threadlock mp1vid reconnect \
faketest events timecache
LDADD = $(GST_LIBS)
AM_CFLAGS = $(GST_CFLAGS)
lat_CFLAGS = $(GST_CFLAGS)
lat_LDFLAGS = $(GST_LIBS)
EXTRA_DIST = README

View file

@ -1,2 +1,3 @@
This directory contains various tests designed to verify GStreamer
behavior. If any of them exit with a non-zero value, something's wrong.
This directory contains various tests designed to test GStreamer's
behavior. When these tests work, they should be recast in the form
of regression tests and moved to ../testsuite.

View file

@ -0,0 +1,6 @@
noinst_PROGRAMS = test1 test2
test1_SOURCES = test1.c gstbuffer.c gstmempool.c
#LIBS += $(GST_LIBS)
CFLAGS += $(GST_CFLAGS)

6
tests/bufspeed/README Normal file
View file

@ -0,0 +1,6 @@
benchmark of 5000000 gst_buffer_new/free on 0.2.1 code
------------------------------------------------------
gstmemchunk, no lock: real 0m1.309s user 0m1.220s sys 0m0.070s
gmemchunk, no lock: real 0m3.872s user 0m3.740s sys 0m0.090s
gstmemchunk, lock: real 0m5.306s user 0m5.160s sys 0m0.100s
gmemchunk, lock: real 0m8.001s user 0m7.890s sys 0m0.080s

495
tests/bufspeed/gstbuffer.c Normal file
View file

@ -0,0 +1,495 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstbuffer.c: Buffer operations
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* this file makes too much noise for most debugging sessions */
#define GST_DEBUG_FORCE_DISABLE
#include "gst/gst_private.h"
#include "gstbuffer.h"
#include "gstmempool.h"
GType _gst_buffer_type;
static GstMemPool *_gst_buffer_pool;
static void
gst_buffer_alloc_func (GstMemPool *pool, gpointer data)
{
GstBuffer *buffer = GST_BUFFER (data);
GST_DATA_TYPE(buffer) = _gst_buffer_type;
buffer->lock = g_mutex_new ();
}
static void
gst_buffer_free_func (GstMemPool *pool, gpointer data)
{
GstBuffer *buffer = GST_BUFFER (data);
g_mutex_free (buffer->lock);
}
void
_gst_buffer_initialize (void)
{
int buffersize = sizeof(GstBuffer);
static const GTypeInfo buffer_info = {
0, // sizeof(class),
NULL,
NULL,
NULL,
NULL,
NULL,
0, // sizeof(object),
0,
NULL,
};
// round up to the nearest 32 bytes for cache-line and other efficiencies
buffersize = (((buffersize-1) / 32) + 1) * 32;
_gst_buffer_pool = gst_mem_pool_new ("GstBuffer", buffersize,
buffersize * 32, G_ALLOC_AND_FREE, gst_buffer_alloc_func, gst_buffer_free_func);
_gst_buffer_type = g_type_register_static (G_TYPE_INT, "GstBuffer", &buffer_info, 0);
}
/**
* gst_buffer_new:
*
* Create a new buffer.
*
* Returns: new buffer
*/
GstBuffer*
gst_buffer_new (void)
{
GstBuffer *buffer;
buffer = gst_mem_pool_alloc (_gst_buffer_pool);
GST_INFO (GST_CAT_BUFFER,"creating new buffer %p",buffer);
#ifdef HAVE_ATOMIC_H
atomic_set (&buffer->refcount, 1);
#else
buffer->refcount = 1;
#endif
buffer->offset = -1;
buffer->flags = 0;
buffer->data = NULL;
buffer->size = 0;
buffer->maxsize = 0;
buffer->timestamp = 0;
buffer->parent = NULL;
buffer->pool = NULL;
buffer->pool_private = NULL;
buffer->free = NULL;
buffer->copy = NULL;
return buffer;
}
/**
* gst_buffer_new_from_pool:
* @pool: the buffer pool to use
*
* Create a new buffer using the specified bufferpool.
*
* Returns: new buffer
*/
GstBuffer*
gst_buffer_new_from_pool (GstBufferPool *pool, guint32 offset, guint32 size)
{
GstBuffer *buffer;
g_return_val_if_fail (pool != NULL, NULL);
g_return_val_if_fail (pool->buffer_new != NULL, NULL);
buffer = pool->buffer_new (pool, offset, size, pool->user_data);
buffer->pool = pool;
buffer->free = pool->buffer_free;
buffer->copy = pool->buffer_copy;
GST_INFO (GST_CAT_BUFFER,"creating new buffer %p from pool %p (size %x, offset %x)",
buffer, pool, size, offset);
return buffer;
}
/**
* gst_buffer_create_sub:
* @parent: parent buffer
* @offset: offset into parent buffer
* @size: size of new subbuffer
*
* Creates a sub-buffer from the parent at a given offset.
*
* Returns: new buffer
*/
GstBuffer*
gst_buffer_create_sub (GstBuffer *parent,
guint32 offset,
guint32 size)
{
GstBuffer *buffer;
g_return_val_if_fail (parent != NULL, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(parent) > 0, NULL);
g_return_val_if_fail (size > 0, NULL);
g_return_val_if_fail ((offset+size) <= parent->size, NULL);
buffer = gst_mem_pool_alloc (_gst_buffer_pool);
GST_DATA_TYPE(buffer) = _gst_buffer_type;
GST_INFO (GST_CAT_BUFFER,"creating new subbuffer %p from parent %p (size %u, offset %u)",
buffer, parent, size, offset);
#ifdef HAVE_ATOMIC_H
atomic_set (&buffer->refcount, 1);
#else
buffer->refcount = 1;
#endif
// copy flags and type from parent, for lack of better
buffer->flags = parent->flags;
// set the data pointer, size, offset, and maxsize
buffer->data = parent->data + offset;
buffer->size = size;
buffer->maxsize = parent->size - offset;
// deal with bogus/unknown offsets
if (parent->offset != -1)
buffer->offset = parent->offset + offset;
else
buffer->offset = -1;
// again, for lack of better, copy parent's timestamp
buffer->timestamp = parent->timestamp;
buffer->maxage = parent->maxage;
// if the parent buffer is a subbuffer itself, use its parent, a real buffer
if (parent->parent != NULL)
parent = parent->parent;
// set parentage and reference the parent
buffer->parent = parent;
gst_buffer_ref (parent);
buffer->pool = NULL;
return buffer;
}
// FIXME FIXME: how does this overlap with the newly-added gst_buffer_span() ???
/**
* gst_buffer_append:
* @buffer: a buffer
* @append: the buffer to append
*
* Creates a new buffer by appending the data of append to the
* existing data of buffer.
*
* Returns: new buffer
*/
GstBuffer*
gst_buffer_append (GstBuffer *buffer,
GstBuffer *append)
{
guint size;
GstBuffer *newbuf;
g_return_val_if_fail (buffer != NULL, NULL);
g_return_val_if_fail (append != NULL, NULL);
g_return_val_if_fail (buffer->pool == NULL, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(append) > 0, NULL);
GST_INFO (GST_CAT_BUFFER,"appending buffers %p and %p",buffer,append);
GST_BUFFER_LOCK (buffer);
// the buffer is not used by anyone else
if (GST_BUFFER_REFCOUNT (buffer) == 1 && buffer->parent == NULL
&& !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_DONTFREE)) {
// save the old size
size = buffer->size;
buffer->size += append->size;
buffer->data = g_realloc (buffer->data, buffer->size);
memcpy(buffer->data + size, append->data, append->size);
GST_BUFFER_UNLOCK (buffer);
}
// the buffer is used, create a new one
else {
newbuf = gst_buffer_new ();
newbuf->size = buffer->size+append->size;
newbuf->data = g_malloc (newbuf->size);
memcpy (newbuf->data, buffer->data, buffer->size);
memcpy (newbuf->data+buffer->size, append->data, append->size);
GST_BUFFER_UNLOCK (buffer);
gst_buffer_unref (buffer);
buffer = newbuf;
}
return buffer;
}
/**
* gst_buffer_destroy:
* @buffer: the GstBuffer to destroy
*
* destroy the buffer
*/
void
gst_buffer_destroy (GstBuffer *buffer)
{
g_return_if_fail (buffer != NULL);
GST_INFO (GST_CAT_BUFFER, "freeing %sbuffer %p",
(buffer->parent?"sub":""),
buffer);
// free the data only if there is some, DONTFREE isn't set, and not sub
if (GST_BUFFER_DATA (buffer) &&
!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_DONTFREE) &&
(buffer->parent == NULL)) {
// if there's a free function, use it
if (buffer->free != NULL) {
(buffer->free)(buffer);
} else {
g_free (GST_BUFFER_DATA (buffer));
}
}
// unreference the parent if there is one
if (buffer->parent != NULL)
gst_buffer_unref (buffer->parent);
// remove it entirely from memory
gst_mem_pool_free (_gst_buffer_pool,buffer);
}
/**
* gst_buffer_ref:
* @buffer: the GstBuffer to reference
*
* Increment the refcount of this buffer.
*/
void
gst_buffer_ref (GstBuffer *buffer)
{
g_return_if_fail (buffer != NULL);
g_return_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0);
GST_INFO (GST_CAT_BUFFER, "ref buffer %p\n", buffer);
#ifdef HAVE_ATOMIC_H
atomic_inc (&(buffer->refcount));
#else
GST_BUFFER_LOCK (buffer);
buffer->refcount++;
GST_BUFFER_UNLOCK (buffer);
#endif
}
/**
* gst_buffer_unref:
* @buffer: the GstBuffer to unref
*
* Decrement the refcount of this buffer. If the refcount is
* zero, the buffer will be destroyed.
*/
void
gst_buffer_unref (GstBuffer *buffer)
{
gint zero;
g_return_if_fail (buffer != NULL);
g_return_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0);
GST_INFO (GST_CAT_BUFFER, "unref buffer %p\n", buffer);
#ifdef HAVE_ATOMIC_H
zero = atomic_dec_and_test (&(buffer->refcount));
#else
GST_BUFFER_LOCK (buffer);
buffer->refcount--;
zero = (buffer->refcount == 0);
GST_BUFFER_UNLOCK (buffer);
#endif
/* if we ended up with the refcount at zero, destroy the buffer */
if (zero) {
gst_buffer_destroy (buffer);
}
}
/**
* gst_buffer_copy:
* @buffer: the orignal GstBuffer to make a copy of
*
* Make a full copy of the give buffer, data and all.
*
* Returns: new buffer
*/
GstBuffer *
gst_buffer_copy (GstBuffer *buffer)
{
GstBuffer *newbuf;
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0, NULL);
// if a copy function exists, use it, else copy the bytes
if (buffer->copy != NULL) {
newbuf = (buffer->copy)(buffer);
} else {
// allocate a new buffer
newbuf = gst_buffer_new();
// copy the absolute size
newbuf->size = buffer->size;
// allocate space for the copy
newbuf->data = (guchar *)g_malloc (buffer->size);
// copy the data straight across
memcpy(newbuf->data,buffer->data,buffer->size);
// the new maxsize is the same as the size, since we just malloc'd it
newbuf->maxsize = newbuf->size;
}
newbuf->offset = buffer->offset;
newbuf->timestamp = buffer->timestamp;
newbuf->maxage = buffer->maxage;
// since we just created a new buffer, so we have no ties to old stuff
newbuf->parent = NULL;
newbuf->pool = NULL;
return newbuf;
}
/*
* gst_buffer_is_span_fast
* @buf1: first source buffer
* @buf2: second source buffer
*
* Determines whether a gst_buffer_span is free, or requires a memcpy.
*
* Returns: TRUE if the buffers are contiguous, FALSE if a copy would be required.
*/
gboolean
gst_buffer_is_span_fast (GstBuffer *buf1, GstBuffer *buf2)
{
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf1) > 0, FALSE);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf2) > 0, FALSE);
return (buf1->parent && buf2->parent &&
(buf1->parent == buf2->parent) &&
((buf1->data + buf1->size) == buf2->data));
}
/**
* gst_buffer_span:
* @buf1: first source buffer to merge
* @offset: offset in first buffer to start new buffer
* @buf2: second source buffer to merge
* @len: length of new buffer
*
* Create a new buffer that consists of part of buf1 and buf2.
* Logically, buf1 and buf2 are concatenated into a single larger
* buffer, and a new buffer is created at the given offset inside
* this space, with a given length.
*
* If the two source buffers are children of the same larger buffer,
* and are contiguous, the new buffer will be a child of the shared
* parent, and thus no copying is necessary.
*
* Returns: new buffer that spans the two source buffers
*/
// FIXME need to think about CoW and such...
GstBuffer *
gst_buffer_span (GstBuffer *buf1, guint32 offset, GstBuffer *buf2, guint32 len)
{
GstBuffer *newbuf;
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf1) > 0, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf2) > 0, NULL);
// make sure buf1 has a lower address than buf2
if (buf1->data > buf2->data) {
GstBuffer *tmp = buf1;
g_print ("swapping buffers\n");
buf1 = buf2;
buf2 = tmp;
}
// if the two buffers have the same parent and are adjacent
if (gst_buffer_is_span_fast(buf1,buf2)) {
// we simply create a subbuffer of the common parent
newbuf = gst_buffer_create_sub (buf1->parent, buf1->data - (buf1->parent->data) + offset, len);
}
else {
g_print ("slow path taken in buffer_span\n");
// otherwise we simply have to brute-force copy the buffers
newbuf = gst_buffer_new ();
// put in new size
newbuf->size = len;
// allocate space for the copy
newbuf->data = (guchar *)g_malloc(len);
// copy the first buffer's data across
memcpy(newbuf->data, buf1->data + offset, buf1->size - offset);
// copy the second buffer's data across
memcpy(newbuf->data + (buf1->size - offset), buf2->data, len - (buf1->size - offset));
if (newbuf->offset != -1)
newbuf->offset = buf1->offset + offset;
newbuf->timestamp = buf1->timestamp;
if (buf2->maxage > buf1->maxage) newbuf->maxage = buf2->maxage;
else newbuf->maxage = buf1->maxage;
}
return newbuf;
}
/**
* gst_buffer_merge:
* @buf1: first source buffer to merge
* @buf2: second source buffer to merge
*
* Create a new buffer that is the concatenation of the two source
* buffers. The original source buffers will not be modified or
* unref'd.
*
* Internally is nothing more than a specialized gst_buffer_span,
* so the same optimizations can occur.
*
* Returns: new buffer that's the concatenation of the source buffers
*/
GstBuffer *
gst_buffer_merge (GstBuffer *buf1, GstBuffer *buf2)
{
// we're just a specific case of the more general gst_buffer_span()
return gst_buffer_span (buf1, 0, buf2, buf1->size + buf2->size);
}

171
tests/bufspeed/gstbuffer.h Normal file
View file

@ -0,0 +1,171 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstbuffer.h: Header for GstBuffer object
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_BUFFER_H__
#define __GST_BUFFER_H__
//
// Define this to add file:line info to each GstBuffer showing
// the location in the source code where the buffer was created.
//
// #define GST_BUFFER_WHERE
//
// Then in gdb, you can `call gst_buffer_print_live()' to get a list
// of allocated GstBuffers and also the file:line where they were
// allocated.
//
#include <gst/gstdata.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_ATOMIC_H
#include <asm/atomic.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
extern GType _gst_buffer_type;
#define GST_TYPE_BUFFER (_gst_buffer_type)
#define GST_BUFFER(buf) ((GstBuffer *)(buf))
#define GST_IS_BUFFER(buf) (GST_DATA_TYPE(buf) == GST_TYPE_BUFFER)
#define GST_BUFFER_FLAGS(buf) (GST_BUFFER(buf)->flags)
#define GST_BUFFER_FLAG_IS_SET(buf,flag) (GST_BUFFER_FLAGS(buf) & (1<<(flag)))
#define GST_BUFFER_FLAG_SET(buf,flag) G_STMT_START{ (GST_BUFFER_FLAGS(buf) |= (1<<(flag))); }G_STMT_END
#define GST_BUFFER_FLAG_UNSET(buf,flag) G_STMT_START{ (GST_BUFFER_FLAGS(buf) &= ~(1<<(flag))); }G_STMT_END
#define GST_BUFFER_DATA(buf) (GST_BUFFER(buf)->data)
#define GST_BUFFER_SIZE(buf) (GST_BUFFER(buf)->size)
#define GST_BUFFER_OFFSET(buf) (GST_BUFFER(buf)->offset)
#define GST_BUFFER_MAXSIZE(buf) (GST_BUFFER(buf)->maxsize)
#define GST_BUFFER_TIMESTAMP(buf) (GST_BUFFER(buf)->timestamp)
#define GST_BUFFER_MAXAGE(buf) (GST_BUFFER(buf)->maxage)
#define GST_BUFFER_BUFFERPOOL(buf) (GST_BUFFER(buf)->pool)
#define GST_BUFFER_PARENT(buf) (GST_BUFFER(buf)->parent)
#define GST_BUFFER_POOL_PRIVATE(buf) (GST_BUFFER(buf)->pool_private)
#define GST_BUFFER_COPY_FUNC(buf) (GST_BUFFER(buf)->copy)
#define GST_BUFFER_FREE_FUNC(buf) (GST_BUFFER(buf)->free)
#define GST_BUFFER_LOCK(buf) (g_mutex_lock(GST_BUFFER(buf)->lock))
#define GST_BUFFER_TRYLOCK(buf) (g_mutex_trylock(GST_BUFFER(buf)->lock))
#define GST_BUFFER_UNLOCK(buf) (g_mutex_unlock(GST_BUFFER(buf)->lock))
typedef enum {
GST_BUFFER_READONLY,
GST_BUFFER_ORIGINAL,
GST_BUFFER_DONTFREE,
} GstBufferFlags;
typedef struct _GstBuffer GstBuffer;
typedef void (*GstBufferFreeFunc) (GstBuffer *buf);
typedef GstBuffer *(*GstBufferCopyFunc) (GstBuffer *srcbuf);
#include <gst/gstbufferpool.h>
struct _GstBuffer {
GstData data_type;
/* locking */
GMutex *lock;
/* refcounting */
#ifdef HAVE_ATOMIC_H
atomic_t refcount;
#define GST_BUFFER_REFCOUNT(buf) (atomic_read(&(GST_BUFFER((buf))->refcount)))
#else
int refcount;
#define GST_BUFFER_REFCOUNT(buf) (GST_BUFFER(buf)->refcount)
#endif
/* flags */
guint16 flags;
/* pointer to data, its size, and offset in original source if known */
guchar *data;
guint32 size;
guint32 maxsize;
guint32 offset;
/* timestamp */
gint64 timestamp;
gint64 maxage;
/* subbuffer support, who's my parent? */
GstBuffer *parent;
/* this is a pointer to the buffer pool (if any) */
GstBufferPool *pool;
gpointer pool_private;
/* utility function pointers */
GstBufferFreeFunc free; // free the data associated with the buffer
GstBufferCopyFunc copy; // copy the data from one buffer to another
};
/* initialisation */
void _gst_buffer_initialize (void);
/* creating a new buffer from scratch */
GstBuffer* gst_buffer_new (void);
GstBuffer* gst_buffer_new_from_pool (GstBufferPool *pool, guint32 offset, guint32 size);
/* creating a subbuffer */
GstBuffer* gst_buffer_create_sub (GstBuffer *parent, guint32 offset, guint32 size);
/* refcounting */
void gst_buffer_ref (GstBuffer *buffer);
void gst_buffer_unref (GstBuffer *buffer);
/* destroying the buffer */
void gst_buffer_destroy (GstBuffer *buffer);
/* copy buffer */
GstBuffer* gst_buffer_copy (GstBuffer *buffer);
/* merge, span, or append two buffers, intelligently */
GstBuffer* gst_buffer_merge (GstBuffer *buf1, GstBuffer *buf2);
GstBuffer* gst_buffer_span (GstBuffer *buf1,guint32 offset,GstBuffer *buf2,guint32 len);
GstBuffer* gst_buffer_append (GstBuffer *buf, GstBuffer *buf2);
gboolean gst_buffer_is_span_fast (GstBuffer *buf1, GstBuffer *buf2);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __GST_BUFFER_H__ */

191
tests/bufspeed/gstmempool.c Normal file
View file

@ -0,0 +1,191 @@
#include "gstmempool.h"
#ifdef __SMP__
#define POOL_LOCK "lock ; "
#else
#define POOL_LOCK ""
#endif
#define GST_MEM_POOL_AREA(pool) (((GstMemPoolElement*)(pool))->area)
#define GST_MEM_POOL_DATA(pool) ((gpointer)(((GstMemPoolElement*)(pool)) + 1))
#define GST_MEM_POOL_LINK(mem) ((GstMemPoolElement*)((guint8*)(mem) - sizeof (GstMemPoolElement)))
#define USE_ASM
/*******************************************************
* area size
* +-----------------------------------------+
* pool size
* +------------+
*
* !next!data... !next!data.... !next!data...
* ! ^ ! ^ !
* +-------------+ +------------+ +---> NULL
*
*/
static gboolean
populate (GstMemPool *mem_pool)
{
guint8 *area;
gint i;
if (mem_pool->cleanup)
return FALSE;
area = (guint8 *) g_malloc (mem_pool->area_size);
for (i=0; i < mem_pool->area_size; i += mem_pool->pool_size) {
guint8 *areap = area + i;
GST_MEM_POOL_AREA (areap) = (GstMemPoolElement *)area;
if (mem_pool->alloc_func) {
mem_pool->alloc_func (mem_pool, GST_MEM_POOL_DATA (areap));
}
gst_mem_pool_free (mem_pool, GST_MEM_POOL_DATA (areap));
}
return TRUE;
}
GstMemPool*
gst_mem_pool_new (gchar* name, gint atom_size, gulong area_size, gint type,
GstMemPoolAllocFunc alloc_func,
GstMemPoolFreeFunc free_func)
{
GstMemPool *mem_pool;
g_return_val_if_fail (atom_size > 0, NULL);
g_return_val_if_fail (area_size >= atom_size, NULL);
mem_pool = g_malloc (sizeof (GstMemPool));
mem_pool->pool_size = atom_size + sizeof (GstMemPoolElement);
area_size = (area_size/atom_size) * mem_pool->pool_size;
mem_pool->name = g_strdup (name);
mem_pool->free = NULL;
mem_pool->cnt = 0;
mem_pool->atom_size = atom_size;
mem_pool->area_size = area_size;
mem_pool->cleanup = FALSE;
mem_pool->alloc_func = alloc_func;
mem_pool->free_func = free_func;
mem_pool->chunk_lock = g_mutex_new ();
populate (mem_pool);
return mem_pool;
}
static gboolean
free_area (gpointer key, gpointer value, gpointer user_data)
{
g_print ("free %p\n", key);
g_free (key);
return TRUE;
}
void
gst_mem_pool_destroy (GstMemPool *mem_pool)
{
GHashTable *elements = g_hash_table_new (NULL, NULL);
gpointer data;
mem_pool->cleanup = TRUE;
data = gst_mem_pool_alloc (mem_pool);
while (data) {
GstMemPoolElement *elem = GST_MEM_POOL_LINK (data);
g_hash_table_insert (elements, GST_MEM_POOL_AREA (elem), NULL);
data = gst_mem_pool_alloc (mem_pool);
}
g_hash_table_foreach_remove (elements, free_area, NULL);
g_hash_table_destroy (elements);
g_free (mem_pool->name);
g_free (mem_pool);
}
gpointer
gst_mem_pool_alloc (GstMemPool *mem_pool)
{
GstMemPoolElement *pool = NULL;
g_return_val_if_fail (mem_pool != NULL, NULL);
again:
#ifdef USE_ASM
__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"
POOL_LOCK "cmpxchg8b %1 \n\t"
" jz 20f \n\t"
" testl %%eax, %%eax \n\t"
" jnz 10b \n"
"20:\t"
:"=a" (pool)
:"m" (*mem_pool), "a" (mem_pool->free), "d" (mem_pool->cnt)
:"ecx", "ebx");
#else
g_mutex_lock (mem_pool->chunk_lock);
if (mem_pool->free) {
pool = mem_pool->free;
mem_pool->free = pool->link;
}
g_mutex_unlock (mem_pool->chunk_lock);
#endif
if (!pool) {
//g_print ("extending\n");
if (populate (mem_pool))
goto again;
else
return NULL;
}
return GST_MEM_POOL_DATA (pool);
}
gpointer
gst_mem_pool_alloc0 (GstMemPool *mem_pool)
{
gpointer mem = gst_mem_pool_alloc (mem_pool);
if (mem)
memset (mem, 0, mem_pool->atom_size);
return mem;
}
void
gst_mem_pool_free (GstMemPool *mem_pool, gpointer mem)
{
GstMemPoolElement *pool;
g_return_if_fail (mem_pool != NULL);
g_return_if_fail (mem != NULL);
pool = GST_MEM_POOL_LINK (mem);
#ifdef USE_ASM
__asm__ __volatile__ ( "1: \t"
" movl %2, (%1) \n"
POOL_LOCK "cmpxchg %1, %0 \n\t"
" jnz 1b \n\t"
:
:"m" (*mem_pool), "r" (pool), "a" (mem_pool->free));
#else
g_mutex_lock (mem_pool->chunk_lock);
pool->link = mem_pool->free;
mem_pool->free = pool;
g_mutex_unlock (mem_pool->chunk_lock);
#endif
}

View file

@ -0,0 +1,43 @@
#include <glib.h>
typedef struct _GstMemPool GstMemPool;
typedef struct _GstMemPoolElement GstMemPoolElement;
typedef void (*GstMemPoolAllocFunc) (GstMemPool *pool, gpointer data);
typedef void (*GstMemPoolFreeFunc) (GstMemPool *pool, gpointer data);
struct _GstMemPoolElement
{
GstMemPoolElement *link; /* next cell in the lifo */
GstMemPoolElement *area;
};
struct _GstMemPool
{
volatile GstMemPoolElement *free; /* the first free element */
volatile gulong cnt; /* used to avoid ABA problem */
gchar *name;
gulong area_size;
gulong pool_size;
gulong atom_size;
gboolean cleanup;
GstMemPoolAllocFunc alloc_func;
GstMemPoolFreeFunc free_func;
GMutex *chunk_lock;
};
GstMemPool* gst_mem_pool_new (gchar *name,
gint atom_size,
gulong area_size,
gint type,
GstMemPoolAllocFunc alloc_func,
GstMemPoolFreeFunc free_func);
void gst_mem_pool_destroy (GstMemPool *mem_pool);
gpointer gst_mem_pool_alloc (GstMemPool *mem_pool);
gpointer gst_mem_pool_alloc0 (GstMemPool *mem_pool);
void gst_mem_pool_free (GstMemPool *mem_pool,
gpointer mem);

19
tests/bufspeed/test1.c Normal file
View file

@ -0,0 +1,19 @@
#include "gstbuffer.h"
int
main (int argc, char *argv[])
{
GstBuffer *buf;
guint i;
g_thread_init (NULL);
gtk_init (&argc, &argv);
_gst_buffer_initialize ();
for (i=0; i<5000000; i++) {
buf = gst_buffer_new ();
gst_buffer_unref (buf);
}
return 0;
}

19
tests/bufspeed/test2.c Normal file
View file

@ -0,0 +1,19 @@
#include <gst/gst.h>
int
main (int argc, char *argv[])
{
GstBuffer *buf;
guint i;
g_thread_init (NULL);
gtk_init (&argc, &argv);
_gst_buffer_initialize ();
for (i=0; i<5000000; i++) {
buf = gst_buffer_new ();
gst_buffer_unref (buf);
}
return 0;
}

View 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 = $(GLIB_CFLAGS) $(XML_CFLAGS) $(GST_CFLAGS)

View 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();
}

View file

@ -0,0 +1,162 @@
#include "gstmemchunk.h"
#ifdef __SMP__
#define CHUNK_LOCK "lock ; "
#else
#define CHUNK_LOCK ""
#endif
#define GST_MEM_CHUNK_AREA(chunk) (((GstMemChunkElement*)(chunk))->area)
#define GST_MEM_CHUNK_DATA(chunk) ((gpointer)(((GstMemChunkElement*)(chunk)) + 1))
#define GST_MEM_CHUNK_LINK(mem) ((GstMemChunkElement*)((guint8*)(mem) - sizeof (GstMemChunkElement)))
/*******************************************************
* area size
* +-----------------------------------------+
* chunk size
* +------------+
*
* !next!data... !next!data.... !next!data...
* ! ^ ! ^ !
* +-------------+ +------------+ +---> NULL
*
*/
static gboolean
populate (GstMemChunk *mem_chunk)
{
guint8 *area;
gint i;
if (mem_chunk->cleanup)
return FALSE;
area = (guint8 *) g_malloc (mem_chunk->area_size);
g_print ("alloc %p\n", area);
for (i=0; i < mem_chunk->area_size; i += mem_chunk->chunk_size) {
GST_MEM_CHUNK_AREA (area + i) = (GstMemChunkElement *)area;
gst_mem_chunk_free (mem_chunk, GST_MEM_CHUNK_DATA (area + i));
}
return TRUE;
}
GstMemChunk*
gst_mem_chunk_new (gchar* name, gint atom_size, gulong area_size, gint type)
{
GstMemChunk *mem_chunk;
g_return_val_if_fail (atom_size > 0, NULL);
g_return_val_if_fail (area_size >= atom_size, NULL);
mem_chunk = g_malloc (sizeof (GstMemChunk));
mem_chunk->chunk_size = atom_size + sizeof (GstMemChunkElement);
area_size = (area_size/atom_size) * mem_chunk->chunk_size;
mem_chunk->name = g_strdup (name);
mem_chunk->free = NULL;
mem_chunk->cnt = 0;
mem_chunk->atom_size = atom_size;
mem_chunk->area_size = area_size;
mem_chunk->cleanup = FALSE;
populate (mem_chunk);
return mem_chunk;
}
static gboolean
free_area (gpointer key, gpointer value, gpointer user_data)
{
g_print ("free %p\n", key);
g_free (key);
return TRUE;
}
void
gst_mem_chunk_destroy (GstMemChunk *mem_chunk)
{
GHashTable *elements = g_hash_table_new (NULL, NULL);
gpointer data;
mem_chunk->cleanup = TRUE;
data = gst_mem_chunk_alloc (mem_chunk);
while (data) {
GstMemChunkElement *elem = GST_MEM_CHUNK_LINK (data);
g_hash_table_insert (elements, GST_MEM_CHUNK_AREA (elem), NULL);
data = gst_mem_chunk_alloc (mem_chunk);
}
g_hash_table_foreach_remove (elements, free_area, NULL);
g_hash_table_destroy (elements);
g_free (mem_chunk->name);
g_free (mem_chunk);
}
gpointer
gst_mem_chunk_alloc (GstMemChunk *mem_chunk)
{
GstMemChunkElement *chunk = NULL;
g_return_val_if_fail (mem_chunk != NULL, NULL);
again:
__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) {
//g_print ("extending\n");
if (populate (mem_chunk))
goto again;
else
return NULL;
}
return GST_MEM_CHUNK_DATA (chunk);
}
gpointer
gst_mem_chunk_alloc0 (GstMemChunk *mem_chunk)
{
gpointer mem = gst_mem_chunk_alloc (mem_chunk);
if (mem)
memset (mem, 0, mem_chunk->atom_size);
return mem;
}
void
gst_mem_chunk_free (GstMemChunk *mem_chunk, gpointer mem)
{
GstMemChunkElement *chunk;
g_return_if_fail (mem_chunk != NULL);
g_return_if_fail (mem != NULL);
chunk = GST_MEM_CHUNK_LINK (mem);
__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));
}

View file

@ -0,0 +1,34 @@
#include <gst/gst.h>
typedef struct _GstMemChunk GstMemChunk;
typedef struct _GstMemChunkElement GstMemChunkElement;
struct _GstMemChunkElement
{
GstMemChunkElement *link; /* next cell in the lifo */
GstMemChunkElement *area;
};
struct _GstMemChunk
{
volatile GstMemChunkElement *free; /* the first free element */
volatile gulong cnt; /* used to avoid ABA problem */
gchar *name;
gulong area_size;
gulong chunk_size;
gulong atom_size;
gboolean cleanup;
};
GstMemChunk* gst_mem_chunk_new (gchar *name,
gint atom_size,
gulong area_size,
gint type);
void gst_mem_chunk_destroy (GstMemChunk *mem_chunk);
gpointer gst_mem_chunk_alloc (GstMemChunk *mem_chunk);
void gst_mem_chunk_free (GstMemChunk *mem_chunk,
gpointer mem);

View file

@ -0,0 +1,79 @@
#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);
for(t=0; t < num_threads; t++) {
pthread_join (threads[t], NULL);
}
g_mem_chunk_info();
gst_mem_chunk_destroy (_chunks);
return 0;
}