Remove memchunk benchmark stuff, this is taken over by GLib bug 118439.

Original commit message from CVS:
2005-09-26  Andy Wingo  <wingo@pobox.com>

* configure.ac:
* tests/Makefile.am:
* tests/memchunk: Remove memchunk benchmark stuff, this is taken
over by GLib bug 118439.

* gst/base/gstbasesink.c (gst_base_sink_wait): Factor out the wait
routines to a function.

* docs/libs/gstreamer-libs-sections.txt: I am a good person today.

* libs/gst/controller/gsthelper.c:
* libs/gst/controller/gstcontroller.h (gst_controller_sync_values)
(gst_object_sync_values): Renamed from sink_values. Ugh.

* libs/gst/controller/gsthelper.c: Update for __gst_controller_key.

* libs/gst/controller/gstcontroller.c (__gst_controller_key):
Renamed from controller_key, as it is exported.

* gst/gstvalue.c (_gst_value_initialize): Fake out the compiler.
This commit is contained in:
Andy Wingo 2005-09-26 15:43:30 +00:00
parent b98900a0a0
commit 2f46ef713d
16 changed files with 108 additions and 616 deletions

View file

@ -1,3 +1,26 @@
2005-09-26 Andy Wingo <wingo@pobox.com>
* configure.ac:
* tests/Makefile.am:
* tests/memchunk: Remove memchunk benchmark stuff, this is taken
over by GLib bug 118439.
* gst/base/gstbasesink.c (gst_base_sink_wait): Factor out the wait
routines to a function.
* docs/libs/gstreamer-libs-sections.txt: I am a good person today.
* libs/gst/controller/gsthelper.c:
* libs/gst/controller/gstcontroller.h (gst_controller_sync_values)
(gst_object_sync_values): Renamed from sink_values. Ugh.
* libs/gst/controller/gsthelper.c: Update for __gst_controller_key.
* libs/gst/controller/gstcontroller.c (__gst_controller_key):
Renamed from controller_key, as it is exported.
* gst/gstvalue.c (_gst_value_initialize): Fake out the compiler.
2005-09-26 Thomas Vander Stichele <thomas at apestaart dot org>
* gst/Makefile.am:

View file

@ -657,7 +657,6 @@ po/Makefile.in
check/Makefile
tests/Makefile
tests/instantiate/Makefile
tests/memchunk/Makefile
tests/muxing/Makefile
tests/seeking/Makefile
tests/sched/Makefile

View file

@ -58,7 +58,7 @@ gst_controller_set_from_list
gst_controller_unset
gst_controller_get
gst_controller_get_all
gst_controller_sink_values
gst_controller_sync_values
gst_controller_get_value_arrays
gst_controller_get_value_array
gst_controller_set_interpolation_mode
@ -86,7 +86,7 @@ gst_object_control_properties
gst_object_uncontrol_properties
gst_object_get_controller
gst_object_set_controller
gst_object_sink_values
gst_object_sync_values
gst_object_get_value_arrays
gst_object_get_value_array
<SUBSECTION Standard>

View file

@ -886,6 +886,29 @@ gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
}
}
/* with STREAM_LOCK and LOCK*/
static GstClockReturn
gst_base_sink_wait (GstBaseSink * basesink, GstClockTime time)
{
GstClockReturn ret;
/* clock_id should be NULL outside of this function */
g_assert (basesink->clock_id == NULL);
g_assert (GST_CLOCK_TIME_IS_VALID (time));
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock, time);
/* release the object lock while waiting */
GST_UNLOCK (basesink);
ret = gst_clock_id_wait (basesink->clock_id, NULL);
GST_LOCK (basesink);
gst_clock_id_unref (basesink->clock_id);
basesink->clock_id = NULL;
return ret;
}
/* perform synchronisation on a buffer
*
* 1) check if we have a clock, if not, do nothing
@ -957,30 +980,22 @@ gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
GstClockTime base_time;
GST_LOCK (basesink);
base_time = GST_ELEMENT (basesink)->base_time;
GST_LOG_OBJECT (basesink,
"waiting for clock, base time %" GST_TIME_FORMAT,
GST_TIME_ARGS (base_time));
/* save clock id so that we can unlock it if needed */
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
stream_start + base_time);
/* also save end_time of this buffer so that we can wait
* to signal EOS */
if (end_valid)
basesink->end_time = stream_end + base_time;
else
basesink->end_time = GST_CLOCK_TIME_NONE;
GST_UNLOCK (basesink);
ret = gst_clock_id_wait (basesink->clock_id, NULL);
ret = gst_base_sink_wait (basesink, stream_start + base_time);
GST_LOCK (basesink);
if (basesink->clock_id) {
gst_clock_id_unref (basesink->clock_id);
basesink->clock_id = NULL;
}
GST_UNLOCK (basesink);
GST_LOG_OBJECT (basesink, "clock entry done: %d", ret);
@ -1016,17 +1031,7 @@ gst_base_sink_handle_event (GstBaseSink * basesink, GstEvent * event)
if (basesink->clock) {
/* wait for last buffer to finish if we have a valid end time */
if (GST_CLOCK_TIME_IS_VALID (basesink->end_time)) {
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
basesink->end_time);
GST_UNLOCK (basesink);
gst_clock_id_wait (basesink->clock_id, NULL);
GST_LOCK (basesink);
if (basesink->clock_id) {
gst_clock_id_unref (basesink->clock_id);
basesink->clock_id = NULL;
}
gst_base_sink_wait (basesink, basesink->end_time);
basesink->end_time = GST_CLOCK_TIME_NONE;
}
}

View file

@ -3392,6 +3392,11 @@ _gst_value_initialize (void)
gst_value_register_subtract_func (GST_TYPE_DOUBLE_RANGE,
GST_TYPE_DOUBLE_RANGE, gst_value_subtract_double_range_double_range);
#if GLIB_CHECK_VERSION(2,8,0)
/* see bug #317246 */
GST_LOG ("Faking out the compiler: %d", G_TYPE_DATE);
#endif
gst_value_register_union_func (G_TYPE_INT, GST_TYPE_INT_RANGE,
gst_value_union_int_int_range);
gst_value_register_union_func (GST_TYPE_INT_RANGE, GST_TYPE_INT_RANGE,

View file

@ -886,6 +886,29 @@ gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
}
}
/* with STREAM_LOCK and LOCK*/
static GstClockReturn
gst_base_sink_wait (GstBaseSink * basesink, GstClockTime time)
{
GstClockReturn ret;
/* clock_id should be NULL outside of this function */
g_assert (basesink->clock_id == NULL);
g_assert (GST_CLOCK_TIME_IS_VALID (time));
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock, time);
/* release the object lock while waiting */
GST_UNLOCK (basesink);
ret = gst_clock_id_wait (basesink->clock_id, NULL);
GST_LOCK (basesink);
gst_clock_id_unref (basesink->clock_id);
basesink->clock_id = NULL;
return ret;
}
/* perform synchronisation on a buffer
*
* 1) check if we have a clock, if not, do nothing
@ -957,30 +980,22 @@ gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
GstClockTime base_time;
GST_LOCK (basesink);
base_time = GST_ELEMENT (basesink)->base_time;
GST_LOG_OBJECT (basesink,
"waiting for clock, base time %" GST_TIME_FORMAT,
GST_TIME_ARGS (base_time));
/* save clock id so that we can unlock it if needed */
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
stream_start + base_time);
/* also save end_time of this buffer so that we can wait
* to signal EOS */
if (end_valid)
basesink->end_time = stream_end + base_time;
else
basesink->end_time = GST_CLOCK_TIME_NONE;
GST_UNLOCK (basesink);
ret = gst_clock_id_wait (basesink->clock_id, NULL);
ret = gst_base_sink_wait (basesink, stream_start + base_time);
GST_LOCK (basesink);
if (basesink->clock_id) {
gst_clock_id_unref (basesink->clock_id);
basesink->clock_id = NULL;
}
GST_UNLOCK (basesink);
GST_LOG_OBJECT (basesink, "clock entry done: %d", ret);
@ -1016,17 +1031,7 @@ gst_base_sink_handle_event (GstBaseSink * basesink, GstEvent * event)
if (basesink->clock) {
/* wait for last buffer to finish if we have a valid end time */
if (GST_CLOCK_TIME_IS_VALID (basesink->end_time)) {
basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
basesink->end_time);
GST_UNLOCK (basesink);
gst_clock_id_wait (basesink->clock_id, NULL);
GST_LOCK (basesink);
if (basesink->clock_id) {
gst_clock_id_unref (basesink->clock_id);
basesink->clock_id = NULL;
}
gst_base_sink_wait (basesink, basesink->end_time);
basesink->end_time = GST_CLOCK_TIME_NONE;
}
}

View file

@ -38,7 +38,7 @@
* </para></listitem>
* <listitem><para>
* when processing data (get, chain, loop function) at the beginning call
* gst_object_sink_values(element,timestamp).
* gst_object_sync_values(element,timestamp).
* This will made the controller to update all gobject properties that are under
* control with the current values based on timestamp.
* </para></listitem>
@ -73,7 +73,7 @@
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
static GObjectClass *parent_class = NULL;
GQuark controller_key;
GQuark __gst_controller_key;
/* imports from gst-interpolation.c */
@ -94,7 +94,7 @@ on_object_controlled_property_changed (const GObject * object, GParamSpec * arg,
GST_INFO ("notify for '%s'", prop->name);
ctrl = g_object_get_qdata (G_OBJECT (object), controller_key);
ctrl = g_object_get_qdata (G_OBJECT (object), __gst_controller_key);
g_return_if_fail (ctrl);
if (g_mutex_trylock (ctrl->lock)) {
@ -420,7 +420,7 @@ gst_controller_new_valist (GObject * object, va_list var_args)
GstParent will be in core after all.
*/
self = g_object_get_qdata (object, controller_key);
self = g_object_get_qdata (object, __gst_controller_key);
// create GstControlledProperty for each property
while ((name = va_arg (var_args, gchar *))) {
// test if this property isn't yet controlled
@ -432,7 +432,7 @@ gst_controller_new_valist (GObject * object, va_list var_args)
self = g_object_new (GST_TYPE_CONTROLLER, NULL);
self->object = object;
// store the controller
g_object_set_qdata (object, controller_key, self);
g_object_set_qdata (object, __gst_controller_key, self);
} else {
// increment ref-count (this causes red-count-leaks
//self = g_object_ref (self);
@ -730,7 +730,7 @@ gst_controller_get_all (GstController * self, gchar * property_name)
}
/**
* gst_controller_sink_values:
* gst_controller_sync_values:
* @self: the controller that handles the values
* @timestamp: the time that should be processed
*
@ -742,7 +742,7 @@ gst_controller_get_all (GstController * self, gchar * property_name)
* Since: 0.9
*/
gboolean
gst_controller_sink_values (GstController * self, GstClockTime timestamp)
gst_controller_sync_values (GstController * self, GstClockTime timestamp)
{
GstControlledProperty *prop;
GList *node;
@ -752,7 +752,7 @@ gst_controller_sink_values (GstController * self, GstClockTime timestamp)
g_return_val_if_fail (GST_IS_CONTROLLER (self), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
GST_INFO ("sink_values");
GST_INFO ("sync_values");
g_mutex_lock (self->lock);
// go over the controlled properties of the controller
@ -954,7 +954,7 @@ _gst_controller_finalize (GObject * object)
}
g_mutex_free (self->lock);
/* remove controller from objects qdata list */
g_object_set_qdata (self->object, controller_key, NULL);
g_object_set_qdata (self->object, __gst_controller_key, NULL);
if (G_OBJECT_CLASS (parent_class)->finalize)
(G_OBJECT_CLASS (parent_class)->finalize) (object);
@ -978,7 +978,7 @@ _gst_controller_class_init (GstControllerClass * klass)
gobject_class->finalize = _gst_controller_finalize;
controller_key = g_quark_from_string ("gst::controller");
__gst_controller_key = g_quark_from_string ("gst::controller");
// register properties
// register signals

View file

@ -225,7 +225,7 @@ const GList *gst_controller_get_all (GstController * self,
gchar * property_name);
gboolean gst_controller_sink_values (GstController * self,
gboolean gst_controller_sync_values (GstController * self,
GstClockTime timestamp);
gboolean gst_controller_get_value_arrays (GstController * self,
@ -245,7 +245,7 @@ gboolean gst_object_uncontrol_properties (GObject * object, ...);
GstController *gst_object_get_controller (GObject * object);
gboolean gst_object_set_controller (GObject * object, GstController * controller);
gboolean gst_object_sink_values (GObject * object, GstClockTime timestamp);
gboolean gst_object_sync_values (GObject * object, GstClockTime timestamp);
gboolean gst_object_get_value_arrays (GObject * object,
GstClockTime timestamp, GSList * value_arrays);

View file

@ -35,7 +35,7 @@
#define GST_CAT_DEFAULT gst_controller_debug
GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
extern GQuark controller_key;
extern GQuark __gst_controller_key;
/**
* gst_object_control_properties:
@ -88,7 +88,7 @@ gst_object_uncontrol_properties (GObject * object, ...)
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
if ((ctrl = g_object_get_qdata (object, controller_key))) {
if ((ctrl = g_object_get_qdata (object, __gst_controller_key))) {
va_list var_args;
va_start (var_args, object);
@ -110,7 +110,7 @@ gst_object_get_controller (GObject * object)
{
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
return (g_object_get_qdata (object, controller_key));
return (g_object_get_qdata (object, __gst_controller_key));
}
/**
@ -131,33 +131,33 @@ gst_object_set_controller (GObject * object, GstController * controller)
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
g_return_val_if_fail (controller, FALSE);
if (!(ctrl = g_object_get_qdata (object, controller_key))) {
g_object_set_qdata (object, controller_key, controller);
if (!(ctrl = g_object_get_qdata (object, __gst_controller_key))) {
g_object_set_qdata (object, __gst_controller_key, controller);
return (TRUE);
}
return (FALSE);
}
/**
* gst_object_sink_values:
* gst_object_sync_values:
* @object: the object that has controlled properties
* @timestamp: the time that should be processed
*
* Convenience function for GObject
*
* Returns: same thing as gst_controller_sink_values()
* Returns: same thing as gst_controller_sync_values()
* Since: 0.9
*/
gboolean
gst_object_sink_values (GObject * object, GstClockTime timestamp)
gst_object_sync_values (GObject * object, GstClockTime timestamp)
{
GstController *ctrl = NULL;
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
if ((ctrl = g_object_get_qdata (object, controller_key))) {
return gst_controller_sink_values (ctrl, timestamp);
if ((ctrl = g_object_get_qdata (object, __gst_controller_key))) {
return gst_controller_sync_values (ctrl, timestamp);
}
return (FALSE);
}
@ -189,7 +189,7 @@ gst_object_get_value_arrays (GObject * object, GstClockTime timestamp,
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
if ((ctrl = g_object_get_qdata (object, controller_key))) {
if ((ctrl = g_object_get_qdata (object, __gst_controller_key))) {
return gst_controller_get_value_arrays (ctrl, timestamp, value_arrays);
}
return (FALSE);
@ -220,7 +220,7 @@ gst_object_get_value_array (GObject * object, GstClockTime timestamp,
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
if ((ctrl = g_object_get_qdata (object, controller_key))) {
if ((ctrl = g_object_get_qdata (object, __gst_controller_key))) {
return gst_controller_get_value_array (ctrl, timestamp, value_array);
}
return (FALSE);

View file

@ -1,5 +1,5 @@
SUBDIRS = instantiate memchunk muxing sched threadstate seeking
SUBDIRS = instantiate muxing sched threadstate seeking
if GST_DISABLE_TRACE
LAT =
@ -15,4 +15,4 @@ LIBS = $(GST_OBJ_LIBS) \
$(top_builddir)/gst/base/libgstbase-@GST_MAJORMINOR@.la
EXTRA_DIST = README
DIST_SUBDIRS= instantiate memchunk muxing sched threadstate seeking
DIST_SUBDIRS= instantiate muxing sched threadstate seeking

View file

@ -1,5 +0,0 @@
gmemchunktest
gstmemchunktest
*.bb
*.bbg
*.da

View file

@ -1,7 +0,0 @@
noinst_PROGRAMS = gmemchunktest gstmemchunktest
gmemchunktest_SOURCES = gmemchunktest.c
gstmemchunktest_SOURCES = gstmemchunktest.c gstmemchunk.c gstmemchunk.h
LDADD = $(GST_OBJ_LIBS)
AM_CFLAGS = $(GST_OBJ_CFLAGS)

View file

@ -1,252 +0,0 @@
/* GStreamer
* Copyright (C) 2005 Andy Wingo <wingo at pobox.com>
*
* 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.
*/
#include <stdlib.h>
#include <glib.h>
#include <gmodule.h>
#include <gst/gstmemchunk.h>
#define MAX_THREADS 100
#define CHUNK_SIZE 32
#define GMEMCHUNK_THREADSAFE
typedef gpointer (*alloc_func_t) (void);
typedef void (*free_func_t) (gpointer);
static gint num_allocs;
static gint num_threads;
static alloc_func_t _alloc = NULL;
static free_func_t _free = NULL;
static GMemChunk *_gmemchunk;
static GMutex *_gmemchunklock;
static GstMemChunk *_gstmemchunk;
static GCond *ready_cond;
static GCond *start_cond;
static GMutex *sync_mutex;
static gdouble
get_current_time (void)
{
GTimeVal tv;
g_get_current_time (&tv);
return tv.tv_sec + ((gdouble) tv.tv_usec) / G_USEC_PER_SEC;
}
/*
* GMemChunk implementation
*/
static gpointer
gmemchunk_alloc (void)
{
gpointer ret;
#ifdef GMEMCHUNK_THREADSAFE
g_mutex_lock (_gmemchunklock);
#endif
ret = g_mem_chunk_alloc (_gmemchunk);
#ifdef GMEMCHUNK_THREADSAFE
g_mutex_unlock (_gmemchunklock);
#endif
return ret;
}
static void
gmemchunk_free (gpointer chunk)
{
#ifdef GMEMCHUNK_THREADSAFE
g_mutex_lock (_gmemchunklock);
#endif
g_mem_chunk_free (_gmemchunk, chunk);
#ifdef GMEMCHUNK_THREADSAFE
g_mutex_unlock (_gmemchunklock);
#endif
}
/*
* GstMemChunk implementation
*/
static gpointer
gstmemchunk_alloc (void)
{
return gst_mem_chunk_alloc (_gstmemchunk);
}
static void
gstmemchunk_free (gpointer chunk)
{
gst_mem_chunk_free (_gstmemchunk, chunk);
}
/*
* Normal (malloc/free) implementation
*/
static gpointer
normal_alloc (void)
{
return g_malloc (CHUNK_SIZE);
}
static void
normal_free (gpointer chunk)
{
g_free (chunk);
}
/*
* Normal (malloc/free) implementation
*/
void *(*_google_malloc) (gsize) = NULL;
void (*_google_free) (void *) = NULL;
static gpointer
google_alloc (void)
{
return _google_malloc (CHUNK_SIZE);
}
static void
google_free (gpointer chunk)
{
_google_free (chunk);
}
/*
* The test
*/
void *
worker_thread (void *threadid)
{
gint i;
gpointer chunk;
g_mutex_lock (sync_mutex);
g_cond_signal (ready_cond);
g_cond_wait (start_cond, sync_mutex);
g_mutex_unlock (sync_mutex);
for (i = 0; i < num_allocs; i++) {
chunk = _alloc ();
_free (chunk);
}
return NULL;
}
gdouble
run_test (alloc_func_t alloc_func, free_func_t free_func)
{
gdouble start, end;
GThread *threads[MAX_THREADS];
GError *error;
int t;
_alloc = alloc_func;
_free = free_func;
g_mutex_lock (sync_mutex);
for (t = 0; t < num_threads; t++) {
error = NULL;
threads[t] =
g_thread_create (worker_thread, GINT_TO_POINTER (t), TRUE, &error);
g_assert (threads[t]);
g_cond_wait (ready_cond, sync_mutex);
}
g_cond_broadcast (start_cond);
start = get_current_time ();
g_mutex_unlock (sync_mutex);
for (t = 0; t < num_threads; t++)
g_thread_join (threads[t]);
end = get_current_time ();
return end - start;
}
gint
main (gint argc, gchar * argv[])
{
gdouble time;
GModule *google_lib;
g_thread_init (NULL);
ready_cond = g_cond_new ();
start_cond = g_cond_new ();
sync_mutex = g_mutex_new ();
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]);
g_assert (num_threads > 0);
g_assert (num_allocs > 0);
_gmemchunk =
g_mem_chunk_new ("test", CHUNK_SIZE, CHUNK_SIZE * 16, G_ALLOC_ONLY);
_gmemchunklock = g_mutex_new ();
_gstmemchunk =
gst_mem_chunk_new ("test", CHUNK_SIZE, CHUNK_SIZE * 16, G_ALLOC_ONLY);
g_print ("%d alloc+frees X %d threads\n", num_allocs, num_threads);
time = run_test (gmemchunk_alloc, gmemchunk_free);
g_print ("%fs (%fs/thread) - GMemChunk\n", time, time / num_threads);
time = run_test (gstmemchunk_alloc, gstmemchunk_free);
g_print ("%fs (%fs/thread) - GstMemChunk\n", time, time / num_threads);
time = run_test (normal_alloc, normal_free);
g_print ("%fs (%fs/thread) - g_malloc/g_free\n", time, time / num_threads);
google_lib = g_module_open ("libtcmalloc.so", G_MODULE_BIND_LOCAL);
if (google_lib) {
gpointer sym;
g_module_symbol (google_lib, "malloc", &sym);
g_assert (sym);
_google_malloc = sym;
g_module_symbol (google_lib, "free", &sym);
g_assert (sym);
_google_free = sym;
time = run_test (google_alloc, google_free);
g_print ("%fs (%fs/thread) - google malloc/free\n", time,
time / num_threads);
} else {
g_print ("google malloc unavailable: %s\n", g_module_error ());
}
/* g_mem_chunk_info (); */
return 0;
}

View file

@ -1,162 +0,0 @@
#include <string.h> /* memset */
#include <stdlib.h> /* memset */
#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:
#ifdef HAVE_I386
__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");
#else
fprintf (stderr, "This only compiles correctly on i386. Sorry\n");
abort ();
#endif
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);
#ifdef HAVE_I386
__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));
#else
fprintf (stderr, "This only compiles correctly on i386. Sorry\n");
abort ();
#endif
}

View file

@ -1,34 +0,0 @@
#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

@ -1,85 +0,0 @@
#include <string.h> /* strerror */
#include <stdlib.h> /* strerror */
#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;
g_usleep (G_USEC_PER_SEC);
for (i = 0; i < num_allocs; i++) {
chunk = alloc_chunk ();
free_chunk (chunk);
}
g_thread_exit (NULL);
return NULL;
}
gint
main (gint argc, gchar * argv[])
{
GThread *threads[MAX_THREADS];
GError *error;
int 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++) {
error = NULL;
threads[t] = g_thread_create (run_test, GINT_TO_POINTER (t), TRUE, &error);
if (error) {
printf ("ERROR: g_thread_create() %s\n", error->message);
exit (-1);
}
}
printf ("main(): Created %d threads.\n", t);
for (t = 0; t < num_threads; t++) {
g_thread_join (threads[t]);
}
g_mem_chunk_info ();
gst_mem_chunk_destroy (_chunks);
return 0;
}