1959826caSMatt Macy /*- 2959826caSMatt Macy * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3959826caSMatt Macy * 4959826caSMatt Macy * Copyright (c) 2018, Matthew Macy 528dd6730SMitchell Horne * Copyright (c) 2021, The FreeBSD Foundation 628dd6730SMitchell Horne * 728dd6730SMitchell Horne * Portions of this software were developed by Mitchell Horne 828dd6730SMitchell Horne * under sponsorship from the FreeBSD Foundation. 9959826caSMatt Macy * 10959826caSMatt Macy * Redistribution and use in source and binary forms, with or without 11959826caSMatt Macy * modification, are permitted provided that the following conditions 12959826caSMatt Macy * are met: 13959826caSMatt Macy * 1. Redistributions of source code must retain the above copyright 14959826caSMatt Macy * notice, this list of conditions and the following disclaimer. 15959826caSMatt Macy * 2. Redistributions in binary form must reproduce the above copyright 16959826caSMatt Macy * notice, this list of conditions and the following disclaimer in the 17959826caSMatt Macy * documentation and/or other materials provided with the distribution. 18959826caSMatt Macy * 19959826caSMatt Macy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20959826caSMatt Macy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21959826caSMatt Macy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22959826caSMatt Macy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23959826caSMatt Macy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24959826caSMatt Macy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25959826caSMatt Macy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26959826caSMatt Macy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27959826caSMatt Macy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28959826caSMatt Macy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29959826caSMatt Macy * SUCH DAMAGE. 30959826caSMatt Macy * 31959826caSMatt Macy * $FreeBSD$ 32959826caSMatt Macy * 33959826caSMatt Macy */ 34959826caSMatt Macy 35959826caSMatt Macy #include <sys/types.h> 36959826caSMatt Macy #include <sys/errno.h> 3724e337beSRyan Moeller #include <sys/pmc.h> 38959826caSMatt Macy #include <sys/sysctl.h> 39959826caSMatt Macy #include <stddef.h> 40959826caSMatt Macy #include <stdlib.h> 41959826caSMatt Macy #include <limits.h> 42f3dbece8SEmmanuel Vadot #include <regex.h> 43959826caSMatt Macy #include <string.h> 44959826caSMatt Macy #include <pmc.h> 45959826caSMatt Macy #include <pmclog.h> 461b000b50SMatt Macy #include <assert.h> 47959826caSMatt Macy #include <libpmcstat.h> 48959826caSMatt Macy #include "pmu-events/pmu-events.h" 49959826caSMatt Macy 50959826caSMatt Macy struct pmu_alias { 51959826caSMatt Macy const char *pa_alias; 52959826caSMatt Macy const char *pa_name; 53959826caSMatt Macy }; 5481eb4dcfSMatt Macy 550024f1aaSMitchell Horne #if defined(__amd64__) || defined(__i386__) 5681eb4dcfSMatt Macy typedef enum { 5781eb4dcfSMatt Macy PMU_INVALID, 5881eb4dcfSMatt Macy PMU_INTEL, 5981eb4dcfSMatt Macy PMU_AMD, 6081eb4dcfSMatt Macy } pmu_mfr_t; 6181eb4dcfSMatt Macy 6281eb4dcfSMatt Macy static struct pmu_alias pmu_intel_alias_table[] = { 63*e144cd92SAlexander Motin {"UNHALTED_CORE_CYCLES", "cpu_clk_unhalted.thread"}, 64*e144cd92SAlexander Motin {"UNHALTED-CORE-CYCLES", "cpu_clk_unhalted.thread"}, 65959826caSMatt Macy {"LLC_MISSES", "LONGEST_LAT_CACHE.MISS"}, 66959826caSMatt Macy {"LLC-MISSES", "LONGEST_LAT_CACHE.MISS"}, 67959826caSMatt Macy {"LLC_REFERENCE", "LONGEST_LAT_CACHE.REFERENCE"}, 68959826caSMatt Macy {"LLC-REFERENCE", "LONGEST_LAT_CACHE.REFERENCE"}, 69959826caSMatt Macy {"LLC_MISS_RHITM", "mem_load_l3_miss_retired.remote_hitm"}, 70959826caSMatt Macy {"LLC-MISS-RHITM", "mem_load_l3_miss_retired.remote_hitm"}, 71959826caSMatt Macy {"RESOURCE_STALL", "RESOURCE_STALLS.ANY"}, 72959826caSMatt Macy {"RESOURCE_STALLS_ANY", "RESOURCE_STALLS.ANY"}, 73959826caSMatt Macy {"BRANCH_INSTRUCTION_RETIRED", "BR_INST_RETIRED.ALL_BRANCHES"}, 74959826caSMatt Macy {"BRANCH-INSTRUCTION-RETIRED", "BR_INST_RETIRED.ALL_BRANCHES"}, 75959826caSMatt Macy {"BRANCH_MISSES_RETIRED", "BR_MISP_RETIRED.ALL_BRANCHES"}, 76959826caSMatt Macy {"BRANCH-MISSES-RETIRED", "BR_MISP_RETIRED.ALL_BRANCHES"}, 77*e144cd92SAlexander Motin {"unhalted-cycles", "cpu_clk_unhalted.thread"}, 78*e144cd92SAlexander Motin {"instructions", "inst_retired.any"}, 7996cbd26aSMatt Macy {"branch-mispredicts", "br_misp_retired.all_branches"}, 8096cbd26aSMatt Macy {"branches", "br_inst_retired.all_branches"}, 8196cbd26aSMatt Macy {"interrupts", "hw_interrupts.received"}, 8296cbd26aSMatt Macy {"ic-misses", "frontend_retired.l1i_miss"}, 83959826caSMatt Macy {NULL, NULL}, 84959826caSMatt Macy }; 85959826caSMatt Macy 8681eb4dcfSMatt Macy static struct pmu_alias pmu_amd_alias_table[] = { 8781eb4dcfSMatt Macy {"UNHALTED_CORE_CYCLES", "ls_not_halted_cyc"}, 8881eb4dcfSMatt Macy {"UNHALTED-CORE-CYCLES", "ls_not_halted_cyc"}, 89a20c1089SMitchell Horne {"LLC_MISSES", "l3_comb_clstr_state.request_miss"}, 90a20c1089SMitchell Horne {"LLC-MISSES", "l3_comb_clstr_state.request_miss"}, 91a20c1089SMitchell Horne {"LLC_REFERENCE", "l3_request_g1.caching_l3_cache_accesses"}, 92a20c1089SMitchell Horne {"LLC-REFERENCE", "l3_request_g1.caching_l3_cache_accesses"}, 93a20c1089SMitchell Horne {"BRANCH_INSTRUCTION_RETIRED", "ex_ret_brn"}, 94a20c1089SMitchell Horne {"BRANCH-INSTRUCTION-RETIRED", "ex_ret_brn"}, 95a20c1089SMitchell Horne {"BRANCH_MISSES_RETIRED", "ex_ret_brn_misp"}, 96a20c1089SMitchell Horne {"BRANCH-MISSES-RETIRED", "ex_ret_brn_misp"}, 97a20c1089SMitchell Horne {"unhalted-cycles", "ls_not_halted_cyc"}, 98a20c1089SMitchell Horne {"instructions", "ex_ret_instr",}, 99a20c1089SMitchell Horne {"branch-mispredicts", "ex_ret_brn_misp"}, 100a20c1089SMitchell Horne {"branches", "ex_ret_brn"}, 101a20c1089SMitchell Horne {"interrupts", "ls_int_taken"}, /* Not on amdzen1 */ 10281eb4dcfSMatt Macy {NULL, NULL}, 10381eb4dcfSMatt Macy }; 10481eb4dcfSMatt Macy 10581eb4dcfSMatt Macy 10681eb4dcfSMatt Macy static pmu_mfr_t 10781eb4dcfSMatt Macy pmu_events_mfr(void) 10881eb4dcfSMatt Macy { 10924e337beSRyan Moeller char buf[PMC_CPUID_LEN]; 11024e337beSRyan Moeller size_t s = sizeof(buf); 11181eb4dcfSMatt Macy pmu_mfr_t mfr; 11281eb4dcfSMatt Macy 11324e337beSRyan Moeller if (sysctlbyname("kern.hwpmc.cpuid", buf, &s, 11481eb4dcfSMatt Macy (void *)NULL, 0) == -1) 11581eb4dcfSMatt Macy return (PMU_INVALID); 11653071ed1SKonstantin Belousov if (strcasestr(buf, "AuthenticAMD") != NULL || 11753071ed1SKonstantin Belousov strcasestr(buf, "HygonGenuine") != NULL) 11881eb4dcfSMatt Macy mfr = PMU_AMD; 11981eb4dcfSMatt Macy else if (strcasestr(buf, "GenuineIntel") != NULL) 12081eb4dcfSMatt Macy mfr = PMU_INTEL; 12181eb4dcfSMatt Macy else 12281eb4dcfSMatt Macy mfr = PMU_INVALID; 12381eb4dcfSMatt Macy return (mfr); 12481eb4dcfSMatt Macy } 12581eb4dcfSMatt Macy 12607d80fd8SMatt Macy /* 12707d80fd8SMatt Macy * The Intel fixed mode counters are: 12807d80fd8SMatt Macy * "inst_retired.any", 12907d80fd8SMatt Macy * "cpu_clk_unhalted.thread", 13007d80fd8SMatt Macy * "cpu_clk_unhalted.thread_any", 13107d80fd8SMatt Macy * "cpu_clk_unhalted.ref_tsc", 13207d80fd8SMatt Macy * 13307d80fd8SMatt Macy */ 134a191ed2dSMatt Macy 135959826caSMatt Macy static const char * 136959826caSMatt Macy pmu_alias_get(const char *name) 137959826caSMatt Macy { 13881eb4dcfSMatt Macy pmu_mfr_t mfr; 139959826caSMatt Macy struct pmu_alias *pa; 14081eb4dcfSMatt Macy struct pmu_alias *pmu_alias_table; 14181eb4dcfSMatt Macy 14281eb4dcfSMatt Macy if ((mfr = pmu_events_mfr()) == PMU_INVALID) 14381eb4dcfSMatt Macy return (name); 14481eb4dcfSMatt Macy if (mfr == PMU_AMD) 14581eb4dcfSMatt Macy pmu_alias_table = pmu_amd_alias_table; 14681eb4dcfSMatt Macy else if (mfr == PMU_INTEL) 14781eb4dcfSMatt Macy pmu_alias_table = pmu_intel_alias_table; 14881eb4dcfSMatt Macy else 14981eb4dcfSMatt Macy return (name); 150959826caSMatt Macy 151959826caSMatt Macy for (pa = pmu_alias_table; pa->pa_alias != NULL; pa++) 152959826caSMatt Macy if (strcasecmp(name, pa->pa_alias) == 0) 153959826caSMatt Macy return (pa->pa_name); 15481eb4dcfSMatt Macy 155959826caSMatt Macy return (name); 156959826caSMatt Macy } 157b48a2770SLeandro Lupori #elif defined(__powerpc64__) 158b48a2770SLeandro Lupori 159b48a2770SLeandro Lupori static const char * 160b48a2770SLeandro Lupori pmu_alias_get(const char *name) 161b48a2770SLeandro Lupori { 162b48a2770SLeandro Lupori return (name); 163b48a2770SLeandro Lupori } 164959826caSMatt Macy 16528dd6730SMitchell Horne #elif defined(__aarch64__) 16628dd6730SMitchell Horne 16728dd6730SMitchell Horne static struct pmu_alias pmu_armv8_alias_table[] = { 16828dd6730SMitchell Horne {NULL, NULL}, 16928dd6730SMitchell Horne }; 17028dd6730SMitchell Horne 17128dd6730SMitchell Horne static const char * 17228dd6730SMitchell Horne pmu_alias_get(const char *name) 17328dd6730SMitchell Horne { 17428dd6730SMitchell Horne struct pmu_alias *pa; 17528dd6730SMitchell Horne 17628dd6730SMitchell Horne for (pa = pmu_armv8_alias_table; pa->pa_alias != NULL; pa++) 17728dd6730SMitchell Horne if (strcasecmp(name, pa->pa_alias) == 0) 17828dd6730SMitchell Horne return (pa->pa_name); 17928dd6730SMitchell Horne 18028dd6730SMitchell Horne return (name); 18128dd6730SMitchell Horne } 18228dd6730SMitchell Horne 1830024f1aaSMitchell Horne #else 1840024f1aaSMitchell Horne 1850024f1aaSMitchell Horne static const char * 1860024f1aaSMitchell Horne pmu_alias_get(const char *name) 1870024f1aaSMitchell Horne { 1880024f1aaSMitchell Horne 1890024f1aaSMitchell Horne return (name); 1900024f1aaSMitchell Horne } 1910024f1aaSMitchell Horne #endif 1920024f1aaSMitchell Horne 193959826caSMatt Macy struct pmu_event_desc { 194959826caSMatt Macy uint64_t ped_period; 195959826caSMatt Macy uint64_t ped_offcore_rsp; 196dacc43dfSMatt Macy uint64_t ped_l3_thread; 197dacc43dfSMatt Macy uint64_t ped_l3_slice; 198959826caSMatt Macy uint32_t ped_event; 199959826caSMatt Macy uint32_t ped_frontend; 200959826caSMatt Macy uint32_t ped_ldlat; 201959826caSMatt Macy uint32_t ped_config1; 20207d80fd8SMatt Macy int16_t ped_umask; 203959826caSMatt Macy uint8_t ped_cmask; 204959826caSMatt Macy uint8_t ped_any; 205959826caSMatt Macy uint8_t ped_inv; 206959826caSMatt Macy uint8_t ped_edge; 207959826caSMatt Macy uint8_t ped_fc_mask; 208959826caSMatt Macy uint8_t ped_ch_mask; 209959826caSMatt Macy }; 210959826caSMatt Macy 211959826caSMatt Macy static const struct pmu_events_map * 212bfb46e2bSMatt Macy pmu_events_map_get(const char *cpuid) 213959826caSMatt Macy { 214a0ac5706SEmmanuel Vadot regex_t re; 215a0ac5706SEmmanuel Vadot regmatch_t pmatch[1]; 21624e337beSRyan Moeller char buf[PMC_CPUID_LEN]; 21724e337beSRyan Moeller size_t s = sizeof(buf); 218a0ac5706SEmmanuel Vadot int match; 219959826caSMatt Macy const struct pmu_events_map *pme; 220959826caSMatt Macy 221bfb46e2bSMatt Macy if (cpuid != NULL) { 22224e337beSRyan Moeller strlcpy(buf, cpuid, s); 223bfb46e2bSMatt Macy } else { 224959826caSMatt Macy if (sysctlbyname("kern.hwpmc.cpuid", buf, &s, 225959826caSMatt Macy (void *)NULL, 0) == -1) 226959826caSMatt Macy return (NULL); 227bfb46e2bSMatt Macy } 228a0ac5706SEmmanuel Vadot for (pme = pmu_events_map; pme->cpuid != NULL; pme++) { 229a0ac5706SEmmanuel Vadot if (regcomp(&re, pme->cpuid, REG_EXTENDED) != 0) { 230a0ac5706SEmmanuel Vadot printf("regex '%s' failed to compile, ignoring\n", 231a0ac5706SEmmanuel Vadot pme->cpuid); 232a0ac5706SEmmanuel Vadot continue; 233a0ac5706SEmmanuel Vadot } 234a0ac5706SEmmanuel Vadot match = regexec(&re, buf, 1, pmatch, 0); 235a0ac5706SEmmanuel Vadot regfree(&re); 236a0ac5706SEmmanuel Vadot if (match == 0) { 2371791cad0SAlexander Motin if (pmatch[0].rm_so == 0 && (buf[pmatch[0].rm_eo] == 0 2381791cad0SAlexander Motin || buf[pmatch[0].rm_eo] == '-')) 239959826caSMatt Macy return (pme); 240a0ac5706SEmmanuel Vadot } 241a0ac5706SEmmanuel Vadot } 242959826caSMatt Macy return (NULL); 243959826caSMatt Macy } 244959826caSMatt Macy 245959826caSMatt Macy static const struct pmu_event * 246bfb46e2bSMatt Macy pmu_event_get(const char *cpuid, const char *event_name, int *idx) 247959826caSMatt Macy { 248959826caSMatt Macy const struct pmu_events_map *pme; 249959826caSMatt Macy const struct pmu_event *pe; 250959826caSMatt Macy int i; 251959826caSMatt Macy 252bfb46e2bSMatt Macy if ((pme = pmu_events_map_get(cpuid)) == NULL) 253959826caSMatt Macy return (NULL); 254959826caSMatt Macy for (i = 0, pe = pme->table; pe->name || pe->desc || pe->event; pe++, i++) { 255959826caSMatt Macy if (pe->name == NULL) 256959826caSMatt Macy continue; 257959826caSMatt Macy if (strcasecmp(pe->name, event_name) == 0) { 258959826caSMatt Macy if (idx) 259959826caSMatt Macy *idx = i; 260959826caSMatt Macy return (pe); 261959826caSMatt Macy } 262959826caSMatt Macy } 263959826caSMatt Macy return (NULL); 264959826caSMatt Macy } 265959826caSMatt Macy 266bfb46e2bSMatt Macy int 267bfb46e2bSMatt Macy pmc_pmu_idx_get_by_event(const char *cpuid, const char *event) 268bfb46e2bSMatt Macy { 269bfb46e2bSMatt Macy int idx; 270bfb46e2bSMatt Macy const char *realname; 271bfb46e2bSMatt Macy 272bfb46e2bSMatt Macy realname = pmu_alias_get(event); 273bfb46e2bSMatt Macy if (pmu_event_get(cpuid, realname, &idx) == NULL) 274bfb46e2bSMatt Macy return (-1); 275bfb46e2bSMatt Macy return (idx); 276bfb46e2bSMatt Macy } 277bfb46e2bSMatt Macy 278959826caSMatt Macy const char * 279b2ca2e50SMatt Macy pmc_pmu_event_get_by_idx(const char *cpuid, int idx) 280959826caSMatt Macy { 281959826caSMatt Macy const struct pmu_events_map *pme; 282959826caSMatt Macy 283b2ca2e50SMatt Macy if ((pme = pmu_events_map_get(cpuid)) == NULL) 284959826caSMatt Macy return (NULL); 2851b000b50SMatt Macy assert(pme->table[idx].name); 2861b000b50SMatt Macy return (pme->table[idx].name); 287959826caSMatt Macy } 288959826caSMatt Macy 289959826caSMatt Macy static int 290959826caSMatt Macy pmu_parse_event(struct pmu_event_desc *ped, const char *eventin) 291959826caSMatt Macy { 292959826caSMatt Macy char *event; 2938bed125dSMatt Macy char *kvp, *key, *value, *r; 294959826caSMatt Macy char *debug; 295959826caSMatt Macy 296959826caSMatt Macy if ((event = strdup(eventin)) == NULL) 297959826caSMatt Macy return (ENOMEM); 2988bed125dSMatt Macy r = event; 299959826caSMatt Macy bzero(ped, sizeof(*ped)); 3000204d85aSMatt Macy ped->ped_period = DEFAULT_SAMPLE_COUNT; 30107d80fd8SMatt Macy ped->ped_umask = -1; 302959826caSMatt Macy while ((kvp = strsep(&event, ",")) != NULL) { 303959826caSMatt Macy key = strsep(&kvp, "="); 304959826caSMatt Macy if (key == NULL) 305959826caSMatt Macy abort(); 306959826caSMatt Macy value = kvp; 307959826caSMatt Macy if (strcmp(key, "umask") == 0) 308959826caSMatt Macy ped->ped_umask = strtol(value, NULL, 16); 309959826caSMatt Macy else if (strcmp(key, "event") == 0) 310959826caSMatt Macy ped->ped_event = strtol(value, NULL, 16); 311959826caSMatt Macy else if (strcmp(key, "period") == 0) 312959826caSMatt Macy ped->ped_period = strtol(value, NULL, 10); 313959826caSMatt Macy else if (strcmp(key, "offcore_rsp") == 0) 314959826caSMatt Macy ped->ped_offcore_rsp = strtol(value, NULL, 16); 315959826caSMatt Macy else if (strcmp(key, "any") == 0) 316959826caSMatt Macy ped->ped_any = strtol(value, NULL, 10); 317959826caSMatt Macy else if (strcmp(key, "cmask") == 0) 318959826caSMatt Macy ped->ped_cmask = strtol(value, NULL, 10); 319959826caSMatt Macy else if (strcmp(key, "inv") == 0) 320959826caSMatt Macy ped->ped_inv = strtol(value, NULL, 10); 321959826caSMatt Macy else if (strcmp(key, "edge") == 0) 322959826caSMatt Macy ped->ped_edge = strtol(value, NULL, 10); 323959826caSMatt Macy else if (strcmp(key, "frontend") == 0) 324959826caSMatt Macy ped->ped_frontend = strtol(value, NULL, 16); 325959826caSMatt Macy else if (strcmp(key, "ldlat") == 0) 326959826caSMatt Macy ped->ped_ldlat = strtol(value, NULL, 16); 327959826caSMatt Macy else if (strcmp(key, "fc_mask") == 0) 328959826caSMatt Macy ped->ped_fc_mask = strtol(value, NULL, 16); 329959826caSMatt Macy else if (strcmp(key, "ch_mask") == 0) 330959826caSMatt Macy ped->ped_ch_mask = strtol(value, NULL, 16); 331959826caSMatt Macy else if (strcmp(key, "config1") == 0) 332959826caSMatt Macy ped->ped_config1 = strtol(value, NULL, 16); 333dacc43dfSMatt Macy else if (strcmp(key, "l3_thread_mask") == 0) 334dacc43dfSMatt Macy ped->ped_l3_thread = strtol(value, NULL, 16); 335dacc43dfSMatt Macy else if (strcmp(key, "l3_slice_mask") == 0) 336dacc43dfSMatt Macy ped->ped_l3_slice = strtol(value, NULL, 16); 337959826caSMatt Macy else { 338959826caSMatt Macy debug = getenv("PMUDEBUG"); 339959826caSMatt Macy if (debug != NULL && strcmp(debug, "true") == 0 && value != NULL) 340959826caSMatt Macy printf("unrecognized kvpair: %s:%s\n", key, value); 341959826caSMatt Macy } 342959826caSMatt Macy } 3438bed125dSMatt Macy free(r); 344959826caSMatt Macy return (0); 345959826caSMatt Macy } 346959826caSMatt Macy 347959826caSMatt Macy uint64_t 348959826caSMatt Macy pmc_pmu_sample_rate_get(const char *event_name) 349959826caSMatt Macy { 350959826caSMatt Macy const struct pmu_event *pe; 351959826caSMatt Macy struct pmu_event_desc ped; 352959826caSMatt Macy 353959826caSMatt Macy event_name = pmu_alias_get(event_name); 354bfb46e2bSMatt Macy if ((pe = pmu_event_get(NULL, event_name, NULL)) == NULL) 355959826caSMatt Macy return (DEFAULT_SAMPLE_COUNT); 356959826caSMatt Macy if (pe->event == NULL) 357959826caSMatt Macy return (DEFAULT_SAMPLE_COUNT); 358959826caSMatt Macy if (pmu_parse_event(&ped, pe->event)) 359959826caSMatt Macy return (DEFAULT_SAMPLE_COUNT); 360959826caSMatt Macy return (ped.ped_period); 361959826caSMatt Macy } 362959826caSMatt Macy 363959826caSMatt Macy int 364959826caSMatt Macy pmc_pmu_enabled(void) 365959826caSMatt Macy { 366959826caSMatt Macy 367bfb46e2bSMatt Macy return (pmu_events_map_get(NULL) != NULL); 368959826caSMatt Macy } 369959826caSMatt Macy 370959826caSMatt Macy void 371fbf962e6SMatt Macy pmc_pmu_print_counters(const char *event_name) 372959826caSMatt Macy { 373959826caSMatt Macy const struct pmu_events_map *pme; 374959826caSMatt Macy const struct pmu_event *pe; 375959826caSMatt Macy struct pmu_event_desc ped; 376959826caSMatt Macy char *debug; 377959826caSMatt Macy int do_debug; 378959826caSMatt Macy 379959826caSMatt Macy debug = getenv("PMUDEBUG"); 380959826caSMatt Macy do_debug = 0; 381959826caSMatt Macy 382959826caSMatt Macy if (debug != NULL && strcmp(debug, "true") == 0) 383959826caSMatt Macy do_debug = 1; 384bfb46e2bSMatt Macy if ((pme = pmu_events_map_get(NULL)) == NULL) 385959826caSMatt Macy return; 386959826caSMatt Macy for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) { 387959826caSMatt Macy if (pe->name == NULL) 388959826caSMatt Macy continue; 389fbf962e6SMatt Macy if (event_name != NULL && strcasestr(pe->name, event_name) == NULL) 390fbf962e6SMatt Macy continue; 391959826caSMatt Macy printf("\t%s\n", pe->name); 392959826caSMatt Macy if (do_debug) 393959826caSMatt Macy pmu_parse_event(&ped, pe->event); 394959826caSMatt Macy } 395959826caSMatt Macy } 396959826caSMatt Macy 397959826caSMatt Macy void 398959826caSMatt Macy pmc_pmu_print_counter_desc(const char *ev) 399959826caSMatt Macy { 400959826caSMatt Macy const struct pmu_events_map *pme; 401959826caSMatt Macy const struct pmu_event *pe; 402959826caSMatt Macy 403bfb46e2bSMatt Macy if ((pme = pmu_events_map_get(NULL)) == NULL) 404959826caSMatt Macy return; 405959826caSMatt Macy for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) { 406959826caSMatt Macy if (pe->name == NULL) 407959826caSMatt Macy continue; 408959826caSMatt Macy if (strcasestr(pe->name, ev) != NULL && 409959826caSMatt Macy pe->desc != NULL) 410959826caSMatt Macy printf("%s:\t%s\n", pe->name, pe->desc); 411959826caSMatt Macy } 412959826caSMatt Macy } 413959826caSMatt Macy 414959826caSMatt Macy void 415959826caSMatt Macy pmc_pmu_print_counter_desc_long(const char *ev) 416959826caSMatt Macy { 417959826caSMatt Macy const struct pmu_events_map *pme; 418959826caSMatt Macy const struct pmu_event *pe; 419959826caSMatt Macy 420bfb46e2bSMatt Macy if ((pme = pmu_events_map_get(NULL)) == NULL) 421959826caSMatt Macy return; 422959826caSMatt Macy for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) { 423959826caSMatt Macy if (pe->name == NULL) 424959826caSMatt Macy continue; 425959826caSMatt Macy if (strcasestr(pe->name, ev) != NULL) { 426959826caSMatt Macy if (pe->long_desc != NULL) 427959826caSMatt Macy printf("%s:\n%s\n", pe->name, pe->long_desc); 428959826caSMatt Macy else if (pe->desc != NULL) 429959826caSMatt Macy printf("%s:\t%s\n", pe->name, pe->desc); 430959826caSMatt Macy } 431959826caSMatt Macy } 432959826caSMatt Macy } 433959826caSMatt Macy 434fbf962e6SMatt Macy void 435fbf962e6SMatt Macy pmc_pmu_print_counter_full(const char *ev) 436fbf962e6SMatt Macy { 437fbf962e6SMatt Macy const struct pmu_events_map *pme; 438fbf962e6SMatt Macy const struct pmu_event *pe; 439fbf962e6SMatt Macy 440bfb46e2bSMatt Macy if ((pme = pmu_events_map_get(NULL)) == NULL) 441fbf962e6SMatt Macy return; 442fbf962e6SMatt Macy for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) { 443fbf962e6SMatt Macy if (pe->name == NULL) 444fbf962e6SMatt Macy continue; 445fbf962e6SMatt Macy if (strcasestr(pe->name, ev) == NULL) 446fbf962e6SMatt Macy continue; 447fbf962e6SMatt Macy printf("name: %s\n", pe->name); 448fbf962e6SMatt Macy if (pe->long_desc != NULL) 449fbf962e6SMatt Macy printf("desc: %s\n", pe->long_desc); 450fbf962e6SMatt Macy else if (pe->desc != NULL) 451fbf962e6SMatt Macy printf("desc: %s\n", pe->desc); 452fbf962e6SMatt Macy if (pe->event != NULL) 453fbf962e6SMatt Macy printf("event: %s\n", pe->event); 454fbf962e6SMatt Macy if (pe->topic != NULL) 455fbf962e6SMatt Macy printf("topic: %s\n", pe->topic); 456fbf962e6SMatt Macy if (pe->pmu != NULL) 457fbf962e6SMatt Macy printf("pmu: %s\n", pe->pmu); 458fbf962e6SMatt Macy if (pe->unit != NULL) 459fbf962e6SMatt Macy printf("unit: %s\n", pe->unit); 460fbf962e6SMatt Macy if (pe->perpkg != NULL) 461fbf962e6SMatt Macy printf("perpkg: %s\n", pe->perpkg); 462fbf962e6SMatt Macy if (pe->metric_expr != NULL) 463fbf962e6SMatt Macy printf("metric_expr: %s\n", pe->metric_expr); 464fbf962e6SMatt Macy if (pe->metric_name != NULL) 465fbf962e6SMatt Macy printf("metric_name: %s\n", pe->metric_name); 466fbf962e6SMatt Macy if (pe->metric_group != NULL) 467fbf962e6SMatt Macy printf("metric_group: %s\n", pe->metric_group); 468fbf962e6SMatt Macy } 469fbf962e6SMatt Macy } 470fbf962e6SMatt Macy 4710024f1aaSMitchell Horne #if defined(__amd64__) || defined(__i386__) 47281eb4dcfSMatt Macy static int 473dacc43dfSMatt Macy pmc_pmu_amd_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm, 47481eb4dcfSMatt Macy struct pmu_event_desc *ped) 475959826caSMatt Macy { 47681eb4dcfSMatt Macy struct pmc_md_amd_op_pmcallocate *amd; 477dacc43dfSMatt Macy const struct pmu_event *pe; 478dacc43dfSMatt Macy int idx = -1; 47981eb4dcfSMatt Macy 48081eb4dcfSMatt Macy amd = &pm->pm_md.pm_amd; 48181eb4dcfSMatt Macy if (ped->ped_umask > 0) { 48281eb4dcfSMatt Macy pm->pm_caps |= PMC_CAP_QUALIFIER; 48381eb4dcfSMatt Macy amd->pm_amd_config |= AMD_PMC_TO_UNITMASK(ped->ped_umask); 48481eb4dcfSMatt Macy } 48581eb4dcfSMatt Macy pm->pm_class = PMC_CLASS_K8; 486dacc43dfSMatt Macy pe = pmu_event_get(NULL, event_name, &idx); 48781eb4dcfSMatt Macy 488dacc43dfSMatt Macy if (strcmp("l3cache", pe->topic) == 0){ 489dacc43dfSMatt Macy amd->pm_amd_config |= AMD_PMC_TO_EVENTMASK(ped->ped_event); 490dacc43dfSMatt Macy amd->pm_amd_sub_class = PMC_AMD_SUB_CLASS_L3_CACHE; 491dacc43dfSMatt Macy amd->pm_amd_config |= AMD_PMC_TO_L3SLICE(ped->ped_l3_slice); 492dacc43dfSMatt Macy amd->pm_amd_config |= AMD_PMC_TO_L3CORE(ped->ped_l3_thread); 493dacc43dfSMatt Macy } 494dacc43dfSMatt Macy else if (strcmp("data fabric", pe->topic) == 0){ 495dacc43dfSMatt Macy 496dacc43dfSMatt Macy amd->pm_amd_config |= AMD_PMC_TO_EVENTMASK_DF(ped->ped_event); 497dacc43dfSMatt Macy amd->pm_amd_sub_class = PMC_AMD_SUB_CLASS_DATA_FABRIC; 498dacc43dfSMatt Macy } 499dacc43dfSMatt Macy else{ 500dacc43dfSMatt Macy amd->pm_amd_config |= AMD_PMC_TO_EVENTMASK(ped->ped_event); 501dacc43dfSMatt Macy amd->pm_amd_sub_class = PMC_AMD_SUB_CLASS_CORE; 50281eb4dcfSMatt Macy if ((pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == 0 || 50381eb4dcfSMatt Macy (pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == 50481eb4dcfSMatt Macy (PMC_CAP_USER|PMC_CAP_SYSTEM)) 50581eb4dcfSMatt Macy amd->pm_amd_config |= (AMD_PMC_USR | AMD_PMC_OS); 50681eb4dcfSMatt Macy else if (pm->pm_caps & PMC_CAP_USER) 50781eb4dcfSMatt Macy amd->pm_amd_config |= AMD_PMC_USR; 50881eb4dcfSMatt Macy else if (pm->pm_caps & PMC_CAP_SYSTEM) 50981eb4dcfSMatt Macy amd->pm_amd_config |= AMD_PMC_OS; 51081eb4dcfSMatt Macy if (ped->ped_edge) 51181eb4dcfSMatt Macy amd->pm_amd_config |= AMD_PMC_EDGE; 51281eb4dcfSMatt Macy if (ped->ped_inv) 513037dd0a9SAlexander Motin amd->pm_amd_config |= AMD_PMC_INVERT; 51481eb4dcfSMatt Macy if (pm->pm_caps & PMC_CAP_INTERRUPT) 51581eb4dcfSMatt Macy amd->pm_amd_config |= AMD_PMC_INT; 516dacc43dfSMatt Macy } 51781eb4dcfSMatt Macy return (0); 51881eb4dcfSMatt Macy } 51981eb4dcfSMatt Macy 52081eb4dcfSMatt Macy static int 52181eb4dcfSMatt Macy pmc_pmu_intel_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm, 52281eb4dcfSMatt Macy struct pmu_event_desc *ped) 52381eb4dcfSMatt Macy { 524959826caSMatt Macy struct pmc_md_iap_op_pmcallocate *iap; 525959826caSMatt Macy 52681eb4dcfSMatt Macy iap = &pm->pm_md.pm_iap; 52707d80fd8SMatt Macy if (strcasestr(event_name, "UNC_") == event_name || 528785dd70dSMatt Macy strcasestr(event_name, "uncore") != NULL) { 529785dd70dSMatt Macy pm->pm_class = PMC_CLASS_UCP; 530a191ed2dSMatt Macy pm->pm_caps |= PMC_CAP_QUALIFIER; 53173b7b181SAlexander Motin } else if (ped->ped_event == 0x0) { 53207d80fd8SMatt Macy pm->pm_class = PMC_CLASS_IAF; 53307d80fd8SMatt Macy } else { 534959826caSMatt Macy pm->pm_class = PMC_CLASS_IAP; 53507d80fd8SMatt Macy pm->pm_caps |= PMC_CAP_QUALIFIER; 536785dd70dSMatt Macy } 53781eb4dcfSMatt Macy iap->pm_iap_config |= IAP_EVSEL(ped->ped_event); 53881eb4dcfSMatt Macy if (ped->ped_umask > 0) 53981eb4dcfSMatt Macy iap->pm_iap_config |= IAP_UMASK(ped->ped_umask); 54081eb4dcfSMatt Macy iap->pm_iap_config |= IAP_CMASK(ped->ped_cmask); 54181eb4dcfSMatt Macy iap->pm_iap_rsp = ped->ped_offcore_rsp; 542959826caSMatt Macy 54381eb4dcfSMatt Macy if ((pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == 0 || 54481eb4dcfSMatt Macy (pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == 54581eb4dcfSMatt Macy (PMC_CAP_USER|PMC_CAP_SYSTEM)) 546959826caSMatt Macy iap->pm_iap_config |= (IAP_USR | IAP_OS); 54781eb4dcfSMatt Macy else if (pm->pm_caps & PMC_CAP_USER) 54881eb4dcfSMatt Macy iap->pm_iap_config |= IAP_USR; 54981eb4dcfSMatt Macy else if (pm->pm_caps & PMC_CAP_SYSTEM) 55081eb4dcfSMatt Macy iap->pm_iap_config |= IAP_OS; 55181eb4dcfSMatt Macy if (ped->ped_edge) 552959826caSMatt Macy iap->pm_iap_config |= IAP_EDGE; 55381eb4dcfSMatt Macy if (ped->ped_any) 554959826caSMatt Macy iap->pm_iap_config |= IAP_ANY; 55581eb4dcfSMatt Macy if (ped->ped_inv) 556037dd0a9SAlexander Motin iap->pm_iap_config |= IAP_INV; 557959826caSMatt Macy if (pm->pm_caps & PMC_CAP_INTERRUPT) 558959826caSMatt Macy iap->pm_iap_config |= IAP_INT; 559959826caSMatt Macy return (0); 560959826caSMatt Macy } 561959826caSMatt Macy 56281eb4dcfSMatt Macy int 56381eb4dcfSMatt Macy pmc_pmu_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm) 56481eb4dcfSMatt Macy { 56581eb4dcfSMatt Macy const struct pmu_event *pe; 56681eb4dcfSMatt Macy struct pmu_event_desc ped; 56781eb4dcfSMatt Macy pmu_mfr_t mfr; 56881eb4dcfSMatt Macy int idx = -1; 56981eb4dcfSMatt Macy 57081eb4dcfSMatt Macy if ((mfr = pmu_events_mfr()) == PMU_INVALID) 57181eb4dcfSMatt Macy return (ENOENT); 57281eb4dcfSMatt Macy 57381eb4dcfSMatt Macy bzero(&pm->pm_md, sizeof(pm->pm_md)); 57481eb4dcfSMatt Macy pm->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 57581eb4dcfSMatt Macy event_name = pmu_alias_get(event_name); 57681eb4dcfSMatt Macy if ((pe = pmu_event_get(NULL, event_name, &idx)) == NULL) 57781eb4dcfSMatt Macy return (ENOENT); 57881eb4dcfSMatt Macy assert(idx >= 0); 57981eb4dcfSMatt Macy pm->pm_ev = idx; 58081eb4dcfSMatt Macy 58181eb4dcfSMatt Macy if (pe->event == NULL) 58281eb4dcfSMatt Macy return (ENOENT); 58381eb4dcfSMatt Macy if (pmu_parse_event(&ped, pe->event)) 58481eb4dcfSMatt Macy return (ENOENT); 58581eb4dcfSMatt Macy 58681eb4dcfSMatt Macy if (mfr == PMU_INTEL) 58781eb4dcfSMatt Macy return (pmc_pmu_intel_pmcallocate(event_name, pm, &ped)); 58881eb4dcfSMatt Macy else 58981eb4dcfSMatt Macy return (pmc_pmu_amd_pmcallocate(event_name, pm, &ped)); 59081eb4dcfSMatt Macy } 59181eb4dcfSMatt Macy 592b48a2770SLeandro Lupori #elif defined(__powerpc64__) 593b48a2770SLeandro Lupori 594b48a2770SLeandro Lupori int 595b48a2770SLeandro Lupori pmc_pmu_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm) 596b48a2770SLeandro Lupori { 597b48a2770SLeandro Lupori const struct pmu_event *pe; 598b48a2770SLeandro Lupori struct pmu_event_desc ped; 599b48a2770SLeandro Lupori int idx = -1; 600b48a2770SLeandro Lupori 601b48a2770SLeandro Lupori bzero(&pm->pm_md, sizeof(pm->pm_md)); 602b48a2770SLeandro Lupori pm->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 603b48a2770SLeandro Lupori event_name = pmu_alias_get(event_name); 604b48a2770SLeandro Lupori 605b48a2770SLeandro Lupori if ((pe = pmu_event_get(NULL, event_name, &idx)) == NULL) 606b48a2770SLeandro Lupori return (ENOENT); 607b48a2770SLeandro Lupori if (pe->event == NULL) 608b48a2770SLeandro Lupori return (ENOENT); 609b48a2770SLeandro Lupori if (pmu_parse_event(&ped, pe->event)) 610b48a2770SLeandro Lupori return (ENOENT); 611b48a2770SLeandro Lupori 612b48a2770SLeandro Lupori assert(ped.ped_event >= 0); 613b48a2770SLeandro Lupori pm->pm_ev = idx; 614b48a2770SLeandro Lupori pm->pm_md.pm_event = ped.ped_event; 615b48a2770SLeandro Lupori pm->pm_class = PMC_CLASS_POWER8; 616b48a2770SLeandro Lupori return (0); 617b48a2770SLeandro Lupori } 618b48a2770SLeandro Lupori 61928dd6730SMitchell Horne #elif defined(__aarch64__) 62028dd6730SMitchell Horne 62128dd6730SMitchell Horne int 62228dd6730SMitchell Horne pmc_pmu_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm) 62328dd6730SMitchell Horne { 62428dd6730SMitchell Horne const struct pmu_event *pe; 62527ea55fcSMitchell Horne struct pmu_event_desc ped; 62628dd6730SMitchell Horne int idx = -1; 62728dd6730SMitchell Horne 62828dd6730SMitchell Horne event_name = pmu_alias_get(event_name); 62928dd6730SMitchell Horne if ((pe = pmu_event_get(NULL, event_name, &idx)) == NULL) 63028dd6730SMitchell Horne return (ENOENT); 63128dd6730SMitchell Horne if (pe->event == NULL) 63228dd6730SMitchell Horne return (ENOENT); 63327ea55fcSMitchell Horne if (pmu_parse_event(&ped, pe->event)) 63427ea55fcSMitchell Horne return (ENOENT); 63528dd6730SMitchell Horne 63628dd6730SMitchell Horne assert(idx >= 0); 63727ea55fcSMitchell Horne pm->pm_ev = idx; 63827ea55fcSMitchell Horne pm->pm_md.pm_md_config = ped.ped_event; 63928dd6730SMitchell Horne pm->pm_md.pm_md_flags |= PM_MD_RAW_EVENT; 64028dd6730SMitchell Horne pm->pm_class = PMC_CLASS_ARMV8; 64128dd6730SMitchell Horne pm->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); 64228dd6730SMitchell Horne 64328dd6730SMitchell Horne return (0); 64428dd6730SMitchell Horne } 64528dd6730SMitchell Horne 646959826caSMatt Macy #else 6478b20f975SMatt Macy 6488b20f975SMatt Macy int 6498b20f975SMatt Macy pmc_pmu_pmcallocate(const char *e __unused, struct pmc_op_pmcallocate *p __unused) 6508b20f975SMatt Macy { 6518b20f975SMatt Macy return (EOPNOTSUPP); 6528b20f975SMatt Macy } 653959826caSMatt Macy #endif 654