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

/*
 * Performance-Monitoring Counters Library, for Intel/AMD Processors and Linux
 * Author:  Don Heller, dheller@scl.ameslab.gov
 * Last revised:  5 October 2001
 */

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

/* compile with one of
 *   gcc -DPMC_P5 -o pmc_toggle pmc_toggle.c -lpmc
 *   gcc -DPMC_P6 -o pmc_toggle pmc_toggle.c -lpmc
 *   gcc -DPMC_K7 -o pmc_toggle pmc_toggle.c -lpmc
 */

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

#include <stdio.h>

/* for open() */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

/* for read(), write(), lseek() */
#include <sys/types.h>
#include <unistd.h>

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

#include <pmc_dev.h>
#include <pmc_lib.h>

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

pmc_uint32_t reg32[10];
pmc_uint64_t reg64[10];
pmc_uint64_t reg[3];

char al_fmt[] = "Process alignment checking = 0x%lx\n";

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

int main(int argc, char *argv[])
{
  int DevPMC = -1;	/* file descriptor */
  int i, ret;
  pmc_control_t Ctl = pmc_control_null;

  DevPMC = open("/dev/pmc", O_RDWR);

  if (DevPMC == -1)
    { perror("open(/dev/pmc) failed"); exit(1); }
  else
    { printf("open(/dev/pmc) ok\n"); }

  printf("\n");


#define R(selection_code,fmt,dest) \
  if ((ret = read(DevPMC, &dest, selection_code)) == sizeof(dest)) \
    { printf("read " #selection_code "\t" fmt "\n", dest); } \
  else \
    { printf("read " #selection_code " failed, returned %d\n", ret); }

#define W(selection_code,fmt,src) \
  if ((ret = write(DevPMC, &src, selection_code)) == sizeof(src)) \
    { printf("write " #selection_code "\t" fmt "\n", src); } \
  else \
    { printf("write " #selection_code " failed, returned %d\n", ret); }


  R(PMC_READ_CR4,"0x%08lx",reg32[0]);
  printf("CR4.TSD = %d\n", (int) lseek(DevPMC, PMC_QUERY_RDTSC, SEEK_SET));

  if ((ret = lseek(DevPMC, PMC_DISABLE_RDTSC, SEEK_SET)) == 0)
    { printf("lseek PMC_DISABLE_RDTSC ok\n"); }
  else
    { printf("lseek PMC_DISABLE_RDTSC failed, returned %d\n", ret); }

  R(PMC_READ_CR4,"0x%08lx",reg32[0]);
  printf("CR4.TSD = %d\n", (int) lseek(DevPMC, PMC_QUERY_RDTSC, SEEK_SET));

  if ((ret = lseek(DevPMC, PMC_ENABLE_RDTSC, SEEK_SET)) == 0)
    { printf("lseek PMC_ENABLE_RDTSC ok\n"); }
  else
    { printf("lseek PMC_ENABLE_RDTSC failed, returned %d\n", ret); }

  R(PMC_READ_CR4,"0x%08lx",reg32[0]);
  printf("CR4.TSD = %d\n", (int) lseek(DevPMC, PMC_QUERY_RDTSC, SEEK_SET));
  printf("\n");


  R(PMC_READ_CR4,"0x%08lx",reg32[0]);
  printf("CR4.PCE = %d\n", (int) lseek(DevPMC, PMC_QUERY_RDPMC, SEEK_SET));

  if ((ret = lseek(DevPMC, PMC_DISABLE_RDPMC, SEEK_SET)) == 0)
    { printf("lseek PMC_DISABLE_RDPMC ok\n"); }
  else
    { printf("lseek PMC_DISABLE_RDPMC failed, returned %d\n", ret); }

  R(PMC_READ_CR4,"0x%08lx",reg32[0]);
  printf("CR4.PCE = %d\n", (int) lseek(DevPMC, PMC_QUERY_RDPMC, SEEK_SET));

  if ((ret = lseek(DevPMC, PMC_ENABLE_RDPMC, SEEK_SET)) == 0)
    { printf("lseek PMC_ENABLE_RDPMC ok\n"); }
  else
    { printf("lseek PMC_ENABLE_RDPMC failed, returned %d\n", ret); }

  R(PMC_READ_CR4,"0x%08lx",reg32[0]);
  printf("CR4.PCE = %d\n", (int) lseek(DevPMC, PMC_QUERY_RDPMC, SEEK_SET));
  printf("\n");


  if ((ret = lseek(DevPMC, PMC_FLUSH_CACHE, SEEK_SET)) == 0)
    { printf("lseek PMC_FLUSH_CACHE ok\n"); }
  else
    { printf("lseek PMC_FLUSH_CACHE failed, returned %d\n", ret); }

  R(PMC_READ_CR0,"0x%08lx",reg32[0]);
  if (lseek(DevPMC, PMC_QUERY_CACHE, SEEK_SET))
    { printf("cache is enabled\n"); }
  else
    { printf("cache is disabled\n"); }

  if ((ret = lseek(DevPMC, PMC_DISABLE_CACHE, SEEK_SET)) == 0)
    { printf("lseek PMC_DISABLE_CACHE ok\n"); }
  else
    {
      printf("lseek PMC_DISABLE_CACHE failed, returned %d\n", ret);
#ifndef PMC_ALLOW_CACHE_DISABLE
      printf("  (PMC_ALLOW_CACHE_DISABLE is not defined)\n");
#endif
    }

  R(PMC_READ_CR0,"0x%08lx",reg32[0]);
  if (lseek(DevPMC, PMC_QUERY_CACHE, SEEK_SET))
    { printf("cache is enabled\n"); }
  else
    { printf("cache is disabled\n"); }

  if ((ret = lseek(DevPMC, PMC_ENABLE_CACHE, SEEK_SET)) == 0)
    { printf("lseek PMC_ENABLE_CACHE ok\n"); }
  else
    { printf("lseek PMC_ENABLE_CACHE failed, returned %d\n", ret); }

  R(PMC_READ_CR0,"0x%08lx",reg32[0]);
  if (lseek(DevPMC, PMC_QUERY_CACHE, SEEK_SET))
    { printf("cache is enabled\n"); }
  else
    { printf("cache is disabled\n"); }
  printf("\n");


  R(PMC_READ_CR0,"0x%08lx",reg32[0]);
  if (lseek(DevPMC, PMC_QUERY_ALIGNMENT_CHECKING, SEEK_SET))
    { printf("system alignment checking is enabled\n"); }
  else
    { printf("system alignment checking is disabled\n"); }

  if ((ret = lseek(DevPMC, PMC_DISABLE_ALIGNMENT_CHECKING, SEEK_SET)) == 0)
    { printf("lseek PMC_DISABLE_ALIGNMENT_CHECKING ok\n"); }
  else
    { printf("lseek PMC_DISABLE_ALIGNMENT_CHECKING failed, returned %d\n", ret); }

  R(PMC_READ_CR0,"0x%08lx",reg32[0]);
  if (lseek(DevPMC, PMC_QUERY_ALIGNMENT_CHECKING, SEEK_SET))
    { printf("system alignment checking is enabled\n"); }
  else
    { printf("system alignment checking is disabled\n"); }

  if ((ret = lseek(DevPMC, PMC_ENABLE_ALIGNMENT_CHECKING, SEEK_SET)) == 0)
    { printf("lseek PMC_ENABLE_ALIGNMENT_CHECKING ok\n"); }
  else
    { printf("lseek PMC_ENABLE_ALIGNMENT_CHECKING failed, returned %d\n", ret); }

  R(PMC_READ_CR0,"0x%08lx",reg32[0]);
  if (lseek(DevPMC, PMC_QUERY_ALIGNMENT_CHECKING, SEEK_SET))
    { printf("system alignment checking is enabled\n"); }
  else
    { printf("system alignment checking is disabled\n"); }

  printf("\n");


  ret = close(DevPMC);
  if (ret != 0)
    { printf("close(/dev/pmc) failed\n"); }
  else
    { printf("close(/dev/pmc) ok\n"); }

  printf("\n");


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

  ret = pmc_open(0);
  if (ret == FALSE)
    { printf("pmc_open() failed\n"); exit(1); }
  else
    { printf("pmc_open() ok\n"); }

  printf("pmc_configure(PMC_CONFIGURE_CACHE, PMC_CONFIGURE_QUERY) = %d\n",
    pmc_configure(PMC_CONFIGURE_CACHE, PMC_CONFIGURE_QUERY));

  printf("pmc_configure(PMC_CONFIGURE_CACHE, PMC_CONFIGURE_OFF) = %d\n",
    pmc_configure(PMC_CONFIGURE_CACHE, PMC_CONFIGURE_OFF));

  printf("pmc_configure(PMC_CONFIGURE_CACHE, PMC_CONFIGURE_QUERY) = %d\n",
    pmc_configure(PMC_CONFIGURE_CACHE, PMC_CONFIGURE_QUERY));

  printf("pmc_configure(PMC_CONFIGURE_CACHE, PMC_CONFIGURE_ON) = %d\n",
    pmc_configure(PMC_CONFIGURE_CACHE, PMC_CONFIGURE_ON));

  printf("pmc_configure(PMC_CONFIGURE_CACHE, PMC_CONFIGURE_QUERY) = %d\n",
    pmc_configure(PMC_CONFIGURE_CACHE, PMC_CONFIGURE_QUERY));

  printf("pmc_configure(PMC_CONFIGURE_CACHE, PMC_CONFIGURE_FLUSH) = %d\n",
    pmc_configure(PMC_CONFIGURE_CACHE, PMC_CONFIGURE_FLUSH));

  printf("pmc_configure(PMC_CONFIGURE_CACHE, PMC_CONFIGURE_QUERY) = %d\n",
    pmc_configure(PMC_CONFIGURE_CACHE, PMC_CONFIGURE_QUERY));

  printf("\n");


  printf("pmc_configure(PMC_CONFIGURE_SYSTEM_ALIGNMENT_CHECKING, PMC_CONFIGURE_QUERY) = %d\n",
    pmc_configure(PMC_CONFIGURE_SYSTEM_ALIGNMENT_CHECKING, PMC_CONFIGURE_QUERY));

  printf("pmc_configure(PMC_CONFIGURE_SYSTEM_ALIGNMENT_CHECKING, PMC_CONFIGURE_OFF) = %d\n",
    pmc_configure(PMC_CONFIGURE_SYSTEM_ALIGNMENT_CHECKING, PMC_CONFIGURE_OFF));

  printf("pmc_configure(PMC_CONFIGURE_SYSTEM_ALIGNMENT_CHECKING, PMC_CONFIGURE_QUERY) = %d\n",
    pmc_configure(PMC_CONFIGURE_SYSTEM_ALIGNMENT_CHECKING, PMC_CONFIGURE_QUERY));

  printf("pmc_configure(PMC_CONFIGURE_SYSTEM_ALIGNMENT_CHECKING, PMC_CONFIGURE_ON) = %d\n",
    pmc_configure(PMC_CONFIGURE_SYSTEM_ALIGNMENT_CHECKING, PMC_CONFIGURE_ON));

  printf("pmc_configure(PMC_CONFIGURE_SYSTEM_ALIGNMENT_CHECKING, PMC_CONFIGURE_QUERY) = %d\n",
    pmc_configure(PMC_CONFIGURE_SYSTEM_ALIGNMENT_CHECKING, PMC_CONFIGURE_QUERY));

  printf("\n");


  printf(al_fmt,
    pmc_configure(PMC_CONFIGURE_PROCESS_ALIGNMENT_CHECKING, PMC_CONFIGURE_QUERY));

  printf("flushing stdout\n");
  fflush(stdout);
  printf("now turn process alignment checking on\n");
  printf("a segmentation fault could occur\n");
  fflush(stdout);

  if ((ret = pmc_configure(PMC_CONFIGURE_PROCESS_ALIGNMENT_CHECKING, PMC_CONFIGURE_ON)) != -1)
    { printf("turn alignment checking on, ok\n"); }
  else
    { printf("turn process alignment checking on, failed, returned %d\n", ret); }

  printf(al_fmt,
    pmc_configure(PMC_CONFIGURE_PROCESS_ALIGNMENT_CHECKING, PMC_CONFIGURE_QUERY));

  if ((ret = pmc_configure(PMC_CONFIGURE_PROCESS_ALIGNMENT_CHECKING, PMC_CONFIGURE_OFF)) != -1)
    { printf("turn process alignment checking off, ok\n"); }
  else
    { printf("turn process alignment checking off, failed, returned %d\n", ret); }

  printf(al_fmt,
    pmc_configure(PMC_CONFIGURE_PROCESS_ALIGNMENT_CHECKING, PMC_CONFIGURE_QUERY));

  printf("process alignment checking = 0x%lx\n",
    (unsigned long int) pmc_configure(PMC_CONFIGURE_PROCESS_ALIGNMENT_CHECKING, PMC_CONFIGURE_QUERY));

  i = pmc_configure(PMC_CONFIGURE_PROCESS_ALIGNMENT_CHECKING, PMC_CONFIGURE_QUERY);
  printf(al_fmt, i);


  pmc_close();
  printf("finished!\n");
  exit(0);
}

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