Blame tests/slice-concurrent.c

Packit ae235b
/* test for gslice cross thread allocation/free
Packit ae235b
 * Copyright (C) 2006 Stefan Westerfeld
Packit ae235b
 * Copyright (C) 2007 Tim Janik
Packit ae235b
 *
Packit ae235b
 * This library is free software; you can redistribute it and/or
Packit ae235b
 * modify it under the terms of the GNU Lesser General Public
Packit ae235b
 * License as published by the Free Software Foundation; either
Packit ae235b
 * version 2.1 of the License, or (at your option) any later version.
Packit ae235b
 *
Packit ae235b
 * This library is distributed in the hope that it will be useful,
Packit ae235b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ae235b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit ae235b
 * Lesser General Public License for more details.
Packit ae235b
 *
Packit ae235b
 * You should have received a copy of the GNU Lesser General Public
Packit ae235b
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit ae235b
 */
Packit ae235b
#include <glib.h>
Packit ae235b
#include <stdlib.h>
Packit ae235b
#ifdef G_OS_UNIX
Packit ae235b
#include <unistd.h>
Packit ae235b
#endif
Packit ae235b
Packit ae235b
#define N_THREADS	8
Packit ae235b
#define N_ALLOCS	50000
Packit ae235b
#define MAX_BLOCK_SIZE  64
Packit ae235b
Packit ae235b
struct ThreadData
Packit ae235b
{
Packit ae235b
  int	   thread_id;
Packit ae235b
  GThread* gthread;
Packit ae235b
Packit ae235b
  GMutex   to_free_mutex;
Packit ae235b
  void*    to_free [N_THREADS * N_ALLOCS];
Packit ae235b
  int      bytes_to_free [N_THREADS * N_ALLOCS];
Packit ae235b
  int      n_to_free;
Packit ae235b
  int      n_freed;
Packit ae235b
} tdata[N_THREADS];
Packit ae235b
Packit ae235b
static void *
Packit ae235b
thread_func (void *arg)
Packit ae235b
{
Packit ae235b
  struct ThreadData *td = arg;
Packit ae235b
  int i;
Packit ae235b
/*   g_print ("Thread %d starting\n", td->thread_id); */
Packit ae235b
  for (i = 0; i < N_ALLOCS; i++)
Packit ae235b
    {
Packit ae235b
      int bytes;
Packit ae235b
      char *mem;
Packit ae235b
      int f;
Packit ae235b
      int t;
Packit ae235b
Packit ae235b
      if (rand() % (N_ALLOCS / 20) == 0)
Packit ae235b
	g_print ("%c", 'a' - 1 + td->thread_id);
Packit ae235b
Packit ae235b
      /* allocate block of random size and randomly fill */
Packit ae235b
      bytes = rand() % MAX_BLOCK_SIZE + 1;
Packit ae235b
      mem = g_slice_alloc (bytes);
Packit ae235b
Packit ae235b
      for (f = 0; f < bytes; f++)
Packit ae235b
	mem[f] = rand();
Packit ae235b
Packit ae235b
      /* associate block with random thread */
Packit ae235b
      t = rand() % N_THREADS;
Packit ae235b
      g_mutex_lock (&tdata[t].to_free_mutex);
Packit ae235b
      tdata[t].to_free[tdata[t].n_to_free] = mem;
Packit ae235b
      tdata[t].bytes_to_free[tdata[t].n_to_free] = bytes;
Packit ae235b
      tdata[t].n_to_free++;
Packit ae235b
      g_mutex_unlock (&tdata[t].to_free_mutex);
Packit ae235b
Packit ae235b
      /* shuffle thread execution order every once in a while */
Packit ae235b
      if (rand() % 97 == 0)
Packit ae235b
        {
Packit ae235b
          if (rand() % 2)
Packit ae235b
            g_thread_yield();   /* concurrent shuffling for single core */
Packit ae235b
          else
Packit ae235b
            g_usleep (1000);    /* concurrent shuffling for multi core */
Packit ae235b
        }
Packit ae235b
Packit ae235b
      /* free a block associated with this thread */
Packit ae235b
      g_mutex_lock (&td->to_free_mutex);
Packit ae235b
      if (td->n_to_free > 0)
Packit ae235b
	{
Packit ae235b
	  td->n_to_free--;
Packit ae235b
	  g_slice_free1 (td->bytes_to_free[td->n_to_free], td->to_free[td->n_to_free]);
Packit ae235b
	  td->n_freed++;
Packit ae235b
	}
Packit ae235b
      g_mutex_unlock (&td->to_free_mutex);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return NULL;
Packit ae235b
}
Packit ae235b
Packit ae235b
int
Packit ae235b
main (void)
Packit ae235b
{
Packit ae235b
  int t;
Packit ae235b
Packit ae235b
  for (t = 0; t < N_THREADS; t++)
Packit ae235b
    {
Packit ae235b
      tdata[t].thread_id = t + 1;
Packit ae235b
      tdata[t].n_to_free = 0;
Packit ae235b
      tdata[t].n_freed = 0;
Packit ae235b
    }
Packit ae235b
  g_print ("Starting %d threads for concurrent GSlice usage...\n", N_THREADS);
Packit ae235b
  for (t = 0; t < N_THREADS; t++)
Packit ae235b
    {
Packit ae235b
      tdata[t].gthread   = g_thread_create (thread_func, &tdata[t], TRUE, NULL);
Packit ae235b
      g_assert (tdata[t].gthread != NULL);
Packit ae235b
    }
Packit ae235b
  for (t = 0; t < N_THREADS; t++)
Packit ae235b
    {
Packit ae235b
      g_thread_join (tdata[t].gthread);
Packit ae235b
    }
Packit ae235b
  g_print ("\n");
Packit ae235b
  for (t = 0; t < N_THREADS; t++)
Packit ae235b
    {
Packit ae235b
      g_print ("Thread %d: %d blocks freed, %d blocks not freed\n",
Packit ae235b
		    tdata[t].thread_id, tdata[t].n_freed, tdata[t].n_to_free);
Packit ae235b
    }
Packit ae235b
  return 0;
Packit ae235b
}