Addition of PAPI to RTS
[ghc.git] / rts / Papi.c
1
2
3 #include "Papi.h"
4 #include "Rts.h"
5 #include "RtsUtils.h"
6 #include "Stats.h"
7
8
9 /* These constants specify which events to keep track of.
10 * Probably it is better to count one set of events at a time.
11 * The reason is that processors have limited counters and
12 * multiplexing is not enabled (yet).
13 */
14 #define PAPI_COUNT_BRANCHES 0
15 /* The one below is Opteron specific.
16 */
17 #define PAPI_COUNT_STALLS 0
18 #define PAPI_COUNT_DCACHE1_MISSES 1
19 #define PAPI_COUNT_DCACHE2_MISSES 0
20
21 struct _papi_events {
22 int event_code;
23 char * event_name;
24 };
25
26 #define PAPI_ADD_EVENT(EVENT) { EVENT, #EVENT }
27
28 /* Beware, these counters are Opteron specific */
29 #define FR_BR 0x40000040
30 #define FR_BR_MIS 0x40000041
31 #define FR_BR_MISCOMPARE 0x40000048
32 #define DC_ACCESS 0x40000019
33 #define DC_MISS 0x4000001a
34 #define FR_DISPATCH_STALLS_BR 0x40000055
35 #define FR_DISPATCH_STALLS_FULL_LS 0x4000005b
36
37 /* Report the value of a counter */
38 #define PAPI_REPORT(EVENTSET,EVENT) \
39 { \
40 ullong_format_string(papi_counter(EVENTSET,EVENT),temp,rtsTrue/*commas*/); \
41 statsPrintf(" (" #EVENT ") : %s\n",temp); \
42 }
43
44 /* Report the value of a counter as a percentage of another counter */
45 #define PAPI_REPORT_PCT(EVENTSET,EVENT,EVENTTOT) \
46 statsPrintf(" (" #EVENT ") %% of (" #EVENTTOT ") : %.1f%%\n", \
47 papi_counter(EVENTSET,EVENT)*100.0/papi_counter(EVENTSET,EVENTTOT))
48
49 /* Number of counted events, computed from size of papi_events */
50 #define N_PAPI_EVENTS ((int)(sizeof(papi_events)/sizeof(struct _papi_events)))
51
52 /* This is bad, it should be in a header */
53 #define BIG_STRING_LEN 512
54
55 /* While PAPI reporting is going on this flag is on */
56 int papi_is_reporting;
57
58 /* Event sets and counter arrays for GC and mutator */
59
60 int MutatorEvents = PAPI_NULL;
61 int GCEvents = PAPI_NULL;
62
63 int papi_error;
64
65
66 /* If you want to add events to count, extend the
67 * papi_events array and the papi_report function.
68 */
69
70 /* Events counted during GC and Mutator execution */
71 /* There's a trailing comma, do all C compilers accept that? */
72 static struct _papi_events papi_events[] = {
73 PAPI_ADD_EVENT(PAPI_TOT_CYC),
74 #if PAPI_COUNT_BRANCHES
75 PAPI_ADD_EVENT(FR_BR),
76 PAPI_ADD_EVENT(FR_BR_MIS),
77 /* Docs are wrong? Opteron does not count indirect branch misses apparently */
78 PAPI_ADD_EVENT(FR_BR_MISCOMPARE),
79 #endif
80 #if PAPI_COUNT_STALLS
81 PAPI_ADD_EVENT(FR_DISPATCH_STALLS_BR),
82 PAPI_ADD_EVENT(FR_DISPATCH_STALLS_FULL_LS),
83 #endif
84 #if PAPI_COUNT_DCACHE1_MISSES
85 PAPI_ADD_EVENT(PAPI_L1_DCA),
86 PAPI_ADD_EVENT(PAPI_L1_DCM),
87 #endif
88 #if PAPI_COUNT_DCACHE2_MISSES
89 PAPI_ADD_EVENT(PAPI_L2_DCA),
90 PAPI_ADD_EVENT(PAPI_L2_DCM),
91 #endif
92 };
93
94 long_long MutatorCounters[N_PAPI_EVENTS];
95 long_long GCCounters[N_PAPI_EVENTS];
96
97
98 /* Extract the value corresponding to an event */
99 long_long
100 papi_counter(long_long values[],int event)
101 {
102 int i;
103 for(i=0;i<N_PAPI_EVENTS;i++) {
104 if(papi_events[i].event_code==event) {
105 return values[i];
106 }
107 }
108 /* Passed a wrong event? */
109 debugBelch("Event %d is not part of event set\n",event);
110 return 0;
111 }
112
113 /* This function reports counters for GC and mutator */
114 void
115 papi_report(long_long PapiCounters[])
116 {
117 char temp[BIG_STRING_LEN];
118
119 /* I need to improve formatting aesthetics */
120 PAPI_REPORT(PapiCounters,PAPI_TOT_CYC);
121 #if PAPI_COUNT_BRANCHES
122 PAPI_REPORT(PapiCounters,FR_BR);
123 PAPI_REPORT(PapiCounters,FR_BR_MIS);
124 PAPI_REPORT_PCT(PapiCounters,FR_BR_MIS,FR_BR);
125 PAPI_REPORT_PCT(PapiCounters,FR_BR_MISCOMPARE,FR_BR);
126 #endif
127 #if PAPI_COUNT_STALLS
128 PAPI_REPORT(PapiCounters,FR_DISPATCH_STALLS_BR);
129 PAPI_REPORT_PCT(PapiCounters,FR_DISPATCH_STALLS_BR,PAPI_TOT_CYC);
130 PAPI_REPORT(PapiCounters,FR_DISPATCH_STALLS_FULL_LS);
131 PAPI_REPORT_PCT(PapiCounters,FR_DISPATCH_STALLS_FULL_LS,PAPI_TOT_CYC);
132 #endif
133 #if PAPI_COUNT_DCACHE1_MISSES
134 PAPI_REPORT(PapiCounters,PAPI_L1_DCA);
135 PAPI_REPORT(PapiCounters,PAPI_L1_DCM);
136 PAPI_REPORT_PCT(PapiCounters,PAPI_L1_DCM,PAPI_L1_DCA);
137 #endif
138 #if PAPI_COUNT_DCACHE2_MISSES
139 PAPI_REPORT(PapiCounters,PAPI_L2_DCA);
140 PAPI_REPORT(PapiCounters,PAPI_L2_DCM);
141 PAPI_REPORT_PCT(PapiCounters,PAPI_L2_DCM,PAPI_L2_DCA);
142 #endif
143 }
144
145 /* Add the events of papi_events into an event set */
146 void
147 papi_add_events(int EventSet)
148 {
149 int i;
150 for(i=0;i<N_PAPI_EVENTS;i++) {
151 if((papi_error=PAPI_add_event(EventSet,
152 papi_events[i].event_code))
153 != PAPI_OK)
154 debugBelch("Failed adding %s to event set with error code %d\n",
155 papi_events[i].event_name,papi_error);
156 }
157 }
158
159 void
160 papi_init_eventsets(void)
161 {
162
163 /* One event set for the mutator and another for the GC */
164 PAPI_CHECK( PAPI_create_eventset(&MutatorEvents));
165 PAPI_CHECK( PAPI_create_eventset(&GCEvents));
166
167 /* Both sets contain the same events */
168 papi_add_events(MutatorEvents);
169 papi_add_events(GCEvents);
170
171 }
172
173 void
174 papi_start_mutator_count(void)
175 {
176 PAPI_CHECK( PAPI_start(MutatorEvents));
177 }
178
179 void
180 papi_stop_mutator_count(void)
181 {
182 PAPI_CHECK( PAPI_accum(MutatorEvents,MutatorCounters));
183 PAPI_CHECK( PAPI_stop(MutatorEvents,NULL));
184 }
185
186 void
187 papi_start_gc_count(void)
188 {
189 PAPI_CHECK( PAPI_start(GCEvents));
190 }
191
192 void
193 papi_stop_gc_count(void)
194 {
195 PAPI_CHECK( PAPI_accum(GCEvents,GCCounters));
196 PAPI_CHECK( PAPI_stop(GCEvents,NULL));
197 }