/*
 * Written by Matz Kindahl (matkin@docs.uu.se)
 */
#include <sys/time.h>
#include <sys/resource.h>

#define NTIMES 50000

/* This is a program to measure the improvement of replacing the */
/* normal strcmp-function with the following macro. */
#define STRCMP(x,y) (*(x) == *(y) ? strcmp((x),(y)) : *(x) - *(y))

#define RAND(x) ((rand() >> 2) % (x))

/* Macro to implement the measuring loop */
#define MEASURE(f,b,a) \
  do { int _cnt; \
       getrusage(RUSAGE_SELF, &(b)); \
       for (_cnt = 0 ; _cnt < NTIMES ; _cnt++) { \
	 generate(str1); generate(str2); \
	 f(str1, str2); \
       } getrusage(RUSAGE_SELF, &(a)); \
     } while (0)

static double
delta_time(struct rusage b, struct rusage a)
{
  return
    (a.ru_utime.tv_sec - b.ru_utime.tv_sec)
      + ((double) a.ru_utime.tv_usec - b.ru_utime.tv_usec) / 1e6;
}

/*
 * generate:
 *    This function generates a random string and stores it at the
 *    place pointed to by 'str'. Make sure there is at least 11 bytes
 *    of space where 'str' points.
 */
void
generate(char *str)
{
  int cnt;
  int len = RAND(11);

  for (cnt = 0 ; cnt < len ; cnt++)
    str[cnt] = RAND('z' - 'a') + 'a';
  str[len] = '\0';
}

int
main()
{
  unsigned int cnt;
  struct rusage before, after;
  double overhead, standard, macro;

  static char str1[64], str2[64];

  srand(getpid());

/* Measure the overhead */
  getrusage(RUSAGE_SELF, &before);
  for (cnt = 0 ; cnt < NTIMES ; cnt++) {
    generate(str1);
    generate(str2);
  }
  getrusage(RUSAGE_SELF, &after);

  overhead = delta_time(before, after);
#ifdef remove
  printf("Overhead: %f s (%f s/round)\n",
	 overhead, overhead / NTIMES);
#endif

/* Measure standard function */
  MEASURE(strcmp, before, after);

  standard = delta_time(before, after) - overhead;

/* Measure macro version */
  MEASURE(STRCMP, before, after);

  macro = delta_time(before, after) - overhead;

  printf("Macro version is %.1f%% of the standard version.\n",
	 macro / standard * 100);
}

