/*
 * $Header: /home/gene/library/website/docsrc/wgc/wgcperf/RCS/demo0003.c,v 395.1 2008/04/20 17:25:48 gene Exp $
 *
 * Compare performances of garbage collection & manual memory
 * management by allocating & removing blocks in a loop.  Keeps
 * a large array of pointers to allocated blocks.  So blocks are
 * allocated & released in random order.
 */

#include "this.h"

static int S_block_size = 28 * 1024;

static clock_t
S_Loop (void *(*alloc) (), void (*free) (), long count)
{
  clock_t start;
  long i;
  int length = 9001;                    /* pulled this number from the air */
  int step = count / 20;
  char **a;
  int j;

  start = clock ();
  a = (char **) (*alloc) (length * sizeof *a);
  assert (a != NULL);
  memset (a, 0, sizeof *a);

  /*
   * Allocate blocks in a tight loop.  When compiled for
   * malloc/free, we free the block each time.  Otherwise,
   * we still call xfree (to keep the code clean)
   */
  for (i = 0; i < count; ++i) {
    if (i % step == 0) printf ("\n%ld", i);
    j = rand () % length;
    if (a[j] != NULL) {
      (*free) (a[j]);
    }
    a[j] = (*alloc) (S_block_size);
    assert (a[j] != NULL);
  }

  /* Clean-up.  Don't need to do this with garbage collection, so
   * it could screw the results in the favor of malloc/free, but
   * what the hell.
   */
  for (j = 0; j < length; ++j) {
    if (a[j] != NULL) {
      (*free) (a[j]);
    }
  }
  (*free) (a);
  printf ("\n");
  return clock () - start;
}

int
main ()
{
  int rc = 0;
  long count;

  count = Iterations (S_block_size);
  ReportLine (S_Loop (&GC_malloc, &GC_free, count),
              S_Loop (&malloc, &free, count),
              count,
              "blocks in random order",
              __FILE__);
  return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}

/* --- end of file --- */
