5b4f7852db948d1fb4785101706486e0b283c376
[ghc-hetmet.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 */