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