akaros/user/perfmon/pfmlib_intel_nhm_unc.c
<<
>>
Prefs
   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
  60static 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
  68static const int nhm_models[] = {
  69        26,
  70        30,
  71        31,
  72        0
  73};
  74
  75static const int wsm_dp_models[] = {
  76        44, /* Westmere-EP, Gulftown */
  77        47, /* Westmere E7 */
  78        0,
  79};
  80
  81static int
  82pfm_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
 286pfmlib_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
 318pfmlib_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};
 349