akaros/user/perfmon/pfmlib_intel_x86_arch.c
<<
>>
Prefs
   1/*
   2 * pfmlib_intel_x86_arch.c : Intel architectural PMU v1, v2, v3
   3 *
   4 * Copyright (c) 2005-2007 Hewlett-Packard Development Company, L.P.
   5 * Contributed by Stephane Eranian <eranian@hpl.hp.com>
   6 *
   7 *
   8 * Permission is hereby granted, free of charge, to any person obtaining a copy
   9 * of this software and associated documentation files (the "Software"), to deal
  10 * in the Software without restriction, including without limitation the rights
  11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  12 * of the Software, and to permit persons to whom the Software is furnished to do so,
  13 * subject to the following conditions:
  14 *
  15 * The above copyright notice and this permission notice shall be included in all
  16 * copies or substantial portions of the Software.
  17 *
  18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  19 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  20 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  22 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
  23 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24 *
  25 *
  26 * This file implements supports for the IA-32 architectural PMU as specified
  27 * in the following document:
  28 *      "IA-32 Intel Architecture Software Developer's Manual - Volume 3B: System
  29 *      Programming Guide"
  30 */
  31#include <sys/types.h>
  32#include <ctype.h>
  33#include <string.h>
  34#include <stdlib.h>
  35#include <stdio.h>
  36
  37/* private headers */
  38#include "pfmlib_priv.h"                        /* library private */
  39#include "pfmlib_intel_x86_priv.h"              /* architecture private */
  40
  41#include "events/intel_x86_arch_events.h"       /* architected event table */
  42
  43extern pfmlib_pmu_t intel_x86_arch_support;
  44
  45static intel_x86_entry_t *x86_arch_pe;
  46/*
  47 * .byte 0x53 == push ebx. it's universal for 32 and 64 bit
  48 * .byte 0x5b == pop ebx.
  49 * Some gcc's (4.1.2 on Core2) object to pairing push/pop and ebx in 64 bit mode.
  50 * Using the opcode directly avoids this problem.
  51 */
  52static inline void
  53cpuid(unsigned int op, unsigned int *a, unsigned int *b, unsigned int *c, unsigned int *d)
  54{
  55  __asm__ __volatile__ (".byte 0x53\n\tcpuid\n\tmovl %%ebx, %%esi\n\t.byte 0x5b"
  56       : "=a" (*a),
  57             "=S" (*b),
  58                 "=c" (*c),
  59                 "=d" (*d)
  60       : "a" (op));
  61}
  62
  63
  64/*
  65 * create architected event table
  66 */
  67static int
  68create_arch_event_table(unsigned int mask, int version)
  69{
  70        intel_x86_entry_t *pe;
  71        int i, num_events = 0;
  72        int m;
  73
  74        DPRINT("version=%d evt_msk=0x%x\n", version, mask);
  75
  76        /*
  77         * first pass: count the number of supported events
  78         */
  79        m = mask;
  80        for(i=0; i < 7; i++, m>>=1) {
  81                if ((m & 0x1)  == 0)
  82                        num_events++;
  83        }
  84        intel_x86_arch_support.pme_count = num_events;
  85
  86        pe = calloc(num_events, sizeof(intel_x86_entry_t));
  87        if (pe == NULL)
  88                return PFM_ERR_NOTSUPP;
  89
  90        x86_arch_pe = pe;
  91        intel_x86_arch_support.pe = pe;
  92
  93        /*
  94         * second pass: populate the table
  95         */
  96        m = mask;
  97        for(i=0; i < 7; i++, m>>=1) {
  98                if (!(m & 0x1)) {
  99                        *pe = intel_x86_arch_pe[i];
 100
 101                        switch(version) {
 102                        case 3:
 103                                pe->modmsk = INTEL_V3_ATTRS;
 104                                break;
 105                        default:
 106                                pe->modmsk = INTEL_V2_ATTRS;
 107                                break;
 108                        }
 109                        pe++;
 110                }
 111        }
 112        return PFM_SUCCESS;
 113}
 114
 115static int
 116check_arch_pmu(int family)
 117{
 118        union {
 119                unsigned int val;
 120                intel_x86_pmu_eax_t eax;
 121                intel_x86_pmu_edx_t edx;
 122        } eax, ecx, edx, ebx;
 123
 124        /*
 125         * check family number to reject for processors
 126         * older than Pentium (family=5). Those processors
 127         * did not have the CPUID instruction
 128         */
 129        if (family < 5 || family == 15)
 130                return PFM_ERR_NOTSUPP;
 131
 132        /*
 133         * check if CPU supports 0xa function of CPUID
 134         * 0xa started with Core Duo. Needed to detect if
 135         * architected PMU is present
 136         */
 137        cpuid(0x0, &eax.val, &ebx.val, &ecx.val, &edx.val);
 138        if (eax.val < 0xa)
 139                return PFM_ERR_NOTSUPP;
 140
 141        /*
 142         * extract architected PMU information
 143         */
 144        cpuid(0xa, &eax.val, &ebx.val, &ecx.val, &edx.val);
 145
 146        /*
 147         * version must be greater than zero
 148         */
 149        return eax.eax.version < 1 ? PFM_ERR_NOTSUPP : PFM_SUCCESS;
 150}
 151
 152static int
 153pfm_intel_x86_arch_detect(void *this)
 154{
 155        int ret;
 156
 157        ret = pfm_intel_x86_detect();
 158        if (ret != PFM_SUCCESS)
 159                return ret;
 160
 161        return check_arch_pmu(pfm_intel_x86_cfg.family);
 162}
 163
 164static int
 165pfm_intel_x86_arch_init(void *this)
 166{
 167        union {
 168                unsigned int val;
 169                intel_x86_pmu_eax_t eax;
 170                intel_x86_pmu_edx_t edx;
 171        } eax, ecx, edx, ebx;
 172
 173        /*
 174         * extract architected PMU information
 175         */
 176        if (!pfm_cfg.forced_pmu) {
 177                cpuid(0xa, &eax.val, &ebx.val, &ecx.val, &edx.val);
 178                intel_x86_arch_support.num_cntrs = eax.eax.num_cnt;
 179                intel_x86_arch_support.num_fixed_cntrs = edx.edx.num_cnt;
 180        } else {
 181                eax.eax.version = 3;
 182                ebx.val = 0; /* no restriction */
 183                intel_x86_arch_support.num_cntrs = 0;
 184                intel_x86_arch_support.num_fixed_cntrs = 0;
 185        }
 186        /*
 187         * must be called after impl_cntrs has been initialized
 188         */
 189        return create_arch_event_table(ebx.val, eax.eax.version);
 190}
 191
 192void
 193pfm_intel_x86_arch_terminate(void *this)
 194{
 195        /* workaround const void for intel_x86_arch_support.pe */
 196        if (x86_arch_pe)
 197                free(x86_arch_pe);
 198}
 199
 200/* architected PMU */
 201pfmlib_pmu_t intel_x86_arch_support={
 202        .desc                   = "Intel X86 architectural PMU",
 203        .name                   = "ix86arch",
 204        .pmu                    = PFM_PMU_INTEL_X86_ARCH,
 205        .pme_count              = 0,
 206        .pe                     = NULL,
 207        .atdesc                 = intel_x86_mods,
 208        .flags                  = PFMLIB_PMU_FL_RAW_UMASK | PFMLIB_PMU_FL_ARCH_DFL,
 209        .type                   = PFM_PMU_TYPE_CORE,
 210        .max_encoding           = 1,
 211
 212        .pmu_detect             = pfm_intel_x86_arch_detect,
 213        .pmu_init               = pfm_intel_x86_arch_init,
 214        .pmu_terminate          = pfm_intel_x86_arch_terminate,
 215        .get_event_encoding[PFM_OS_NONE] = pfm_intel_x86_get_encoding,
 216         PFMLIB_ENCODE_PERF(pfm_intel_x86_get_perf_encoding),
 217        .get_event_first        = pfm_intel_x86_get_event_first,
 218        .get_event_next         = pfm_intel_x86_get_event_next,
 219        .event_is_valid         = pfm_intel_x86_event_is_valid,
 220        .get_event_info         = pfm_intel_x86_get_event_info,
 221        .get_event_attr_info    = pfm_intel_x86_get_event_attr_info,
 222        PFMLIB_VALID_PERF_PATTRS(pfm_intel_x86_perf_validate_pattrs),
 223        .get_event_nattrs       = pfm_intel_x86_get_event_nattrs,
 224};
 225