1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2018, Matthew Macy 5 * Copyright (c) 2021, The FreeBSD Foundation 6 * 7 * Portions of this software were developed by Mitchell Horne 8 * under sponsorship from the FreeBSD Foundation. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $FreeBSD$ 32 * 33 */ 34 35 #include <sys/types.h> 36 #include <sys/errno.h> 37 #include <sys/pmc.h> 38 #include <sys/sysctl.h> 39 #include <stddef.h> 40 #include <stdlib.h> 41 #include <limits.h> 42 #include <regex.h> 43 #include <string.h> 44 #include <pmc.h> 45 #include <pmclog.h> 46 #include <assert.h> 47 #include <libpmcstat.h> 48 #include "pmu-events/pmu-events.h" 49 50 struct pmu_alias { 51 const char *pa_alias; 52 const char *pa_name; 53 }; 54 55 #if defined(__amd64__) || defined(__i386__) 56 typedef enum { 57 PMU_INVALID, 58 PMU_INTEL, 59 PMU_AMD, 60 } pmu_mfr_t; 61 62 static struct pmu_alias pmu_intel_alias_table[] = { 63 {"UNHALTED_CORE_CYCLES", "cpu_clk_unhalted.thread"}, 64 {"UNHALTED-CORE-CYCLES", "cpu_clk_unhalted.thread"}, 65 {"LLC_MISSES", "LONGEST_LAT_CACHE.MISS"}, 66 {"LLC-MISSES", "LONGEST_LAT_CACHE.MISS"}, 67 {"LLC_REFERENCE", "LONGEST_LAT_CACHE.REFERENCE"}, 68 {"LLC-REFERENCE", "LONGEST_LAT_CACHE.REFERENCE"}, 69 {"LLC_MISS_RHITM", "mem_load_l3_miss_retired.remote_hitm"}, 70 {"LLC-MISS-RHITM", "mem_load_l3_miss_retired.remote_hitm"}, 71 {"RESOURCE_STALL", "RESOURCE_STALLS.ANY"}, 72 {"RESOURCE_STALLS_ANY", "RESOURCE_STALLS.ANY"}, 73 {"BRANCH_INSTRUCTION_RETIRED", "BR_INST_RETIRED.ALL_BRANCHES"}, 74 {"BRANCH-INSTRUCTION-RETIRED", "BR_INST_RETIRED.ALL_BRANCHES"}, 75 {"BRANCH_MISSES_RETIRED", "BR_MISP_RETIRED.ALL_BRANCHES"}, 76 {"BRANCH-MISSES-RETIRED", "BR_MISP_RETIRED.ALL_BRANCHES"}, 77 {"unhalted-cycles", "cpu_clk_unhalted.thread"}, 78 {"instructions", "inst_retired.any"}, 79 {"branch-mispredicts", "br_misp_retired.all_branches"}, 80 {"branches", "br_inst_retired.all_branches"}, 81 {"interrupts", "hw_interrupts.received"}, 82 {"ic-misses", "frontend_retired.l1i_miss"}, 83 {NULL, NULL}, 84 }; 85 86 static struct pmu_alias pmu_amd_alias_table[] = { 87 {"UNHALTED_CORE_CYCLES", "ls_not_halted_cyc"}, 88 {"UNHALTED-CORE-CYCLES", "ls_not_halted_cyc"}, 89 {"LLC_MISSES", "l3_comb_clstr_state.request_miss"}, 90 {"LLC-MISSES", "l3_comb_clstr_state.request_miss"}, 91 {"LLC_REFERENCE", "l3_request_g1.caching_l3_cache_accesses"}, 92 {"LLC-REFERENCE", "l3_request_g1.caching_l3_cache_accesses"}, 93 {"BRANCH_INSTRUCTION_RETIRED", "ex_ret_brn"}, 94 {"BRANCH-INSTRUCTION-RETIRED", "ex_ret_brn"}, 95 {"BRANCH_MISSES_RETIRED", "ex_ret_brn_misp"}, 96 {"BRANCH-MISSES-RETIRED", "ex_ret_brn_misp"}, 97 {"unhalted-cycles", "ls_not_halted_cyc"}, 98 {"instructions", "ex_ret_instr",}, 99 {"branch-mispredicts", "ex_ret_brn_misp"}, 100 {"branches", "ex_ret_brn"}, 101 {"interrupts", "ls_int_taken"}, /* Not on amdzen1 */ 102 {NULL, NULL}, 103 }; 104 105 106 static pmu_mfr_t 107 pmu_events_mfr(void) 108 { 109 char buf[PMC_CPUID_LEN]; 110 size_t s = sizeof(buf); 111 pmu_mfr_t mfr; 112 113 if (sysctlbyname("kern.hwpmc.cpuid", buf, &s, 114 (void *)NULL, 0) == -1) 115 return (PMU_INVALID); 116 if (strcasestr(buf, "AuthenticAMD") != NULL || 117 strcasestr(buf, "HygonGenuine") != NULL) 118 mfr = PMU_AMD; 119 else if (strcasestr(buf, "GenuineIntel") != NULL) 120 mfr = PMU_INTEL; 121 else 122 mfr = PMU_INVALID; 123 return (mfr); 124 } 125 126 /* 127 * The Intel fixed mode counters are: 128 * "inst_retired.any", 129 * "cpu_clk_unhalted.thread", 130 * "cpu_clk_unhalted.thread_any", 131 * "cpu_clk_unhalted.ref_tsc", 132 * 133 */ 134 135 static const char * 136 pmu_alias_get(const char *name) 137 { 138 pmu_mfr_t mfr; 139 struct pmu_alias *pa; 140 struct pmu_alias *pmu_alias_table; 141 142 if ((mfr = pmu_events_mfr()) == PMU_INVALID) 143 return (name); 144 if (mfr == PMU_AMD) 145 pmu_alias_table = pmu_amd_alias_table; 146 else if (mfr == PMU_INTEL) 147 pmu_alias_table = pmu_intel_alias_table; 148 else 149 return (name); 150 151 for (pa = pmu_alias_table; pa->pa_alias != NULL; pa++) 152 if (strcasecmp(name, pa->pa_alias) == 0) 153 return (pa->pa_name); 154 155 return (name); 156 } 157 #elif defined(__powerpc64__) 158 159 static const char * 160 pmu_alias_get(const char *name) 161 { 162 return (name); 163 } 164 165 #elif defined(__aarch64__) 166 167 static struct pmu_alias pmu_armv8_alias_table[] = { 168 {"UNHALTED_CORE_CYCLES", "CPU_CYCLES"}, 169 {"UNHALTED-CORE-CYCLES", "CPU_CYCLES"}, 170 {"LLC_MISSES", "LL_CACHE_MISS_RD"}, 171 {"LLC-MISSES", "LL_CACHE_MISS_RD"}, 172 {"LLC_REFERENCE", "LL_CACHE_RD"}, 173 {"LLC-REFERENCE", "LL_CACHE_RD"}, 174 {"BRANCH_INSTRUCTION_RETIRED", "BR_RETIRED"}, 175 {"BRANCH-INSTRUCTION-RETIRED", "BR_RETIRED"}, 176 {"BRANCH_MISSES_RETIRED", "BR_MIS_PRED_RETIRED"}, 177 {"BRANCH-MISSES-RETIRED", "BR_MIS_PRED_RETIRED"}, 178 {"unhalted-cycles", "CPU_CYCLES"}, 179 {"instructions", "INST_RETIRED",}, 180 {"branch-mispredicts", "BR_MIS_PRED_RETIRED"}, 181 {"branches", "BR_RETIRED"}, 182 {"interrupts", "EXC_IRQ"}, 183 {NULL, NULL}, 184 }; 185 186 static const char * 187 pmu_alias_get(const char *name) 188 { 189 struct pmu_alias *pa; 190 191 for (pa = pmu_armv8_alias_table; pa->pa_alias != NULL; pa++) 192 if (strcasecmp(name, pa->pa_alias) == 0) 193 return (pa->pa_name); 194 195 return (name); 196 } 197 198 #else 199 200 static const char * 201 pmu_alias_get(const char *name) 202 { 203 204 return (name); 205 } 206 #endif 207 208 struct pmu_event_desc { 209 uint64_t ped_period; 210 uint64_t ped_offcore_rsp; 211 uint64_t ped_l3_thread; 212 uint64_t ped_l3_slice; 213 uint32_t ped_event; 214 uint32_t ped_frontend; 215 uint32_t ped_ldlat; 216 uint32_t ped_config1; 217 int16_t ped_umask; 218 uint8_t ped_cmask; 219 uint8_t ped_any; 220 uint8_t ped_inv; 221 uint8_t ped_edge; 222 uint8_t ped_fc_mask; 223 uint8_t ped_ch_mask; 224 }; 225 226 static const struct pmu_events_map * 227 pmu_events_map_get(const char *cpuid) 228 { 229 regex_t re; 230 regmatch_t pmatch[1]; 231 char buf[PMC_CPUID_LEN]; 232 size_t s = sizeof(buf); 233 int match; 234 const struct pmu_events_map *pme; 235 236 if (cpuid != NULL) { 237 strlcpy(buf, cpuid, s); 238 } else { 239 if (sysctlbyname("kern.hwpmc.cpuid", buf, &s, 240 (void *)NULL, 0) == -1) 241 return (NULL); 242 } 243 for (pme = pmu_events_map; pme->cpuid != NULL; pme++) { 244 if (regcomp(&re, pme->cpuid, REG_EXTENDED) != 0) { 245 printf("regex '%s' failed to compile, ignoring\n", 246 pme->cpuid); 247 continue; 248 } 249 match = regexec(&re, buf, 1, pmatch, 0); 250 regfree(&re); 251 if (match == 0) { 252 if (pmatch[0].rm_so == 0 && (buf[pmatch[0].rm_eo] == 0 253 || buf[pmatch[0].rm_eo] == '-')) 254 return (pme); 255 } 256 } 257 return (NULL); 258 } 259 260 static const struct pmu_event * 261 pmu_event_get(const char *cpuid, const char *event_name, int *idx) 262 { 263 const struct pmu_events_map *pme; 264 const struct pmu_event *pe; 265 int i; 266 267 if ((pme = pmu_events_map_get(cpuid)) == NULL) 268 return (NULL); 269 for (i = 0, pe = pme->table; pe->name || pe->desc || pe->event; pe++, i++) { 270 if (pe->name == NULL) 271 continue; 272 if (strcasecmp(pe->name, event_name) == 0) { 273 if (idx) 274 *idx = i; 275 return (pe); 276 } 277 } 278 return (NULL); 279 } 280 281 int 282 pmc_pmu_idx_get_by_event(const char *cpuid, const char *event) 283 { 284 int idx; 285 const char *realname; 286 287 realname = pmu_alias_get(event); 288 if (pmu_event_get(cpuid, realname, &idx) == NULL) 289 return (-1); 290 return (idx); 291 } 292 293 const char * 294 pmc_pmu_event_get_by_idx(const char *cpuid, int idx) 295 { 296 const struct pmu_events_map *pme; 297 298 if ((pme = pmu_events_map_get(cpuid)) == NULL) 299 return (NULL); 300 assert(pme->table[idx].name); 301 return (pme->table[idx].name); 302 } 303 304 static int 305 pmu_parse_event(struct pmu_event_desc *ped, const char *eventin) 306 { 307 char *event; 308 char *kvp, *key, *value, *r; 309 char *debug; 310 311 if ((event = strdup(eventin)) == NULL) 312 return (ENOMEM); 313 r = event; 314 bzero(ped, sizeof(*ped)); 315 ped->ped_period = DEFAULT_SAMPLE_COUNT; 316 ped->ped_umask = -1; 317 while ((kvp = strsep(&event, ",")) != NULL) { 318 key = strsep(&kvp, "="); 319 if (key == NULL) 320 abort(); 321 value = kvp; 322 if (strcmp(key, "umask") == 0) 323 ped->ped_umask = strtol(value, NULL, 16); 324 else if (strcmp(key, "event") == 0) 325 ped->ped_event = strtol(value, NULL, 16); 326 else if (strcmp(key, "period") == 0) 327 ped->ped_period = strtol(value, NULL, 10); 328 else if (strcmp(key, "offcore_rsp") == 0) 329 ped->ped_offcore_rsp = strtol(value, NULL, 16); 330 else if (strcmp(key, "any") == 0) 331 ped->ped_any = strtol(value, NULL, 10); 332 else if (strcmp(key, "cmask") == 0) 333 ped->ped_cmask = strtol(value, NULL, 10); 334 else if (strcmp(key, "inv") == 0) 335 ped->ped_inv = strtol(value, NULL, 10); 336 else if (strcmp(key, "edge") == 0) 337 ped->ped_edge = strtol(value, NULL, 10); 338 else if (strcmp(key, "frontend") == 0) 339 ped->ped_frontend = strtol(value, NULL, 16); 340 else if (strcmp(key, "ldlat") == 0) 341 ped->ped_ldlat = strtol(value, NULL, 16); 342 else if (strcmp(key, "fc_mask") == 0) 343 ped->ped_fc_mask = strtol(value, NULL, 16); 344 else if (strcmp(key, "ch_mask") == 0) 345 ped->ped_ch_mask = strtol(value, NULL, 16); 346 else if (strcmp(key, "config1") == 0) 347 ped->ped_config1 = strtol(value, NULL, 16); 348 else if (strcmp(key, "l3_thread_mask") == 0) 349 ped->ped_l3_thread = strtol(value, NULL, 16); 350 else if (strcmp(key, "l3_slice_mask") == 0) 351 ped->ped_l3_slice = strtol(value, NULL, 16); 352 else { 353 debug = getenv("PMUDEBUG"); 354 if (debug != NULL && strcmp(debug, "true") == 0 && value != NULL) 355 printf("unrecognized kvpair: %s:%s\n", key, value); 356 } 357 } 358 free(r); 359 return (0); 360 } 361 362 uint64_t 363 pmc_pmu_sample_rate_get(const char *event_name) 364 { 365 const struct pmu_event *pe; 366 struct pmu_event_desc ped; 367 368 event_name = pmu_alias_get(event_name); 369 if ((pe = pmu_event_get(NULL, event_name, NULL)) == NULL) 370 return (DEFAULT_SAMPLE_COUNT); 371 if (pe->event == NULL) 372 return (DEFAULT_SAMPLE_COUNT); 373 if (pmu_parse_event(&ped, pe->event)) 374 return (DEFAULT_SAMPLE_COUNT); 375 return (ped.ped_period); 376 } 377 378 int 379 pmc_pmu_enabled(void) 380 { 381 382 return (pmu_events_map_get(NULL) != NULL); 383 } 384 385 void 386 pmc_pmu_print_counters(const char *event_name) 387 { 388 const struct pmu_events_map *pme; 389 const struct pmu_event *pe; 390 struct pmu_event_desc ped; 391 char *debug; 392 int do_debug; 393 394 debug = getenv("PMUDEBUG"); 395 do_debug = 0; 396 397 if (debug != NULL && strcmp(debug, "true") == 0) 398 do_debug = 1; 399 if ((pme = pmu_events_map_get(NULL)) == NULL) 400 return; 401 for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) { 402 if (pe->name == NULL) 403 continue; 404 if (event_name != NULL && strcasestr(pe->name, event_name) == NULL) 405 continue; 406 printf("\t%s\n", pe->name); 407 if (do_debug) 408 pmu_parse_event(&ped, pe->event); 409 } 410 } 411 412 void 413 pmc_pmu_print_counter_desc(const char *ev) 414 { 415 const struct pmu_events_map *pme; 416 const struct pmu_event *pe; 417 418 if ((pme = pmu_events_map_get(NULL)) == NULL) 419 return; 420 for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) { 421 if (pe->name == NULL) 422 continue; 423 if (strcasestr(pe->name, ev) != NULL && 424 pe->desc != NULL) 425 printf("%s:\t%s\n", pe->name, pe->desc); 426 } 427 } 428 429 void 430 pmc_pmu_print_counter_desc_long(const char *ev) 431 { 432 const struct pmu_events_map *pme; 433 const struct pmu_event *pe; 434 435 if ((pme = pmu_events_map_get(NULL)) == NULL) 436 return; 437 for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) { 438 if (pe->name == NULL) 439 continue; 440 if (strcasestr(pe->name, ev) != NULL) { 441 if (pe->long_desc != NULL) 442 printf("%s:\n%s\n", pe->name, pe->long_desc); 443 else if (pe->desc != NULL) 444 printf("%s:\t%s\n", pe->name, pe->desc); 445 } 446 } 447 } 448 449 void 450 pmc_pmu_print_counter_full(const char *ev) 451 { 452 const struct pmu_events_map *pme; 453 const struct pmu_event *pe; 454 455 if ((pme = pmu_events_map_get(NULL)) == NULL) 456 return; 457 for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) { 458 if (pe->name == NULL) 459 continue; 460 if (strcasestr(pe->name, ev) == NULL) 461 continue; 462 printf("name: %s\n", pe->name); 463 if (pe->long_desc != NULL) 464 printf("desc: %s\n", pe->long_desc); 465 else if (pe->desc != NULL) 466 printf("desc: %s\n", pe->desc); 467 if (pe->event != NULL) 468 printf("event: %s\n", pe->event); 469 if (pe->topic != NULL) 470 printf("topic: %s\n", pe->topic); 471 if (pe->pmu != NULL) 472 printf("pmu: %s\n", pe->pmu); 473 if (pe->unit != NULL) 474 printf("unit: %s\n", pe->unit); 475 if (pe->perpkg != NULL) 476 printf("perpkg: %s\n", pe->perpkg); 477 if (pe->metric_expr != NULL) 478 printf("metric_expr: %s\n", pe->metric_expr); 479 if (pe->metric_name != NULL) 480 printf("metric_name: %s\n", pe->metric_name); 481 if (pe->metric_group != NULL) 482 printf("metric_group: %s\n", pe->metric_group); 483 } 484 } 485 486 #if defined(__amd64__) || defined(__i386__) 487 static int 488 pmc_pmu_amd_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm, 489 struct pmu_event_desc *ped) 490 { 491 struct pmc_md_amd_op_pmcallocate *amd; 492 const struct pmu_event *pe; 493 int idx = -1; 494 495 amd = &pm->pm_md.pm_amd; 496 if (ped->ped_umask > 0) { 497 pm->pm_caps |= PMC_CAP_QUALIFIER; 498 amd->pm_amd_config |= AMD_PMC_TO_UNITMASK(ped->ped_umask); 499 } 500 pm->pm_class = PMC_CLASS_K8; 501 pe = pmu_event_get(NULL, event_name, &idx); 502 503 if (strcmp("l3cache", pe->topic) == 0){ 504 amd->pm_amd_config |= AMD_PMC_TO_EVENTMASK(ped->ped_event); 505 amd->pm_amd_sub_class = PMC_AMD_SUB_CLASS_L3_CACHE; 506 amd->pm_amd_config |= AMD_PMC_TO_L3SLICE(ped->ped_l3_slice); 507 amd->pm_amd_config |= AMD_PMC_TO_L3CORE(ped->ped_l3_thread); 508 } 509 else if (strcmp("data fabric", pe->topic) == 0){ 510 511 amd->pm_amd_config |= AMD_PMC_TO_EVENTMASK_DF(ped->ped_event); 512 amd->pm_amd_sub_class = PMC_AMD_SUB_CLASS_DATA_FABRIC; 513 } 514 else{ 515 amd->pm_amd_config |= AMD_PMC_TO_EVENTMASK(ped->ped_event); 516 amd->pm_amd_sub_class = PMC_AMD_SUB_CLASS_CORE; 517 if ((pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == 0 || 518 (pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == 519 (PMC_CAP_USER|PMC_CAP_SYSTEM)) 520 amd->pm_amd_config |= (AMD_PMC_USR | AMD_PMC_OS); 521 else if (pm->pm_caps & PMC_CAP_USER) 522 amd->pm_amd_config |= AMD_PMC_USR; 523 else if (pm->pm_caps & PMC_CAP_SYSTEM) 524 amd->pm_amd_config |= AMD_PMC_OS; 525 if (ped->ped_edge) 526 amd->pm_amd_config |= AMD_PMC_EDGE; 527 if (ped->ped_inv) 528 amd->pm_amd_config |= AMD_PMC_INVERT; 529 if (pm->pm_caps & PMC_CAP_INTERRUPT) 530 amd->pm_amd_config |= AMD_PMC_INT; 531 } 532 return (0); 533 } 534 535 static int 536 pmc_pmu_intel_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm, 537 struct pmu_event_desc *ped) 538 { 539 struct pmc_md_iap_op_pmcallocate *iap; 540 541 iap = &pm->pm_md.pm_iap; 542 if (strcasestr(event_name, "UNC_") == event_name || 543 strcasestr(event_name, "uncore") != NULL) { 544 pm->pm_class = PMC_CLASS_UCP; 545 pm->pm_caps |= PMC_CAP_QUALIFIER; 546 } else if (ped->ped_event == 0x0) { 547 pm->pm_class = PMC_CLASS_IAF; 548 } else { 549 pm->pm_class = PMC_CLASS_IAP; 550 pm->pm_caps |= PMC_CAP_QUALIFIER; 551 } 552 iap->pm_iap_config |= IAP_EVSEL(ped->ped_event); 553 if (ped->ped_umask > 0) 554 iap->pm_iap_config |= IAP_UMASK(ped->ped_umask); 555 iap->pm_iap_config |= IAP_CMASK(ped->ped_cmask); 556 iap->pm_iap_rsp = ped->ped_offcore_rsp; 557 558 if ((pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == 0 || 559 (pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == 560 (PMC_CAP_USER|PMC_CAP_SYSTEM)) 561 iap->pm_iap_config |= (IAP_USR | IAP_OS); 562 else if (pm->pm_caps & PMC_CAP_USER) 563 iap->pm_iap_config |= IAP_USR; 564 else if (pm->pm_caps & PMC_CAP_SYSTEM) 565 iap->pm_iap_config |= IAP_OS; 566 if (ped->ped_edge) 567 iap->pm_iap_config |= IAP_EDGE; 568 if (ped->ped_any) 569 iap->pm_iap_config |= IAP_ANY; 570 if (ped->ped_inv) 571 iap->pm_iap_config |= IAP_INV; 572 if (pm->pm_caps & PMC_CAP_INTERRUPT) 573 iap->pm_iap_config |= IAP_INT; 574 return (0); 575 } 576 577 int 578 pmc_pmu_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm) 579 { 580 const struct pmu_event *pe; 581 struct pmu_event_desc ped; 582 pmu_mfr_t mfr; 583 int idx = -1; 584 585 if ((mfr = pmu_events_mfr()) == PMU_INVALID) 586 return (ENOENT); 587 588 bzero(&pm->pm_md, sizeof(pm->pm_md)); 589 pm->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 590 event_name = pmu_alias_get(event_name); 591 if ((pe = pmu_event_get(NULL, event_name, &idx)) == NULL) 592 return (ENOENT); 593 assert(idx >= 0); 594 pm->pm_ev = idx; 595 596 if (pe->event == NULL) 597 return (ENOENT); 598 if (pmu_parse_event(&ped, pe->event)) 599 return (ENOENT); 600 601 if (mfr == PMU_INTEL) 602 return (pmc_pmu_intel_pmcallocate(event_name, pm, &ped)); 603 else 604 return (pmc_pmu_amd_pmcallocate(event_name, pm, &ped)); 605 } 606 607 #elif defined(__powerpc64__) 608 609 int 610 pmc_pmu_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm) 611 { 612 const struct pmu_event *pe; 613 struct pmu_event_desc ped; 614 int idx = -1; 615 616 bzero(&pm->pm_md, sizeof(pm->pm_md)); 617 pm->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 618 event_name = pmu_alias_get(event_name); 619 620 if ((pe = pmu_event_get(NULL, event_name, &idx)) == NULL) 621 return (ENOENT); 622 if (pe->event == NULL) 623 return (ENOENT); 624 if (pmu_parse_event(&ped, pe->event)) 625 return (ENOENT); 626 627 assert(ped.ped_event >= 0); 628 pm->pm_ev = idx; 629 pm->pm_md.pm_event = ped.ped_event; 630 pm->pm_class = PMC_CLASS_POWER8; 631 return (0); 632 } 633 634 #elif defined(__aarch64__) 635 636 int 637 pmc_pmu_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm) 638 { 639 const struct pmu_event *pe; 640 struct pmu_event_desc ped; 641 int idx = -1; 642 643 event_name = pmu_alias_get(event_name); 644 if ((pe = pmu_event_get(NULL, event_name, &idx)) == NULL) 645 return (ENOENT); 646 if (pe->event == NULL) 647 return (ENOENT); 648 if (pmu_parse_event(&ped, pe->event)) 649 return (ENOENT); 650 651 assert(idx >= 0); 652 pm->pm_ev = idx; 653 pm->pm_md.pm_md_config = ped.ped_event; 654 pm->pm_md.pm_md_flags |= PM_MD_RAW_EVENT; 655 pm->pm_class = PMC_CLASS_ARMV8; 656 pm->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 657 658 return (0); 659 } 660 661 #else 662 663 int 664 pmc_pmu_pmcallocate(const char *e __unused, struct pmc_op_pmcallocate *p __unused) 665 { 666 return (EOPNOTSUPP); 667 } 668 #endif 669