/*----------------------------------------------------------------------------*/

/*
 * Performance-Monitoring Counters Library, for Intel/AMD Processors and Linux
 * Author:  Don Heller, dheller@scl.ameslab.gov
 * Last revised:  19 January 2001
 *
 * use with rabbit5.sh
 */

/*----------------------------------------------------------------------------*/

/* select a test case, print "interesting" events */

#ifndef TESTNUMBER
#define TESTNUMBER 0
#endif
	// up to 18

#define TRIALS 1000000
#define CUTOFF 0.05

/*----------------------------------------------------------------------------*/

#include <pmc_lib.h>
#include <math.h>

/*----------------------------------------------------------------------------*/

pmc_data_t t3;

int main(int argc, char * argv[])
{
  pmc_control_t Ctl = pmc_control_null;

  int k;
  pmc_data_t t0, t1, t2;

  printf("test number %d\n", TESTNUMBER);

  /* initialize internal data structures, read command-line arguments */

  Ctl.clean = 10;
  Ctl.stats = 1;
  for (k = 0; k < pmc_event_counters; k++)
    { Ctl.os[k] = 0; }

  if (pmc_getargs(stderr, argv[0], &argc, &argv, &Ctl) == FALSE)
    { exit(RABBIT_FAILURE); }

  if (pmc_open(0) == FALSE)		/* open /dev/pmc */
    { exit(RABBIT_FAILURE); }

      pmc_select_clock(&Ctl.counters[0]);
      for (k = 0; k < TRIALS; k++) {
	pmc_read_clock(&t0);

#if TESTNUMBER == 0
	  /* nothing */
#endif

#if TESTNUMBER == 1
	    __asm__ __volatile__ (
	        "xorl %%eax,%%eax\n\t"            /* eax = 0 */
	        "cpuid"                           /* registers affected */
	        :                                 /* output */
	        :                                 /* input */
	        : "eax", "ebx", "ecx", "edx"      /* clobbered */
	      );
#endif

#if TESTNUMBER == 2
	    __asm__ __volatile__ (
	        "movl $0,%%eax\n\t"               /* eax = 0 */
	        "cpuid"                           /* registers affected */
	        :                                 /* output */
	        :                                 /* input */
	        : "eax", "ebx", "ecx", "edx"      /* clobbered */
	      );
#endif

#if TESTNUMBER == 3
	    __asm__ __volatile__ (
	        "movl $1,%%eax\n\t"               /* eax = 1 */
	        "cpuid"                           /* registers affected */
	        :                                 /* output */
	        :                                 /* input */
	        : "eax", "ebx", "ecx", "edx"      /* clobbered */
	      );
#endif

#if TESTNUMBER == 4
	    __asm__ __volatile__ (
	        "movl $2,%%eax\n\t"               /* eax = 2 */
	        "cpuid"                           /* registers affected */
	        :                                 /* output */
	        :                                 /* input */
	        : "eax", "ebx", "ecx", "edx"      /* clobbered */
	      );
#endif

#if TESTNUMBER == 5
	    __asm__ __volatile__ (
	        "movl $3,%%eax\n\t"               /* eax = 3 */
	        "cpuid"                           /* registers affected */
	        :                                 /* output */
	        :                                 /* input */
	        : "eax", "ebx", "ecx", "edx"      /* clobbered */
	      );
#endif

#if TESTNUMBER == 6
  __asm__ __volatile__ (
      "rdtsc\n\t"
      "movl %%eax,0(%%ebx)\n\t"
      "movl %%edx,4(%%ebx)"
      :                                 /* output */
      : "ebx" (&t2)                     /* input */
      : "eax", "edx"                    /* clobbered */
    );
#endif

#if TESTNUMBER == 7
  __asm__ __volatile__ (
      "xorl %%ecx,%%ecx\n\t"            /* ecx = 0 */
      "rdpmc\n\t"
#if defined(PMC_P6)
      "andl $255,%%edx\n\t"             /* clean the upper 24 bits */
#endif
      "movl %%eax,8(%%ebx)\n\t"
      "movl %%edx,12(%%ebx)"
      :                                 /* output */
      : "ebx" (&t2)                     /* input */
      : "eax", "ecx", "edx"             /* clobbered */
    );
#endif

#if TESTNUMBER == 8
  __asm__ __volatile__ (
      "movl $0,%%ecx\n\t"               /* ecx = 0 */
      "rdpmc\n\t"
#if defined(PMC_P6)
      "andl $255,%%edx\n\t"             /* clean the upper 24 bits */
#endif
      "movl %%eax,8(%%ebx)\n\t"
      "movl %%edx,12(%%ebx)"
      :                                 /* output */
      : "ebx" (&t2)                     /* input */
      : "eax", "ecx", "edx"             /* clobbered */
    );
#endif

#if TESTNUMBER == 9
  __asm__ __volatile__ (
      "movl $1,%%ecx\n\t"               /* ecx = 1 */
      "rdpmc\n\t"
#if defined(PMC_P6)
      "andl $255,%%edx\n\t"             /* clean the upper 24 bits */
#endif
      "movl %%eax,16(%%ebx)\n\t"
      "movl %%edx,20(%%ebx)"
      :                                 /* output */
      : "ebx" (&t2)                     /* input */
      : "eax", "ecx", "edx"             /* clobbered */
    );
#endif

#if TESTNUMBER == 10
  __asm__ __volatile__ (
      "rdtsc\n\t"
      "movl %%eax,0(%%ebx)\n\t"
      "movl %%edx,4(%%ebx)\n\t"
      "xorl %%ecx,%%ecx\n\t"            /* ecx = 0 */
      "rdpmc\n\t"
#if defined(PMC_P6)
      "andl $255,%%edx\n\t"             /* clean the upper 24 bits */
#endif
      "movl %%eax,8(%%ebx)\n\t"
      "movl %%edx,12(%%ebx)"
      :                                 /* output */
      : "ebx" (&t2)                     /* input */
      : "eax", "ecx", "edx"             /* clobbered */
    );
#endif

#if TESTNUMBER == 11
  __asm__ __volatile__ (
      "rdtsc\n\t"
      "movl %%eax,0(%%ebx)\n\t"
      "movl %%edx,4(%%ebx)\n\t"
      "movl $0,%%ecx\n\t"               /* ecx = 0 */
      "rdpmc\n\t"
#if defined(PMC_P6)
      "andl $255,%%edx\n\t"             /* clean the upper 24 bits */
#endif
      "movl %%eax,8(%%ebx)\n\t"
      "movl %%edx,12(%%ebx)"
      :                                 /* output */
      : "ebx" (&t2)                     /* input */
      : "eax", "ecx", "edx"             /* clobbered */
    );
#endif

#if TESTNUMBER == 12
  __asm__ __volatile__ (
      "rdtsc\n\t"
      "movl %%eax,0(%%ebx)\n\t"
      "movl %%edx,4(%%ebx)\n\t"
      "xorl %%ecx,%%ecx\n\t"            /* ecx = 0 */
      "rdpmc\n\t"
#if defined(PMC_P6)
      "andl $255,%%edx\n\t"             /* clean the upper 24 bits */
#endif
      "movl %%eax,8(%%ebx)\n\t"
      "movl %%edx,12(%%ebx)\n\t"
      "movl $1,%%ecx\n\t"               /* ecx = 1 */
      "rdpmc\n\t"
#if defined(PMC_P6)
      "andl $255,%%edx\n\t"             /* clean the upper 24 bits */
#endif
      "movl %%eax,16(%%ebx)\n\t"
      "movl %%edx,20(%%ebx)"
      :                                 /* output */
      : "ebx" (&t2)                     /* input */
      : "eax", "ecx", "edx"             /* clobbered */
    );
#endif

#if TESTNUMBER == 13
  __asm__ __volatile__ (
      "rdtsc\n\t"
      "movl %%eax,0(%%ebx)\n\t"
      "movl %%edx,4(%%ebx)\n\t"
      "movl $0,%%ecx\n\t"               /* ecx = 0 */
      "rdpmc\n\t"
#if defined(PMC_P6)
      "andl $255,%%edx\n\t"             /* clean the upper 24 bits */
#endif
      "movl %%eax,8(%%ebx)\n\t"
      "movl %%edx,12(%%ebx)\n\t"
      "movl $1,%%ecx\n\t"               /* ecx = 1 */
      "rdpmc\n\t"
#if defined(PMC_P6)
      "andl $255,%%edx\n\t"             /* clean the upper 24 bits */
#endif
      "movl %%eax,16(%%ebx)\n\t"
      "movl %%edx,20(%%ebx)"
      :                                 /* output */
      : "ebx" (&t2)                     /* input */
      : "eax", "ecx", "edx"             /* clobbered */
    );
#endif

#if TESTNUMBER == 14
  __asm__ __volatile__ (
      "rdtsc\n\t"
      "movl %%eax,0(%%ebx)\n\t"
      "movl %%edx,4(%%ebx)\n\t"
      "xorl %%ecx,%%ecx\n\t"            /* ecx = 0 */
      "rdpmc\n\t"
#if defined(PMC_P6)
      "andl $255,%%edx\n\t"             /* clean the upper 24 bits */
#endif
      "movl %%eax,8(%%ebx)\n\t"
      "movl %%edx,12(%%ebx)\n\t"
      "incl %%ecx\n\t"                  /* ecx = 1 */
      "rdpmc\n\t"
#if defined(PMC_P6)
      "andl $255,%%edx\n\t"             /* clean the upper 24 bits */
#endif
      "movl %%eax,16(%%ebx)\n\t"
      "movl %%edx,20(%%ebx)"
      :                                 /* output */
      : "ebx" (&t2)                     /* input */
      : "eax", "ecx", "edx"             /* clobbered */
    );
#endif

#if TESTNUMBER == 15
  __asm__ __volatile__ (
      "rdtsc\n\t"
      "movl %%eax,0(%%ebx)\n\t"
      "movl %%edx,4(%%ebx)\n\t"
      "movl $0,%%ecx\n\t"               /* ecx = 0 */
      "rdpmc\n\t"
#if defined(PMC_P6)
      "andl $255,%%edx\n\t"             /* clean the upper 24 bits */
#endif
      "movl %%eax,8(%%ebx)\n\t"
      "movl %%edx,12(%%ebx)\n\t"
      "incl %%ecx\n\t"                  /* ecx = 1 */
      "rdpmc\n\t"
#if defined(PMC_P6)
      "andl $255,%%edx\n\t"             /* clean the upper 24 bits */
#endif
      "movl %%eax,16(%%ebx)\n\t"
      "movl %%edx,20(%%ebx)"
      :                                 /* output */
      : "ebx" (&t2)                     /* input */
      : "eax", "ecx", "edx"             /* clobbered */
    );
#endif

#if TESTNUMBER == 16
	  pmc_read_clock(&t1);
#endif

#if TESTNUMBER == 17
	  pmc_read_clock(&t2);
#endif

#if TESTNUMBER == 18
	  pmc_read_clock(&t3);
#endif

	pmc_read_clock(&t1);
	pmc_accumulate_clock(&Ctl.counters[0], &t1, &t0);
      }

  pmc_close();				/* close /dev/pmc */

  printf("Cycles        Min      Mean      Max    Std.Dev.\n");
  {
    pmc_cycles_t Min, Max;
    double Mean, StdDev;

	  Min  = pmc_min_cycles(&Ctl.counters[0]);
	  Mean = pmc_mean_cycles(&Ctl.counters[0]);
	  Max  = pmc_max_cycles(&Ctl.counters[0]);
	  StdDev = sqrt(pmc_variance_cycles(&Ctl.counters[0]));
	    printf("cycles    %7lld %9.3f %8lld %11.6f\n",
		  Min, Mean, Max, StdDev);
  }

  exit(RABBIT_SUCCESS);
}

/*----------------------------------------------------------------------------*/
