akaros/user/perfmon/pfmlib_common.c
<<
>>
Prefs
   1/*
   2 * pfmlib_common.c: set of functions common to all PMU models
   3 *
   4 * Copyright (c) 2009 Google, Inc
   5 * Contributed by Stephane Eranian <eranian@gmail.com>
   6 *
   7 * Based on:
   8 * Copyright (c) 2001-2006 Hewlett-Packard Development Company, L.P.
   9 * Contributed by Stephane Eranian <eranian@hpl.hp.com>
  10 *
  11 * Permission is hereby granted, free of charge, to any person obtaining a copy
  12 * of this software and associated documentation files (the "Software"), to deal
  13 * in the Software without restriction, including without limitation the rights
  14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  15 * of the Software, and to permit persons to whom the Software is furnished to do so,
  16 * subject to the following conditions:
  17 *
  18 * The above copyright notice and this permission notice shall be included in all
  19 * copies or substantial portions of the Software.
  20 *
  21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  22 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  23 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  25 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
  26 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27 */
  28#include <sys/types.h>
  29#include <ctype.h>
  30#include <string.h>
  31#include <stdio.h>
  32#include <stdlib.h>
  33#include <stdarg.h>
  34#include <limits.h>
  35
  36#include <perfmon/pfmlib.h>
  37
  38#include "pfmlib_priv.h"
  39
  40static pfmlib_pmu_t *pfmlib_pmus[]=
  41{
  42
  43#ifdef CONFIG_PFMLIB_ARCH_IA64
  44#if 0
  45        &montecito_support,
  46        &itanium2_support,
  47        &itanium_support,
  48        &generic_ia64_support,  /* must always be last for IA-64 */
  49#endif
  50#endif
  51
  52#ifdef CONFIG_PFMLIB_ARCH_I386
  53        /* 32-bit only processors */
  54        &intel_pii_support,
  55        &intel_ppro_support,
  56        &intel_p6_support,
  57        &intel_pm_support,
  58        &intel_coreduo_support,
  59#endif
  60
  61#ifdef CONFIG_PFMLIB_ARCH_X86
  62        /* 32 and 64 bit processors */
  63        &netburst_support,
  64        &netburst_p_support,
  65        &amd64_k7_support,
  66        &amd64_k8_revb_support,
  67        &amd64_k8_revc_support,
  68        &amd64_k8_revd_support,
  69        &amd64_k8_reve_support,
  70        &amd64_k8_revf_support,
  71        &amd64_k8_revg_support,
  72        &amd64_fam10h_barcelona_support,
  73        &amd64_fam10h_shanghai_support,
  74        &amd64_fam10h_istanbul_support,
  75        &amd64_fam11h_turion_support,
  76        &amd64_fam12h_llano_support,
  77        &amd64_fam14h_bobcat_support,
  78        &amd64_fam15h_interlagos_support,
  79        &amd64_fam15h_nb_support,
  80        &intel_core_support,
  81        &intel_atom_support,
  82        &intel_nhm_support,
  83        &intel_nhm_ex_support,
  84        &intel_nhm_unc_support,
  85        &intel_wsm_sp_support,
  86        &intel_wsm_dp_support,
  87        &intel_wsm_unc_support,
  88        &intel_snb_support,
  89        &intel_snb_unc_cbo0_support,
  90        &intel_snb_unc_cbo1_support,
  91        &intel_snb_unc_cbo2_support,
  92        &intel_snb_unc_cbo3_support,
  93        &intel_snb_ep_support,
  94        &intel_ivb_support,
  95        &intel_ivb_unc_cbo0_support,
  96        &intel_ivb_unc_cbo1_support,
  97        &intel_ivb_unc_cbo2_support,
  98        &intel_ivb_unc_cbo3_support,
  99        &intel_ivb_ep_support,
 100        &intel_hsw_support,
 101        &intel_hsw_ep_support,
 102        &intel_bdw_support,
 103        &intel_rapl_support,
 104        &intel_snbep_unc_cb0_support,
 105        &intel_snbep_unc_cb1_support,
 106        &intel_snbep_unc_cb2_support,
 107        &intel_snbep_unc_cb3_support,
 108        &intel_snbep_unc_cb4_support,
 109        &intel_snbep_unc_cb5_support,
 110        &intel_snbep_unc_cb6_support,
 111        &intel_snbep_unc_cb7_support,
 112        &intel_snbep_unc_ha_support,
 113        &intel_snbep_unc_imc0_support,
 114        &intel_snbep_unc_imc1_support,
 115        &intel_snbep_unc_imc2_support,
 116        &intel_snbep_unc_imc3_support,
 117        &intel_snbep_unc_pcu_support,
 118        &intel_snbep_unc_qpi0_support,
 119        &intel_snbep_unc_qpi1_support,
 120        &intel_snbep_unc_ubo_support,
 121        &intel_snbep_unc_r2pcie_support,
 122        &intel_snbep_unc_r3qpi0_support,
 123        &intel_snbep_unc_r3qpi1_support,
 124        &intel_knc_support,
 125        &intel_slm_support,
 126        &intel_ivbep_unc_cb0_support,
 127        &intel_ivbep_unc_cb1_support,
 128        &intel_ivbep_unc_cb2_support,
 129        &intel_ivbep_unc_cb3_support,
 130        &intel_ivbep_unc_cb4_support,
 131        &intel_ivbep_unc_cb5_support,
 132        &intel_ivbep_unc_cb6_support,
 133        &intel_ivbep_unc_cb7_support,
 134        &intel_ivbep_unc_cb8_support,
 135        &intel_ivbep_unc_cb9_support,
 136        &intel_ivbep_unc_cb10_support,
 137        &intel_ivbep_unc_cb11_support,
 138        &intel_ivbep_unc_cb12_support,
 139        &intel_ivbep_unc_cb13_support,
 140        &intel_ivbep_unc_cb14_support,
 141        &intel_ivbep_unc_ha0_support,
 142        &intel_ivbep_unc_ha1_support,
 143        &intel_ivbep_unc_imc0_support,
 144        &intel_ivbep_unc_imc1_support,
 145        &intel_ivbep_unc_imc2_support,
 146        &intel_ivbep_unc_imc3_support,
 147        &intel_ivbep_unc_imc4_support,
 148        &intel_ivbep_unc_imc5_support,
 149        &intel_ivbep_unc_imc6_support,
 150        &intel_ivbep_unc_imc7_support,
 151        &intel_ivbep_unc_pcu_support,
 152        &intel_ivbep_unc_qpi0_support,
 153        &intel_ivbep_unc_qpi1_support,
 154        &intel_ivbep_unc_qpi2_support,
 155        &intel_ivbep_unc_ubo_support,
 156        &intel_ivbep_unc_r2pcie_support,
 157        &intel_ivbep_unc_r3qpi0_support,
 158        &intel_ivbep_unc_r3qpi1_support,
 159        &intel_ivbep_unc_r3qpi2_support,
 160        &intel_ivbep_unc_irp_support,
 161        &intel_x86_arch_support, /* must always be last for x86 */
 162#endif
 163
 164#ifdef CONFIG_PFMLIB_ARCH_MIPS
 165        &mips_74k_support,
 166#endif
 167
 168#ifdef CONFIG_PFMLIB_ARCH_SICORTEX
 169        &sicortex_support,
 170#endif
 171
 172#ifdef CONFIG_PFMLIB_ARCH_POWERPC
 173        &power4_support,
 174        &ppc970_support,
 175        &ppc970mp_support,
 176        &power5_support,
 177        &power5p_support,
 178        &power6_support,
 179        &power7_support,
 180        &power8_support,
 181        &torrent_support,
 182#endif
 183
 184#ifdef CONFIG_PFMLIB_ARCH_SPARC
 185        &sparc_ultra12_support,
 186        &sparc_ultra3_support,
 187        &sparc_ultra3i_support,
 188        &sparc_ultra3plus_support,
 189        &sparc_ultra4plus_support,
 190        &sparc_niagara1_support,
 191        &sparc_niagara2_support,
 192#endif
 193
 194#ifdef CONFIG_PFMLIB_CELL
 195        &cell_support,
 196#endif
 197
 198#ifdef CONFIG_PFMLIB_ARCH_ARM
 199        &arm_cortex_a7_support,
 200        &arm_cortex_a8_support,
 201        &arm_cortex_a9_support,
 202        &arm_cortex_a15_support,
 203        &arm_1176_support,
 204        &arm_qcom_krait_support,
 205        &arm_cortex_a57_support,
 206        &arm_cortex_a53_support,
 207        &arm_xgene_support,
 208#endif
 209#ifdef CONFIG_PFMLIB_ARCH_ARM64
 210        &arm_cortex_a57_support,
 211        &arm_cortex_a53_support,
 212        &arm_xgene_support,
 213#endif
 214
 215#ifdef CONFIG_PFMLIB_ARCH_S390X
 216        &s390x_cpum_cf_support,
 217        &s390x_cpum_sf_support,
 218#endif
 219#ifdef __linux__
 220        &perf_event_support,
 221        &perf_event_raw_support,
 222#endif
 223};
 224#define PFMLIB_NUM_PMUS (int)(sizeof(pfmlib_pmus)/sizeof(pfmlib_pmu_t *))
 225
 226static pfmlib_os_t pfmlib_os_none;
 227pfmlib_os_t *pfmlib_os = &pfmlib_os_none;
 228
 229static pfmlib_os_t *pfmlib_oses[]={
 230        &pfmlib_os_none,
 231#ifdef __linux__
 232        &pfmlib_os_perf,
 233        &pfmlib_os_perf_ext,
 234#endif
 235};
 236#define PFMLIB_NUM_OSES (int)(sizeof(pfmlib_oses)/sizeof(pfmlib_os_t *))
 237
 238/*
 239 * Mapping table from PMU index to pfmlib_pmu_t
 240 * table is populated from pfmlib_pmus[] when the library
 241 * is initialized.
 242 *
 243 * Some entries can be NULL if PMU is not implemented on host
 244 * architecture or if the initialization failed.
 245 */
 246static pfmlib_pmu_t *pfmlib_pmus_map[PFM_PMU_MAX];
 247
 248
 249#define pfmlib_for_each_pmu_event(p, e) \
 250        for(e=(p)->get_event_first((p)); e != -1; e = (p)->get_event_next((p), e))
 251
 252#define for_each_pmu_event_attr(u, i) \
 253        for((u)=0; (u) < (i)->nattrs; (u) = (u)+1)
 254
 255#define pfmlib_for_each_pmu(x) \
 256        for((x)= 0 ; (x) < PFMLIB_NUM_PMUS; (x)++)
 257
 258#define pfmlib_for_each_pmu(x) \
 259        for((x)= 0 ; (x) < PFMLIB_NUM_PMUS; (x)++)
 260
 261#define pfmlib_for_each_os(x) \
 262        for((x)= 0 ; (x) < PFMLIB_NUM_OSES; (x)++)
 263
 264pfmlib_config_t pfm_cfg;
 265
 266void
 267__pfm_dbprintf(const char *fmt, ...)
 268{
 269        va_list ap;
 270
 271        if (pfm_cfg.debug == 0)
 272                return;
 273
 274        va_start(ap, fmt);
 275        vfprintf(pfm_cfg.fp, fmt, ap);
 276        va_end(ap);
 277}
 278
 279void
 280__pfm_vbprintf(const char *fmt, ...)
 281{
 282        va_list ap;
 283
 284        if (pfm_cfg.verbose == 0)
 285                return;
 286
 287        va_start(ap, fmt);
 288        vfprintf(pfm_cfg.fp, fmt, ap);
 289        va_end(ap);
 290}
 291
 292/*
 293 * pfmlib_getl: our own equivalent to GNU getline() extension.
 294 * This avoids a dependency on having a C library with
 295 * support for getline().
 296 */
 297int
 298pfmlib_getl(char **buffer, size_t *len, FILE *fp)
 299{
 300#define GETL_DFL_LEN    32
 301        char *b;
 302        int c;
 303        size_t maxsz, maxi, d, i = 0;
 304
 305        if (!len || !fp || !buffer)
 306                return -1;
 307
 308        b = *buffer;
 309
 310        if (!b)
 311                *len = 0;
 312
 313        maxsz = *len;
 314        maxi = maxsz - 2;
 315
 316        while ((c = fgetc(fp)) != EOF) {
 317                if (maxsz == 0 || i == maxi) {
 318                        if (maxsz == 0)
 319                                maxsz = GETL_DFL_LEN;
 320                        else
 321                                maxsz <<= 1;
 322
 323                        if (*buffer)
 324                                d = &b[i] - *buffer;
 325                        else
 326                                d = 0;
 327
 328                        *buffer = realloc(*buffer, maxsz);
 329                        if (!*buffer)
 330                                return -1;
 331
 332                        b = *buffer + d;
 333                        maxi = maxsz - d - 2;
 334                        i = 0;
 335                        *len = maxsz;
 336                }
 337                b[i++] = c;
 338                if (c == '\n')
 339                        break;
 340        }
 341        b[i] = '\0';
 342        return c != EOF ? 0 : -1;
 343}
 344
 345
 346
 347/*
 348 * append fmt+args to str such that the string is no
 349 * more than max characters incl. null termination
 350 */
 351void
 352pfmlib_strconcat(char *str, size_t max, const char *fmt, ...)
 353{
 354        va_list ap;
 355        size_t len, todo;
 356
 357        len = strlen(str);
 358        todo = max - strlen(str);
 359        va_start(ap, fmt);
 360        vsnprintf(str+len, todo, fmt, ap);
 361        va_end(ap);
 362}
 363
 364/*
 365 * compact all pattrs starting from index i
 366 */
 367void
 368pfmlib_compact_pattrs(pfmlib_event_desc_t *e, int i)
 369{
 370        int j;
 371
 372        for (j = i+1; j < e->npattrs; j++)
 373                e->pattrs[j - 1] = e->pattrs[j];
 374
 375        e->npattrs--;
 376}
 377
 378static void
 379pfmlib_compact_attrs(pfmlib_event_desc_t *e, int i)
 380{
 381        int j;
 382
 383        for (j = i+1; j < e->nattrs; j++)
 384                e->attrs[j - 1] = e->attrs[j];
 385
 386        e->nattrs--;
 387}
 388
 389/*
 390 *  0 : different attribute
 391 *  1 : exactly same attribute (duplicate can be removed)
 392 * -1 : same attribute but value differ, this is an error
 393 */
 394static inline int
 395pfmlib_same_attr(pfmlib_event_desc_t *d, int i, int j)
 396{
 397        pfm_event_attr_info_t *a1, *a2;
 398        pfmlib_attr_t *b1, *b2;
 399
 400        a1 = attr(d, i);
 401        a2 = attr(d, j);
 402
 403        b1 = d->attrs+i;
 404        b2 = d->attrs+j;
 405
 406        if (a1->idx == a2->idx
 407            && a1->type == a2->type
 408            && a1->ctrl == a2->ctrl) {
 409                if (b1->ival == b2->ival)
 410                        return 1;
 411                return -1;
 412
 413        }
 414        return 0;
 415}
 416
 417static inline int
 418pfmlib_pmu_active(pfmlib_pmu_t *pmu)
 419{
 420        return !!(pmu->flags & PFMLIB_PMU_FL_ACTIVE);
 421}
 422
 423static inline int
 424pfmlib_pmu_initialized(pfmlib_pmu_t *pmu)
 425{
 426        return !!(pmu->flags & PFMLIB_PMU_FL_INIT);
 427}
 428
 429static inline pfm_pmu_t
 430idx2pmu(int idx)
 431{
 432        return (pfm_pmu_t)(idx >> PFMLIB_PMU_SHIFT) & PFMLIB_PMU_MASK;
 433}
 434
 435static inline pfmlib_pmu_t *
 436pmu2pmuidx(pfm_pmu_t pmu)
 437{
 438        /* pfm_pmu_t is unsigned int enum, so
 439         * just need to check for upper bound
 440         */
 441        if (pmu >= PFM_PMU_MAX)
 442                return NULL;
 443
 444        return pfmlib_pmus_map[pmu];
 445}
 446
 447/*
 448 * external opaque idx -> PMU + internal idx
 449 */
 450static pfmlib_pmu_t *
 451pfmlib_idx2pidx(int idx, int *pidx)
 452{
 453        pfmlib_pmu_t *pmu;
 454        pfm_pmu_t pmu_id;
 455
 456        if (PFMLIB_INITIALIZED() == 0)
 457                return NULL;
 458
 459        if (idx < 0)
 460                return NULL;
 461
 462        pmu_id = idx2pmu(idx);
 463
 464        pmu = pmu2pmuidx(pmu_id);
 465        if (!pmu)
 466                return NULL;
 467
 468        *pidx = idx & PFMLIB_PMU_PIDX_MASK;
 469
 470        if (!pmu->event_is_valid(pmu, *pidx))
 471                return NULL;
 472
 473        return pmu;
 474}
 475
 476static pfmlib_os_t *
 477pfmlib_find_os(pfm_os_t id)
 478{
 479        int o;
 480        pfmlib_os_t *os;
 481
 482        pfmlib_for_each_os(o) {
 483                os = pfmlib_oses[o];
 484                if (os->id == id && (os->flags & PFMLIB_OS_FL_ACTIVATED))
 485                        return os;
 486        }
 487        return NULL;
 488}
 489
 490size_t
 491pfmlib_check_struct(void *st, size_t usz, size_t refsz, size_t sz)
 492{
 493        size_t rsz = sz;
 494
 495        /*
 496         * if user size is zero, then use ABI0 size
 497         */
 498        if (usz == 0)
 499                usz = refsz;
 500
 501        /*
 502         * cannot be smaller than ABI0 size
 503         */
 504        if (usz < refsz) {
 505                DPRINT("pfmlib_check_struct: user size too small %zu\n", usz);
 506                return 0;
 507        }
 508
 509        /*
 510         * if bigger than current ABI, then check that none
 511         * of the extra bits are set. This is to avoid mistake
 512         * by caller assuming the library set those bits.
 513         */
 514        if (usz > sz) {
 515                char *addr = (char *)st + sz;
 516                char *end = (char *)st + usz;
 517                while (addr != end) {
 518                        if (*addr++) {
 519                                DPRINT("pfmlib_check_struct: invalid extra bits\n");
 520                                return 0;
 521                        }
 522                }
 523        }
 524        return rsz;
 525}
 526
 527/*
 528 * check environment variables for:
 529 *  LIBPFM_VERBOSE : enable verbose output (must be 1)
 530 *  LIBPFM_DEBUG   : enable debug output (must be 1)
 531 */
 532static void
 533pfmlib_init_env(void)
 534{
 535        char *str;
 536
 537        pfm_cfg.fp = stderr;
 538
 539        str = getenv("LIBPFM_VERBOSE");
 540        if (str && isdigit((int)*str))
 541                pfm_cfg.verbose = *str - '0';
 542
 543        str = getenv("LIBPFM_DEBUG");
 544        if (str && isdigit((int)*str))
 545                pfm_cfg.debug = *str - '0';
 546
 547        str = getenv("LIBPFM_DEBUG_STDOUT");
 548        if (str)
 549                pfm_cfg.fp = stdout;
 550
 551        pfm_cfg.forced_pmu = getenv("LIBPFM_FORCE_PMU");
 552
 553        str = getenv("LIBPFM_ENCODE_INACTIVE");
 554        if (str)
 555                pfm_cfg.inactive = 1;
 556
 557        str = getenv("LIBPFM_DISABLED_PMUS");
 558        if (str)
 559                pfm_cfg.blacklist_pmus = str;
 560}
 561
 562static int
 563pfmlib_pmu_sanity_checks(pfmlib_pmu_t *p)
 564{
 565        /*
 566         * check event can be encoded
 567         */
 568        if (p->pme_count >= (1<< PFMLIB_PMU_SHIFT)) {
 569                DPRINT("too many events for %s\n", p->desc);
 570                return PFM_ERR_NOTSUPP;
 571        }
 572
 573        if (p->max_encoding > PFMLIB_MAX_ENCODING) {
 574                DPRINT("max encoding too high (%d > %d) for %s\n",
 575                        p->max_encoding, PFMLIB_MAX_ENCODING, p->desc);
 576                return PFM_ERR_NOTSUPP;
 577        }
 578
 579        return PFM_SUCCESS;
 580}
 581
 582int
 583pfmlib_build_fstr(pfmlib_event_desc_t *e, char **fstr)
 584{
 585        /* nothing to do */
 586        if (!fstr)
 587                return PFM_SUCCESS;
 588
 589        *fstr = malloc(strlen(e->fstr) + 2 + strlen(e->pmu->name) + 1);
 590        if (*fstr)
 591                sprintf(*fstr, "%s::%s", e->pmu->name, e->fstr);
 592
 593        return *fstr ? PFM_SUCCESS : PFM_ERR_NOMEM;
 594}
 595
 596static int
 597pfmlib_pmu_activate(pfmlib_pmu_t *p)
 598{
 599        int ret;
 600
 601        if (p->pmu_init) {
 602                ret = p->pmu_init(p);
 603                if (ret != PFM_SUCCESS)
 604                        return ret;
 605        }
 606
 607        p->flags |= PFMLIB_PMU_FL_ACTIVE;
 608
 609        DPRINT("activated %s\n", p->desc);
 610
 611        return PFM_SUCCESS;     
 612}
 613
 614static inline int
 615pfmlib_match_forced_pmu(const char *name)
 616{
 617        const char *p;
 618        size_t l;
 619
 620        /* skip any lower level specifier */
 621        p = strchr(pfm_cfg.forced_pmu, ',');
 622        if (p)
 623                l = p - pfm_cfg.forced_pmu;
 624        else
 625                l = strlen(pfm_cfg.forced_pmu);
 626
 627        return !strncasecmp(name, pfm_cfg.forced_pmu, l);
 628}
 629
 630static int
 631pfmlib_is_blacklisted_pmu(pfmlib_pmu_t *p)
 632{
 633        if (!pfm_cfg.blacklist_pmus)
 634                return 0;
 635
 636        /*
 637         * scan list for matching PMU names, we accept substrings.
 638         * for instance: snbep does match snbep*
 639         */
 640        char *q, buffer[strlen(pfm_cfg.blacklist_pmus) + 1];
 641
 642        strcpy (buffer, pfm_cfg.blacklist_pmus);
 643        for (q = strtok (buffer, ","); q != NULL; q = strtok (NULL, ",")) {
 644                if (strstr (p->name, q) != NULL) {
 645                        return 1;
 646                }
 647        }
 648        return 0;
 649}
 650
 651static int
 652pfmlib_init_pmus(void)
 653{
 654        pfmlib_pmu_t *p;
 655        int i, ret;
 656        int nsuccess = 0;
 657        
 658        /*
 659         * activate all detected PMUs
 660         * when forced, only the designated PMU
 661         * is setup and activated
 662         */
 663        pfmlib_for_each_pmu(i) {
 664
 665                p = pfmlib_pmus[i];
 666
 667                DPRINT("trying %s\n", p->desc);
 668
 669                ret = PFM_SUCCESS;
 670
 671                if (!pfm_cfg.forced_pmu)
 672                        ret = p->pmu_detect(p);
 673                else if (!pfmlib_match_forced_pmu(p->name))
 674                        ret = PFM_ERR_NOTSUPP;
 675
 676                /*
 677                 * basic checks
 678                 * failure causes PMU to not be available
 679                 */
 680                if (pfmlib_pmu_sanity_checks(p) != PFM_SUCCESS)
 681                        continue;
 682
 683                if (pfmlib_is_blacklisted_pmu(p)) {
 684                        DPRINT("%d PMU blacklisted, skipping initialization\n");
 685                        continue;
 686                }
 687                p->flags |= PFMLIB_PMU_FL_INIT;
 688
 689                /*
 690                 * populate mapping table
 691                 */
 692                pfmlib_pmus_map[p->pmu] = p;
 693
 694                if (ret != PFM_SUCCESS)
 695                        continue;
 696
 697                /*
 698                 * check if exported by OS if needed
 699                 */
 700                if (p->os_detect[pfmlib_os->id]) {
 701                        ret = p->os_detect[pfmlib_os->id](p);
 702                        if (ret != PFM_SUCCESS) {
 703                                DPRINT("%s PMU not exported by OS\n", p->name);
 704                                continue;
 705                        }
 706                }
 707
 708                ret = pfmlib_pmu_activate(p);
 709                if (ret == PFM_SUCCESS)
 710                        nsuccess++;
 711
 712                if (pfm_cfg.forced_pmu) {
 713                        __pfm_vbprintf("PMU forced to %s (%s) : %s\n",
 714                                        p->name,
 715                                        p->desc,
 716                                        ret == PFM_SUCCESS ? "success" : "failure");
 717                        return ret;
 718                }
 719        }
 720        DPRINT("%d PMU detected out of %d supported\n", nsuccess, PFMLIB_NUM_PMUS);
 721        return PFM_SUCCESS;
 722}
 723
 724static void
 725pfmlib_init_os(void)
 726{
 727        int o;
 728        pfmlib_os_t *os;
 729
 730        pfmlib_for_each_os(o) {
 731                os = pfmlib_oses[o];
 732
 733                if (!os->detect)
 734                        continue;
 735
 736                if (os->detect(os) != PFM_SUCCESS)
 737                        continue;
 738
 739                if (os != &pfmlib_os_none && pfmlib_os == &pfmlib_os_none)
 740                        pfmlib_os = os;
 741
 742                DPRINT("OS layer %s activated\n", os->name);
 743                os->flags = PFMLIB_OS_FL_ACTIVATED;
 744        }
 745        DPRINT("default OS layer: %s\n", pfmlib_os->name);
 746}
 747
 748int
 749pfm_initialize(void)
 750{
 751        int ret;
 752        /*
 753         * not atomic
 754         */
 755        if (pfm_cfg.initdone)
 756                return PFM_SUCCESS;
 757
 758        /*
 759         * generic sanity checks
 760         */
 761        if (PFM_PMU_MAX & (~PFMLIB_PMU_MASK)) {
 762                DPRINT("PFM_PMU_MAX exceeds PFMLIB_PMU_MASK\n");        
 763                return PFM_ERR_NOTSUPP;
 764        }
 765
 766        pfmlib_init_env();
 767
 768        /* must be done before pfmlib_init_pmus() */
 769        pfmlib_init_os();
 770
 771        ret = pfmlib_init_pmus();
 772        if (ret != PFM_SUCCESS)
 773                return ret;
 774
 775
 776        pfm_cfg.initdone = 1;
 777
 778        return ret;
 779}
 780
 781void
 782pfm_terminate(void)
 783{
 784        pfmlib_pmu_t *pmu;
 785        int i;
 786
 787        if (PFMLIB_INITIALIZED() == 0)
 788                return;
 789
 790        pfmlib_for_each_pmu(i) {
 791                pmu = pfmlib_pmus[i];
 792                if (!pfmlib_pmu_active(pmu))
 793                        continue;
 794                if (pmu->pmu_terminate)
 795                        pmu->pmu_terminate(pmu);
 796        }
 797        pfm_cfg.initdone = 0;
 798}
 799
 800int
 801pfm_find_event(const char *str)
 802{
 803        pfmlib_event_desc_t e;
 804        int ret;
 805
 806        if (PFMLIB_INITIALIZED() == 0)
 807                return PFM_ERR_NOINIT;
 808
 809        if (!str)
 810                return PFM_ERR_INVAL;
 811
 812        memset(&e, 0, sizeof(e));
 813
 814        ret = pfmlib_parse_event(str, &e);
 815        if (ret == PFM_SUCCESS)
 816                return pfmlib_pidx2idx(e.pmu, e.event);
 817
 818        return ret;
 819}
 820
 821static int
 822pfmlib_sanitize_event(pfmlib_event_desc_t *d)
 823{
 824        int i, j, ret;
 825
 826        /*
 827         * fail if duplicate attributes are found
 828         */
 829        for(i=0; i < d->nattrs; i++) {
 830                for(j=i+1; j < d->nattrs; j++) {
 831                        ret = pfmlib_same_attr(d, i, j);
 832                        if (ret == 1)
 833                                pfmlib_compact_attrs(d, j);
 834                        else if (ret == -1)
 835                                return PFM_ERR_ATTR_SET;
 836                }
 837        }
 838        return PFM_SUCCESS;
 839}
 840
 841static int
 842pfmlib_parse_event_attr(char *str, pfmlib_event_desc_t *d)
 843{
 844        pfm_event_attr_info_t *ainfo;
 845        char *s, *p, *q, *endptr;
 846        char yes[2] = "y";
 847        pfm_attr_t type;
 848        int aidx = 0, has_val, has_raw_um = 0, has_um = 0;
 849        int ret = PFM_ERR_INVAL;
 850
 851        s = str;
 852
 853        while(s) {
 854                p = strchr(s, PFMLIB_ATTR_DELIM);
 855                if (p)
 856                        *p++ = '\0';
 857
 858                q = strchr(s, '=');
 859                if (q)
 860                        *q++ = '\0';
 861
 862                has_val = !!q;
 863
 864                /*
 865                 * check for raw umasks in hexdecimal only
 866                 */
 867                if (*s == '0' && tolower(*(s+1)) == 'x') {
 868                        char *endptr = NULL;
 869
 870                        /* can only have one raw umask */
 871                        if (has_raw_um || has_um) {
 872                                DPRINT("cannot mix raw umask with umask\n");
 873                                return PFM_ERR_ATTR;
 874                        }
 875                        if (!(d->pmu->flags & PFMLIB_PMU_FL_RAW_UMASK)) {
 876                                DPRINT("PMU %s does not support RAW umasks\n", d->pmu->name);
 877                                return PFM_ERR_ATTR;
 878                        }
 879
 880                        /* we have reserved an entry at the end of pattrs */
 881                        aidx = d->npattrs;
 882                        ainfo = d->pattrs + aidx;
 883
 884                        ainfo->name = "RAW_UMASK";
 885                        ainfo->type = PFM_ATTR_RAW_UMASK;
 886                        ainfo->ctrl = PFM_ATTR_CTRL_PMU;
 887                        ainfo->idx  = strtoul(s, &endptr, 0);
 888                        ainfo->equiv= NULL;
 889                        if (*endptr) {
 890                                DPRINT("raw umask (%s) is not a number\n");
 891                                return PFM_ERR_ATTR;
 892                        }
 893
 894                        has_raw_um = 1;
 895
 896                        goto found_attr;
 897                }
 898
 899                for(aidx = 0; aidx < d->npattrs; aidx++) {
 900                        if (!strcasecmp(d->pattrs[aidx].name, s)) {
 901                                ainfo = d->pattrs + aidx;
 902                                /* disambiguate modifier and umask
 903                                 * with the same name : snb::L2_LINES_IN:I:I=1
 904                                 */
 905                                if (has_val && ainfo->type == PFM_ATTR_UMASK)
 906                                        continue;
 907                                goto found_attr;
 908                        }
 909                }
 910                DPRINT("cannot find attribute %s\n", s);
 911                return PFM_ERR_ATTR;
 912found_attr:
 913                type = ainfo->type;
 914
 915                if (type == PFM_ATTR_UMASK) {
 916                        has_um = 1;
 917                        if (has_raw_um) {
 918                                DPRINT("cannot mix raw umask with umask\n");
 919                                return PFM_ERR_ATTR;
 920                        }
 921                }
 922
 923                if (ainfo->equiv) {
 924                        char *z;
 925
 926                        /* cannot have equiv for attributes with value */
 927                        if (has_val)
 928                                return PFM_ERR_ATTR_VAL;
 929
 930                        /* copy because it is const */
 931                        z = strdup(ainfo->equiv);
 932                        if (!z)
 933                                return PFM_ERR_NOMEM;
 934
 935                        ret = pfmlib_parse_event_attr(z, d);
 936
 937                        free(z);
 938
 939                        if (ret != PFM_SUCCESS)
 940                                return ret;
 941                        s = p;
 942                        continue;
 943                }
 944                /*
 945                 * we tolerate missing value for boolean attributes.
 946                 * Presence of the attribute is equivalent to
 947                 * attr=1, i.e., attribute is set
 948                 */
 949                if (type != PFM_ATTR_UMASK && type != PFM_ATTR_RAW_UMASK && !has_val) {
 950                        if (type != PFM_ATTR_MOD_BOOL)
 951                                return PFM_ERR_ATTR_VAL;
 952                        s = yes; /* no const */
 953                        goto handle_bool;
 954                }
 955
 956                d->attrs[d->nattrs].ival = 0;
 957                if ((type == PFM_ATTR_UMASK || type == PFM_ATTR_RAW_UMASK) && has_val)
 958                        return PFM_ERR_ATTR_VAL;
 959
 960                if (has_val) {
 961                        s = q;
 962handle_bool:
 963                        ret = PFM_ERR_ATTR_VAL;
 964                        if (!strlen(s))
 965                                goto error;
 966                        if (d->nattrs == PFMLIB_MAX_ATTRS) {
 967                                DPRINT("too many attributes\n");
 968                                ret = PFM_ERR_TOOMANY;
 969                                goto error;
 970                        }
 971
 972                        endptr = NULL;
 973                        switch(type) {
 974                        case PFM_ATTR_MOD_BOOL:
 975                                if (strlen(s) > 1)
 976                                        goto error;
 977
 978                                if (tolower((int)*s) == 'y'
 979                                    || tolower((int)*s) == 't' || *s == '1')
 980                                        d->attrs[d->nattrs].ival = 1;
 981                                else if (tolower((int)*s) == 'n'
 982                                         || tolower((int)*s) == 'f' || *s == '0')
 983                                        d->attrs[d->nattrs].ival = 0;
 984                                else
 985                                        goto error;
 986                                break;
 987                        case PFM_ATTR_MOD_INTEGER:
 988                                d->attrs[d->nattrs].ival = strtoull(s, &endptr, 0);
 989                                if (*endptr != '\0')
 990                                        goto error;
 991                                break;
 992                        default:
 993                                goto error;
 994                        }
 995                }
 996                d->attrs[d->nattrs].id = aidx;
 997                d->nattrs++;
 998                s = p;
 999        }
1000        ret = PFM_SUCCESS;
1001error:
1002        return ret;
1003}
1004
1005static int
1006pfmlib_build_event_pattrs(pfmlib_event_desc_t  *e)
1007{
1008        pfmlib_pmu_t *pmu;
1009        pfmlib_os_t *os;
1010        int i, ret, pmu_nattrs = 0, os_nattrs = 0;
1011        int npattrs;
1012
1013        /*
1014         * cannot satisfy request for an OS that was not activated
1015         */
1016        os = pfmlib_find_os(e->osid);
1017        if (!os)
1018                return PFM_ERR_NOTSUPP;
1019
1020        pmu = e->pmu;
1021
1022        /* get actual PMU number of attributes for the event */
1023        if (pmu->get_event_nattrs)
1024                pmu_nattrs = pmu->get_event_nattrs(pmu, e->event);
1025        if (os && os->get_os_nattrs)
1026                os_nattrs += os->get_os_nattrs(os, e);
1027
1028        npattrs = pmu_nattrs + os_nattrs;
1029
1030        /*
1031         * add extra entry for raw umask, if supported
1032         */
1033        if (pmu->flags & PFMLIB_PMU_FL_RAW_UMASK)
1034                npattrs++;
1035
1036        if (npattrs) {
1037                e->pattrs = malloc(npattrs * sizeof(*e->pattrs));
1038                if (!e->pattrs)
1039                        return PFM_ERR_NOMEM;
1040        }
1041
1042        /* collect all actual PMU attrs */
1043        for(i = 0; i < pmu_nattrs; i++) {
1044                ret = pmu->get_event_attr_info(pmu, e->event, i, e->pattrs+i);
1045                if (ret != PFM_SUCCESS)
1046                        goto error;
1047        }
1048        e->npattrs = pmu_nattrs;
1049
1050        if (os_nattrs) {
1051                if (e->osid == os->id && os->get_os_attr_info) {
1052                        os->get_os_attr_info(os, e);
1053                        /*
1054                         * check for conflicts between HW and OS attributes
1055                         */
1056                        if (pmu->validate_pattrs[e->osid])
1057                                pmu->validate_pattrs[e->osid](pmu, e);
1058                }
1059        }
1060        for (i = 0; i < e->npattrs; i++)
1061                DPRINT("%d %d %d %d %d %s\n", e->event, i, e->pattrs[i].type, e->pattrs[i].ctrl, e->pattrs[i].idx, e->pattrs[i].name);
1062
1063        return PFM_SUCCESS;
1064error:
1065        free(e->pattrs);
1066        e->pattrs = NULL;
1067        return ret;
1068}
1069
1070void
1071pfmlib_release_event(pfmlib_event_desc_t *e)
1072{
1073        free(e->pattrs);
1074        e->pattrs = NULL;
1075}
1076
1077static int
1078match_event(void *this, pfmlib_event_desc_t *d, const char *e, const char *s)
1079{
1080        return strcasecmp(e, s);
1081}
1082
1083static int
1084pfmlib_parse_equiv_event(const char *event, pfmlib_event_desc_t *d)
1085{
1086        pfmlib_pmu_t *pmu = d->pmu;
1087        pfm_event_info_t einfo;
1088        int (*match)(void *this, pfmlib_event_desc_t *d, const char *e, const char *s);
1089        char *str, *s, *p;
1090        int i;
1091        int ret;
1092
1093        /*
1094         * create copy because string is const
1095         */
1096        s = str = strdup(event);
1097        if (!str)
1098                return PFM_ERR_NOMEM;
1099
1100        p = strchr(s, PFMLIB_ATTR_DELIM);
1101        if (p)
1102                *p++ = '\0';
1103
1104        match = pmu->match_event ? pmu->match_event : match_event;
1105
1106        pfmlib_for_each_pmu_event(pmu, i) {
1107                ret = pmu->get_event_info(pmu, i, &einfo);
1108                if (ret != PFM_SUCCESS)
1109                        goto error;
1110                if (!match(pmu, d, einfo.name, s))
1111                        goto found;
1112        }
1113        free(str);
1114        return PFM_ERR_NOTFOUND;
1115found:
1116        d->pmu = pmu;
1117        d->event = i; /* private index */
1118
1119        /*
1120         * build_event_pattrs and parse_event_attr
1121         * cannot be factorized with pfmlib_parse_event()
1122         * because equivalent event may add its own attributes
1123         */
1124        ret = pfmlib_build_event_pattrs(d);
1125        if (ret != PFM_SUCCESS)
1126                goto error;
1127
1128        ret = pfmlib_parse_event_attr(p, d);
1129        if (ret == PFM_SUCCESS)
1130                ret = pfmlib_sanitize_event(d);
1131error:
1132        free(str);
1133
1134        if (ret != PFM_SUCCESS)
1135                pfmlib_release_event(d);
1136
1137        return ret;
1138}
1139
1140int
1141pfmlib_parse_event(const char *event, pfmlib_event_desc_t *d)
1142{
1143        pfm_event_info_t einfo;
1144        char *str, *s, *p;
1145        pfmlib_pmu_t *pmu;
1146        int (*match)(void *this, pfmlib_event_desc_t *d, const char *e, const char *s);
1147        const char *pname = NULL;
1148        int i, j, ret;
1149
1150        /*
1151         * create copy because string is const
1152         */
1153        s = str = strdup(event);
1154        if (!str)
1155                return PFM_ERR_NOMEM;
1156
1157        /*
1158         * ignore everything passed after a comma
1159         * (simplify dealing with const event list)
1160         *
1161         * safe to do before pname, because now
1162         * PMU name cannot have commas in them.
1163         */
1164        p = strchr(s, PFMLIB_EVENT_DELIM);
1165        if (p)
1166                *p = '\0';
1167
1168        /* check for optional PMU name */
1169        p = strstr(s, PFMLIB_PMU_DELIM);
1170        if (p) {
1171                *p = '\0';
1172                pname = s;
1173                s = p + strlen(PFMLIB_PMU_DELIM);
1174        }
1175        p = strchr(s, PFMLIB_ATTR_DELIM);
1176        if (p)
1177                *p++ = '\0';
1178        /*
1179         * for each pmu
1180         */
1181        pfmlib_for_each_pmu(j) {
1182                pmu = pfmlib_pmus[j];
1183                /*
1184                 * if no explicit PMU name is given, then
1185                 * only look for active PMU models
1186                 */
1187                if (!pname && !pfmlib_pmu_active(pmu))
1188                        continue;
1189                /*
1190                 * check for requested PMU name,
1191                 */
1192                if (pname && strcasecmp(pname, pmu->name))
1193                        continue;
1194                /*
1195                 * only allow event on inactive PMU if enabled via
1196                 * environement variable
1197                 */
1198                if (pname && !pfmlib_pmu_active(pmu) && !pfm_cfg.inactive)
1199                        continue;
1200
1201                match = pmu->match_event ? pmu->match_event : match_event;
1202                /*
1203                 * for each event
1204                 */
1205                pfmlib_for_each_pmu_event(pmu, i) {
1206                        ret = pmu->get_event_info(pmu, i, &einfo);
1207                        if (ret != PFM_SUCCESS)
1208                                goto error;
1209                        if (!match(pmu, d, einfo.name, s))
1210                                goto found;
1211                }
1212        }
1213        free(str);
1214        return PFM_ERR_NOTFOUND;
1215found:
1216        d->pmu = pmu;
1217        /*
1218         * handle equivalence
1219         */
1220        if (einfo.equiv) {
1221                ret = pfmlib_parse_equiv_event(einfo.equiv, d);
1222                if (ret != PFM_SUCCESS)
1223                        goto error;
1224        } else {
1225                d->event = i; /* private index */
1226
1227                ret = pfmlib_build_event_pattrs(d);
1228                if (ret != PFM_SUCCESS)
1229                        goto error;
1230        }
1231        /*
1232         * parse attributes from original event
1233         */
1234        ret = pfmlib_parse_event_attr(p, d);
1235        if (ret == PFM_SUCCESS)
1236                ret = pfmlib_sanitize_event(d);
1237
1238        for (i = 0; i < d->nattrs; i++) {
1239                pfm_event_attr_info_t *a = attr(d, i);
1240                if (a->type != PFM_ATTR_RAW_UMASK)
1241                        DPRINT("%d %d %d %s\n", d->event, i, a->idx, d->pattrs[d->attrs[i].id].name);
1242                else
1243                        DPRINT("%d %d RAW_UMASK (0x%x)\n", d->event, i, a->idx);
1244        }
1245error:
1246        free(str);
1247        if (ret != PFM_SUCCESS)
1248                pfmlib_release_event(d);
1249        return ret;
1250}
1251
1252/* sorry, only English supported at this point! */
1253static const char *pfmlib_err_list[]=
1254{
1255        "success",
1256        "not supported",
1257        "invalid parameters",
1258        "pfmlib not initialized",
1259        "event not found",
1260        "invalid combination of model specific features",
1261        "invalid or missing unit mask",
1262        "out of memory",
1263        "invalid event attribute",
1264        "invalid event attribute value",
1265        "attribute value already set",
1266        "too many parameters",
1267        "parameter is too small",
1268};
1269static int pfmlib_err_count = (int)sizeof(pfmlib_err_list)/sizeof(char *);
1270
1271const char *
1272pfm_strerror(int code)
1273{
1274        code = -code;
1275        if (code <0 || code >= pfmlib_err_count)
1276                return "unknown error code";
1277
1278        return pfmlib_err_list[code];
1279}
1280
1281int
1282pfm_get_version(void)
1283{
1284        return LIBPFM_VERSION;
1285}
1286
1287int
1288pfm_get_event_next(int idx)
1289{
1290        pfmlib_pmu_t *pmu;
1291        int pidx;
1292
1293        pmu = pfmlib_idx2pidx(idx, &pidx);
1294        if (!pmu)
1295                return -1;
1296
1297        pidx = pmu->get_event_next(pmu, pidx);
1298        return pidx == -1 ? -1 : pfmlib_pidx2idx(pmu, pidx);
1299}
1300
1301int
1302pfm_get_os_event_encoding(const char *str, int dfl_plm, pfm_os_t uos, void *args)
1303{
1304        pfmlib_os_t *os;
1305
1306        if (PFMLIB_INITIALIZED() == 0)
1307                return PFM_ERR_NOINIT;
1308
1309        if (!(args && str))
1310                return PFM_ERR_INVAL;
1311
1312        if (dfl_plm & ~(PFM_PLM_ALL))
1313                return PFM_ERR_INVAL;
1314
1315        os = pfmlib_find_os(uos);
1316        if (!os)
1317                return PFM_ERR_NOTSUPP;
1318
1319        return os->encode(os, str, dfl_plm, args);
1320}
1321
1322/*
1323 * old API maintained for backward compatibility with existing apps
1324 * prefer pfm_get_os_event_encoding()
1325 */
1326int
1327pfm_get_event_encoding(const char *str, int dfl_plm, char **fstr, int *idx, uint64_t **codes, int *count)
1328{
1329        pfm_pmu_encode_arg_t arg;
1330        int ret;
1331
1332        if (!(str && codes && count))
1333                return PFM_ERR_INVAL;
1334
1335        if ((*codes && !*count) || (!*codes && *count))
1336                return PFM_ERR_INVAL;
1337
1338        memset(&arg, 0, sizeof(arg));
1339
1340        arg.fstr = fstr;
1341        arg.codes = *codes;
1342        arg.count = *count;
1343        arg.size  = sizeof(arg);
1344
1345        /*
1346         * request RAW PMU encoding
1347         */
1348        ret = pfm_get_os_event_encoding(str, dfl_plm, PFM_OS_NONE, &arg);
1349        if (ret != PFM_SUCCESS)
1350                return ret;
1351
1352        /* handle the case where the array was allocated */
1353        *codes = arg.codes;
1354        *count = arg.count;
1355
1356        if (idx)
1357                *idx = arg.idx;
1358
1359        return PFM_SUCCESS;
1360}
1361
1362static int
1363pfmlib_check_event_pattrs(pfmlib_pmu_t *pmu, int pidx, pfm_os_t osid, FILE *fp)
1364{
1365        pfmlib_event_desc_t e;
1366        int i, j, ret;
1367
1368        memset(&e, 0, sizeof(e));
1369        e.event = pidx;
1370        e.osid  = osid;
1371        e.pmu   = pmu;
1372
1373        ret = pfmlib_build_event_pattrs(&e);
1374        if (ret != PFM_SUCCESS) {
1375                fprintf(fp, "invalid pattrs for event %d\n", pidx);
1376                return ret;
1377        }
1378
1379        ret = PFM_ERR_ATTR;
1380
1381        for (i = 0; i < e.npattrs; i++) {
1382                for (j = i+1; j < e.npattrs; j++) {
1383                        if (!strcmp(e.pattrs[i].name, e.pattrs[j].name)) {
1384                                fprintf(fp, "event %d duplicate pattrs %s\n", pidx, e.pattrs[i].name);
1385                                goto error;
1386                        }
1387                }
1388        }
1389        ret = PFM_SUCCESS;
1390error:
1391        /*
1392         * release resources allocated for event
1393         */
1394        pfmlib_release_event(&e);
1395        return ret;
1396}
1397
1398static int
1399pfmlib_validate_encoding(char *buf, int plm)
1400{
1401        uint64_t *codes = NULL;
1402        int count = 0, ret;
1403
1404        ret = pfm_get_event_encoding(buf, plm, NULL, NULL, &codes, &count);
1405        if (ret != PFM_SUCCESS) {
1406                int i;
1407                DPRINT("%s ", buf);
1408                for(i=0; i < count; i++)
1409                        __pfm_dbprintf(" %#"PRIx64, codes[i]);
1410                __pfm_dbprintf("\n");
1411        }
1412        if (codes)
1413                free(codes);
1414
1415        return ret;
1416}
1417
1418static int
1419pfmlib_pmu_validate_encoding(pfmlib_pmu_t *pmu, FILE *fp)
1420{
1421        pfm_event_info_t einfo;
1422        pfm_event_attr_info_t ainfo;
1423        char *buf;
1424        size_t maxlen = 0, len;
1425        int i, u, n = 0, um;
1426        int ret, retval = PFM_SUCCESS;
1427
1428        pfmlib_for_each_pmu_event(pmu, i) {
1429                ret = pmu->get_event_info(pmu, i, &einfo);
1430                if (ret != PFM_SUCCESS)
1431                        return ret;
1432
1433                ret = pfmlib_check_event_pattrs(pmu, i, PFM_OS_NONE, fp);
1434                if (ret != PFM_SUCCESS)
1435                        return ret;
1436
1437                len = strlen(einfo.name);
1438                if (len > maxlen)
1439                        maxlen = len;
1440
1441                for_each_pmu_event_attr(u, &einfo) {
1442                        ret = pmu->get_event_attr_info(pmu, i, u, &ainfo);
1443                        if (ret != PFM_SUCCESS)
1444                                return ret;
1445
1446                        if (ainfo.type != PFM_ATTR_UMASK)
1447                                continue;
1448
1449                        len = strlen(einfo.name) + strlen(ainfo.name);
1450                        if (len > maxlen)
1451                                maxlen = len;
1452                }
1453        }
1454        /* 2 = ::, 1=:, 1=eol */
1455        maxlen += strlen(pmu->name) + 2 + 1 + 1;
1456        buf = malloc(maxlen);
1457        if (!buf)
1458                return PFM_ERR_NOMEM;
1459
1460        pfmlib_for_each_pmu_event(pmu, i) {
1461                ret = pmu->get_event_info(pmu, i, &einfo);
1462                if (ret != PFM_SUCCESS) {
1463                        retval = ret;
1464                        continue;
1465                }
1466
1467                um = 0;
1468                for_each_pmu_event_attr(u, &einfo) {
1469                        ret = pmu->get_event_attr_info(pmu, i, u, &ainfo);
1470                        if (ret != PFM_SUCCESS) {
1471                                retval = ret;
1472                                continue;
1473                        }
1474
1475                        if (ainfo.type != PFM_ATTR_UMASK)
1476                                continue;
1477
1478                        /*
1479                         * XXX: some events may require more than one umasks to encode
1480                         */
1481                        sprintf(buf, "%s::%s:%s", pmu->name, einfo.name, ainfo.name);
1482                        ret = pfmlib_validate_encoding(buf, PFM_PLM3|PFM_PLM0);
1483                        if (ret != PFM_SUCCESS) {
1484                                if (pmu->can_auto_encode) {
1485                                        if (!pmu->can_auto_encode(pmu, i, u))
1486                                                continue;
1487                                }
1488                                /*
1489                                 * some PMU may not support raw encoding
1490                                 */
1491                                if (ret != PFM_ERR_NOTSUPP) {
1492                                        fprintf(fp, "cannot encode event %s : %s\n", buf, pfm_strerror(ret));
1493                                        retval = ret;
1494                                }
1495                                continue;
1496                        }
1497                        um++;
1498                }
1499                if (um == 0) {
1500                        sprintf(buf, "%s::%s", pmu->name, einfo.name);
1501                        ret = pfmlib_validate_encoding(buf, PFM_PLM3|PFM_PLM0);
1502                        if (ret != PFM_SUCCESS) {
1503                                if (pmu->can_auto_encode) {
1504                                        if (!pmu->can_auto_encode(pmu, i, u))
1505                                                continue;
1506                                }
1507                                if (ret != PFM_ERR_NOTSUPP) {
1508                                        fprintf(fp, "cannot encode event %s : %s\n", buf, pfm_strerror(ret));
1509                                        retval = ret;
1510                                }
1511                                continue;
1512                        }
1513                }
1514                n++;
1515        }
1516        free(buf);
1517
1518        return retval;
1519}
1520
1521int
1522pfm_pmu_validate(pfm_pmu_t pmu_id, FILE *fp)
1523{
1524        pfmlib_pmu_t *pmu, *pmx;
1525        int nos = 0;
1526        int i, ret;
1527
1528        if (fp == NULL)
1529                return PFM_ERR_INVAL;
1530
1531        pmu = pmu2pmuidx(pmu_id);
1532        if (!pmu)
1533                return PFM_ERR_INVAL;
1534
1535
1536        if (!pfmlib_pmu_initialized(pmu)) {
1537                fprintf(fp, "pmu: %s :: initialization failed\n", pmu->name);
1538                return PFM_ERR_INVAL;
1539        }
1540
1541        if (!pmu->name) {
1542                fprintf(fp, "pmu id: %d :: no name\n", pmu->pmu);
1543                return PFM_ERR_INVAL;
1544        }
1545
1546        if (!pmu->desc) {
1547                fprintf(fp, "pmu: %s :: no description\n", pmu->name);
1548                return PFM_ERR_INVAL;
1549        }
1550
1551        if (pmu->pmu >= PFM_PMU_MAX) {
1552                fprintf(fp, "pmu: %s :: invalid PMU id\n", pmu->name);
1553                return PFM_ERR_INVAL;
1554        }
1555
1556        if (pmu->max_encoding >= PFMLIB_MAX_ENCODING) {
1557                fprintf(fp, "pmu: %s :: max encoding too high\n", pmu->name);
1558                return PFM_ERR_INVAL;
1559        }
1560
1561        if (pfmlib_pmu_active(pmu)  && !pmu->pme_count) {
1562                fprintf(fp, "pmu: %s :: no events\n", pmu->name);
1563                return PFM_ERR_INVAL;
1564        }
1565        if (!pmu->pmu_detect) {
1566                fprintf(fp, "pmu: %s :: missing pmu_detect callback\n", pmu->name);
1567                return PFM_ERR_INVAL;
1568        }
1569        if (!pmu->get_event_first) {
1570                fprintf(fp, "pmu: %s :: missing get_event_first callback\n", pmu->name);
1571                return PFM_ERR_INVAL;
1572        }
1573        if (!pmu->get_event_next) {
1574                fprintf(fp, "pmu: %s :: missing get_event_next callback\n", pmu->name);
1575                return PFM_ERR_INVAL;
1576        }
1577        if (!pmu->get_event_info) {
1578                fprintf(fp, "pmu: %s :: missing get_event_info callback\n", pmu->name);
1579                return PFM_ERR_INVAL;
1580        }
1581        if (!pmu->get_event_attr_info) {
1582                fprintf(fp, "pmu: %s :: missing get_event_attr_info callback\n", pmu->name);
1583                return PFM_ERR_INVAL;
1584        }
1585        for (i = PFM_OS_NONE; i < PFM_OS_MAX; i++) {
1586                if (pmu->get_event_encoding[i])
1587                        nos++;
1588        }
1589        if (!nos) {
1590                fprintf(fp, "pmu: %s :: no os event encoding callback\n", pmu->name);
1591                return PFM_ERR_INVAL;
1592        }
1593        if (!pmu->max_encoding) {
1594                fprintf(fp, "pmu: %s :: max_encoding is zero\n", pmu->name);
1595                return PFM_ERR_INVAL;
1596        }
1597
1598        /* look for duplicate names, id */
1599        pfmlib_for_each_pmu(i) {
1600                pmx = pfmlib_pmus[i];
1601                if (!pfmlib_pmu_active(pmx))
1602                        continue;
1603                if (pmx == pmu)
1604                        continue;
1605                if (!strcasecmp(pmx->name, pmu->name)) {
1606                        fprintf(fp, "pmu: %s :: duplicate name\n", pmu->name);
1607                        return PFM_ERR_INVAL;
1608                }
1609                if (pmx->pmu == pmu->pmu) {
1610                        fprintf(fp, "pmu: %s :: duplicate id\n", pmu->name);
1611                        return PFM_ERR_INVAL;
1612                }
1613        }
1614
1615        if (pmu->validate_table) {
1616                ret = pmu->validate_table(pmu, fp);
1617                if (ret != PFM_SUCCESS)
1618                        return ret;
1619        }
1620        return pfmlib_pmu_validate_encoding(pmu, fp);
1621}
1622
1623int
1624pfm_get_event_info(int idx, pfm_os_t os, pfm_event_info_t *uinfo)
1625{
1626        pfm_event_info_t info;
1627        pfmlib_event_desc_t e;
1628        pfmlib_pmu_t *pmu;
1629        size_t sz = sizeof(info);
1630        int pidx, ret;
1631
1632        if (!PFMLIB_INITIALIZED())
1633                return PFM_ERR_NOINIT;
1634
1635        if (os >= PFM_OS_MAX)
1636                return PFM_ERR_INVAL;
1637
1638        pmu = pfmlib_idx2pidx(idx, &pidx);
1639        if (!pmu)
1640                return PFM_ERR_INVAL;
1641
1642        if (!uinfo)
1643                return PFM_ERR_INVAL;
1644
1645        sz = pfmlib_check_struct(uinfo, uinfo->size, PFM_EVENT_INFO_ABI0, sz);
1646        if (!sz)
1647                return PFM_ERR_INVAL;
1648
1649        memset(&info, 0, sizeof(info));
1650
1651        info.size = sz;
1652
1653        /* default data type is uint64 */
1654        info.dtype = PFM_DTYPE_UINT64;
1655
1656        /* reset flags */
1657        info.is_precise = 0;
1658
1659        ret = pmu->get_event_info(pmu, pidx, &info);
1660        if (ret != PFM_SUCCESS)
1661                return ret;
1662
1663        info.pmu = pmu->pmu;
1664        info.idx = idx;
1665
1666        memset(&e, 0, sizeof(e));
1667        e.event = pidx;
1668        e.osid  = os;
1669        e.pmu   = pmu;
1670
1671        ret = pfmlib_build_event_pattrs(&e);
1672        if (ret == PFM_SUCCESS) {
1673                info.nattrs = e.npattrs;
1674                memcpy(uinfo, &info, sz);
1675        }
1676
1677        pfmlib_release_event(&e);
1678        return ret;
1679}
1680
1681int
1682pfm_get_event_attr_info(int idx, int attr_idx, pfm_os_t os, pfm_event_attr_info_t *uinfo)
1683{
1684        pfm_event_attr_info_t info;
1685        pfmlib_event_desc_t e;
1686        pfmlib_pmu_t *pmu;
1687        size_t sz = sizeof(info);
1688        int pidx, ret;
1689
1690        if (!PFMLIB_INITIALIZED())
1691                return PFM_ERR_NOINIT;
1692
1693        if (attr_idx < 0)
1694                return PFM_ERR_INVAL;
1695
1696        if (os >= PFM_OS_MAX)
1697                return PFM_ERR_INVAL;
1698
1699        pmu = pfmlib_idx2pidx(idx, &pidx);
1700        if (!pmu)
1701                return PFM_ERR_INVAL;
1702
1703        if (!uinfo)
1704                return PFM_ERR_INVAL;
1705
1706        sz = pfmlib_check_struct(uinfo, uinfo->size, PFM_ATTR_INFO_ABI0, sz);
1707        if (!sz)
1708                return PFM_ERR_INVAL;
1709
1710        memset(&e, 0, sizeof(e));
1711        e.event = pidx;
1712        e.osid  = os;
1713        e.pmu   = pmu;
1714
1715        ret = pfmlib_build_event_pattrs(&e);
1716        if (ret != PFM_SUCCESS)
1717                return ret;
1718
1719        ret = PFM_ERR_INVAL;
1720
1721        if (attr_idx >= e.npattrs)
1722                goto error;
1723
1724        /*
1725         * copy event_attr_info
1726         */
1727        info = e.pattrs[attr_idx];
1728
1729        /*
1730         * rewrite size to reflect what we are returning
1731         */
1732        info.size = sz;
1733        /*
1734         * info.idx = private, namespace specific index,
1735         * should not be visible externally, so override
1736         * with public index
1737         */
1738        info.idx  = attr_idx;
1739
1740        memcpy(uinfo, &info, sz);
1741
1742        ret = PFM_SUCCESS;
1743error:
1744        pfmlib_release_event(&e);
1745        return ret;
1746}
1747
1748int
1749pfm_get_pmu_info(pfm_pmu_t pmuid, pfm_pmu_info_t *uinfo)
1750{
1751        pfm_pmu_info_t info;
1752        pfmlib_pmu_t *pmu;
1753        size_t sz = sizeof(info);
1754        int pidx;
1755
1756        if (!PFMLIB_INITIALIZED())
1757                return PFM_ERR_NOINIT;
1758
1759        if (pmuid >= PFM_PMU_MAX)
1760                return PFM_ERR_INVAL;
1761
1762        if (!uinfo)
1763                return PFM_ERR_INVAL;
1764
1765        sz = pfmlib_check_struct(uinfo, uinfo->size, PFM_PMU_INFO_ABI0, sz);
1766        if (!sz)
1767                return PFM_ERR_INVAL;
1768 
1769        pmu = pfmlib_pmus_map[pmuid];
1770        if (!pmu)
1771                return PFM_ERR_NOTSUPP;
1772
1773        info.name = pmu->name;
1774        info.desc = pmu->desc;
1775        info.pmu  = pmuid;
1776        info.size = sz;
1777
1778        info.max_encoding    = pmu->max_encoding;
1779        info.num_cntrs       = pmu->num_cntrs;
1780        info.num_fixed_cntrs = pmu->num_fixed_cntrs;
1781
1782        pidx = pmu->get_event_first(pmu);
1783        if (pidx == -1)
1784                info.first_event = -1;
1785        else
1786                info.first_event = pfmlib_pidx2idx(pmu, pidx);
1787
1788        /*
1789         * XXX: pme_count only valid when PMU is detected
1790         */
1791        info.is_present = pfmlib_pmu_active(pmu);
1792        info.is_dfl     = !!(pmu->flags & PFMLIB_PMU_FL_ARCH_DFL);
1793        info.type       = pmu->type;
1794
1795        if (pmu->get_num_events)
1796                info.nevents = pmu->get_num_events(pmu);
1797        else
1798                info.nevents    = pmu->pme_count;
1799
1800        memcpy(uinfo, &info, sz);
1801
1802        return PFM_SUCCESS;
1803}
1804
1805pfmlib_pmu_t *
1806pfmlib_get_pmu_by_type(pfm_pmu_type_t t)
1807{
1808        pfmlib_pmu_t *pmu;
1809        int i;
1810
1811        pfmlib_for_each_pmu(i) {
1812                pmu = pfmlib_pmus[i];
1813
1814                if (!pfmlib_pmu_active(pmu))
1815                        continue;
1816
1817                /* first match */
1818                if (pmu->type != t)
1819                        continue;
1820
1821                return pmu;
1822        }
1823        return NULL;
1824}
1825
1826static int
1827pfmlib_compare_attr_id(const void *a, const void *b)
1828{
1829        const pfmlib_attr_t *t1 = a;
1830        const pfmlib_attr_t *t2 = b;
1831
1832        if (t1->id < t2->id)
1833                return -1;
1834        return t1->id == t2->id ? 0 : 1;
1835}
1836
1837void
1838pfmlib_sort_attr(pfmlib_event_desc_t *e)
1839{
1840        qsort(e->attrs, e->nattrs, sizeof(pfmlib_attr_t), pfmlib_compare_attr_id);
1841}
1842
1843static int
1844pfmlib_raw_pmu_encode(void *this, const char *str, int dfl_plm, void *data)
1845{
1846        pfm_pmu_encode_arg_t arg;
1847        pfm_pmu_encode_arg_t *uarg = data;
1848
1849        pfmlib_pmu_t *pmu;
1850        pfmlib_event_desc_t e;
1851        size_t sz = sizeof(arg);
1852        int ret, i;
1853
1854        sz = pfmlib_check_struct(uarg, uarg->size, PFM_RAW_ENCODE_ABI0, sz);
1855        if (!sz)
1856                return PFM_ERR_INVAL;
1857
1858        memset(&arg, 0, sizeof(arg));
1859
1860        /*
1861         * get input data
1862         */
1863        memcpy(&arg, uarg, sz);
1864
1865        memset(&e, 0, sizeof(e));
1866
1867        e.osid    = PFM_OS_NONE;
1868        e.dfl_plm = dfl_plm;
1869
1870        ret = pfmlib_parse_event(str, &e);
1871        if (ret != PFM_SUCCESS)
1872                return ret;
1873
1874        pmu = e.pmu;
1875
1876        if (!pmu->get_event_encoding[PFM_OS_NONE]) {
1877                DPRINT("PMU %s does not support PFM_OS_NONE\n", pmu->name);
1878                return PFM_ERR_NOTSUPP;
1879        }
1880
1881        ret = pmu->get_event_encoding[PFM_OS_NONE](pmu, &e);
1882        if (ret != PFM_SUCCESS)
1883                goto error;
1884        /*
1885         * return opaque event identifier
1886         */
1887        arg.idx = pfmlib_pidx2idx(e.pmu, e.event);
1888
1889        if (arg.codes == NULL) {
1890                ret = PFM_ERR_NOMEM;
1891                arg.codes = malloc(sizeof(uint64_t) * e.count);
1892                if (!arg.codes)
1893                        goto error_fstr;
1894        } else if (arg.count < e.count) {
1895                ret = PFM_ERR_TOOSMALL;
1896                goto error_fstr;
1897        }
1898
1899        arg.count = e.count;
1900
1901        for (i = 0; i < e.count; i++)
1902                arg.codes[i] = e.codes[i];
1903
1904        if (arg.fstr) {
1905                ret = pfmlib_build_fstr(&e, arg.fstr);
1906                if (ret != PFM_SUCCESS)
1907                        goto error;
1908        }
1909
1910        ret = PFM_SUCCESS;
1911
1912        /* copy out results */
1913        memcpy(uarg, &arg, sz);
1914
1915error_fstr:
1916        if (ret != PFM_SUCCESS)
1917                free(arg.fstr);
1918error:
1919        /*
1920         * release resources allocated for event
1921         */
1922        pfmlib_release_event(&e);
1923        return ret;
1924}
1925
1926static int
1927pfmlib_raw_pmu_detect(void *this)
1928{
1929        return PFM_SUCCESS;
1930}
1931
1932static pfmlib_os_t pfmlib_os_none= {
1933        .name = "No OS (raw PMU)",
1934        .id = PFM_OS_NONE,
1935        .flags = PFMLIB_OS_FL_ACTIVATED,
1936        .encode = pfmlib_raw_pmu_encode,
1937        .detect = pfmlib_raw_pmu_detect,
1938};
1939