<commit_before>/* 
* File:    linux-perfctr.c
* CVS:     $Id$
* Author:  <NAME>
*          <EMAIL>
* Mods:    dan terpstra
*          <EMAIL>
* Mods:    <NAME>
*          <EMAIL>
*/  

#ifdef PERFCTR20
#define PERFCTR18
#endif
/* This substrate should never malloc anything. All allocation should be
   done by the high level API. */

/* The values defined in this file may be X86-specific (2 general 
   purpose counters, 1 special purpose counter, etc.*/

/* PAPI stuff */

#include SUBSTRATE

/* First entry is mask, counter code 1, counter code 2, and TSC. 
A high bit in the mask entry means it is an OR mask, not an
and mask. This means that the same even is available on either
counter. */

static hwd_preset_t *preset_map = NULL;

static hwd_preset_t p6_preset_map[PAPI_MAX_PRESET_EVENTS] = { 
  {CNTR2|CNTR1,0,0,{{0x45,0x45,0x0,0x0}},""},	// L1 Cache Dmisses 
  {CNTR2|CNTR1,0,0,{{0xf28,0xf28,0x0,0x0}},""},	// L1 Cache Imisses 
  {0,0,0,{{0,0,0x0,0x0}},""}, 			// L2 Cache Dmisses
  {CNTR2|CNTR1,0,0,{{0x81,0x81,0x0,0x0}},""},	// L2 Cache Imisses 
  {0,0,0,{{0,0,0x0,0x0}},""}, 			// L3 Cache Dmisses
  {0,0,0,{{0,0,0x0,0x0}},""}, 			// L3 Cache Imisses
  {CNTR2|CNTR1,0,0,{{0xf2e,0xf2e,0x0,0x0}},""},	// L1 Total Cache misses 
  {CNTR2|CNTR1,0,0,{{0x24,0x24,0x0,0x0}},""}, 	// L2 Total Cache misses
  {0,0,0,{{0,0,0x0,0x0}},""}, 			// L3 Total Cache misses
  {0,0,0,{{0,0,0x0,0x0}},""},			// Snoops
  {CNTR2|CNTR1,0,0,{{0x222e,0x222e,0x0,0x0}},""},	// Req. access to shared cache line
  {CNTR2|CNTR1,0,0,{{0x212e,0x212e,0x0,0x0}},""},	// Req. access to clean cache line
  {CNTR2|CNTR1,0,0,{{0x2069,0x2069,0x0,0x0}},""},	// Req. Cache Line Invalidation
  {CNTR2|CNTR1,0,0,{{0x2e2e,0x2e2e,0x0,0x0}},""},	// Req. Cache Line Intervention
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3 LDM
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3 STM
  {0,0,0,{{0,0,0x0,0x0}},""},			// cycles branch idle
  {0,0,0,{{0,0,0x0,0x0}},""},			// cycles int idle
  {0,0,0,{{0,0,0x0,0x0}},""},			// cycles fpu idle
  {0,0,0,{{0,0,0x0,0x0}},""},			// cycles load/store idle
  {0,0,0,{{0,0,0x0,0x0}},""},		 	// D-TLB misses
  {CNTR2|CNTR1,0,0,{{0x85,0x85,0x0,0x0}},""},	// I-TLB misses
  {0,0,0,{{0,0,0x0,0x0}},""},			// Total TLB misses
  {CNTR2|CNTR1,0,0,{{0xf29,0xf29,0x0,0x0}},""},	// L1 load M
  {CNTR2|CNTR1,0,0,{{0xf2A,0xf2A,0x0,0x0}},""},	// L1 store M
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2 load M
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2 store M
  {CNTR2|CNTR1,0,0,{{0xe2,0xe2,0x0,0x0}},""},	// BTAC misses
  {0,0,0,{{0,0,0x0,0x0}},""},	                // Prefmiss
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3DCH
  {0,0,0,{{0,0,0x0,0x0}},""},			// TLB shootdowns
  {0,0,0,{{0,0,0x0,0x0}},""},			// Failed Store cond.
  {0,0,0,{{0,0,0x0,0x0}},""},			// Suc. store cond.
  {0,0,0,{{0,0,0x0,0x0}},""},			// total. store cond.
  {0,0,0,{{0,0,0x0,0x0}},""},	                // Cycles stalled waiting for memory /
  {0,0,0,{{0,0,0x0,0x0}},""},		   	// Cycles stalled waiting for memory read /
  {0,0,0,{{0,0,0x0,0x0}},""},		   	// Cycles stalled waiting for memory write /
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles no instructions issued /
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles max instructions issued /
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles no instructions comleted /
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles max instructions completed /
  {CNTR2|CNTR1,0,0,{{0xC8,0xC8,0x0,0x0}},""},	// hardware interrupts
  {0,0,0,{{0,0,0x0,0x0}},""},	                // Uncond. branches executed
  {CNTR2|CNTR1,0,0,{{0xC4,0xC4,0x0,0x0}},""},	// Cond. Branch inst. executed
  {CNTR2|CNTR1,0,0,{{0xC9,0xC9,0x0,0x0}},""},	// Cond. Branch inst. taken
  {CNTR2|CNTR1,DERIVED_SUB,0,{{0xC4,0xC9,0x0,0x0}},""}, // Cond. Branch inst. not taken
  {CNTR2|CNTR1,0,0,{{0xC5,0xC5,0x0,0x0}},""},	// Cond. branch inst. mispred.
  {CNTR2|CNTR1,DERIVED_SUB,0,{{0xC4,0xC5,0x0,0x0}},""}, // Cond. branch inst. corr. pred.
  {0,0,0,{{0,0,0x0,0x0}},""},			// FMA
  {CNTR2|CNTR1,0,0,{{0xD0,0xD0,0x0,0x0}},""},	// Total inst. issued
  {CNTR2|CNTR1,0,0,{{0xC0,0xC0,0x0,0x0}},""},	// Total inst. executed
  {0,0,0,{{0,0,0x0,0x0}},""},			// Integer inst. executed
  {CNTR1,0,0,{{0xC1,0,0x0,0x0}},""},		// Floating Pt. inst. executed
  {0,0,0,{{0,0,0x0,0x0}},""},			// Loads executed
  {0,0,0,{{0,0,0x0,0x0}},""},			// Stores executed
  {CNTR2|CNTR1,0,0,{{0xC4,0xC4,0x0,0x0}},""},	// Branch inst. executed
  {CNTR2|CNTR1,0,0,{{0xB0,0xB0,0x0,0x0}},""},	// Vector/SIMD inst. executed 
  {CNTR2|CNTR1,DERIVED_PS,1,{{0xC1,0x79,0x0,0x0}},""}, // FLOPS
  {CNTR2|CNTR1,0,0,{{0xA2,0xA2,0x0,0x0}},""},	// Cycles any resource stalls
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles FPU stalled
  {CNTR2|CNTR1,0,0,{{0x79,0x79,0x0,0x0}},""},	// Total cycles
  {CNTR2|CNTR1,DERIVED_PS,1,{{0xC0,0x79,0x0,0x0}},""}, // IPS
  {0,0,0,{{0,0,0,0}},""},			// Total load/store inst. exec
  {0,0,0,{{0,0,0x0,0x0}},""},			// SYnc exec.
  {CNTR2|CNTR1,DERIVED_SUB,0,{{0x43,0x45,0x0,0x0}},""}, // L1_DCH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_DCH
  {CNTR2|CNTR1,0,0,{{0x43,0x43,0x0,0x0}},""},	// L1_DCA
  {CNTR2|CNTR1,DERIVED_ADD,0,{{0xf29,0xf2a,0x0,0x0}},""}, // L2_DCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_DCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_DCR
  {CNTR2|CNTR1,0,0,{{0xf29,0xf29,0x0,0x0}},""},	// L2_DCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_DCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_DCW
  {CNTR2|CNTR1,0,0,{{0xf2a,0xf2a,0x0,0x0}},""},	// L2_DCW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_DCW
  {CNTR2|CNTR1,DERIVED_SUB,0,{{0x80,0xf28,0x0,0x0}},""}, // L1_ICH
  {CNTR2|CNTR1,DERIVED_SUB,0,{{0xf28,0x81,0x0,0x0}},""}, // L2_ICH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_ICH
  {CNTR2|CNTR1,0,0,{{0x80,0x80,0x0,0x0}},""},	// L1_ICA
  {CNTR2|CNTR1,0,0,{{0xf28,0xf28,0x0,0x0}},""},	// L2_ICA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_ICA
  {CNTR2|CNTR1,0,0,{{0x80,0x80,0x0,0x0}},""},	// L1_ICR
  {CNTR2|CNTR1,0,0,{{0xf28,0xf28,0x0,0x0}},""},	// L2_ICR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_ICR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_ICW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_ICW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_ICW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_TCH
  {CNTR2|CNTR1,DERIVED_SUB,0,{{0xf2e,0x24,0x0,0x0}},""}, // L2_TCH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_TCH
  {CNTR2|CNTR1,DERIVED_ADD,0,{{0x43,0x80,0x0,0x0}},""},	// L1_TCA
  {CNTR2|CNTR1,0,0,{{0xf2e,0xf2e,0x0,0x0}},""},	// L2_TCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_TCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_TCR
  {CNTR2|CNTR1,DERIVED_ADD,0,{{0xf29,0xf28,0x0,0x0}},""}, // L2_TCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_TCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_TCW
  {CNTR2|CNTR1,0,0,{{0xf2a,0xf2a,0x0,0x0}},""},	// L2_TCW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_TCW
  {CNTR2,0,0,{{0,0x12,0x0,0x0}},""},		// FPM
  {0,0,0,{{0,0,0x0,0x0}},""},			// FPA
  {CNTR2,0,0,{{0,0x13,0x0,0x0}},""},		// FPD
  {0,0,0,{{0,0,0x0,0x0}},""},			// FPSQ
  {0,0,0,{{0,0,0x0,0x0}},""},			// FPI
};

static hwd_preset_t k7_preset_map[PAPI_MAX_PRESET_EVENTS] = { 
  {ALLCNTRS,0,0,{{0x41,0x41,0x41,0x41}},""},	// L1 Cache Dmisses 
  {ALLCNTRS,0,0,{{0x81,0x81,0x81,0x81}},""},	// L1 Cache Imisses 
  {ALLCNTRS,0,0,{{0x42,0x42,0x42,0x42}},""}, 	// L2 Cache Dmisses
  {ALLCNTRS,0,0,{{0x83,0x83,0x83,0x83}},""}, 	// L2 Cache Imisses
  {0,0,0,{{0,0,0x0,0x0}},""}, 			// L3 Cache Dmisses
  {0,0,0,{{0,0,0x0,0x0}},""}, 			// L3 Cache Imisses
  {ALLCNTRS,0,0,{{0x73,0x73,0x73,0x73}},""}, 	// L1 Total Cache misses 
  {0,0,0,{{0,0,0x0,0x0}},""}, 			// L2 Total Cache misses
  {0,0,0,{{0,0,0x0,0x0}},""}, 			// L3 Total Cache misses
  {0,0,0,{{0,0,0x0,0x0}},""},			// Snoops
  {0,0,0,{{0,0,0x0,0x0}},""},			// Req. access to shared cache line
  {0,0,0,{{0,0,0x0,0x0}},""},			// Req. access to clean cache line
  {0,0,0,{{0,0,0x0,0x0}},""},			// Req. Cache Line Invalidation
  {0,0,0,{{0,0,0x0,0x0}},""},			// Req. Cache Line Intervention
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3 LDM
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3 STM
  {0,0,0,{{0,0,0x0,0x0}},""},			// cycles branch idle
  {0,0,0,{{0,0,0x0,0x0}},""},			// cycles int idle
  {0,0,0,{{0,0,0x0,0x0}},""},			// cycles fpu idle
  {0,0,0,{{0,0,0x0,0x0}},""},			// cycles load/store idle
  {ALLCNTRS,0,0,{{0x46,0x46,0x46,0x46}},""},	// D-TLB misses
  {CNTR1|CNTR2,DERIVED_ADD,0,{{0x84,0x85,0x0,0x0}},""}, // I-TLB misses
  {CNTR1|CNTR2|CNTR3,DERIVED_ADD,0,{{0x84,0x85,0x46,0x0}},""}, // Total TLB misses
  {0,0,0,{{0,0,0x0,0x0}},""},		   	// L1 load M
  {0,0,0,{{0,0,0x0,0x0}},""},		   	// L1 store M
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2 load M
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2 store M
  {0,0,0,{{0,0,0x0,0x0}},""},		   	// BTAC misses
  {0,0,0,{{0,0,0x0,0x0}},""},	                // Prefmiss
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3DCH
  {0,0,0,{{0,0,0x0,0x0}},""},			// TLB shootdowns
  {0,0,0,{{0,0,0x0,0x0}},""},			// Failed Store cond.
  {0,0,0,{{0,0,0x0,0x0}},""},			// Suc. store cond.
  {0,0,0,{{0,0,0x0,0x0}},""},			// total. store cond.
  {0,0,0,{{0,0,0x0,0x0}},""},	                // Cycles stalled waiting for memory /
  {0,0,0,{{0,0,0x0,0x0}},""},		   	// Cycles stalled waiting for memory read /
  {0,0,0,{{0,0,0x0,0x0}},""},		   	// Cycles stalled waiting for memory write /
  {0,0,0,{{0,0,0x0,0x0}},""},		   	// Cycles no instructions issued /
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles max instructions issued /
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles no instructions completed /
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles max instructions completed /
  {ALLCNTRS,0,0,{{0xcf,0xcf,0xcf,0xcf}},""},	// hardware interrupts
  {ALLCNTRS,0,0,{{0xc6,0xc6,0xc6,0xc6}},""},	// Uncond. branches executed
  {ALLCNTRS,0,0,{{0xC2,0xC2,0xc2,0xc2}},""},	// Cond. Branch inst. executed
  {ALLCNTRS,0,0,{{0xC4,0xC4,0xc4,0xc4}},""},	// Cond. Branch inst. taken
  {CNTR1|CNTR2,DERIVED_SUB,0,{{0xC4,0xC2,0x0,0x0}},""}, // Cond. Branch inst. not taken
  {ALLCNTRS,0,0,{{0xC3,0xC3,0xC3,0xC3}},""},	// Cond. branch inst. mispred.
  {CNTR1|CNTR2,DERIVED_SUB,0,{{0xC2,0xC3,0x0,0x0}},""}, // Cond. branch inst. corr. pred.
  {0,0,0,{{0,0,0x0,0x0}},""},			// FMA
  {0,0,0,{{0,0,0x0,0x0}},""},                   // Total inst. issued
  {ALLCNTRS,0,0,{{0xC0,0xC0,0xC0,0xC0}},""},	// Total inst. executed
  {0,0,0,{{0,0,0x0,0x0}},""},			// Integer inst. executed
  {0,0,0,{{0,0,0x0,0x0}},""},                   // Floating Pt. inst. executed
  {0,0,0,{{0,0,0x0,0x0}},""},			// Loads executed
  {0,0,0,{{0,0,0x0,0x0}},""},			// Stores executed
  {ALLCNTRS,0,0,{{0xC4,0xC4,0x0,0x0}},""},	// Branch inst. executed
  {ALLCNTRS,0,0,{{0xB0,0xB0,0x0,0x0}},""},	// Vector/SIMD inst. executed 
  {0,0,0,{{0,0,0x0,0x0}},""},                   // FLOPS
  {ALLCNTRS,0,0,{{0xd9,0xd9,0xd9,0xd9}},""},    // Cycles any resource stalls
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles FPU stalled
  {ALLCNTRS,0,0,{{0x76,0x76,0x76,0x76}},""},	// Total cycles
  {CNTR1|CNTR2,DERIVED_PS,1,{{0xC0,0x76,0x0,0x0}},""}, // IPS
  {0,0,0,{{0,0,0x0,0x0}},""},			// Total load/store inst. exec
  {0,0,0,{{0,0,0x0,0x0}},""},			// SYnc exec.
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_DCH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_DCH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_DCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_DCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_DCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_DCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_DCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_DCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_DCW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_DCW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_DCW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_ICH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_ICH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_ICH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_ICA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_ICA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_ICA
  {ALLCNTRS,0,0,{{0x80,0x80,0x80,0x80}},""},	// L1_ICR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_ICR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_ICR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_ICW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_ICW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_ICW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_TCH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_TCH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_TCH
  {CNTR1|CNTR2,DERIVED_ADD,0,{{0x40,0x80,0x0,0x0}},""}, // L1_TCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_TCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_TCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_TCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_TCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_TCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_TCW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_TCW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_TCW
  {0,0,0,{{0,0,0x0,0x0}},""},			// FPM
  {0,0,0,{{0,0,0x0,0x0}},""},			// FPA
  {0,0,0,{{0,0,0x0,0x0}},""},			// FPD
  {0,0,0,{{0,0,0x0,0x0}},""},			// FPSQ
  {0,0,0,{{0,0,0x0,0x0}},""},			// FPI
};

/* Low level functions, should not handle errors, just return codes. */

inline static char *search_cpu_info(FILE *f, char *search_str, char *line)
{
  /* This code courtesy of our friends in Germany. Thanks <NAME>! */
  /* See the PCL home page for the German version of PAPI. */

  char *s;

  while (fgets(line, 256, f) != NULL)
    {
      if (strstr(line, search_str) != NULL)
	{
	  /* ignore all characters in line up to : */
	  for (s = line; *s && (*s != ':'); ++s)
	    ;
	  if (*s)
	    return(s);
	}
    }
  return(NULL);

  /* End stolen code */
}

static inline unsigned long long get_cycles (void)
{
	unsigned long long ret;
        __asm__ __volatile__("rdtsc"
			    : "=A" (ret)
			    : /* no inputs */);
        return ret;
}

/* Dumb hack to make sure I get the cycle time correct. */

static float calc_mhz(void)
{
  unsigned long long ostamp;
  unsigned long long stamp;
  float correction = 4000.0, mhz;

  /* Warm the cache */

  ostamp = get_cycles();
  usleep(1);
  stamp = get_cycles();
  stamp = stamp - ostamp;
  mhz = (float)stamp/(float)(1000000.0 + correction);

  ostamp = get_cycles();
  sleep(1);
  stamp = get_cycles();
  stamp = stamp - ostamp;
  mhz = (float)stamp/(float)(1000000.0 + correction);

  return(mhz);
}

inline static int setup_all_presets(int cpu_type)
{
  int pnum, s;
  char note[100];

  if ((cpu_type == PERFCTR_X86_WINCHIP_C6) ||
      (cpu_type == PERFCTR_X86_WINCHIP_2))
    {
      fprintf(stderr,"Ask yourself, why am I tuning code on a WinChip?\n");
      abort();
    }

  if (cpu_type == PERFCTR_X86_AMD_K7)
    preset_map = k7_preset_map;
  else
    preset_map = p6_preset_map;

  for (pnum = 0; pnum < PAPI_MAX_PRESET_EVENTS; pnum++)
    {
      if ((s = preset_map[pnum].selector))
	{
	  if (_papi_system_info.num_cntrs == 2)
	    {
	      sprintf(note,"0x%x,0x%x",
		      preset_map[pnum].counter_cmd.evntsel[0],
		      preset_map[pnum].counter_cmd.evntsel[1]);
	      strcat(preset_map[pnum].note,note);
	    }
	  else if (_papi_system_info.num_cntrs == 4)
	    {
	      sprintf(note,"0x%x,0x%x,0x%x,0x%x",
		      preset_map[pnum].counter_cmd.evntsel[0],
		      preset_map[pnum].counter_cmd.evntsel[1],
		      preset_map[pnum].counter_cmd.evntsel[2],
		      preset_map[pnum].counter_cmd.evntsel[3]);
	      strcat(preset_map[pnum].note,note);
	    }
	  else
	    abort();
	}
    }
  return(PAPI_OK);
}

/* Utility functions */

/* Go from highest counter to lowest counter. Why? Because there are usually
   more counters on #1, so we try the least probable first. */

inline static int get_avail_hwcntr_bits(int cntr_avail_bits)
{
  int tmp = 0, i = 1 << (_papi_system_info.num_cntrs-1);
  
  while (i)
    {
      tmp = i & cntr_avail_bits;
      if (tmp)
	return(tmp);
      i = i >> 1;
    }
  return(0);
}

#ifdef PERFCTR20
inline static void set_hwcntr_codes(int selector, struct perfctr_cpu_control *from, struct perfctr_cpu_control *to)
#else
inline static void set_hwcntr_codes(int selector, struct perfctr_control *from, struct perfctr_control *to)
#endif
{
  int useme, i;
  
  for (i=0;i<_papi_system_info.num_cntrs;i++)
    {
      useme = (1 << i) & selector;
      if (useme)
	{
	  to->evntsel[i] = to->evntsel[i] & ~PERF_EVNT_MASK;
	  to->evntsel[i] = to->evntsel[i] | from->evntsel[i];
#ifdef PERFCTR20
	  to->pmc_map[i] = i;
#endif
	}
    }
}

inline static void init_config(hwd_control_state_t *ptr)
{
  int def_mode;

  switch (_papi_system_info.default_domain)
    {
    case PAPI_DOM_USER:
      def_mode = PERF_USR;
      break;
    case PAPI_DOM_KERNEL:
      def_mode = PERF_OS;
      break;
    case PAPI_DOM_ALL:
      def_mode = PERF_OS | PERF_USR;
      break;
    default:
      abort();
    }

  ptr->selector = 0;
#ifdef PERFCTR20
  ptr->counter_cmd.cpu_control.evntsel[0] |= def_mode | PERF_ENABLE;
  ptr->counter_cmd.cpu_control.evntsel[1] |= def_mode;
  ptr->counter_cmd.cpu_control.tsc_on=1;
  ptr->counter_cmd.cpu_control.nractrs=2;
  ptr->counter_cmd.cpu_control.pmc_map[0]=0;
  ptr->counter_cmd.cpu_control.pmc_map[1]=1;
#else
  ptr->counter_cmd.evntsel[0] |= def_mode | PERF_ENABLE;
  ptr->counter_cmd.evntsel[1] |= def_mode;
#endif
}

#ifdef PERFCTR18
static int get_system_info(const struct vperfctr *dev)
#else
static int get_system_info(struct perfctr_dev *dev)
#endif
{
  struct perfctr_info info;
  pid_t pid;
  int tmp;
  float mhz;
  char maxargs[PAPI_MAX_STR_LEN], *t, *s;
  FILE *f;

  /* Path and args */

  pid = getpid();
  if (pid == -1)
    return(PAPI_ESYS);

  sprintf(maxargs,"/proc/%d/exe",(int)getpid());
  if (readlink(maxargs,_papi_system_info.exe_info.fullname,PAPI_MAX_STR_LEN) == -1)
    return(PAPI_ESYS);
  sprintf(_papi_system_info.exe_info.name,"%s",basename(_papi_system_info.exe_info.fullname));

  DBG((stderr,"Executable is %s\n",_papi_system_info.exe_info.name));
  DBG((stderr,"Full Executable is %s\n",_papi_system_info.exe_info.fullname));

  if ((f = fopen("/proc/cpuinfo", "r")) == NULL)
    return -1;
 
  /* Hardware info */

  _papi_system_info.hw_info.ncpu = sysconf(_SC_NPROCESSORS_ONLN);
  _papi_system_info.hw_info.nnodes = 1;
  _papi_system_info.hw_info.totalcpus = sysconf(_SC_NPROCESSORS_CONF);
  _papi_system_info.hw_info.vendor = -1;

  rewind(f);
  s = search_cpu_info(f,"vendor_id",maxargs);
  if (s && (t = strchr(s+2,'\n')))
    {
      *t = '\0';
      strcpy(_papi_system_info.hw_info.vendor_string,s+2);
    }

  rewind(f);
  s = search_cpu_info(f,"stepping",maxargs);
  if (s)
    sscanf(s+1, "%d", &tmp);
  _papi_system_info.hw_info.revision = (float)tmp;

#ifdef PERFCTR18  /* And PERFCTR20 */
  if (vperfctr_info(dev, &info) < 0)
    return(PAPI_ESYS);
  strcpy(_papi_system_info.hw_info.model_string,perfctr_cpu_name(&info));
  _papi_system_info.supports_hw_overflow = 
    (info.cpu_features & PERFCTR_FEATURE_PCINT) ? 1 : 0;
  DBG((stderr,"Hardware/OS %s support counter generated interrupts\n",
       _papi_system_info.supports_hw_overflow ? "does" : "does not"));
#ifndef PAPI_PERFCTR_INTR_SUPPORT
  if(_papi_system_info.supports_hw_overflow)
    DBG((stderr,"PAPI_PERFCTR_INTR_SUPPORT disabled at compile time.\n"));
  _papi_system_info.supports_hw_overflow = 0;
#endif
  _papi_system_info.supports_hw_profile = 0; /* != _papi_system_info.supports_hw_overflow? */
#ifdef PERFCTR20
  _papi_system_info.num_cntrs = perfctr_cpu_nrctrs(&info);
  _papi_system_info.num_gp_cntrs = perfctr_cpu_nrctrs(&info);
#else /* PERFCTR20 */
  _papi_system_info.num_cntrs = perfctr_cpu_nrctrs(&info) - 1;
  _papi_system_info.num_gp_cntrs = perfctr_cpu_nrctrs(&info) - 1;
#endif /* PERFCTR20 */
#elif defined(PERFCTR16)  /* Neither PERFCTR18 nor PERFCTR20 */
  if (perfctr_info(dev, &info) < 0)
    return(PAPI_ESYS);
  strcpy(_papi_system_info.hw_info.model_string,perfctr_cpu_name(&info));
  _papi_system_info.num_cntrs = perfctr_cpu_nrctrs(&info) - 1;
  _papi_system_info.num_gp_cntrs = perfctr_cpu_nrctrs(&info) - 1;
#endif /* PERFCTR18 */

  _papi_system_info.hw_info.model = (int)info.cpu_type;
  _papi_system_info.hw_info.mhz = (float) info.cpu_khz / 1000.0; 
  DBG((stderr,"Detected MHZ is %f\n",_papi_system_info.hw_info.mhz));
  mhz = calc_mhz();
  DBG((stderr,"Calculated MHZ is %f\n",mhz));

  /* If difference is larger than 5% (e.g. system info is 0) use 
     calculated value. (If CPU value seems reasonable use it) */
  if (abs(mhz-_papi_system_info.hw_info.mhz) > 0.95*_papi_system_info.hw_info.mhz)
    _papi_system_info.hw_info.mhz = mhz;

#ifndef PERFCTR20 /* Skip truncating MHz value */
  {
    int tmp = (int)_papi_system_info.hw_info.mhz;
    _papi_system_info.hw_info.mhz = (float)tmp;
  }
#endif
  DBG((stderr,"Actual MHZ is %f\n",_papi_system_info.hw_info.mhz));

  /* Setup presets */

  tmp = setup_all_presets((int)info.cpu_type);
  if (tmp)
    return(tmp);

  return(PAPI_OK);
} 

#ifdef DEBUG
#ifdef PERFCTR20
static void dump_cmd(struct vperfctr_control *t)
#else
static void dump_cmd(struct perfctr_control *t)
#endif
{
  int i;

#ifdef PERFCTR20
  DBG((stderr,"tsc_on=0x%x  nractrs=0x%x, nrictrs=0x%x\n",
       t->cpu_control.tsc_on,t->cpu_control.nractrs,t->cpu_control.nrictrs));
  for (i=0;i<_papi_system_info.num_cntrs;i++)
    DBG((stderr,"Event %d: 0x%x\n",i,t->cpu_control.evntsel[i]));
#else
  for (i=0;i<_papi_system_info.num_cntrs;i++)
    DBG((stderr,"Event %d: 0x%x\n",i,t->evntsel[i]));
#endif
}
#endif

#ifdef PERFCTR20
inline static int counter_event_shared(const struct vperfctr_control *a, const struct vperfctr_control *b, int cntr)
#else
inline static int counter_event_shared(const struct perfctr_control *a, const struct perfctr_control *b, int cntr)
#endif
{
#ifdef PERFCTR20
  if (a->cpu_control.evntsel[cntr] == b->cpu_control.evntsel[cntr])
    return(1);
#else
  if (a->evntsel[cntr] == b->evntsel[cntr])
    return(1);
#endif

  return(0);
}

#ifdef PERFCTR20
inline static int counter_event_compat(const struct vperfctr_control *a, const struct vperfctr_control *b, int cntr)
#else
inline static int counter_event_compat(const struct perfctr_control *a, const struct perfctr_control *b, int cntr)
#endif
{
  unsigned int priv_mask = ~PERF_EVNT_MASK;

#ifdef PERFCTR20
  if ((a->cpu_control.evntsel[cntr] & priv_mask) ==
      (b->cpu_control.evntsel[cntr] & priv_mask))
#else
  if ((a->evntsel[cntr] & priv_mask) == (b->evntsel[cntr] & priv_mask))
#endif
    return(1);

  return(0);
}

#ifdef PERFCTR20
inline static void counter_event_copy(const struct vperfctr_control *a, struct vperfctr_control *b, int cntr)
#else
inline static void counter_event_copy(const struct perfctr_control *a, struct perfctr_control *b, int cntr)
#endif
{
#ifdef PERFCTR20
  b->cpu_control.evntsel[cntr] = a->cpu_control.evntsel[cntr];
#else
  b->evntsel[cntr] = a->evntsel[cntr];
#endif
}

inline static int update_global_hwcounters(EventSetInfo *global)
{
  hwd_control_state_t *machdep = global->machdep;
#ifdef PERFCTR20
  struct perfctr_sum_ctrs sum;
#else
  struct vperfctr_state state;
#endif
  int i;

#ifdef PERFCTR20
  vperfctr_read_ctrs(machdep->self, &sum);
#else
  if (vperfctr_read_state(machdep->self, &state) < 0) 
    return(PAPI_ESYS);
#endif
  
  for (i=0;i<_papi_system_info.num_cntrs;i++)
    {
#ifdef PERFCTR20
      DBG((stderr,"update_global_hwcounters() %d: G%lld = G%lld + C%lld\n",i,
	   global->hw_start[i]+sum.pmc[i],
	   global->hw_start[i],sum.pmc[i]));
      global->hw_start[i] = global->hw_start[i] + sum.pmc[i];
#else
      DBG((stderr,"update_global_hwcounters() %d: G%lld = G%lld + C%lld\n",i,
	   global->hw_start[i]+state.sum.ctr[i+1],
	   global->hw_start[i],state.sum.ctr[i+1]));
      global->hw_start[i] = global->hw_start[i] + state.sum.ctr[i+1];
#endif
    }

  if (vperfctr_control(machdep->self, &machdep->counter_cmd) < 0) 
    return(PAPI_ESYS);

  return(PAPI_OK);
}

inline static int correct_local_hwcounters(EventSetInfo *global, EventSetInfo *local, long long *correct)
{
  int i;

  for (i=0;i<_papi_system_info.num_cntrs;i++)
    {
      DBG((stderr,"correct_local_hwcounters() %d: L%lld = G%lld - L%lld\n",i,
	   global->hw_start[i]-local->hw_start[i],global->hw_start[i],local->hw_start[i]));
      correct[i] = global->hw_start[i] - local->hw_start[i];
    }

  return(0);
}

inline static int set_domain(hwd_control_state_t *this_state, int domain)
{
  int mode0 = 0, mode1 = 0, did = 0;
  
  if (domain & PAPI_DOM_USER)
    {
      did = 1;
      mode0 |= PERF_USR | PERF_ENABLE;
      mode1 |= PERF_USR;
    }
  if (domain & PAPI_DOM_KERNEL)
    {
      did = 1;
      mode0 |= PERF_OS | PERF_ENABLE;
      mode1 |= PERF_OS;
    }

  if (!did)
    return(PAPI_EINVAL);

#ifdef PERFCTR20
  this_state->counter_cmd.cpu_control.evntsel[0] &= ~(PERF_OS|PERF_USR);
  this_state->counter_cmd.cpu_control.evntsel[0] |= mode0;
  this_state->counter_cmd.cpu_control.evntsel[1] &= ~(PERF_OS|PERF_USR);
  this_state->counter_cmd.cpu_control.evntsel[1] |= mode1;
#else
  this_state->counter_cmd.evntsel[0] &= ~(PERF_OS|PERF_USR);
  this_state->counter_cmd.evntsel[0] |= mode0;
  this_state->counter_cmd.evntsel[1] &= ~(PERF_OS|PERF_USR);
  this_state->counter_cmd.evntsel[1] |= mode1;
#endif

  return(PAPI_OK);
}

inline static int set_granularity(hwd_control_state_t *this_state, int domain)
{
  switch (domain)
    {
    case PAPI_GRN_THR:
      break;
    default:
      return(PAPI_EINVAL);
    }
  return(PAPI_OK);
}

/* This function should tell your kernel extension that your children
   inherit performance register information and propagate the values up
   upon child exit and parent wait. */

inline static int set_inherit(int arg)
{
  return(PAPI_ESBSTR);
}

inline static int set_default_domain(EventSetInfo *zero, int domain)
{
  hwd_control_state_t *current_state = (hwd_control_state_t *)zero->machdep;
  return(set_domain(current_state,domain));
}

inline static int set_default_granularity(EventSetInfo *zero, int granularity)
{
  hwd_control_state_t *current_state = (hwd_control_state_t *)zero->machdep;
  return(set_granularity(current_state,granularity));
}

/* At init time, the higher level library should always allocate and 
   reserve EventSet zero. */

#ifndef PERFCTR18
struct perfctr_dev *dev;
#endif
int _papi_hwd_init_global(void)
{
  int retval;

  /* Opened once for all threads. */

#ifdef PERFCTR18
  struct vperfctr *dev;
  dev = vperfctr_open();
  DBG((stderr,"_papi_hwd_init_global dev=%p\n",dev));
#else
  dev = perfctr_dev_open();
#endif
  if (!dev)
    return(PAPI_ESYS);

  /* Fill in what we can of the papi_system_info. */
  
  retval = get_system_info(dev);
  if (retval)
    return(retval);
  
  DBG((stderr,"Found %d %s %s CPU's at %f Mhz.\n",
       _papi_system_info.hw_info.totalcpus,
       _papi_system_info.hw_info.vendor_string,
       _papi_system_info.hw_info.model_string,
       _papi_system_info.hw_info.mhz));

#ifdef PERFCTR18
  vperfctr_close(dev);
#endif
  return(PAPI_OK);
}

int _papi_hwd_shutdown_global(void)
{
#ifndef PERFCTR18
  perfctr_dev_close(dev);
#endif
  return(PAPI_OK);
}

int _papi_hwd_init(EventSetInfo *zero)
{
  hwd_control_state_t *machdep = zero->machdep;
  
  /* Initialize our global machdep. */

#ifdef PERFCTR18
  if ((machdep->self = vperfctr_open()) == NULL) 
    return(PAPI_ESYS);
  DBG((stderr,"_papi_hwd_init dev=%p\n",machdep->self));
#else
  if ((machdep->self = vperfctr_attach(dev)) == NULL) 
    return(PAPI_ESYS);
#endif

  /* Initialize the event fields */

  init_config(zero->machdep);

  /* Start the TSC counter */
  if(vperfctr_control(machdep->self, &machdep->counter_cmd) < 0)
    return(PAPI_ESYS);

  return(PAPI_OK);
}

long long _papi_hwd_get_real_usec (void)
{
  long long cyc;

  cyc = get_cycles()*(unsigned long long)1000;
  cyc = cyc / (long long)_papi_system_info.hw_info.mhz;
  return(cyc / (long long)1000);
}

long long _papi_hwd_get_real_cycles (void)
{
  return(get_cycles());
}

long long _papi_hwd_get_virt_usec (EventSetInfo *zero)
{
  long long retval;
/*  struct tms buffer; */

  retval = _papi_hwd_get_virt_cycles(zero);
  retval = retval / _papi_system_info.hw_info.mhz;
  return(retval);

  /*
  times(&buffer);
  retval = (long long)buffer.tms_utime*(long long)(1000000/CLK_TCK);
  return(retval);
   */
}

long long _papi_hwd_get_virt_cycles (EventSetInfo *zero)
{
  unsigned long long lcyc;
  hwd_control_state_t *machdep = zero->machdep;
/*  float usec, cyc; */

  lcyc = vperfctr_read_tsc(machdep->self);
  DBG((stderr,"Read virt. cycles is %llu (%p -> %p)\n",lcyc,machdep,machdep->self));
  return(lcyc);

  /*  
  usec = (float)_papi_hwd_get_virt_usec(zero);
  cyc = usec * _papi_system_info.hw_info.mhz;
  return((long long)cyc);
  */
}

void _papi_hwd_error(int error, char *where)
{
  sprintf(where,"Substrate error: %s",strerror(error));
}

int _papi_hwd_add_event(hwd_control_state_t *this_state, unsigned int EventCode, EventInfo_t *out)
{
  int selector = 0;
  int avail = 0;
#ifdef PERFCTR20
  struct perfctr_cpu_control tmp_cmd, *codes;
#else
  struct perfctr_control tmp_cmd, *codes;
#endif

  if (EventCode & PRESET_MASK)
    { <commit_msg>Fix to support perfctr 1.6 as well, thanks Rick for pointing this out.<commit_after>/* 
* File:    linux-perfctr.c
* CVS:     $Id$
* Author:  <NAME>
*          <EMAIL>
* Mods:    dan terpstra
*          <EMAIL>
* Mods:    <NAME>
*          <EMAIL>
*/  

#ifdef PERFCTR20
#define PERFCTR18
#endif
/* This substrate should never malloc anything. All allocation should be
   done by the high level API. */

/* The values defined in this file may be X86-specific (2 general 
   purpose counters, 1 special purpose counter, etc.*/

/* PAPI stuff */

#include SUBSTRATE

/* First entry is mask, counter code 1, counter code 2, and TSC. 
A high bit in the mask entry means it is an OR mask, not an
and mask. This means that the same even is available on either
counter. */

static hwd_preset_t *preset_map = NULL;

static hwd_preset_t p6_preset_map[PAPI_MAX_PRESET_EVENTS] = { 
  {CNTR2|CNTR1,0,0,{{0x45,0x45,0x0,0x0}},""},	// L1 Cache Dmisses 
  {CNTR2|CNTR1,0,0,{{0xf28,0xf28,0x0,0x0}},""},	// L1 Cache Imisses 
  {0,0,0,{{0,0,0x0,0x0}},""}, 			// L2 Cache Dmisses
  {CNTR2|CNTR1,0,0,{{0x81,0x81,0x0,0x0}},""},	// L2 Cache Imisses 
  {0,0,0,{{0,0,0x0,0x0}},""}, 			// L3 Cache Dmisses
  {0,0,0,{{0,0,0x0,0x0}},""}, 			// L3 Cache Imisses
  {CNTR2|CNTR1,0,0,{{0xf2e,0xf2e,0x0,0x0}},""},	// L1 Total Cache misses 
  {CNTR2|CNTR1,0,0,{{0x24,0x24,0x0,0x0}},""}, 	// L2 Total Cache misses
  {0,0,0,{{0,0,0x0,0x0}},""}, 			// L3 Total Cache misses
  {0,0,0,{{0,0,0x0,0x0}},""},			// Snoops
  {CNTR2|CNTR1,0,0,{{0x222e,0x222e,0x0,0x0}},""},	// Req. access to shared cache line
  {CNTR2|CNTR1,0,0,{{0x212e,0x212e,0x0,0x0}},""},	// Req. access to clean cache line
  {CNTR2|CNTR1,0,0,{{0x2069,0x2069,0x0,0x0}},""},	// Req. Cache Line Invalidation
  {CNTR2|CNTR1,0,0,{{0x2e2e,0x2e2e,0x0,0x0}},""},	// Req. Cache Line Intervention
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3 LDM
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3 STM
  {0,0,0,{{0,0,0x0,0x0}},""},			// cycles branch idle
  {0,0,0,{{0,0,0x0,0x0}},""},			// cycles int idle
  {0,0,0,{{0,0,0x0,0x0}},""},			// cycles fpu idle
  {0,0,0,{{0,0,0x0,0x0}},""},			// cycles load/store idle
  {0,0,0,{{0,0,0x0,0x0}},""},		 	// D-TLB misses
  {CNTR2|CNTR1,0,0,{{0x85,0x85,0x0,0x0}},""},	// I-TLB misses
  {0,0,0,{{0,0,0x0,0x0}},""},			// Total TLB misses
  {CNTR2|CNTR1,0,0,{{0xf29,0xf29,0x0,0x0}},""},	// L1 load M
  {CNTR2|CNTR1,0,0,{{0xf2A,0xf2A,0x0,0x0}},""},	// L1 store M
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2 load M
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2 store M
  {CNTR2|CNTR1,0,0,{{0xe2,0xe2,0x0,0x0}},""},	// BTAC misses
  {0,0,0,{{0,0,0x0,0x0}},""},	                // Prefmiss
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3DCH
  {0,0,0,{{0,0,0x0,0x0}},""},			// TLB shootdowns
  {0,0,0,{{0,0,0x0,0x0}},""},			// Failed Store cond.
  {0,0,0,{{0,0,0x0,0x0}},""},			// Suc. store cond.
  {0,0,0,{{0,0,0x0,0x0}},""},			// total. store cond.
  {0,0,0,{{0,0,0x0,0x0}},""},	                // Cycles stalled waiting for memory /
  {0,0,0,{{0,0,0x0,0x0}},""},		   	// Cycles stalled waiting for memory read /
  {0,0,0,{{0,0,0x0,0x0}},""},		   	// Cycles stalled waiting for memory write /
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles no instructions issued /
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles max instructions issued /
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles no instructions comleted /
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles max instructions completed /
  {CNTR2|CNTR1,0,0,{{0xC8,0xC8,0x0,0x0}},""},	// hardware interrupts
  {0,0,0,{{0,0,0x0,0x0}},""},	                // Uncond. branches executed
  {CNTR2|CNTR1,0,0,{{0xC4,0xC4,0x0,0x0}},""},	// Cond. Branch inst. executed
  {CNTR2|CNTR1,0,0,{{0xC9,0xC9,0x0,0x0}},""},	// Cond. Branch inst. taken
  {CNTR2|CNTR1,DERIVED_SUB,0,{{0xC4,0xC9,0x0,0x0}},""}, // Cond. Branch inst. not taken
  {CNTR2|CNTR1,0,0,{{0xC5,0xC5,0x0,0x0}},""},	// Cond. branch inst. mispred.
  {CNTR2|CNTR1,DERIVED_SUB,0,{{0xC4,0xC5,0x0,0x0}},""}, // Cond. branch inst. corr. pred.
  {0,0,0,{{0,0,0x0,0x0}},""},			// FMA
  {CNTR2|CNTR1,0,0,{{0xD0,0xD0,0x0,0x0}},""},	// Total inst. issued
  {CNTR2|CNTR1,0,0,{{0xC0,0xC0,0x0,0x0}},""},	// Total inst. executed
  {0,0,0,{{0,0,0x0,0x0}},""},			// Integer inst. executed
  {CNTR1,0,0,{{0xC1,0,0x0,0x0}},""},		// Floating Pt. inst. executed
  {0,0,0,{{0,0,0x0,0x0}},""},			// Loads executed
  {0,0,0,{{0,0,0x0,0x0}},""},			// Stores executed
  {CNTR2|CNTR1,0,0,{{0xC4,0xC4,0x0,0x0}},""},	// Branch inst. executed
  {CNTR2|CNTR1,0,0,{{0xB0,0xB0,0x0,0x0}},""},	// Vector/SIMD inst. executed 
  {CNTR2|CNTR1,DERIVED_PS,1,{{0xC1,0x79,0x0,0x0}},""}, // FLOPS
  {CNTR2|CNTR1,0,0,{{0xA2,0xA2,0x0,0x0}},""},	// Cycles any resource stalls
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles FPU stalled
  {CNTR2|CNTR1,0,0,{{0x79,0x79,0x0,0x0}},""},	// Total cycles
  {CNTR2|CNTR1,DERIVED_PS,1,{{0xC0,0x79,0x0,0x0}},""}, // IPS
  {0,0,0,{{0,0,0,0}},""},			// Total load/store inst. exec
  {0,0,0,{{0,0,0x0,0x0}},""},			// SYnc exec.
  {CNTR2|CNTR1,DERIVED_SUB,0,{{0x43,0x45,0x0,0x0}},""}, // L1_DCH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_DCH
  {CNTR2|CNTR1,0,0,{{0x43,0x43,0x0,0x0}},""},	// L1_DCA
  {CNTR2|CNTR1,DERIVED_ADD,0,{{0xf29,0xf2a,0x0,0x0}},""}, // L2_DCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_DCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_DCR
  {CNTR2|CNTR1,0,0,{{0xf29,0xf29,0x0,0x0}},""},	// L2_DCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_DCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_DCW
  {CNTR2|CNTR1,0,0,{{0xf2a,0xf2a,0x0,0x0}},""},	// L2_DCW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_DCW
  {CNTR2|CNTR1,DERIVED_SUB,0,{{0x80,0xf28,0x0,0x0}},""}, // L1_ICH
  {CNTR2|CNTR1,DERIVED_SUB,0,{{0xf28,0x81,0x0,0x0}},""}, // L2_ICH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_ICH
  {CNTR2|CNTR1,0,0,{{0x80,0x80,0x0,0x0}},""},	// L1_ICA
  {CNTR2|CNTR1,0,0,{{0xf28,0xf28,0x0,0x0}},""},	// L2_ICA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_ICA
  {CNTR2|CNTR1,0,0,{{0x80,0x80,0x0,0x0}},""},	// L1_ICR
  {CNTR2|CNTR1,0,0,{{0xf28,0xf28,0x0,0x0}},""},	// L2_ICR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_ICR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_ICW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_ICW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_ICW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_TCH
  {CNTR2|CNTR1,DERIVED_SUB,0,{{0xf2e,0x24,0x0,0x0}},""}, // L2_TCH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_TCH
  {CNTR2|CNTR1,DERIVED_ADD,0,{{0x43,0x80,0x0,0x0}},""},	// L1_TCA
  {CNTR2|CNTR1,0,0,{{0xf2e,0xf2e,0x0,0x0}},""},	// L2_TCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_TCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_TCR
  {CNTR2|CNTR1,DERIVED_ADD,0,{{0xf29,0xf28,0x0,0x0}},""}, // L2_TCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_TCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_TCW
  {CNTR2|CNTR1,0,0,{{0xf2a,0xf2a,0x0,0x0}},""},	// L2_TCW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_TCW
  {CNTR2,0,0,{{0,0x12,0x0,0x0}},""},		// FPM
  {0,0,0,{{0,0,0x0,0x0}},""},			// FPA
  {CNTR2,0,0,{{0,0x13,0x0,0x0}},""},		// FPD
  {0,0,0,{{0,0,0x0,0x0}},""},			// FPSQ
  {0,0,0,{{0,0,0x0,0x0}},""},			// FPI
};

static hwd_preset_t k7_preset_map[PAPI_MAX_PRESET_EVENTS] = { 
  {ALLCNTRS,0,0,{{0x41,0x41,0x41,0x41}},""},	// L1 Cache Dmisses 
  {ALLCNTRS,0,0,{{0x81,0x81,0x81,0x81}},""},	// L1 Cache Imisses 
  {ALLCNTRS,0,0,{{0x42,0x42,0x42,0x42}},""}, 	// L2 Cache Dmisses
  {ALLCNTRS,0,0,{{0x83,0x83,0x83,0x83}},""}, 	// L2 Cache Imisses
  {0,0,0,{{0,0,0x0,0x0}},""}, 			// L3 Cache Dmisses
  {0,0,0,{{0,0,0x0,0x0}},""}, 			// L3 Cache Imisses
  {ALLCNTRS,0,0,{{0x73,0x73,0x73,0x73}},""}, 	// L1 Total Cache misses 
  {0,0,0,{{0,0,0x0,0x0}},""}, 			// L2 Total Cache misses
  {0,0,0,{{0,0,0x0,0x0}},""}, 			// L3 Total Cache misses
  {0,0,0,{{0,0,0x0,0x0}},""},			// Snoops
  {0,0,0,{{0,0,0x0,0x0}},""},			// Req. access to shared cache line
  {0,0,0,{{0,0,0x0,0x0}},""},			// Req. access to clean cache line
  {0,0,0,{{0,0,0x0,0x0}},""},			// Req. Cache Line Invalidation
  {0,0,0,{{0,0,0x0,0x0}},""},			// Req. Cache Line Intervention
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3 LDM
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3 STM
  {0,0,0,{{0,0,0x0,0x0}},""},			// cycles branch idle
  {0,0,0,{{0,0,0x0,0x0}},""},			// cycles int idle
  {0,0,0,{{0,0,0x0,0x0}},""},			// cycles fpu idle
  {0,0,0,{{0,0,0x0,0x0}},""},			// cycles load/store idle
  {ALLCNTRS,0,0,{{0x46,0x46,0x46,0x46}},""},	// D-TLB misses
  {CNTR1|CNTR2,DERIVED_ADD,0,{{0x84,0x85,0x0,0x0}},""}, // I-TLB misses
  {CNTR1|CNTR2|CNTR3,DERIVED_ADD,0,{{0x84,0x85,0x46,0x0}},""}, // Total TLB misses
  {0,0,0,{{0,0,0x0,0x0}},""},		   	// L1 load M
  {0,0,0,{{0,0,0x0,0x0}},""},		   	// L1 store M
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2 load M
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2 store M
  {0,0,0,{{0,0,0x0,0x0}},""},		   	// BTAC misses
  {0,0,0,{{0,0,0x0,0x0}},""},	                // Prefmiss
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3DCH
  {0,0,0,{{0,0,0x0,0x0}},""},			// TLB shootdowns
  {0,0,0,{{0,0,0x0,0x0}},""},			// Failed Store cond.
  {0,0,0,{{0,0,0x0,0x0}},""},			// Suc. store cond.
  {0,0,0,{{0,0,0x0,0x0}},""},			// total. store cond.
  {0,0,0,{{0,0,0x0,0x0}},""},	                // Cycles stalled waiting for memory /
  {0,0,0,{{0,0,0x0,0x0}},""},		   	// Cycles stalled waiting for memory read /
  {0,0,0,{{0,0,0x0,0x0}},""},		   	// Cycles stalled waiting for memory write /
  {0,0,0,{{0,0,0x0,0x0}},""},		   	// Cycles no instructions issued /
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles max instructions issued /
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles no instructions completed /
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles max instructions completed /
  {ALLCNTRS,0,0,{{0xcf,0xcf,0xcf,0xcf}},""},	// hardware interrupts
  {ALLCNTRS,0,0,{{0xc6,0xc6,0xc6,0xc6}},""},	// Uncond. branches executed
  {ALLCNTRS,0,0,{{0xC2,0xC2,0xc2,0xc2}},""},	// Cond. Branch inst. executed
  {ALLCNTRS,0,0,{{0xC4,0xC4,0xc4,0xc4}},""},	// Cond. Branch inst. taken
  {CNTR1|CNTR2,DERIVED_SUB,0,{{0xC4,0xC2,0x0,0x0}},""}, // Cond. Branch inst. not taken
  {ALLCNTRS,0,0,{{0xC3,0xC3,0xC3,0xC3}},""},	// Cond. branch inst. mispred.
  {CNTR1|CNTR2,DERIVED_SUB,0,{{0xC2,0xC3,0x0,0x0}},""}, // Cond. branch inst. corr. pred.
  {0,0,0,{{0,0,0x0,0x0}},""},			// FMA
  {0,0,0,{{0,0,0x0,0x0}},""},                   // Total inst. issued
  {ALLCNTRS,0,0,{{0xC0,0xC0,0xC0,0xC0}},""},	// Total inst. executed
  {0,0,0,{{0,0,0x0,0x0}},""},			// Integer inst. executed
  {0,0,0,{{0,0,0x0,0x0}},""},                   // Floating Pt. inst. executed
  {0,0,0,{{0,0,0x0,0x0}},""},			// Loads executed
  {0,0,0,{{0,0,0x0,0x0}},""},			// Stores executed
  {ALLCNTRS,0,0,{{0xC4,0xC4,0x0,0x0}},""},	// Branch inst. executed
  {ALLCNTRS,0,0,{{0xB0,0xB0,0x0,0x0}},""},	// Vector/SIMD inst. executed 
  {0,0,0,{{0,0,0x0,0x0}},""},                   // FLOPS
  {ALLCNTRS,0,0,{{0xd9,0xd9,0xd9,0xd9}},""},    // Cycles any resource stalls
  {0,0,0,{{0,0,0x0,0x0}},""},			// Cycles FPU stalled
  {ALLCNTRS,0,0,{{0x76,0x76,0x76,0x76}},""},	// Total cycles
  {CNTR1|CNTR2,DERIVED_PS,1,{{0xC0,0x76,0x0,0x0}},""}, // IPS
  {0,0,0,{{0,0,0x0,0x0}},""},			// Total load/store inst. exec
  {0,0,0,{{0,0,0x0,0x0}},""},			// SYnc exec.
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_DCH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_DCH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_DCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_DCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_DCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_DCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_DCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_DCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_DCW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_DCW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_DCW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_ICH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_ICH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_ICH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_ICA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_ICA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_ICA
  {ALLCNTRS,0,0,{{0x80,0x80,0x80,0x80}},""},	// L1_ICR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_ICR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_ICR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_ICW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_ICW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_ICW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_TCH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_TCH
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_TCH
  {CNTR1|CNTR2,DERIVED_ADD,0,{{0x40,0x80,0x0,0x0}},""}, // L1_TCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_TCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_TCA
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_TCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_TCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_TCR
  {0,0,0,{{0,0,0x0,0x0}},""},			// L1_TCW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L2_TCW
  {0,0,0,{{0,0,0x0,0x0}},""},			// L3_TCW
  {0,0,0,{{0,0,0x0,0x0}},""},			// FPM
  {0,0,0,{{0,0,0x0,0x0}},""},			// FPA
  {0,0,0,{{0,0,0x0,0x0}},""},			// FPD
  {0,0,0,{{0,0,0x0,0x0}},""},			// FPSQ
  {0,0,0,{{0,0,0x0,0x0}},""},			// FPI
};

/* Low level functions, should not handle errors, just return codes. */

inline static char *search_cpu_info(FILE *f, char *search_str, char *line)
{
  /* This code courtesy of our friends in Germany. Thanks <NAME>! */
  /* See the PCL home page for the German version of PAPI. */

  char *s;

  while (fgets(line, 256, f) != NULL)
    {
      if (strstr(line, search_str) != NULL)
	{
	  /* ignore all characters in line up to : */
	  for (s = line; *s && (*s != ':'); ++s)
	    ;
	  if (*s)
	    return(s);
	}
    }
  return(NULL);

  /* End stolen code */
}

static inline unsigned long long get_cycles (void)
{
	unsigned long long ret;
        __asm__ __volatile__("rdtsc"
			    : "=A" (ret)
			    : /* no inputs */);
        return ret;
}

/* Dumb hack to make sure I get the cycle time correct. */

static float calc_mhz(void)
{
  unsigned long long ostamp;
  unsigned long long stamp;
  float correction = 4000.0, mhz;

  /* Warm the cache */

  ostamp = get_cycles();
  usleep(1);
  stamp = get_cycles();
  stamp = stamp - ostamp;
  mhz = (float)stamp/(float)(1000000.0 + correction);

  ostamp = get_cycles();
  sleep(1);
  stamp = get_cycles();
  stamp = stamp - ostamp;
  mhz = (float)stamp/(float)(1000000.0 + correction);

  return(mhz);
}

inline static int setup_all_presets(int cpu_type)
{
  int pnum, s;
  char note[100];

  if ((cpu_type == PERFCTR_X86_WINCHIP_C6) ||
      (cpu_type == PERFCTR_X86_WINCHIP_2))
    {
      fprintf(stderr,"Ask yourself, why am I tuning code on a WinChip?\n");
      abort();
    }

  if (cpu_type == PERFCTR_X86_AMD_K7)
    preset_map = k7_preset_map;
  else
    preset_map = p6_preset_map;

  for (pnum = 0; pnum < PAPI_MAX_PRESET_EVENTS; pnum++)
    {
      if ((s = preset_map[pnum].selector))
	{
	  if (_papi_system_info.num_cntrs == 2)
	    {
	      sprintf(note,"0x%x,0x%x",
		      preset_map[pnum].counter_cmd.evntsel[0],
		      preset_map[pnum].counter_cmd.evntsel[1]);
	      strcat(preset_map[pnum].note,note);
	    }
	  else if (_papi_system_info.num_cntrs == 4)
	    {
	      sprintf(note,"0x%x,0x%x,0x%x,0x%x",
		      preset_map[pnum].counter_cmd.evntsel[0],
		      preset_map[pnum].counter_cmd.evntsel[1],
		      preset_map[pnum].counter_cmd.evntsel[2],
		      preset_map[pnum].counter_cmd.evntsel[3]);
	      strcat(preset_map[pnum].note,note);
	    }
	  else
	    abort();
	}
    }
  return(PAPI_OK);
}

/* Utility functions */

/* Go from highest counter to lowest counter. Why? Because there are usually
   more counters on #1, so we try the least probable first. */

inline static int get_avail_hwcntr_bits(int cntr_avail_bits)
{
  int tmp = 0, i = 1 << (_papi_system_info.num_cntrs-1);
  
  while (i)
    {
      tmp = i & cntr_avail_bits;
      if (tmp)
	return(tmp);
      i = i >> 1;
    }
  return(0);
}

#ifdef PERFCTR20
inline static void set_hwcntr_codes(int selector, struct perfctr_cpu_control *from, struct perfctr_cpu_control *to)
#else
inline static void set_hwcntr_codes(int selector, struct perfctr_control *from, struct perfctr_control *to)
#endif
{
  int useme, i;
  
  for (i=0;i<_papi_system_info.num_cntrs;i++)
    {
      useme = (1 << i) & selector;
      if (useme)
	{
	  to->evntsel[i] = to->evntsel[i] & ~PERF_EVNT_MASK;
	  to->evntsel[i] = to->evntsel[i] | from->evntsel[i];
#ifdef PERFCTR20
	  to->pmc_map[i] = i;
#endif
	}
    }
}

inline static void init_config(hwd_control_state_t *ptr)
{
  int def_mode;

  switch (_papi_system_info.default_domain)
    {
    case PAPI_DOM_USER:
      def_mode = PERF_USR;
      break;
    case PAPI_DOM_KERNEL:
      def_mode = PERF_OS;
      break;
    case PAPI_DOM_ALL:
      def_mode = PERF_OS | PERF_USR;
      break;
    default:
      abort();
    }

  ptr->selector = 0;
#ifdef PERFCTR20
  ptr->counter_cmd.cpu_control.evntsel[0] |= def_mode | PERF_ENABLE;
  ptr->counter_cmd.cpu_control.evntsel[1] |= def_mode;
  ptr->counter_cmd.cpu_control.tsc_on=1;
  ptr->counter_cmd.cpu_control.nractrs=2;
  ptr->counter_cmd.cpu_control.pmc_map[0]=0;
  ptr->counter_cmd.cpu_control.pmc_map[1]=1;
#else
  ptr->counter_cmd.evntsel[0] |= def_mode | PERF_ENABLE;
  ptr->counter_cmd.evntsel[1] |= def_mode;
#endif
}

#ifdef PERFCTR18
static int get_system_info(const struct vperfctr *dev)
#else
static int get_system_info(struct perfctr_dev *dev)
#endif
{
  struct perfctr_info info;
  pid_t pid;
  int tmp;
  float mhz;
  char maxargs[PAPI_MAX_STR_LEN], *t, *s;
  FILE *f;

  /* Path and args */

  pid = getpid();
  if (pid == -1)
    return(PAPI_ESYS);

  sprintf(maxargs,"/proc/%d/exe",(int)getpid());
  if (readlink(maxargs,_papi_system_info.exe_info.fullname,PAPI_MAX_STR_LEN) == -1)
    return(PAPI_ESYS);
  sprintf(_papi_system_info.exe_info.name,"%s",basename(_papi_system_info.exe_info.fullname));

  DBG((stderr,"Executable is %s\n",_papi_system_info.exe_info.name));
  DBG((stderr,"Full Executable is %s\n",_papi_system_info.exe_info.fullname));

  if ((f = fopen("/proc/cpuinfo", "r")) == NULL)
    return -1;
 
  /* Hardware info */

  _papi_system_info.hw_info.ncpu = sysconf(_SC_NPROCESSORS_ONLN);
  _papi_system_info.hw_info.nnodes = 1;
  _papi_system_info.hw_info.totalcpus = sysconf(_SC_NPROCESSORS_CONF);
  _papi_system_info.hw_info.vendor = -1;

  rewind(f);
  s = search_cpu_info(f,"vendor_id",maxargs);
  if (s && (t = strchr(s+2,'\n')))
    {
      *t = '\0';
      strcpy(_papi_system_info.hw_info.vendor_string,s+2);
    }

  rewind(f);
  s = search_cpu_info(f,"stepping",maxargs);
  if (s)
    sscanf(s+1, "%d", &tmp);
  _papi_system_info.hw_info.revision = (float)tmp;

#ifdef PERFCTR18  /* And PERFCTR20 */
  if (vperfctr_info(dev, &info) < 0)
    return(PAPI_ESYS);
  strcpy(_papi_system_info.hw_info.model_string,perfctr_cpu_name(&info));
  _papi_system_info.supports_hw_overflow = 
    (info.cpu_features & PERFCTR_FEATURE_PCINT) ? 1 : 0;
  DBG((stderr,"Hardware/OS %s support counter generated interrupts\n",
       _papi_system_info.supports_hw_overflow ? "does" : "does not"));
#ifndef PAPI_PERFCTR_INTR_SUPPORT
  if(_papi_system_info.supports_hw_overflow)
    DBG((stderr,"PAPI_PERFCTR_INTR_SUPPORT disabled at compile time.\n"));
  _papi_system_info.supports_hw_overflow = 0;
#endif
  _papi_system_info.supports_hw_profile = 0; /* != _papi_system_info.supports_hw_overflow? */
#ifdef PERFCTR20
  _papi_system_info.num_cntrs = perfctr_cpu_nrctrs(&info);
  _papi_system_info.num_gp_cntrs = perfctr_cpu_nrctrs(&info);
#else /* PERFCTR20 */
  _papi_system_info.num_cntrs = perfctr_cpu_nrctrs(&info) - 1;
  _papi_system_info.num_gp_cntrs = perfctr_cpu_nrctrs(&info) - 1;
#endif /* PERFCTR20 */
#elif defined(PERFCTR16)  /* Neither PERFCTR18 nor PERFCTR20 */
  if (perfctr_info(dev, &info) < 0)
    return(PAPI_ESYS);
  strcpy(_papi_system_info.hw_info.model_string,perfctr_cpu_name(&info));
  _papi_system_info.num_cntrs = perfctr_cpu_nrctrs(&info) - 1;
  _papi_system_info.num_gp_cntrs = perfctr_cpu_nrctrs(&info) - 1;
#endif /* PERFCTR18 */

  _papi_system_info.hw_info.model = (int)info.cpu_type;
  _papi_system_info.hw_info.mhz = (float) info.cpu_khz / 1000.0; 
  DBG((stderr,"Detected MHZ is %f\n",_papi_system_info.hw_info.mhz));
  mhz = calc_mhz();
  DBG((stderr,"Calculated MHZ is %f\n",mhz));

  /* If difference is larger than 5% (e.g. system info is 0) use 
     calculated value. (If CPU value seems reasonable use it) */
  if (abs(mhz-_papi_system_info.hw_info.mhz) > 0.95*_papi_system_info.hw_info.mhz)
    _papi_system_info.hw_info.mhz = mhz;

#ifndef PERFCTR20 /* Skip truncating MHz value */
  {
    int tmp = (int)_papi_system_info.hw_info.mhz;
    _papi_system_info.hw_info.mhz = (float)tmp;
  }
#endif
  DBG((stderr,"Actual MHZ is %f\n",_papi_system_info.hw_info.mhz));

  /* Setup presets */

  tmp = setup_all_presets((int)info.cpu_type);
  if (tmp)
    return(tmp);

  return(PAPI_OK);
} 

#ifdef DEBUG
#ifdef PERFCTR20
static void dump_cmd(struct vperfctr_control *t)
#else
static void dump_cmd(struct perfctr_control *t)
#endif
{
  int i;

#ifdef PERFCTR20
  DBG((stderr,"tsc_on=0x%x  nractrs=0x%x, nrictrs=0x%x\n",
       t->cpu_control.tsc_on,t->cpu_control.nractrs,t->cpu_control.nrictrs));
  for (i=0;i<_papi_system_info.num_cntrs;i++)
    DBG((stderr,"Event %d: 0x%x\n",i,t->cpu_control.evntsel[i]));
#else
  for (i=0;i<_papi_system_info.num_cntrs;i++)
    DBG((stderr,"Event %d: 0x%x\n",i,t->evntsel[i]));
#endif
}
#endif

#ifdef PERFCTR20
inline static int counter_event_shared(const struct vperfctr_control *a, const struct vperfctr_control *b, int cntr)
#else
inline static int counter_event_shared(const struct perfctr_control *a, const struct perfctr_control *b, int cntr)
#endif
{
#ifdef PERFCTR20
  if (a->cpu_control.evntsel[cntr] == b->cpu_control.evntsel[cntr])
    return(1);
#else
  if (a->evntsel[cntr] == b->evntsel[cntr])
    return(1);
#endif

  return(0);
}

#ifdef PERFCTR20
inline static int counter_event_compat(const struct vperfctr_control *a, const struct vperfctr_control *b, int cntr)
#else
inline static int counter_event_compat(const struct perfctr_control *a, const struct perfctr_control *b, int cntr)
#endif
{
  unsigned int priv_mask = ~PERF_EVNT_MASK;

#ifdef PERFCTR20
  if ((a->cpu_control.evntsel[cntr] & priv_mask) ==
      (b->cpu_control.evntsel[cntr] & priv_mask))
#else
  if ((a->evntsel[cntr] & priv_mask) == (b->evntsel[cntr] & priv_mask))
#endif
    return(1);

  return(0);
}

#ifdef PERFCTR20
inline static void counter_event_copy(const struct vperfctr_control *a, struct vperfctr_control *b, int cntr)
#else
inline static void counter_event_copy(const struct perfctr_control *a, struct perfctr_control *b, int cntr)
#endif
{
#ifdef PERFCTR20
  b->cpu_control.evntsel[cntr] = a->cpu_control.evntsel[cntr];
#else
  b->evntsel[cntr] = a->evntsel[cntr];
#endif
}

inline static int update_global_hwcounters(EventSetInfo *global)
{
  hwd_control_state_t *machdep = global->machdep;
#ifdef PERFCTR20
  struct perfctr_sum_ctrs sum;
#else
  struct vperfctr_state state;
#endif
  int i;

#ifdef PERFCTR20
  vperfctr_read_ctrs(machdep->self, &sum);
#else
  if (vperfctr_read_state(machdep->self, &state) < 0) 
    return(PAPI_ESYS);
#endif
  
  for (i=0;i<_papi_system_info.num_cntrs;i++)
    {
#ifdef PERFCTR20
      DBG((stderr,"update_global_hwcounters() %d: G%lld = G%lld + C%lld\n",i,
	   global->hw_start[i]+sum.pmc[i],
	   global->hw_start[i],sum.pmc[i]));
      global->hw_start[i] = global->hw_start[i] + sum.pmc[i];
#else
      DBG((stderr,"update_global_hwcounters() %d: G%lld = G%lld + C%lld\n",i,
	   global->hw_start[i]+state.sum.ctr[i+1],
	   global->hw_start[i],state.sum.ctr[i+1]));
      global->hw_start[i] = global->hw_start[i] + state.sum.ctr[i+1];
#endif
    }

  if (vperfctr_control(machdep->self, &machdep->counter_cmd) < 0) 
    return(PAPI_ESYS);

  return(PAPI_OK);
}

inline static int correct_local_hwcounters(EventSetInfo *global, EventSetInfo *local, long long *correct)
{
  int i;

  for (i=0;i<_papi_system_info.num_cntrs;i++)
    {
      DBG((stderr,"correct_local_hwcounters() %d: L%lld = G%lld - L%lld\n",i,
	   global->hw_start[i]-local->hw_start[i],global->hw_start[i],local->hw_start[i]));
      correct[i] = global->hw_start[i] - local->hw_start[i];
    }

  return(0);
}

inline static int set_domain(hwd_control_state_t *this_state, int domain)
{
  int mode0 = 0, mode1 = 0, did = 0;
  
  if (domain & PAPI_DOM_USER)
    {
      did = 1;
      mode0 |= PERF_USR | PERF_ENABLE;
      mode1 |= PERF_USR;
    }
  if (domain & PAPI_DOM_KERNEL)
    {
      did = 1;
      mode0 |= PERF_OS | PERF_ENABLE;
      mode1 |= PERF_OS;
    }

  if (!did)
    return(PAPI_EINVAL);

#ifdef PERFCTR20
  this_state->counter_cmd.cpu_control.evntsel[0] &= ~(PERF_OS|PERF_USR);
  this_state->counter_cmd.cpu_control.evntsel[0] |= mode0;
  this_state->counter_cmd.cpu_control.evntsel[1] &= ~(PERF_OS|PERF_USR);
  this_state->counter_cmd.cpu_control.evntsel[1] |= mode1;
#else
  this_state->counter_cmd.evntsel[0] &= ~(PERF_OS|PERF_USR);
  this_state->counter_cmd.evntsel[0] |= mode0;
  this_state->counter_cmd.evntsel[1] &= ~(PERF_OS|PERF_USR);
  this_state->counter_cmd.evntsel[1] |= mode1;
#endif

  return(PAPI_OK);
}

inline static int set_granularity(hwd_control_state_t *this_state, int domain)
{
  switch (domain)
    {
    case PAPI_GRN_THR:
      break;
    default:
      return(PAPI_EINVAL);
    }
  return(PAPI_OK);
}

/* This function should tell your kernel extension that your children
   inherit performance register information and propagate the values up
   upon child exit and parent wait. */

inline static int set_inherit(int arg)
{
  return(PAPI_ESBSTR);
}

inline static int set_default_domain(EventSetInfo *zero, int domain)
{
  hwd_control_state_t *current_state = (hwd_control_state_t *)zero->machdep;
  return(set_domain(current_state,domain));
}

inline static int set_default_granularity(EventSetInfo *zero, int granularity)
{
  hwd_control_state_t *current_state = (hwd_control_state_t *)zero->machdep;
  return(set_granularity(current_state,granularity));
}

/* At init time, the higher level library should always allocate and 
   reserve EventSet zero. */

#ifndef PERFCTR18
struct perfctr_dev *dev;
#endif
int _papi_hwd_init_global(void)
{
  int retval;

  /* Opened once for all threads. */

#ifdef PERFCTR18
  struct vperfctr *dev;
  dev = vperfctr_open();
  DBG((stderr,"_papi_hwd_init_global dev=%p\n",dev));
#else
  dev = perfctr_dev_open();
#endif
  if (!dev)
    return(PAPI_ESYS);

  /* Fill in what we can of the papi_system_info. */
  
  retval = get_system_info(dev);
  if (retval)
    return(retval);
  
  DBG((stderr,"Found %d %s %s CPU's at %f Mhz.\n",
       _papi_system_info.hw_info.totalcpus,
       _papi_system_info.hw_info.vendor_string,
       _papi_system_info.hw_info.model_string,
       _papi_system_info.hw_info.mhz));

#ifdef PERFCTR18
  vperfctr_close(dev);
#endif
  return(PAPI_OK);
}

int _papi_hwd_shutdown_global(void)
{
#ifndef PERFCTR18
  perfctr_dev_close(dev);
#endif
  return(PAPI_OK);
}

int _papi_hwd_init(EventSetInfo *zero)
{
  hwd_control_state_t *machdep = zero->machdep;
  
  /* Initialize our global machdep. */

#ifdef PERFCTR18
  if ((machdep->self = vperfctr_open()) == NULL) 
    return(PAPI_ESYS);
  DBG((stderr,"_papi_hwd_init dev=%p\n",machdep->self));
#else
  if ((machdep->self = vperfctr_attach(dev)) == NULL) 
    return(PAPI_ESYS);
#endif

  /* Initialize the event fields */

  init_config(zero->machdep);

  /* Start the TSC counter */
  if(vperfctr_control(machdep->self, &machdep->counter_cmd) < 0)
    return(PAPI_ESYS);

  return(PAPI_OK);
}

long long _papi_hwd_get_real_usec (void)
{
  long long cyc;

  cyc = get_cycles()*(unsigned long long)1000;
  cyc = cyc / (long long)_papi_system_info.hw_info.mhz;
  return(cyc / (long long)1000);
}

long long _papi_hwd_get_real_cycles (void)
{
  return(get_cycles());
}

long long _papi_hwd_get_virt_usec (EventSetInfo *zero)
{
  long long retval;
/*  struct tms buffer; */

  retval = _papi_hwd_get_virt_cycles(zero);
  retval = retval / _papi_system_info.hw_info.mhz;
  return(retval);

  /*
  times(&buffer);
  retval = (long long)buffer.tms_utime*(long long)(1000000/CLK_TCK);
  return(retval);
   */
}

long long _papi_hwd_get_virt_cycles (EventSetInfo *zero)
{
/* (NCSA change)
   Reverted back to prior version 2/2/02
*/
#ifdef PERFCTR16

  float usec, cyc;

  usec = (float)_papi_hwd_get_virt_usec(zero);
  cyc = usec * _papi_system_info.hw_info.mhz;
  return((long long)cyc);

#else
  unsigned long long lcyc;
  hwd_control_state_t *machdep = zero->machdep;
/*  float usec, cyc; */

  lcyc = vperfctr_read_tsc(machdep->self);
  DBG((stderr,"Read virt. cycles is %llu (%p -> %p)\n",lcyc,machdep,machdep->self));
  return(lcyc);
#endif
}

void _papi_hwd_error(int error, char *where)
{
  sprintf(where,"Substrate error: %s",strerror(error));
}

int _papi_hwd_add_event(hwd_control_state_t *this_state, unsigned int EventCode, EventInfo_t *out)
{
  int selector = 0;
  int avail = 0;
#ifdef PERFCTR20
  struct perfctr_cpu_control tmp_cmd, *codes;
#else
  struct perfctr_control tmp_cmd, *codes;
#endif

  if (EventCode & PRESET_MASK)
    { 
{'fraction_non_alphanumeric': 0.21524585292523904, 'fraction_numerical': 0.0860354140082854, 'mean_word_length': 4.097567495322107, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 165, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5588995', 'n_tokens_mistral': 29392, 'n_tokens_neox': 28404, 'n_words': 4019}