+#define DC_L2_REFILL_MOES 0x40001e1b
+#define DC_SYS_REFILL_MOES 0x40001e1c
+
+/* This is bad, it should be in a header */
+#define BIG_STRING_LEN 512
+
+
+#define PAPI_CHECK(CALL) \
+ if((papi_error=(CALL)) != PAPI_OK) { \
+ debugBelch("PAPI function failed in module %s at line %d with error code %d\n", \
+ __FILE__,__LINE__,papi_error); \
+ }
+
+/* While PAPI reporting is going on this flag is on */
+int papi_is_reporting;
+
+/* Event sets and counter arrays for GC and mutator */
+
+int MutatorEvents = PAPI_NULL;
+int GCEvents = PAPI_NULL;
+
+int papi_error;
+
+/* Arbitrary, to avoid using malloc */
+#define MAX_PAPI_EVENTS 10
+
+int n_papi_events = 0;
+
+
+/* Events counted during GC and Mutator execution */
+/* There's a trailing comma, do all C compilers accept that? */
+static struct _papi_events papi_events[MAX_PAPI_EVENTS];
+long_long MutatorCounters[MAX_PAPI_EVENTS];
+long_long GCCounters[MAX_PAPI_EVENTS];
+
+long_long start_mutator_cycles;
+long_long start_gc_cycles;
+long_long mutator_cycles;
+long_long gc_cycles;
+
+
+
+static long_long papi_counter(long_long values[],int event);
+static void papi_add_events(int EventSet);
+
+/* If you want to add events to count, extend the
+ * init_countable_events and the papi_report function.
+ * Be aware that your processor can count a limited number
+ * of events simultaneously, you can turn on multiplexing
+ * to increase that number, though.
+ */
+static void
+init_countable_events(void)
+{
+#define PAPI_ADD_EVENT(EVENT) \
+ { \
+ if (n_papi_events >= MAX_PAPI_EVENTS) { \
+ barf("too many PAPI events"); \
+ } \
+ papi_events[n_papi_events].event_code = EVENT; \
+ papi_events[n_papi_events].event_name = #EVENT; \
+ n_papi_events++; \
+ }
+
+ PAPI_ADD_EVENT(PAPI_TOT_INS);
+ if (RtsFlags.PapiFlags.eventType==PAPI_FLAG_BRANCH) {
+ PAPI_ADD_EVENT(FR_BR);
+ PAPI_ADD_EVENT(FR_BR_MIS);
+ /* Docs are wrong? Opteron does not count indirect branch misses exclusively */
+ PAPI_ADD_EVENT(FR_BR_MISCOMPARE);
+ } else if (RtsFlags.PapiFlags.eventType==PAPI_FLAG_STALLS) {
+ PAPI_ADD_EVENT(FR_DISPATCH_STALLS);
+ PAPI_ADD_EVENT(FR_DISPATCH_STALLS_BR);
+ PAPI_ADD_EVENT(FR_DISPATCH_STALLS_FULL_LS);
+ } else if (RtsFlags.PapiFlags.eventType==PAPI_FLAG_CACHE_L1) {
+ PAPI_ADD_EVENT(PAPI_L1_DCA);
+ PAPI_ADD_EVENT(PAPI_L1_DCM);
+ } else if (RtsFlags.PapiFlags.eventType==PAPI_FLAG_CACHE_L2) {
+ PAPI_ADD_EVENT(PAPI_L2_DCA);
+ PAPI_ADD_EVENT(PAPI_L2_DCM);
+ } else if (RtsFlags.PapiFlags.eventType==PAPI_FLAG_CB_EVENTS) {
+ PAPI_ADD_EVENT(DC_L2_REFILL_MOES);
+ PAPI_ADD_EVENT(DC_SYS_REFILL_MOES);
+ PAPI_ADD_EVENT(FR_BR_MIS);
+ } else {
+ PAPI_ADD_EVENT(PAPI_STL_ICY);
+ }
+
+ // We might also consider:
+ // PAPI_BR_MSP Conditional branch instructions mispredicted
+ // PAPI_RES_STL Cycles stalled on any resource
+};
+
+
+static char temp[BIG_STRING_LEN];
+
+void
+papi_mut_cycles()
+{
+ ullong_format_string(mutator_cycles,temp,rtsTrue/*commas*/);
+ statsPrintf(" (MUT_CYCLES) : %s\n",temp);
+}
+
+void
+papi_gc_cycles()
+{
+ ullong_format_string(gc_cycles,temp,rtsTrue/*commas*/);
+ statsPrintf(" (GC_CYCLES) : %s\n",temp);
+}
+
+/* This function reports counters for GC and mutator */
+static void
+papi_report(long_long PapiCounters[])
+{