parlib: Fix the use-after-func issue
[akaros.git] / user / perfmon / pfmlib_intel_nhm_unc.c
1 /*
2  * pfmlib_intel_nhm_unc.c : Intel Nehalem/Westmere uncore PMU
3  *
4  * Copyright (c) 2008 Google, Inc
5  * Contributed by Stephane Eranian <eranian@gmail.com>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11  * of the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
18  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
19  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
22  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include <sys/types.h>
25 #include <ctype.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29
30 /* private headers */
31 #include "pfmlib_priv.h"
32 #include "pfmlib_intel_x86_priv.h"
33
34 #define NHM_UNC_ATTR_E  0
35 #define NHM_UNC_ATTR_I  1
36 #define NHM_UNC_ATTR_C  2
37 #define NHM_UNC_ATTR_O  3
38
39 #define _NHM_UNC_ATTR_I  (1 << NHM_UNC_ATTR_I)
40 #define _NHM_UNC_ATTR_E  (1 << NHM_UNC_ATTR_E)
41 #define _NHM_UNC_ATTR_C  (1 << NHM_UNC_ATTR_C)
42 #define _NHM_UNC_ATTR_O  (1 << NHM_UNC_ATTR_O)
43
44 #define NHM_UNC_ATTRS \
45         (_NHM_UNC_ATTR_I|_NHM_UNC_ATTR_E|_NHM_UNC_ATTR_C|_NHM_UNC_ATTR_O)
46
47 #define NHM_UNC_MOD_OCC_BIT     17
48 #define NHM_UNC_MOD_EDGE_BIT    18
49 #define NHM_UNC_MOD_INV_BIT     23
50 #define NHM_UNC_MOD_CMASK_BIT   24
51
52 #define NHM_UNC_MOD_OCC         (1 << NHM_UNC_MOD_OCC_BIT)
53 #define NHM_UNC_MOD_EDGE        (1 << NHM_UNC_MOD_EDGE_BIT)
54 #define NHM_UNC_MOD_INV         (1 << NHM_UNC_MOD_INV_BIT)
55
56 /* Intel Nehalem/Westmere uncore event table */
57 #include "events/intel_nhm_unc_events.h"
58 #include "events/intel_wsm_unc_events.h"
59
60 static const pfmlib_attr_desc_t nhm_unc_mods[]={
61         PFM_ATTR_B("e", "edge level"),                          /* edge */
62         PFM_ATTR_B("i", "invert"),                              /* invert */
63         PFM_ATTR_I("c", "counter-mask in range [0-255]"),       /* counter-mask */
64         PFM_ATTR_B("o", "queue occupancy"),                     /* queue occupancy */
65         PFM_ATTR_NULL
66 };
67
68 static const int nhm_models[] = {
69         26,
70         30,
71         31,
72         0
73 };
74
75 static const int wsm_dp_models[] = {
76         44, /* Westmere-EP, Gulftown */
77         47, /* Westmere E7 */
78         0,
79 };
80
81 static int
82 pfm_nhm_unc_get_encoding(void *this, pfmlib_event_desc_t *e)
83 {
84         pfm_intel_x86_reg_t reg;
85         pfm_event_attr_info_t *a;
86         const intel_x86_entry_t *pe = this_pe(this);
87         unsigned int grpmsk, ugrpmsk = 0;
88         int umodmsk = 0, modmsk_r = 0;
89         uint64_t val;
90         uint64_t umask;
91         unsigned int modhw = 0;
92         int k, ret, grpid, last_grpid = -1;
93         int grpcounts[INTEL_X86_NUM_GRP];
94         int ncombo[INTEL_X86_NUM_GRP];
95         char umask_str[PFMLIB_EVT_MAX_NAME_LEN];
96
97         memset(grpcounts, 0, sizeof(grpcounts));
98         memset(ncombo, 0, sizeof(ncombo));
99
100         pe = this_pe(this);
101         umask_str[0] = e->fstr[0] = '\0';
102
103         reg.val = 0;
104
105         val = pe[e->event].code;
106
107         grpmsk = (1 << pe[e->event].ngrp)-1;
108         reg.val |= val; /* preset some filters from code */
109
110         /* take into account hardcoded umask */
111         umask = (val >> 8) & 0xff;
112
113         modmsk_r = pe[e->event].modmsk_req;
114
115         for(k=0; k < e->nattrs; k++) {
116                 a = attr(e, k);
117
118                 if (a->ctrl != PFM_ATTR_CTRL_PMU)
119                         continue;
120
121                 if (a->type == PFM_ATTR_UMASK) {
122                         grpid = pe[e->event].umasks[a->idx].grpid;
123
124                         /*
125                          * cfor certain events groups are meant to be
126                          * exclusive, i.e., only unit masks of one group
127                          * can be used
128                          */
129                         if (last_grpid != -1 && grpid != last_grpid
130                             && intel_x86_eflag(this, e->event, INTEL_X86_GRP_EXCL)) {
131                                 DPRINT("exclusive unit mask group error\n");
132                                 return PFM_ERR_FEATCOMB;
133                         }
134                         /*
135                          * upper layer has removed duplicates
136                          * so if we come here more than once, it is for two
137                          * disinct umasks
138                          *
139                          * NCOMBO=no combination of unit masks within the same
140                          * umask group
141                          */
142                         ++grpcounts[grpid];
143
144                         if (intel_x86_uflag(this, e->event, a->idx, INTEL_X86_NCOMBO))
145                                 ncombo[grpid] = 1;
146
147                         if (grpcounts[grpid] > 1 && ncombo[grpid])  {
148                                 DPRINT("event does not support unit mask combination within a group\n");
149                                 return PFM_ERR_FEATCOMB;
150                         }
151
152                         evt_strcat(umask_str, ":%s", pe[e->event].umasks[a->idx].uname);
153
154                         last_grpid = grpid;
155                         modhw    |= pe[e->event].umasks[a->idx].modhw;
156                         umask    |= pe[e->event].umasks[a->idx].ucode >> 8;
157                         ugrpmsk  |= 1 << pe[e->event].umasks[a->idx].grpid;
158
159                         reg.val |= umask << 8;
160
161                         modmsk_r |= pe[e->event].umasks[a->idx].umodmsk_req;
162
163                 } else if (a->type == PFM_ATTR_RAW_UMASK) {
164
165                         /* there can only be one RAW_UMASK per event */
166
167                         /* sanity check */
168                         if (a->idx & ~0xff) {
169                                 DPRINT("raw umask is 8-bit wide\n");
170                                 return PFM_ERR_ATTR;
171                         }
172                         /* override umask */
173                         umask = a->idx & 0xff;
174                         ugrpmsk = grpmsk;
175                 } else {
176                         uint64_t ival = e->attrs[k].ival;
177                         switch(a->idx) {
178                                 case NHM_UNC_ATTR_I: /* invert */
179                                         reg.nhm_unc.usel_inv = !!ival;
180                                         umodmsk |= _NHM_UNC_ATTR_I;
181                                         break;
182                                 case NHM_UNC_ATTR_E: /* edge */
183                                         reg.nhm_unc.usel_edge = !!ival;
184                                         umodmsk |= _NHM_UNC_ATTR_E;
185                                         break;
186                                 case NHM_UNC_ATTR_C: /* counter-mask */
187                                         /* already forced, cannot overwrite */
188                                         if (ival > 255)
189                                                 return PFM_ERR_INVAL;
190                                         reg.nhm_unc.usel_cnt_mask = ival;
191                                         umodmsk |= _NHM_UNC_ATTR_C;
192                                         break;
193                                 case NHM_UNC_ATTR_O: /* occupancy */
194                                         reg.nhm_unc.usel_occ = !!ival;
195                                         umodmsk |= _NHM_UNC_ATTR_O;
196                                         break;
197                         }
198                 }
199         }
200
201         if ((modhw & _NHM_UNC_ATTR_I) && reg.nhm_unc.usel_inv)
202                 return PFM_ERR_ATTR_SET;
203         if ((modhw & _NHM_UNC_ATTR_E) && reg.nhm_unc.usel_edge)
204                 return PFM_ERR_ATTR_SET;
205         if ((modhw & _NHM_UNC_ATTR_C) && reg.nhm_unc.usel_cnt_mask)
206                 return PFM_ERR_ATTR_SET;
207         if ((modhw & _NHM_UNC_ATTR_O) && reg.nhm_unc.usel_occ)
208                 return PFM_ERR_ATTR_SET;
209
210         /*
211          * check that there is at least of unit mask in each unit
212          * mask group
213          */
214         if ((ugrpmsk != grpmsk && !intel_x86_eflag(this, e->event, INTEL_X86_GRP_EXCL)) || ugrpmsk == 0) {
215                 ugrpmsk ^= grpmsk;
216                 ret = pfm_intel_x86_add_defaults(this, e, ugrpmsk, &umask, -1);
217                 if (ret != PFM_SUCCESS)
218                         return ret;
219         }
220
221         if (modmsk_r && (umodmsk ^ modmsk_r)) {
222                 DPRINT("required modifiers missing: 0x%x\n", modmsk_r);
223                 return PFM_ERR_ATTR;
224         }
225
226         evt_strcat(e->fstr, "%s", pe[e->event].name);
227         pfmlib_sort_attr(e);
228         for(k=0; k < e->nattrs; k++) {
229                 a = attr(e, k);
230                 if (a->ctrl != PFM_ATTR_CTRL_PMU)
231                         continue;
232                 if (a->type == PFM_ATTR_UMASK)
233                         evt_strcat(e->fstr, ":%s", pe[e->event].umasks[a->idx].uname);
234                 else if (a->type == PFM_ATTR_RAW_UMASK)
235                         evt_strcat(e->fstr, ":0x%x", a->idx);
236         }
237
238         reg.val |= umask << 8;
239
240         reg.nhm_unc.usel_en    = 1; /* force enable bit to 1 */
241         reg.nhm_unc.usel_int   = 1; /* force APIC int to 1 */
242
243         e->codes[0] = reg.val;
244         e->count = 1;
245
246         for (k = 0; k < e->npattrs; k++) {
247                 int idx;
248
249                 if (e->pattrs[k].ctrl != PFM_ATTR_CTRL_PMU)
250                         continue;
251
252                 if (e->pattrs[k].type == PFM_ATTR_UMASK)
253                         continue;
254
255                 idx = e->pattrs[k].idx;
256                 switch(idx) {
257                 case NHM_UNC_ATTR_E:
258                         evt_strcat(e->fstr, ":%s=%lu", nhm_unc_mods[idx].name, reg.nhm_unc.usel_edge);
259                         break;
260                 case NHM_UNC_ATTR_I:
261                         evt_strcat(e->fstr, ":%s=%lu", nhm_unc_mods[idx].name, reg.nhm_unc.usel_inv);
262                         break;
263                 case NHM_UNC_ATTR_C:
264                         evt_strcat(e->fstr, ":%s=%lu", nhm_unc_mods[idx].name, reg.nhm_unc.usel_cnt_mask);
265                         break;
266                 case NHM_UNC_ATTR_O:
267                         evt_strcat(e->fstr, ":%s=%lu", nhm_unc_mods[idx].name, reg.nhm_unc.usel_occ);
268                         break;
269                 }
270         }
271         __pfm_vbprintf("[UNC_PERFEVTSEL=0x%"PRIx64" event=0x%x umask=0x%x en=%d int=%d inv=%d edge=%d occ=%d cnt_msk=%d] %s\n",
272                 reg.val,
273                 reg.nhm_unc.usel_event,
274                 reg.nhm_unc.usel_umask,
275                 reg.nhm_unc.usel_en,
276                 reg.nhm_unc.usel_int,
277                 reg.nhm_unc.usel_inv,
278                 reg.nhm_unc.usel_edge,
279                 reg.nhm_unc.usel_occ,
280                 reg.nhm_unc.usel_cnt_mask,
281                 pe[e->event].name);
282
283         return PFM_SUCCESS;
284 }
285
286 pfmlib_pmu_t intel_nhm_unc_support={
287         .desc                   = "Intel Nehalem uncore",
288         .name                   = "nhm_unc",
289         .perf_name              = "uncore",
290
291         .pmu                    = PFM_PMU_INTEL_NHM_UNC,
292         .pme_count              = LIBPFM_ARRAY_SIZE(intel_nhm_unc_pe),
293         .type                   = PFM_PMU_TYPE_UNCORE,
294         .num_cntrs              = 8,
295         .num_fixed_cntrs        = 1,
296         .max_encoding           = 1,
297         .pe                     = intel_nhm_unc_pe,
298         .atdesc                 = nhm_unc_mods,
299         .flags                  = PFMLIB_PMU_FL_RAW_UMASK,
300
301         .cpu_family             = 6,
302         .cpu_models             = nhm_models,
303         .pmu_detect             = pfm_intel_x86_model_detect,
304
305         .get_event_encoding[PFM_OS_NONE] = pfm_nhm_unc_get_encoding,
306          PFMLIB_ENCODE_PERF(pfm_intel_nhm_unc_get_perf_encoding),
307
308         .get_event_first        = pfm_intel_x86_get_event_first,
309         .get_event_next         = pfm_intel_x86_get_event_next,
310         .event_is_valid         = pfm_intel_x86_event_is_valid,
311         .validate_table         = pfm_intel_x86_validate_table,
312         .get_event_info         = pfm_intel_x86_get_event_info,
313         .get_event_attr_info    = pfm_intel_x86_get_event_attr_info,
314         PFMLIB_VALID_PERF_PATTRS(pfm_intel_x86_perf_validate_pattrs),
315         .get_event_nattrs       = pfm_intel_x86_get_event_nattrs,
316 };
317
318 pfmlib_pmu_t intel_wsm_unc_support={
319         .desc                   = "Intel Westmere uncore",
320         .name                   = "wsm_unc",
321         .perf_name              = "uncore",
322
323         .pmu                    = PFM_PMU_INTEL_WSM_UNC,
324         .pme_count              = LIBPFM_ARRAY_SIZE(intel_wsm_unc_pe),
325         .type                   = PFM_PMU_TYPE_UNCORE,
326         .num_cntrs              = 8,
327         .num_fixed_cntrs        = 1,
328         .max_encoding           = 1,
329         .pe                     = intel_wsm_unc_pe,
330         .atdesc                 = nhm_unc_mods,
331         .flags                  = PFMLIB_PMU_FL_RAW_UMASK,
332
333         .cpu_family             = 6,
334         .cpu_models             = wsm_dp_models,
335         .pmu_detect             = pfm_intel_x86_model_detect,
336
337         .get_event_encoding[PFM_OS_NONE] = pfm_nhm_unc_get_encoding,
338          PFMLIB_ENCODE_PERF(pfm_intel_nhm_unc_get_perf_encoding),
339
340         .get_event_first        = pfm_intel_x86_get_event_first,
341         .get_event_next         = pfm_intel_x86_get_event_next,
342         .event_is_valid         = pfm_intel_x86_event_is_valid,
343         .validate_table         = pfm_intel_x86_validate_table,
344         .get_event_info         = pfm_intel_x86_get_event_info,
345         .get_event_attr_info    = pfm_intel_x86_get_event_attr_info,
346         PFMLIB_VALID_PERF_PATTRS(pfm_intel_x86_perf_validate_pattrs),
347         .get_event_nattrs       = pfm_intel_x86_get_event_nattrs,
348 };