/*********************************************************************
 * mem - memory pool manager tester
 *
 * This program bangs on the mempool code
 *
 * To reduce memory pool thrashing, compute REUSE_FRAGMENTS thus:
 * MAX_POOL / MAX_CHUNKS / N where N is somewhere around 10 or 20.
 * 1/N is the portion of memory that will be sacrificed to reduce
 * thrashing.
 *********************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "mempool.h"

#define MAX_POOL         10000
#define MAX_CHUNKS       10
#define REUSE_FRAGMENTS  100
#define CAP              (MAX_POOL-(MAX_CHUNKS*REUSE_FRAGMENTS))

/*	Return a number from 0 to 1 that is evenly distributed */
float random_w0(void) {
	return((float)rand() / RAND_MAX);
}

/*  Given a number from 0 to 1, return an integer from 0 to X */
int random_int(float n, int x) {
	return((int)(x * n));
}

int main(int argc, char * argv[]) {
   void * pool;
   int handles[MAX_CHUNKS];
   int  amount[MAX_CHUNKS];
   char * ptrs[MAX_CHUNKS];
   int i, j;
   int alloced;

   for (i=0;i<MAX_CHUNKS;i++) {
     handles[i] = 0;
     ptrs[i] = NULL;
     amount[i] = 0;
   }

   pool = init_mem_pool(MAX_CHUNKS, MAX_POOL, REUSE_FRAGMENTS);

   mem_pool_stats(pool);

   alloced = 0;

   for (i=0;i<10000000;i++) {
      j = random_int(random_w0(), MAX_CHUNKS-1);
      if (handles[j]) {
         alloced -= amount[j];
         free_mem_chunk(pool, handles[j]);
         handles[j] = 0;
      } else
      if ((CAP - alloced) > 0) {
         amount[j] = random_int(random_w0(), CAP - alloced);
         if (amount[j]) {
            alloced += amount[j];
            handles[j] = alloc_mem_chunk(pool, amount[j]);
            if (handles[j] == 0) {
               printf("alloc failure\n");
            } else {
               ptrs[j] = lock_mem_chunk(pool, handles[j]);
               if (ptrs[j]) {
                  memset(ptrs[j], 33, amount[j]);
                  release_mem_chunk(pool, handles[j]);
                  ptrs[j] = NULL;
               } else {
                  printf("Could not lock chunk %d\n", handles[j]);
               }
            }
         }
      }
   }
   mem_pool_stats(pool);

   j = random_int(random_w0(), MAX_CHUNKS-1);
   if (handles[j]) {
      printf("Freeing handle %d size %d\n", handles[j], amount[j]);
      alloced -= amount[j];
      free_mem_chunk(pool, handles[j]);
      handles[j] = 0;
   } else
   if ((CAP - alloced) > 0) {
      printf("Alloced is %d, cap is %d\n", alloced, CAP - alloced);
      amount[j] = random_int(random_w0(), CAP - alloced);
      if (amount[j]) {
         alloced += amount[j];
         handles[j] = alloc_mem_chunk(pool, amount[j]);
         printf("Allocated handle %d size %d\n", handles[j], amount[j]);
         if (handles[j] == 0) {
            printf("alloc failure\n");
         }
      }
   }
   mem_pool_stats(pool);

   for (i=0;i<MAX_CHUNKS;i++) {
      if (handles[i]) {
         alloced -= amount[i];
         free_mem_chunk(pool, handles[i]);
         handles[i] = 0;
      }
   }
   printf("Final alloced = %d\n", alloced);
   
   mem_pool_stats(pool);

   free_mem_pool(pool);
   return 0;
}
