1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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_P_ANY"}, 64 {"UNHALTED-CORE-CYCLES", "CPU_CLK_UNHALTED.THREAD_P_ANY"}, 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 {"cycles", "tsc-tsc"}, 78 {"unhalted-cycles", "CPU_CLK_UNHALTED.THREAD_P_ANY"}, 79 {"instructions", "inst_retired.any_p"}, 80 {"branch-mispredicts", "br_misp_retired.all_branches"}, 81 {"branches", "br_inst_retired.all_branches"}, 82 {"interrupts", "hw_interrupts.received"}, 83 {"ic-misses", "frontend_retired.l1i_miss"}, 84 {NULL, NULL}, 85 }; 86 87 static struct pmu_alias pmu_amd_alias_table[] = { 88 {"UNHALTED_CORE_CYCLES", "ls_not_halted_cyc"}, 89 {"UNHALTED-CORE-CYCLES", "ls_not_halted_cyc"}, 90 {NULL, NULL}, 91 }; 92 93 94 static pmu_mfr_t 95 pmu_events_mfr(void) 96 { 97 char buf[PMC_CPUID_LEN]; 98 size_t s = sizeof(buf); 99 pmu_mfr_t mfr; 100 101 if (sysctlbyname("kern.hwpmc.cpuid", buf, &s, 102 (void *)NULL, 0) == -1) 103 return (PMU_INVALID); 104 if (strcasestr(buf, "AuthenticAMD") != NULL || 105 strcasestr(buf, "HygonGenuine") != NULL) 106 mfr = PMU_AMD; 107 else if (strcasestr(buf, "GenuineIntel") != NULL) 108 mfr = PMU_INTEL; 109 else 110 mfr = PMU_INVALID; 111 return (mfr); 112 } 113 114 /* 115 * The Intel fixed mode counters are: 116 * "inst_retired.any", 117 * "cpu_clk_unhalted.thread", 118 * "cpu_clk_unhalted.thread_any", 119 * "cpu_clk_unhalted.ref_tsc", 120 * 121 */ 122 123 static const char * 124 pmu_alias_get(const char *name) 125 { 126 pmu_mfr_t mfr; 127 struct pmu_alias *pa; 128 struct pmu_alias *pmu_alias_table; 129 130 if ((mfr = pmu_events_mfr()) == PMU_INVALID) 131 return (name); 132 if (mfr == PMU_AMD) 133 pmu_alias_table = pmu_amd_alias_table; 134 else if (mfr == PMU_INTEL) 135 pmu_alias_table = pmu_intel_alias_table; 136 else 137 return (name); 138 139 for (pa = pmu_alias_table; pa->pa_alias != NULL; pa++) 140 if (strcasecmp(name, pa->pa_alias) == 0) 141 return (pa->pa_name); 142 143 return (name); 144 } 145 #elif defined(__powerpc64__) 146 147 static const char * 148 pmu_alias_get(const char *name) 149 { 150 return (name); 151 } 152 153 #elif defined(__aarch64__) 154 155 static struct pmu_alias pmu_armv8_alias_table[] = { 156 {NULL, NULL}, 157 }; 158 159 static const char * 160 pmu_alias_get(const char *name) 161 { 162 struct pmu_alias *pa; 163 164 for (pa = pmu_armv8_alias_table; pa->pa_alias != NULL; pa++) 165 if (strcasecmp(name, pa->pa_alias) == 0) 166 return (pa->pa_name); 167 168 return (name); 169 } 170 171 #else 172 173 static const char * 174 pmu_alias_get(const char *name) 175 { 176 177 return (name); 178 } 179 #endif 180 181 struct pmu_event_desc { 182 uint64_t ped_period; 183 uint64_t ped_offcore_rsp; 184 uint64_t ped_l3_thread; 185 uint64_t ped_l3_slice; 186 uint32_t ped_event; 187 uint32_t ped_frontend; 188 uint32_t ped_ldlat; 189 uint32_t ped_config1; 190 int16_t ped_umask; 191 uint8_t ped_cmask; 192 uint8_t ped_any; 193 uint8_t ped_inv; 194 uint8_t ped_edge; 195 uint8_t ped_fc_mask; 196 uint8_t ped_ch_mask; 197 }; 198 199 static const struct pmu_events_map * 200 pmu_events_map_get(const char *cpuid) 201 { 202 regex_t re; 203 regmatch_t pmatch[1]; 204 char buf[PMC_CPUID_LEN]; 205 size_t s = sizeof(buf); 206 int match; 207 const struct pmu_events_map *pme; 208 209 if (cpuid != NULL) { 210 strlcpy(buf, cpuid, s); 211 } else { 212 if (sysctlbyname("kern.hwpmc.cpuid", buf, &s, 213 (void *)NULL, 0) == -1) 214 return (NULL); 215 } 216 for (pme = pmu_events_map; pme->cpuid != NULL; pme++) { 217 if (regcomp(&re, pme->cpuid, REG_EXTENDED) != 0) { 218 printf("regex '%s' failed to compile, ignoring\n", 219 pme->cpuid); 220 continue; 221 } 222 match = regexec(&re, buf, 1, pmatch, 0); 223 regfree(&re); 224 if (match == 0) { 225 if (pmatch[0].rm_so == 0 && (buf[pmatch[0].rm_eo] == 0 226 || buf[pmatch[0].rm_eo] == '-')) 227 return (pme); 228 } 229 } 230 return (NULL); 231 } 232 233 static const struct pmu_event * 234 pmu_event_get(const char *cpuid, const char *event_name, int *idx) 235 { 236 const struct pmu_events_map *pme; 237 const struct pmu_event *pe; 238 int i; 239 240 if ((pme = pmu_events_map_get(cpuid)) == NULL) 241 return (NULL); 242 for (i = 0, pe = pme->table; pe->name || pe->desc || pe->event; pe++, i++) { 243 if (pe->name == NULL) 244 continue; 245 if (strcasecmp(pe->name, event_name) == 0) { 246 if (idx) 247 *idx = i; 248 return (pe); 249 } 250 } 251 return (NULL); 252 } 253 254 int 255 pmc_pmu_idx_get_by_event(const char *cpuid, const char *event) 256 { 257 int idx; 258 const char *realname; 259 260 realname = pmu_alias_get(event); 261 if (pmu_event_get(cpuid, realname, &idx) == NULL) 262 return (-1); 263 return (idx); 264 } 265 266 const char * 267 pmc_pmu_event_get_by_idx(const char *cpuid, int idx) 268 { 269 const struct pmu_events_map *pme; 270 271 if ((pme = pmu_events_map_get(cpuid)) == NULL) 272 return (NULL); 273 assert(pme->table[idx].name); 274 return (pme->table[idx].name); 275 } 276 277 static int 278 pmu_parse_event(struct pmu_event_desc *ped, const char *eventin) 279 { 280 char *event; 281 char *kvp, *key, *value, *r; 282 char *debug; 283 284 if ((event = strdup(eventin)) == NULL) 285 return (ENOMEM); 286 r = event; 287 bzero(ped, sizeof(*ped)); 288 ped->ped_period = DEFAULT_SAMPLE_COUNT; 289 ped->ped_umask = -1; 290 while ((kvp = strsep(&event, ",")) != NULL) { 291 key = strsep(&kvp, "="); 292 if (key == NULL) 293 abort(); 294 value = kvp; 295 if (strcmp(key, "umask") == 0) 296 ped->ped_umask = strtol(value, NULL, 16); 297 else if (strcmp(key, "event") == 0) 298 ped->ped_event = strtol(value, NULL, 16); 299 else if (strcmp(key, "period") == 0) 300 ped->ped_period = strtol(value, NULL, 10); 301 else if (strcmp(key, "offcore_rsp") == 0) 302 ped->ped_offcore_rsp = strtol(value, NULL, 16); 303 else if (strcmp(key, "any") == 0) 304 ped->ped_any = strtol(value, NULL, 10); 305 else if (strcmp(key, "cmask") == 0) 306 ped->ped_cmask = strtol(value, NULL, 10); 307 else if (strcmp(key, "inv") == 0) 308 ped->ped_inv = strtol(value, NULL, 10); 309 else if (strcmp(key, "edge") == 0) 310 ped->ped_edge = strtol(value, NULL, 10); 311 else if (strcmp(key, "frontend") == 0) 312 ped->ped_frontend = strtol(value, NULL, 16); 313 else if (strcmp(key, "ldlat") == 0) 314 ped->ped_ldlat = strtol(value, NULL, 16); 315 else if (strcmp(key, "fc_mask") == 0) 316 ped->ped_fc_mask = strtol(value, NULL, 16); 317 else if (strcmp(key, "ch_mask") == 0) 318 ped->ped_ch_mask = strtol(value, NULL, 16); 319 else if (strcmp(key, "config1") == 0) 320 ped->ped_config1 = strtol(value, NULL, 16); 321 else if (strcmp(key, "l3_thread_mask") == 0) 322 ped->ped_l3_thread = strtol(value, NULL, 16); 323 else if (strcmp(key, "l3_slice_mask") == 0) 324 ped->ped_l3_slice = strtol(value, NULL, 16); 325 else { 326 debug = getenv("PMUDEBUG"); 327 if (debug != NULL && strcmp(debug, "true") == 0 && value != NULL) 328 printf("unrecognized kvpair: %s:%s\n", key, value); 329 } 330 } 331 free(r); 332 return (0); 333 } 334 335 uint64_t 336 pmc_pmu_sample_rate_get(const char *event_name) 337 { 338 const struct pmu_event *pe; 339 struct pmu_event_desc ped; 340 341 event_name = pmu_alias_get(event_name); 342 if ((pe = pmu_event_get(NULL, event_name, NULL)) == NULL) 343 return (DEFAULT_SAMPLE_COUNT); 344 if (pe->event == NULL) 345 return (DEFAULT_SAMPLE_COUNT); 346 if (pmu_parse_event(&ped, pe->event)) 347 return (DEFAULT_SAMPLE_COUNT); 348 return (ped.ped_period); 349 } 350 351 int 352 pmc_pmu_enabled(void) 353 { 354 355 return (pmu_events_map_get(NULL) != NULL); 356 } 357 358 void 359 pmc_pmu_print_counters(const char *event_name) 360 { 361 const struct pmu_events_map *pme; 362 const struct pmu_event *pe; 363 struct pmu_event_desc ped; 364 char *debug; 365 int do_debug; 366 367 debug = getenv("PMUDEBUG"); 368 do_debug = 0; 369 370 if (debug != NULL && strcmp(debug, "true") == 0) 371 do_debug = 1; 372 if ((pme = pmu_events_map_get(NULL)) == NULL) 373 return; 374 for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) { 375 if (pe->name == NULL) 376 continue; 377 if (event_name != NULL && strcasestr(pe->name, event_name) == NULL) 378 continue; 379 printf("\t%s\n", pe->name); 380 if (do_debug) 381 pmu_parse_event(&ped, pe->event); 382 } 383 } 384 385 void 386 pmc_pmu_print_counter_desc(const char *ev) 387 { 388 const struct pmu_events_map *pme; 389 const struct pmu_event *pe; 390 391 if ((pme = pmu_events_map_get(NULL)) == NULL) 392 return; 393 for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) { 394 if (pe->name == NULL) 395 continue; 396 if (strcasestr(pe->name, ev) != NULL && 397 pe->desc != NULL) 398 printf("%s:\t%s\n", pe->name, pe->desc); 399 } 400 } 401 402 void 403 pmc_pmu_print_counter_desc_long(const char *ev) 404 { 405 const struct pmu_events_map *pme; 406 const struct pmu_event *pe; 407 408 if ((pme = pmu_events_map_get(NULL)) == NULL) 409 return; 410 for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) { 411 if (pe->name == NULL) 412 continue; 413 if (strcasestr(pe->name, ev) != NULL) { 414 if (pe->long_desc != NULL) 415 printf("%s:\n%s\n", pe->name, pe->long_desc); 416 else if (pe->desc != NULL) 417 printf("%s:\t%s\n", pe->name, pe->desc); 418 } 419 } 420 } 421 422 void 423 pmc_pmu_print_counter_full(const char *ev) 424 { 425 const struct pmu_events_map *pme; 426 const struct pmu_event *pe; 427 428 if ((pme = pmu_events_map_get(NULL)) == NULL) 429 return; 430 for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) { 431 if (pe->name == NULL) 432 continue; 433 if (strcasestr(pe->name, ev) == NULL) 434 continue; 435 printf("name: %s\n", pe->name); 436 if (pe->long_desc != NULL) 437 printf("desc: %s\n", pe->long_desc); 438 else if (pe->desc != NULL) 439 printf("desc: %s\n", pe->desc); 440 if (pe->event != NULL) 441 printf("event: %s\n", pe->event); 442 if (pe->topic != NULL) 443 printf("topic: %s\n", pe->topic); 444 if (pe->pmu != NULL) 445 printf("pmu: %s\n", pe->pmu); 446 if (pe->unit != NULL) 447 printf("unit: %s\n", pe->unit); 448 if (pe->perpkg != NULL) 449 printf("perpkg: %s\n", pe->perpkg); 450 if (pe->metric_expr != NULL) 451 printf("metric_expr: %s\n", pe->metric_expr); 452 if (pe->metric_name != NULL) 453 printf("metric_name: %s\n", pe->metric_name); 454 if (pe->metric_group != NULL) 455 printf("metric_group: %s\n", pe->metric_group); 456 } 457 } 458 459 #if defined(__amd64__) || defined(__i386__) 460 static int 461 pmc_pmu_amd_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm, 462 struct pmu_event_desc *ped) 463 { 464 struct pmc_md_amd_op_pmcallocate *amd; 465 const struct pmu_event *pe; 466 int idx = -1; 467 468 amd = &pm->pm_md.pm_amd; 469 if (ped->ped_umask > 0) { 470 pm->pm_caps |= PMC_CAP_QUALIFIER; 471 amd->pm_amd_config |= AMD_PMC_TO_UNITMASK(ped->ped_umask); 472 } 473 pm->pm_class = PMC_CLASS_K8; 474 pe = pmu_event_get(NULL, event_name, &idx); 475 476 if (strcmp("l3cache", pe->topic) == 0){ 477 amd->pm_amd_config |= AMD_PMC_TO_EVENTMASK(ped->ped_event); 478 amd->pm_amd_sub_class = PMC_AMD_SUB_CLASS_L3_CACHE; 479 amd->pm_amd_config |= AMD_PMC_TO_L3SLICE(ped->ped_l3_slice); 480 amd->pm_amd_config |= AMD_PMC_TO_L3CORE(ped->ped_l3_thread); 481 } 482 else if (strcmp("data fabric", pe->topic) == 0){ 483 484 amd->pm_amd_config |= AMD_PMC_TO_EVENTMASK_DF(ped->ped_event); 485 amd->pm_amd_sub_class = PMC_AMD_SUB_CLASS_DATA_FABRIC; 486 } 487 else{ 488 amd->pm_amd_config |= AMD_PMC_TO_EVENTMASK(ped->ped_event); 489 amd->pm_amd_sub_class = PMC_AMD_SUB_CLASS_CORE; 490 if ((pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == 0 || 491 (pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == 492 (PMC_CAP_USER|PMC_CAP_SYSTEM)) 493 amd->pm_amd_config |= (AMD_PMC_USR | AMD_PMC_OS); 494 else if (pm->pm_caps & PMC_CAP_USER) 495 amd->pm_amd_config |= AMD_PMC_USR; 496 else if (pm->pm_caps & PMC_CAP_SYSTEM) 497 amd->pm_amd_config |= AMD_PMC_OS; 498 if (ped->ped_edge) 499 amd->pm_amd_config |= AMD_PMC_EDGE; 500 if (ped->ped_inv) 501 amd->pm_amd_config |= AMD_PMC_EDGE; 502 if (pm->pm_caps & PMC_CAP_INTERRUPT) 503 amd->pm_amd_config |= AMD_PMC_INT; 504 } 505 return (0); 506 } 507 508 static int 509 pmc_pmu_intel_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm, 510 struct pmu_event_desc *ped) 511 { 512 struct pmc_md_iap_op_pmcallocate *iap; 513 514 iap = &pm->pm_md.pm_iap; 515 if (strcasestr(event_name, "UNC_") == event_name || 516 strcasestr(event_name, "uncore") != NULL) { 517 pm->pm_class = PMC_CLASS_UCP; 518 pm->pm_caps |= PMC_CAP_QUALIFIER; 519 } else if ((ped->ped_umask == -1) || 520 (ped->ped_event == 0x0 && ped->ped_umask == 0x3)) { 521 pm->pm_class = PMC_CLASS_IAF; 522 } else { 523 pm->pm_class = PMC_CLASS_IAP; 524 pm->pm_caps |= PMC_CAP_QUALIFIER; 525 } 526 iap->pm_iap_config |= IAP_EVSEL(ped->ped_event); 527 if (ped->ped_umask > 0) 528 iap->pm_iap_config |= IAP_UMASK(ped->ped_umask); 529 iap->pm_iap_config |= IAP_CMASK(ped->ped_cmask); 530 iap->pm_iap_rsp = ped->ped_offcore_rsp; 531 532 if ((pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == 0 || 533 (pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == 534 (PMC_CAP_USER|PMC_CAP_SYSTEM)) 535 iap->pm_iap_config |= (IAP_USR | IAP_OS); 536 else if (pm->pm_caps & PMC_CAP_USER) 537 iap->pm_iap_config |= IAP_USR; 538 else if (pm->pm_caps & PMC_CAP_SYSTEM) 539 iap->pm_iap_config |= IAP_OS; 540 if (ped->ped_edge) 541 iap->pm_iap_config |= IAP_EDGE; 542 if (ped->ped_any) 543 iap->pm_iap_config |= IAP_ANY; 544 if (ped->ped_inv) 545 iap->pm_iap_config |= IAP_EDGE; 546 if (pm->pm_caps & PMC_CAP_INTERRUPT) 547 iap->pm_iap_config |= IAP_INT; 548 return (0); 549 } 550 551 int 552 pmc_pmu_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm) 553 { 554 const struct pmu_event *pe; 555 struct pmu_event_desc ped; 556 pmu_mfr_t mfr; 557 int idx = -1; 558 559 if ((mfr = pmu_events_mfr()) == PMU_INVALID) 560 return (ENOENT); 561 562 bzero(&pm->pm_md, sizeof(pm->pm_md)); 563 pm->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 564 event_name = pmu_alias_get(event_name); 565 if ((pe = pmu_event_get(NULL, event_name, &idx)) == NULL) 566 return (ENOENT); 567 assert(idx >= 0); 568 pm->pm_ev = idx; 569 570 if (pe->event == NULL) 571 return (ENOENT); 572 if (pmu_parse_event(&ped, pe->event)) 573 return (ENOENT); 574 575 if (mfr == PMU_INTEL) 576 return (pmc_pmu_intel_pmcallocate(event_name, pm, &ped)); 577 else 578 return (pmc_pmu_amd_pmcallocate(event_name, pm, &ped)); 579 } 580 581 #elif defined(__powerpc64__) 582 583 int 584 pmc_pmu_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm) 585 { 586 const struct pmu_event *pe; 587 struct pmu_event_desc ped; 588 int idx = -1; 589 590 bzero(&pm->pm_md, sizeof(pm->pm_md)); 591 pm->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 592 event_name = pmu_alias_get(event_name); 593 594 if ((pe = pmu_event_get(NULL, event_name, &idx)) == NULL) 595 return (ENOENT); 596 if (pe->event == NULL) 597 return (ENOENT); 598 if (pmu_parse_event(&ped, pe->event)) 599 return (ENOENT); 600 601 assert(ped.ped_event >= 0); 602 pm->pm_ev = idx; 603 pm->pm_md.pm_event = ped.ped_event; 604 pm->pm_class = PMC_CLASS_POWER8; 605 return (0); 606 } 607 608 #elif defined(__aarch64__) 609 610 int 611 pmc_pmu_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm) 612 { 613 const struct pmu_event *pe; 614 struct pmu_event_desc ped; 615 int idx = -1; 616 617 event_name = pmu_alias_get(event_name); 618 if ((pe = pmu_event_get(NULL, event_name, &idx)) == NULL) 619 return (ENOENT); 620 if (pe->event == NULL) 621 return (ENOENT); 622 if (pmu_parse_event(&ped, pe->event)) 623 return (ENOENT); 624 625 assert(idx >= 0); 626 pm->pm_ev = idx; 627 pm->pm_md.pm_md_config = ped.ped_event; 628 pm->pm_md.pm_md_flags |= PM_MD_RAW_EVENT; 629 pm->pm_class = PMC_CLASS_ARMV8; 630 pm->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 631 632 return (0); 633 } 634 635 #else 636 637 int 638 pmc_pmu_pmcallocate(const char *e __unused, struct pmc_op_pmcallocate *p __unused) 639 { 640 return (EOPNOTSUPP); 641 } 642 #endif 643