radix: Implement radix_tree_destroy()
[akaros.git] / user / perfmon / pfmlib_intel_netburst.c
1 /*
2  * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P.
3  * Copyright (c) 2006 IBM Corp.
4  * Contributed by Kevin Corry <kevcorry@us.ibm.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  *
24  * pfmlib_intel_netburst.c
25  *
26  * Support for the Pentium4/Xeon/EM64T processor family (family=15).
27  */
28 /* private headers */
29 #include "pfmlib_priv.h"
30 #include "pfmlib_intel_netburst_priv.h"
31 #include "pfmlib_intel_x86_priv.h"
32 #include "events/intel_netburst_events.h"
33
34 const pfmlib_attr_desc_t netburst_mods[]={
35         PFM_ATTR_B("u", "monitor at priv level 1, 2, 3"),       /* monitor priv level 1, 2, 3 */
36         PFM_ATTR_B("k", "monitor at priv level 0"),             /* monitor priv level 0 */
37         PFM_ATTR_B("cmpl", "complement"),                       /* set: <=, clear: > */
38         PFM_ATTR_B("e", "edge"),                                /* edge */
39         PFM_ATTR_I("thr", "event threshold in range [0-15]"),   /* threshold */
40 };
41 #define NETBURST_MODS_COUNT (sizeof(netburst_mods)/sizeof(pfmlib_attr_desc_t))
42
43
44 extern pfmlib_pmu_t netburst_support;
45
46 static inline int
47 netburst_get_numasks(int pidx)
48 {
49         int i = 0;
50         /*
51          * name = NULL is end-marker
52          */
53         while (netburst_events[pidx].event_masks[i].name)
54                 i++;
55         return i;
56 }
57
58 static void
59 netburst_display_reg(pfmlib_event_desc_t *e)
60 {
61         netburst_escr_value_t escr;
62         netburst_cccr_value_t cccr;
63
64         escr.val = e->codes[0];
65         cccr.val = e->codes[1];
66
67         __pfm_vbprintf("[0x%"PRIx64" 0x%"PRIx64" 0x%"PRIx64" usr=%d os=%d tag_ena=%d tag_val=%d "
68                        "evmask=0x%x evsel=0x%x escr_sel=0x%x comp=%d cmpl=%d thr=%d e=%d",
69                         escr,
70                         cccr,
71                         e->codes[2], /* perf_event code */
72                         escr.bits.t0_usr, /* t1 is identical */
73                         escr.bits.t0_os,  /* t1 is identical */
74                         escr.bits.tag_enable,
75                         escr.bits.tag_value,
76                         escr.bits.event_mask,
77                         escr.bits.event_select,
78                         cccr.bits.escr_select,
79                         cccr.bits.compare,
80                         cccr.bits.complement,
81                         cccr.bits.threshold,
82                         cccr.bits.edge);
83
84         __pfm_vbprintf("] %s\n", e->fstr);
85 }
86
87 static int
88 netburst_add_defaults(pfmlib_event_desc_t *e, unsigned int *evmask)
89 {
90         int i, n;
91
92         n = netburst_get_numasks(e->event);
93
94         for (i = 0; i < n; i++) {
95
96                 if (netburst_events[e->event].event_masks[i].flags & NETBURST_FL_DFL)
97                         goto found;
98         }
99         return PFM_ERR_ATTR;
100 found:
101         *evmask = 1 << netburst_events[e->event].event_masks[i].bit;
102         n = e->nattrs;
103         e->attrs[n].id = i;
104         e->attrs[n].ival = i;
105         e->nattrs = n+1;
106
107         return PFM_SUCCESS;
108 }
109
110 int
111 pfm_netburst_get_encoding(void *this, pfmlib_event_desc_t *e)
112 {
113         pfm_event_attr_info_t *a;
114         netburst_escr_value_t escr;
115         netburst_cccr_value_t cccr;
116         unsigned int evmask = 0;
117         unsigned int plmmsk = 0;
118         int umask_done = 0;
119         const char *n;
120         int k, id, bit, ret;
121         int tag_enable = 0, tag_value = 0;
122
123         e->fstr[0] = '\0';
124
125         escr.val = 0;
126         cccr.val = 0;
127
128         for(k=0; k < e->nattrs; k++) {
129                 a = attr(e, k);
130
131                 if (a->ctrl != PFM_ATTR_CTRL_PMU)
132                         continue;
133
134                 if (a->type == PFM_ATTR_UMASK) {
135
136                         bit = netburst_events[e->event].event_masks[a->idx].bit;
137                         n   = netburst_events[e->event].event_masks[a->idx].name;
138                         /*
139                          * umask combination seems possible, although it does
140                          * not always make sense, e.g., BOGUS vs. NBOGUS
141                          */
142                         if (bit < EVENT_MASK_BITS && n) {
143                                 evmask |= (1 << bit);
144                         } else  if (bit >= EVENT_MASK_BITS && n) {
145                                 tag_value |= (1 << (bit - EVENT_MASK_BITS));
146                                 tag_enable = 1;
147                         }
148                         umask_done = 1;
149                 } else if (a->type == PFM_ATTR_RAW_UMASK) {
150                         /* should not happen */
151                         return PFM_ERR_ATTR;
152                 } else {
153                         uint64_t ival = e->attrs[k].ival;
154                         switch (a->idx) {
155                         case NETBURST_ATTR_U:
156                                 escr.bits.t1_usr = !!ival;
157                                 escr.bits.t0_usr = !!ival;
158                                 plmmsk |= _NETBURST_ATTR_U;
159                                 break;
160                         case NETBURST_ATTR_K:
161                                 escr.bits.t1_os = !!ival;
162                                 escr.bits.t0_os = !!ival;
163                                 plmmsk |= _NETBURST_ATTR_K;
164                                 break;
165                         case NETBURST_ATTR_E:
166                                 if (ival) {
167                                         cccr.bits.compare = 1;
168                                         cccr.bits.edge = 1;
169                                 }
170                                 break;
171                         case NETBURST_ATTR_C:
172                                 if (ival) {
173                                         cccr.bits.compare = 1;
174                                         cccr.bits.complement = 1;
175                                 }
176                                 break;
177                         case NETBURST_ATTR_T:
178                                 if (ival > 15)
179                                         return PFM_ERR_ATTR_VAL;
180
181                                 if (ival) {
182                                         cccr.bits.compare = 1;
183                                         cccr.bits.threshold = ival;
184                                 }
185                                 break;
186                         default:
187                                 return PFM_ERR_ATTR;
188                         }
189                 }
190         }
191         /*
192          * handle case where no priv level mask was passed.
193          * then we use the dfl_plm
194          */
195         if (!(plmmsk & (_NETBURST_ATTR_K|_NETBURST_ATTR_U))) {
196                 if (e->dfl_plm & PFM_PLM0) {
197                         escr.bits.t1_os = 1;
198                         escr.bits.t0_os = 1;
199                 }
200                 if (e->dfl_plm & PFM_PLM3) {
201                         escr.bits.t1_usr = 1;
202                         escr.bits.t0_usr = 1;
203                 }
204         }
205
206         if (!umask_done) {
207                 ret = netburst_add_defaults(e, &evmask);
208                 if (ret != PFM_SUCCESS)
209                         return ret;
210         }
211
212         escr.bits.tag_enable   = tag_enable;
213         escr.bits.tag_value    = tag_value;
214         escr.bits.event_mask   = evmask;
215         escr.bits.event_select = netburst_events[e->event].event_select;
216
217
218         cccr.bits.enable        = 1;
219         cccr.bits.escr_select   = netburst_events[e->event].escr_select;
220         cccr.bits.active_thread = 3;
221
222         if (e->event == PME_REPLAY_EVENT)
223                 escr.bits.event_mask &= P4_REPLAY_REAL_MASK;     /* remove virtual mask bits */
224
225         /*
226          * reorder all the attributes such that the fstr appears always
227          * the same regardless of how the attributes were submitted.
228          */
229         evt_strcat(e->fstr, "%s", netburst_events[e->event].name);
230         pfmlib_sort_attr(e);
231         for(k=0; k < e->nattrs; k++) {
232                 a = attr(e, k);
233                 if (a->ctrl != PFM_ATTR_CTRL_PMU)
234                         continue;
235                 if (a->type == PFM_ATTR_UMASK) {
236                         id = e->attrs[k].id;
237                         evt_strcat(e->fstr, ":%s", netburst_events[e->event].event_masks[id].name);
238                 }
239         }
240
241         evt_strcat(e->fstr, ":%s=%lu", netburst_mods[NETBURST_ATTR_K].name, escr.bits.t0_os);
242         evt_strcat(e->fstr, ":%s=%lu", netburst_mods[NETBURST_ATTR_U].name, escr.bits.t0_usr);
243         evt_strcat(e->fstr, ":%s=%lu", netburst_mods[NETBURST_ATTR_E].name, cccr.bits.edge);
244         evt_strcat(e->fstr, ":%s=%lu", netburst_mods[NETBURST_ATTR_C].name, cccr.bits.complement);
245         evt_strcat(e->fstr, ":%s=%lu", netburst_mods[NETBURST_ATTR_T].name, cccr.bits.threshold);
246
247         e->count = 2;
248         e->codes[0] = escr.val;
249         e->codes[1] = cccr.val;
250
251         netburst_display_reg(e);
252
253         return PFM_SUCCESS;
254 }
255
256 static int
257 pfm_netburst_detect(void *this)
258 {
259         int ret;
260         int model;
261
262         ret = pfm_intel_x86_detect();
263         if (ret != PFM_SUCCESS)
264                 return ret;
265
266         if (pfm_intel_x86_cfg.family != 15)
267                 return PFM_ERR_NOTSUPP;
268
269         model = pfm_intel_x86_cfg.model;
270         if (model == 3 || model == 4 || model == 6)
271                 return PFM_ERR_NOTSUPP;
272
273         return PFM_SUCCESS;
274 }
275
276 static int
277 pfm_netburst_detect_prescott(void *this)
278 {
279         int ret;
280         int model;
281
282         ret = pfm_intel_x86_detect();
283         if (ret != PFM_SUCCESS)
284                 return ret;
285
286         if (pfm_intel_x86_cfg.family != 15)
287                 return PFM_ERR_NOTSUPP;
288
289         /*
290          * prescott has one more event (instr_completed)
291          */
292         model = pfm_intel_x86_cfg.model;
293         if (model != 3 && model != 4 && model != 6)
294                 return PFM_ERR_NOTSUPP;
295
296         return PFM_SUCCESS;
297 }
298
299 static int
300 pfm_netburst_get_event_first(void *this)
301 {
302         pfmlib_pmu_t *p = this;
303         return p->pme_count ? 0 : -1;
304 }
305
306 static int
307 pfm_netburst_get_event_next(void *this, int idx)
308 {
309         pfmlib_pmu_t *p = this;
310
311         if (idx >= (p->pme_count-1))
312                 return -1;
313
314         return idx+1;
315 }
316
317 static int
318 pfm_netburst_event_is_valid(void *this, int pidx)
319 {
320         pfmlib_pmu_t *p = this;
321         return pidx >= 0 && pidx < p->pme_count;
322 }
323
324 static int
325 pfm_netburst_get_event_attr_info(void *this, int pidx, int attr_idx, pfm_event_attr_info_t *info)
326 {
327         const netburst_entry_t *pe = this_pe(this);
328         int numasks, idx;
329
330         numasks = netburst_get_numasks(pidx);
331         if (attr_idx < numasks) {
332                 //idx = pfm_intel_x86_attr2umask(this, pidx, attr_idx);
333                 idx = attr_idx;
334                 info->name = pe[pidx].event_masks[idx].name;
335                 info->desc = pe[pidx].event_masks[idx].desc;
336                 info->equiv= NULL;
337                 info->code = pe[pidx].event_masks[idx].bit;
338                 info->type = PFM_ATTR_UMASK;
339                 info->is_dfl = !!(pe[pidx].event_masks[idx].flags & NETBURST_FL_DFL);
340         } else {
341                 idx = attr_idx - numasks;
342                 info->name = netburst_mods[idx].name;
343                 info->desc = netburst_mods[idx].desc;
344                 info->equiv= NULL;
345                 info->code = idx;
346                 info->type = netburst_mods[idx].type;
347                 info->is_dfl = 0;
348         }
349         info->ctrl = PFM_ATTR_CTRL_PMU;
350         info->idx = idx; /* namespace specific index */
351         info->dfl_val64 = 0;
352
353         return PFM_SUCCESS;
354 }
355
356 static int
357 pfm_netburst_get_event_info(void *this, int idx, pfm_event_info_t *info)
358 {
359         const netburst_entry_t *pe = this_pe(this);
360         pfmlib_pmu_t *pmu = this;
361
362         /*
363          * pmu and idx filled out by caller
364          */
365         info->name  = pe[idx].name;
366         info->desc  = pe[idx].desc;
367         info->code  = pe[idx].event_select | (pe[idx].escr_select << 8);
368         info->equiv = NULL;
369         info->idx   = idx; /* private index */
370         info->pmu   = pmu->pmu;
371
372         info->nattrs  = netburst_get_numasks(idx);
373         info->nattrs += NETBURST_MODS_COUNT;
374
375         return PFM_SUCCESS;
376 }
377
378 static int
379 pfm_netburst_validate_table(void *this, FILE *fp)
380 {
381         pfmlib_pmu_t *pmu = this;
382         const netburst_entry_t *pe = netburst_events;
383         const char *name =  pmu->name;
384         int i, j, noname, ndfl;
385         int error = 0;
386
387         for(i=0; i < pmu->pme_count; i++) {
388
389                 if (!pe[i].name) {
390                         fprintf(fp, "pmu: %s event%d: :: no name (prev event was %s)\n", pmu->name, i,
391                         i > 1 ? pe[i-1].name : "??");
392                         error++;
393                 }
394
395                 if (!pe[i].desc) {
396                         fprintf(fp, "pmu: %s event%d: %s :: no description\n", name, i, pe[i].name);
397                         error++;
398                 }
399
400                 noname = ndfl = 0;
401
402                 /* name = NULL is end-marker, veryfy there is at least one */
403                 for(j= 0; j < EVENT_MASK_BITS; j++) {
404
405                         if (!pe[i].event_masks[j].name)
406                                 noname++;
407
408                         if (pe[i].event_masks[j].name) {
409                                 if (!pe[i].event_masks[j].desc) {
410                                         fprintf(fp, "pmu: %s event%d:%s umask%d: %s :: no description\n", name, i, pe[i].name, j, pe[i].event_masks[j].name);
411                                         error++;
412                                 }
413                                 if (pe[i].event_masks[j].bit >= (EVENT_MASK_BITS+4)) {
414                                         fprintf(fp, "pmu: %s event%d:%s umask%d: %s :: invalid bit field\n", name, i, pe[i].name, j, pe[i].event_masks[j].name);
415                                         error++;
416                                 }
417
418                                 if (pe[i].event_masks[j].flags & NETBURST_FL_DFL)
419                                         ndfl++;
420                         }
421                 }
422                 if (ndfl > 1) {
423                         fprintf(fp, "pmu: %s event%d:%s :: more than one default umask\n", name, i, pe[i].name);
424                         error++;
425                 }
426                 if (!noname) {
427                         fprintf(fp, "pmu: %s event%d:%s :: no event mask end-marker\n", name, i, pe[i].name);
428                         error++;
429                 }
430         }
431         return error ? PFM_ERR_INVAL : PFM_SUCCESS;
432 }
433
434
435 static unsigned int
436 pfm_netburst_get_event_nattrs(void *this, int pidx)
437 {
438         unsigned int nattrs;
439         nattrs  = netburst_get_numasks(pidx);
440         nattrs += NETBURST_MODS_COUNT;
441         return nattrs;
442 }
443
444
445 pfmlib_pmu_t netburst_support = {
446         .desc                   = "Pentium4",
447         .name                   = "netburst",
448         .pmu                    = PFM_PMU_INTEL_NETBURST,
449         .pme_count              = LIBPFM_ARRAY_SIZE(netburst_events) - 1,
450         .type                   = PFM_PMU_TYPE_CORE,
451         .supported_plm          = INTEL_X86_PLM,
452         .atdesc                 = netburst_mods,
453         .pe                     = netburst_events,
454         .max_encoding           = 3,
455         .num_cntrs              = 18,
456
457         .pmu_detect             = pfm_netburst_detect,
458         .get_event_encoding[PFM_OS_NONE] = pfm_netburst_get_encoding,
459          PFMLIB_ENCODE_PERF(pfm_netburst_get_perf_encoding),
460         .get_event_first        = pfm_netburst_get_event_first,
461         .get_event_next         = pfm_netburst_get_event_next,
462         .event_is_valid         = pfm_netburst_event_is_valid,
463         .validate_table         = pfm_netburst_validate_table,
464         .get_event_info         = pfm_netburst_get_event_info,
465         .get_event_attr_info    = pfm_netburst_get_event_attr_info,
466         .get_event_nattrs       = pfm_netburst_get_event_nattrs,
467          PFMLIB_VALID_PERF_PATTRS(pfm_netburst_perf_validate_pattrs),
468 };
469
470 pfmlib_pmu_t netburst_p_support = {
471         .desc                   = "Pentium4 (Prescott)",
472         .name                   = "netburst_p",
473         .pmu                    = PFM_PMU_INTEL_NETBURST_P,
474         .pme_count              = LIBPFM_ARRAY_SIZE(netburst_events),
475         .type                   = PFM_PMU_TYPE_CORE,
476         .supported_plm          = INTEL_X86_PLM,
477         .atdesc                 = netburst_mods,
478         .pe                     = netburst_events,
479         .max_encoding           = 3,
480         .num_cntrs              = 18,
481
482         .pmu_detect             = pfm_netburst_detect_prescott,
483         .get_event_encoding[PFM_OS_NONE] = pfm_netburst_get_encoding,
484          PFMLIB_ENCODE_PERF(pfm_netburst_get_perf_encoding),
485         .get_event_first        = pfm_netburst_get_event_first,
486         .get_event_next         = pfm_netburst_get_event_next,
487         .event_is_valid         = pfm_netburst_event_is_valid,
488         .validate_table         = pfm_netburst_validate_table,
489         .get_event_info         = pfm_netburst_get_event_info,
490         .get_event_attr_info    = pfm_netburst_get_event_attr_info,
491         .get_event_nattrs       = pfm_netburst_get_event_nattrs,
492          PFMLIB_VALID_PERF_PATTRS(pfm_netburst_perf_validate_pattrs),
493 };