Logo Search packages:      
Sourcecode: heaplayers version File versions

mallocperf.c

 


#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include <fcntl.h>

#if defined(UNIX)
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <pthread.h>
#else
#endif

#if defined(WIN32)
#include <windows.h>
#endif


#if defined(SOLARIS)
#include <libgen.h>
#include <sys/synch.h>
#include <procfs.h>
#endif

#if defined(SOLARIS)
#include <signal.h>
#include <siginfo.h>
#include <sys/ucontext.h>

#endif


#if defined(WIN32)
#define     basename
#endif


#if defined(SMARTHEAP)
#include "smrtheap.h"
#endif

typedef     struct basictestdata
{
      int   lock;
      int   nloops;
      int   lowerlimit;
      int   upperlimit;
      int   nallocs;
      int   pagesize;
      char  *program;
} basictest_t;

/*
** In single thrade mode, basictest is simply a function that return an int
** value, but in SMP mode, it needs to be a void
*/

#if defined(_REENTRANT)
void *
#else
int
#endif

basictest(void *);


int   randget(unsigned int index);
int   *randinit(int n);
void  randfill(int *ptr, int n);

#if defined(SOLARIS) || defined(LINUX)
int   getkbytes(int *, int *);
#endif

#if defined(SMARTHEAP)
unsigned MemDefaultPoolFlags = MEM_POOL_SERIALIZE;
#endif


int   verbose=0;
int   testcalloc=0, testrealloc=0;
int   createpools=0, thread_count, finalgo=0;
int   verifybuffer=0, kbytes=0;
int   buffer0[32];
int   *randomnumbers, nrandomnumbers=1000000, registerthread=0;
int   buffer1[32];
int   poolperthread=0;

#if defined(UNIX)
pthread_mutex_t   globalmutex=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t   mutex1=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t   mutex2=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t   countmutex=PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t    condition1=PTHREAD_COND_INITIALIZER;
pthread_cond_t    condition2=PTHREAD_COND_INITIALIZER;
#else
CRITICAL_SECTION  mutex1, mutex2, countmutex, globalmutex;
HANDLE                  event1, event2;
#endif


/********************************************************************************
** Some timing functions
**
**
*/

#if defined(WIN32)
typedef     unsigned int      time_t;
#endif

time_t
getstarttime()
{
time_t      starttime, endtime;

      starttime = endtime = time(NULL);

      while(starttime == endtime)
            starttime = time(NULL);

      return starttime;
}

time_t
getendtime()
{
      return time(NULL);
}


/*****************************************************************************
** ROUTINE: main(int, char**)
**
**
**
*/

main(int argc, char **argv)
{
int   i, lowerlimit=1, upperlimit=248, nloops=10, nentries=10, reps=1;
int   seed=0, nthreads=1, kbytes, pages, totalpages=0;
int   totalK=0;
char  *ptest="basic", atest[8];
time_t      starttime, endtime, elapsedtime=0, totaltime=0;
basictest_t btdata;

#if defined(WIN32)
SYSTEM_INFO si;
#endif

#if defined(SMARTHEAP)
      MemRegisterTask();
#endif

#if defined(PTMALLOC)
      ptmalloc_init();
#endif

      memset(&btdata, 0, sizeof(btdata));

#if defined(UNIX)
      btdata.pagesize = sysconf(_SC_PAGESIZE);
#else
      GetSystemInfo(&si);

      btdata.pagesize = si.dwPageSize;
#endif

      for(i=1; i<argc; i++)
      {
            if(!strcmp(argv[i], "-ul"))
                  upperlimit = atoi(argv[++i]);
            else if(!strcmp(argv[i], "-seed"))
                  seed = 1;
            else if(!strcmp(argv[i], "-t"))
                  nthreads = atoi(argv[++i]);
            else if(!strcmp(argv[i], "-ll"))
                  lowerlimit = atoi(argv[++i]);
            else if(!strcmp(argv[i], "-calloc"))
                  testcalloc = 1;
            else if(!strcmp(argv[i], "-realloc"))
                  testrealloc = 1;
            else if(!strcmp(argv[i], "-p"))
                  nentries = atoi(argv[++i]);
            else if(!strcmp(argv[i], "-nr"))
                  nrandomnumbers = atoi(argv[++i]);
            else if(!strcmp(argv[i], "-r"))
                  reps = atoi(argv[++i]);
            else if(!strcmp(argv[i], "-n"))
                  nloops = atoi(argv[++i]);
            else if(!strcmp(argv[i], "-pg"))
                  btdata.pagesize = atoi(argv[++i]);
            else if(!strcmp(argv[i], "-v"))
                  verbose++;
            else
            {
                  printf("%s: bad switch: %s\n", argv[0], argv[i]);
                  exit(-1);
            }
      }

#if !defined(_REENTRANT)
      if(nthreads > 1)
      {
            printf("%s: This application is single threaded\n", argv[0]);
            exit(-1);
      }
#endif

      btdata.nloops = nloops;
      btdata.lowerlimit = lowerlimit;
      btdata.upperlimit = upperlimit;
      btdata.nallocs = nentries;
      btdata.program = basename(argv[0]);


#if defined(UNIX)
            srand48( (long) time(NULL) );
#else
            srand(time(NULL));
#endif

      randomnumbers = randinit(nrandomnumbers);

      if(nthreads > 0)
      {
        pthread_t       *tid;
      unsigned int      i, allocspins=0, freespins=0, j;
      unsigned int      totalallocspins, totalfreespins, calls;
      unsigned int      fragseeks, poolseeks, reallocs, totalallocs;
      unsigned int      totalfrees, npools, allocs[4], frees[4];

#if defined(_REENTRANT)
#if defined(UNIX)
      pthread_attr_t    attr;

            pthread_attr_init(&attr);

            pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
#endif

#if defined(UNIX)
            pthread_mutex_init(&globalmutex, NULL);
#else
            InitializeCriticalSection( (LPCRITICAL_SECTION) &globalmutex);
                  InitializeCriticalSection( (LPCRITICAL_SECTION) &mutex1);
            InitializeCriticalSection( (LPCRITICAL_SECTION) &mutex2);
            InitializeCriticalSection( (LPCRITICAL_SECTION) &countmutex);
#endif

#if defined(WIN32)
            event1 = CreateEvent(NULL, TRUE, FALSE, NULL);
            event2 = CreateEvent(NULL, TRUE, FALSE, NULL);

            if(event1 == NULL || event2 == NULL)
            {
                  printf("CreateEvent: failed (%x, %x)\n",
                        event1, event2);
                  exit(-1);
            }
#endif
#endif

            tid = (pthread_t *) malloc(sizeof(long) * nthreads);

            totalallocspins = totalfreespins = calls = 0;

            for(i=0; i<reps; i++)
            {
                  thread_count = 0;
                  finalgo = 0;



#define     EVEREST_GET_MEMORY_USAGE      1



#if defined(EVEREST_GET_MEMORY_USAGE)
#if defined(WIN32)
                  ResetEvent(event2);
#endif
#endif
                  starttime = getstarttime();

#if defined(_REENTRANT)
                  /*
                  ** Multi-threaded. Need to create some number of
                  ** threads that call basictest with btdata as the
                  ** argument
                  */

                  for(j=0; j<nthreads; j++)
#if defined(UNIX)
                        pthread_create(&tid[j], &attr,
                                     basictest, &btdata);
#else
                        tid[j] = CreateThread(NULL, 0, 
                              (LPTHREAD_START_ROUTINE) basictest,
                              &btdata, 0, (void*) &tid[j]);
#endif

#else
                  /*
                  ** Single threaded. Just call the function.
                  */

                  basictest(&btdata);
#endif

#if defined(EVEREST_GET_MEMORY_USAGE)
#if defined(_REENTRANT)
#if defined(UNIX)
                  /*
                  ** SIGNAL: Now we wait here for all threads
                  ** to complete.
                  */

                  pthread_mutex_lock(&mutex1);

                  kbytes = 0;

                  while(thread_count < nthreads)
                  {
                        pthread_cond_wait(&condition1, &mutex1);
                  }

                  pthread_mutex_unlock(&mutex1);
#else
                  while(thread_count < nthreads)
                  {
                        ResetEvent(event1);

                        WaitForSingleObject(event1, INFINITE);
                  }
#endif
#endif
#endif


#if defined(EVEREST_GET_MEMORY_USAGE)
#if defined(_REENTRANT)
#if defined(UNIX) 
                  /*
                  ** All threads are now complete, and waiting
                  ** for a signal to exit.
                  ** Lets get the memory foot print now
                  */

                  getkbytes(&kbytes, &pages);

                  /*
                  ** SIGNAL: Now signal the threads to exit.
                  */

                  pthread_mutex_lock(&mutex2);

                  finalgo = 1;

                  pthread_cond_broadcast(&condition2);

                  pthread_mutex_unlock(&mutex2);
#else
                  finalgo = 1;

                  SetEvent(event2);
#endif
#endif
#endif

                  /*
                  ** keep a running total of the memory used by each test
                  ** so we can average them at the end
                  */

                  totalK += kbytes;
                  totalpages += pages;

#if defined(_REENTRANT)
                  /*
                  ** Now we wait for the threads to complete the
                  ** cleanup and exit.
                  */

                  for(j=0; j<nthreads; j++)
                  {
#if defined(UNIX)
                        pthread_join(tid[j], NULL);
#else
                        WaitForSingleObject(tid[j], INFINITE);
#endif
                  }
#endif

                  endtime = getendtime();

                  elapsedtime = endtime - starttime;
                  totaltime += elapsedtime;
                  
                  if(verbose == 2)
                  {
                        printf("%s: %d, T:%d, P:%d, N:%d, LL:%d, UL:%d, K:%d, ",
                              basename(argv[0]), i, nthreads,
                              nentries, nloops, lowerlimit, upperlimit,
                              kbytes);

#if defined(LINUX)
                        printf("V:%d, ", pages);
#endif

                        printf("E:%d\n", 
                              endtime - starttime);
                  }
            }

            randfill(randomnumbers, nrandomnumbers);

            if(verbose)
            {
                  printf("%s: X  T:%d, P:%d, N:%d, LL:%d, UL:%d, K:%d, ",
                        basename(argv[0]), nthreads,
                        nentries, nloops, lowerlimit, upperlimit,
                        totalK/reps);

#if defined(LINUX)
                  printf("V:%d, ", totalpages/reps);
#endif

                  printf("A:%d\n",  totaltime/reps);
            }

            free(tid);

            exit(totaltime/reps);
      }
}


#if defined(WIN32)
#define     PATH_MAX    512
#endif



#define     MALLOCPERF_BUFFER_SIZE        2048
#define     LINUX_PROC_RESIDENTMEM        "VmRSS:"


/****************************************************************************************
** ROUTINE: getkbytes(int *kbytes, int *vmpages)
**
** DESCRIPTION:   return the number of K-bytes utilized y this program, and additionally,
**          on Linux, becauseof discrepencies between various kernel VM parameters
**          in /proc/self/status and /proc/self/statm, also return the number of
**          pages as defined by the /proc/self/statm
**
*/

int
getkbytes(int *kbytes, int *vmpages)
{
char        filename[PATH_MAX], *buffer, *p;
int         fd, size;

#if defined(SOLARIS)
psinfo_t    ps;
#endif


#if defined(SOLARIS)
      *vmpages = -1;
      
      sprintf(filename, "/proc/%d/psinfo", getpid());

      if((fd = open(filename, O_RDONLY)) == -1)
            return -1;

      if(read(fd, &ps, sizeof(ps)) != sizeof(psinfo_t))
      {
            close(fd);
            return -2;
      }

      close(fd);

      *kbytes = ps.pr_size;

      return 0;
#elif defined(LINUX)
      /*
      ** get the kbytes used from /proc/self/status
      */

      sprintf(filename, "/proc/%d/status", getpid());

      if((fd = open(filename, O_RDONLY)) == NULL)
            return -1;

      buffer = (char *) malloc(MALLOCPERF_BUFFER_SIZE);
      memset(buffer, 0,MALLOCPERF_BUFFER_SIZE );

      if(read(fd, buffer, MALLOCPERF_BUFFER_SIZE) == -1)
      {
            free(buffer);
            close(fd);
            return(-1);
      }

      close(fd);

      if(!strstr(buffer, LINUX_PROC_RESIDENTMEM))
      {
            free(buffer);
            return(-1);
      }

      if(p = strstr(buffer, LINUX_PROC_RESIDENTMEM))
      {
            p = strstr(p, ":");
            p++;

            size = atoi(p);

            *kbytes = size;
      }

      /*
      ** get the vmpages used from /proc/self/statm
      */

      sprintf(filename, "/proc/%d/statm", getpid());

      if((fd = open(filename, O_RDONLY)) == NULL)
            return -1;

      buffer = (char *) malloc(MALLOCPERF_BUFFER_SIZE);
      memset(buffer, 0,MALLOCPERF_BUFFER_SIZE );

      if(read(fd, buffer, MALLOCPERF_BUFFER_SIZE) == -1)
      {
            free(buffer);
            close(fd);
            return(-1);
      }

      sscanf(buffer, "%d", vmpages);

      free(buffer);
      close(fd);

      return 0;
#else
      /*
      ** Gettng the memory footprint currently only works on Solaris and Linux
      **
      ** On Windows, one needs the Platform SDK libraries and header files,
      ** neither of which a 3rd party can distribute.
      ** It's work on Linux at some point, we just haven't gotten around to it 
      ** yet.
      */

      return -1;
#endif
}



/***************************************************************************
** ROUTINE: basictest.
**
** DESCRIPTION:   this function is the heart and soul of the Mallocmark
**          performance test suite.
**
** NOTES:   In sigle threaded mode, this function will take the memory
**          footprint after it's done with it's loop and place the 
**          number of K-bytes into a global called kbytes. 
**
**          In SMP mode, it will not return a value but go through a
**          signaling mechanism to infor the main thread that it's now
**          OK  to grab the memory footprint.
**
*/

#if defined(_REENTRANT)
void *
#else
int
#endif
basictest(void * btv)
{
char        *p, *p1, *p2, *p3, **ptr;
int         i, j;
unsigned int      index=0, rindex=0;
int         npointers, nloops, lowerlimit, upperlimit, range, kbytes, pages;

char        **ptr2;
int         *size2, *value2;

#if defined(SOLARIS)
hrtime_t    starttime, endtime;
#endif

#if defined(SOLARIS)
hrtime_t        start, end;
#endif

 basictest_t *btdata = (basictest_t *) btv;

#if defined(UNIX)
      rindex = lrand48();
#else
      rindex = rand();
#endif

      npointers = btdata->nallocs;
      nloops = btdata->nloops;
      lowerlimit = btdata->lowerlimit;
      upperlimit = btdata->upperlimit;
      range = upperlimit - lowerlimit;

      ptr = (char**) calloc(1, npointers*sizeof(char*)); 

      /*
      ** Lets allocate our working set of piinters before entering
      ** the main loop
      */

      for(i=0; i<npointers; i++)
        ptr[i] = (char *) malloc(randget(rindex++) % range + lowerlimit);

      /*
      ** Lets not start from ptr[0]. Lets start in a random place within
      ** the array.
      ** In SMP mode, each thread will start from a different offset,
      ** presumably, if it's a good random number generator!!!
      */

#if defined(UNIX)
      rindex = lrand48();
#else
      rindex = rand();
#endif

      /*
      ** MAIN LOOP
      */

      for(i=0; i<nloops; i++)
      {
      int   randomnumber, size, j, pages;
      char  *p;

            /*
            ** Which element are we going to free?
            ** Get a random number to find out.
            */

            randomnumber = randget(rindex++);

            index = randomnumber % npointers;

            /*
            ** Free the selected pointer.
            */

            if(testrealloc == 0)
                  free(ptr[index]);

            /*
            ** Allocate a new pointer in it's place, resizing the
            ** pointer as well. We do not want it to be the same
            ** size.
            */

            size = (randomnumber % range) + lowerlimit;

            if(testrealloc)
              ptr[index] = (char *) realloc(ptr[index], size);
            else if(testcalloc)
              ptr[index] = (char *) calloc(size, 1);
            else
              ptr[index] = (char *) malloc(size);

            p = ptr[index];

            /*
            ** Simply touch at least 1 byte in every page of 
            ** the memory we just allocated.
            **
            ** compute how many pages we've allocated. if the size is
            ** a multiple of the cpu page size, then the division is
            ** all that is needed. However, if it's not, then we need to 
            ** add 1.
            */

            pages = size / btdata->pagesize;

            if(size % btdata->pagesize != 0)
                  pages++;

            /*
            ** write at least 1 bytes to each page
            */

            for(j=0; j<pages; j++)
                  p[j * btdata->pagesize] = 0;
      }

#if defined(EVEREST_GET_MEMORY_USAGE)
#if !defined(_REENTRANT)
      /*
      ** WHen we running as a single threaded process, basictest() is a
      ** function, so we need to write in the memory footprint into this
      ** global, kbytes
      */

      getkbytes(&kbytes, &pages);
#endif
#endif


#if defined(EVEREST_GET_MEMORY_USAGE)
#if defined(_REENTRANT)
#if defined(UNIX)
      /*
      ** SIGNAL:
      ** before freeing any memory, we must signal the main thread that
      ** we are done, and then wait for the signal to exit so that the main
      ** thread can grab a memory footprint.
      */

      pthread_mutex_lock(&countmutex);
      thread_count++;
      pthread_mutex_unlock(&countmutex);

      pthread_cond_signal(&condition1);

      /*
      ** Now we wait here for notification that all other threads are
      ** complete and the main thread was able to get a memory footprint
      */

      pthread_mutex_lock(&mutex2);

      while(finalgo == 0)
      {
            pthread_cond_wait(&condition2, &mutex2);
      }

      pthread_mutex_unlock(&mutex2);
#else
      EnterCriticalSection(&countmutex);
      thread_count++;
      LeaveCriticalSection(&countmutex);

      SetEvent(event1);

      while(finalgo == 0)
            WaitForSingleObject(event2, INFINITE);
#endif
#endif
#endif

      /*
      ** We're out-a here.
      */

      for(i=0; i<npointers; i++)
            free(ptr[i]);

      free(ptr);
}

int*
randinit(int n)
{
int   i, *ptr;

      nrandomnumbers = n;

      ptr = (int*) malloc(sizeof(int) * nrandomnumbers);

      randfill(ptr, nrandomnumbers);

      return ptr;
}

void
randfill(int *ptr, int n)
{
int   i;

      for(i=0; i<n; i++)
#if defined(UNIX)
            ptr[i] = lrand48();
#else
            ptr[i] = rand();
#endif
}

int
randget(unsigned int index)
{
      return randomnumbers[index % nrandomnumbers];
}



Generated by  Doxygen 1.6.0   Back to index