Date: Tue, 14 Aug 2018 05:18:43 +0000 (UTC) From: Matt Macy <mmacy@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r337735 - in head: lib/libpmc lib/libpmc/pmu-events/arch/x86 lib/libpmc/pmu-events/arch/x86/amdfam17h sys/dev/hwpmc Message-ID: <201808140518.w7E5Ihp2035995@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: mmacy Date: Tue Aug 14 05:18:43 2018 New Revision: 337735 URL: https://svnweb.freebsd.org/changeset/base/337735 Log: Add library and kernel support for AMD Family 17h counters NB: lacks default sample rate for most counters Modified: head/lib/libpmc/libpmc_pmu_util.c head/lib/libpmc/pmu-events/arch/x86/amdfam17h/core.json head/lib/libpmc/pmu-events/arch/x86/amdfam17h/memory.json head/lib/libpmc/pmu-events/arch/x86/mapfile.csv head/sys/dev/hwpmc/hwpmc_amd.c Modified: head/lib/libpmc/libpmc_pmu_util.c ============================================================================== --- head/lib/libpmc/libpmc_pmu_util.c Tue Aug 14 01:57:11 2018 (r337734) +++ head/lib/libpmc/libpmc_pmu_util.c Tue Aug 14 05:18:43 2018 (r337735) @@ -46,7 +46,14 @@ struct pmu_alias { const char *pa_alias; const char *pa_name; }; -static struct pmu_alias pmu_alias_table[] = { + +typedef enum { + PMU_INVALID, + PMU_INTEL, + PMU_AMD, +} pmu_mfr_t; + +static struct pmu_alias pmu_intel_alias_table[] = { {"UNHALTED_CORE_CYCLES", "CPU_CLK_UNHALTED.THREAD_P_ANY"}, {"UNHALTED-CORE-CYCLES", "CPU_CLK_UNHALTED.THREAD_P_ANY"}, {"LLC_MISSES", "LONGEST_LAT_CACHE.MISS"}, @@ -70,6 +77,40 @@ static struct pmu_alias pmu_alias_table[] = { {NULL, NULL}, }; +static struct pmu_alias pmu_amd_alias_table[] = { + {"UNHALTED_CORE_CYCLES", "ls_not_halted_cyc"}, + {"UNHALTED-CORE-CYCLES", "ls_not_halted_cyc"}, + {NULL, NULL}, +}; + + +static pmu_mfr_t +pmu_events_mfr(void) +{ + char *buf; + size_t s; + pmu_mfr_t mfr; + + if (sysctlbyname("kern.hwpmc.cpuid", (void *)NULL, &s, + (void *)NULL, 0) == -1) + return (PMU_INVALID); + if ((buf = malloc(s + 1)) == NULL) + return (PMU_INVALID); + if (sysctlbyname("kern.hwpmc.cpuid", buf, &s, + (void *)NULL, 0) == -1) { + free(buf); + return (PMU_INVALID); + } + if (strcasestr(buf, "AuthenticAMD") != NULL) + mfr = PMU_AMD; + else if (strcasestr(buf, "GenuineIntel") != NULL) + mfr = PMU_INTEL; + else + mfr = PMU_INVALID; + free(buf); + return (mfr); +} + /* * The Intel fixed mode counters are: * "inst_retired.any", @@ -82,11 +123,23 @@ static struct pmu_alias pmu_alias_table[] = { static const char * pmu_alias_get(const char *name) { + pmu_mfr_t mfr; struct pmu_alias *pa; + struct pmu_alias *pmu_alias_table; + if ((mfr = pmu_events_mfr()) == PMU_INVALID) + return (name); + if (mfr == PMU_AMD) + pmu_alias_table = pmu_amd_alias_table; + else if (mfr == PMU_INTEL) + pmu_alias_table = pmu_intel_alias_table; + else + return (name); + for (pa = pmu_alias_table; pa->pa_alias != NULL; pa++) if (strcasecmp(name, pa->pa_alias) == 0) return (pa->pa_name); + return (name); } @@ -352,57 +405,112 @@ pmc_pmu_print_counter_full(const char *ev) } } -int -pmc_pmu_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm) +static int +pmc_pmu_amd_pmcallocate(const char *event_name __unused, struct pmc_op_pmcallocate *pm, + struct pmu_event_desc *ped) { - const struct pmu_event *pe; - struct pmu_event_desc ped; - struct pmc_md_iap_op_pmcallocate *iap; - int idx, isfixed; + struct pmc_md_amd_op_pmcallocate *amd; - iap = &pm->pm_md.pm_iap; - isfixed = 0; - bzero(iap, sizeof(*iap)); - event_name = pmu_alias_get(event_name); - pm->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); - if ((pe = pmu_event_get(NULL, event_name, &idx)) == NULL) - return (ENOENT); - if (pe->alias && (pe = pmu_event_get(NULL, pe->alias, &idx)) == NULL) - return (ENOENT); - if (pe->event == NULL) - return (ENOENT); - if (pmu_parse_event(&ped, pe->event)) - return (ENOENT); + amd = &pm->pm_md.pm_amd; + amd->pm_amd_config = AMD_PMC_TO_EVENTMASK(ped->ped_event); + if (ped->ped_umask > 0) { + pm->pm_caps |= PMC_CAP_QUALIFIER; + amd->pm_amd_config |= AMD_PMC_TO_UNITMASK(ped->ped_umask); + } + pm->pm_class = PMC_CLASS_K8; + if ((pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == 0 || + (pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == + (PMC_CAP_USER|PMC_CAP_SYSTEM)) + amd->pm_amd_config |= (AMD_PMC_USR | AMD_PMC_OS); + else if (pm->pm_caps & PMC_CAP_USER) + amd->pm_amd_config |= AMD_PMC_USR; + else if (pm->pm_caps & PMC_CAP_SYSTEM) + amd->pm_amd_config |= AMD_PMC_OS; + if (ped->ped_edge) + amd->pm_amd_config |= AMD_PMC_EDGE; + if (ped->ped_inv) + amd->pm_amd_config |= AMD_PMC_EDGE; + if (pm->pm_caps & PMC_CAP_INTERRUPT) + amd->pm_amd_config |= AMD_PMC_INT; + return (0); +} +static int +pmc_pmu_intel_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm, + struct pmu_event_desc *ped) +{ + struct pmc_md_iap_op_pmcallocate *iap; + int isfixed; + + isfixed = 0; + iap = &pm->pm_md.pm_iap; if (strcasestr(event_name, "UNC_") == event_name || strcasestr(event_name, "uncore") != NULL) { pm->pm_class = PMC_CLASS_UCP; pm->pm_caps |= PMC_CAP_QUALIFIER; - } else if ((ped.ped_umask == -1) || - (ped.ped_event == 0x0 && ped.ped_umask == 0x3)) { + } else if ((ped->ped_umask == -1) || + (ped->ped_event == 0x0 && ped->ped_umask == 0x3)) { pm->pm_class = PMC_CLASS_IAF; } else { pm->pm_class = PMC_CLASS_IAP; pm->pm_caps |= PMC_CAP_QUALIFIER; } - pm->pm_ev = idx; - iap->pm_iap_config |= IAP_EVSEL(ped.ped_event); - if (ped.ped_umask > 0) - iap->pm_iap_config |= IAP_UMASK(ped.ped_umask); - iap->pm_iap_config |= IAP_CMASK(ped.ped_cmask); - iap->pm_iap_rsp = ped.ped_offcore_rsp; + iap->pm_iap_config |= IAP_EVSEL(ped->ped_event); + if (ped->ped_umask > 0) + iap->pm_iap_config |= IAP_UMASK(ped->ped_umask); + iap->pm_iap_config |= IAP_CMASK(ped->ped_cmask); + iap->pm_iap_rsp = ped->ped_offcore_rsp; - iap->pm_iap_config |= (IAP_USR | IAP_OS); - if (ped.ped_edge) + if ((pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == 0 || + (pm->pm_caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == + (PMC_CAP_USER|PMC_CAP_SYSTEM)) + iap->pm_iap_config |= (IAP_USR | IAP_OS); + else if (pm->pm_caps & PMC_CAP_USER) + iap->pm_iap_config |= IAP_USR; + else if (pm->pm_caps & PMC_CAP_SYSTEM) + iap->pm_iap_config |= IAP_OS; + if (ped->ped_edge) iap->pm_iap_config |= IAP_EDGE; - if (ped.ped_any) + if (ped->ped_any) iap->pm_iap_config |= IAP_ANY; - if (ped.ped_inv) + if (ped->ped_inv) iap->pm_iap_config |= IAP_EDGE; if (pm->pm_caps & PMC_CAP_INTERRUPT) iap->pm_iap_config |= IAP_INT; return (0); +} + +int +pmc_pmu_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm) +{ + const struct pmu_event *pe; + struct pmu_event_desc ped; + pmu_mfr_t mfr; + int idx = -1; + + if ((mfr = pmu_events_mfr()) == PMU_INVALID) + return (ENOENT); + + bzero(&pm->pm_md, sizeof(pm->pm_md)); + pm->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); + event_name = pmu_alias_get(event_name); + if ((pe = pmu_event_get(NULL, event_name, &idx)) == NULL) + return (ENOENT); + if (pe->alias && (pe = pmu_event_get(NULL, pe->alias, &idx)) == NULL) + return (ENOENT); + assert(idx >= 0); + pm->pm_ev = idx; + + if (pe->event == NULL) + return (ENOENT); + if (pmu_parse_event(&ped, pe->event)) + return (ENOENT); + + if (mfr == PMU_INTEL) + return (pmc_pmu_intel_pmcallocate(event_name, pm, &ped)); + else + return (pmc_pmu_amd_pmcallocate(event_name, pm, &ped)); } /* Modified: head/lib/libpmc/pmu-events/arch/x86/amdfam17h/core.json ============================================================================== --- head/lib/libpmc/pmu-events/arch/x86/amdfam17h/core.json Tue Aug 14 01:57:11 2018 (r337734) +++ head/lib/libpmc/pmu-events/arch/x86/amdfam17h/core.json Tue Aug 14 05:18:43 2018 (r337735) @@ -3,16 +3,19 @@ "EventName": "ex_ret_instr", "EventCode": "0xc0", "BriefDescription": "Retired Instructions." + "SampleAfterValue": "2000003", }, { "EventName": "ex_ret_cops", "EventCode": "0xc1", "BriefDescription": "The number of uOps retired. This includes all processor activity (instructions, exceptions, interrupts, microcode assists, etc.). The number of events logged per cycle can vary from 0 to 4." + "SampleAfterValue": "2000003", }, { "EventName": "ex_ret_brn", "EventCode": "0xc2", "BriefDescription": "The number of branch instructions retired. This includes all types of architectural control flow changes, including exceptions and interrupts." + "SampleAfterValue": "2000003", }, { "EventName": "ex_ret_brn_misp", Modified: head/lib/libpmc/pmu-events/arch/x86/amdfam17h/memory.json ============================================================================== --- head/lib/libpmc/pmu-events/arch/x86/amdfam17h/memory.json Tue Aug 14 01:57:11 2018 (r337734) +++ head/lib/libpmc/pmu-events/arch/x86/amdfam17h/memory.json Tue Aug 14 05:18:43 2018 (r337735) @@ -221,5 +221,6 @@ "EventName": "ls_not_halted_cyc", "EventCode": "0x76", "BriefDescription": "Cycles not in Halt." + "SampleAfterValue": "2000003", } ] Modified: head/lib/libpmc/pmu-events/arch/x86/mapfile.csv ============================================================================== --- head/lib/libpmc/pmu-events/arch/x86/mapfile.csv Tue Aug 14 01:57:11 2018 (r337734) +++ head/lib/libpmc/pmu-events/arch/x86/mapfile.csv Tue Aug 14 05:18:43 2018 (r337735) @@ -36,4 +36,8 @@ GenuineIntel-6-2C,v2,westmereep-dp,core GenuineIntel-6-25,v2,westmereep-sp,core GenuineIntel-6-2F,v2,westmereex,core GenuineIntel-6-55,v1,skylakex,core -AuthenticAMD-23-1,v1,amdfam17h,core +AuthenticAMD-23-01,v1,amdfam17h,core +AuthenticAMD-23-02,v1,amdfam17h,core +AuthenticAMD-23-03,v1,amdfam17h,core +AuthenticAMD-23-04,v1,amdfam17h,core +AuthenticAMD-23-05,v1,amdfam17h,core Modified: head/sys/dev/hwpmc/hwpmc_amd.c ============================================================================== --- head/sys/dev/hwpmc/hwpmc_amd.c Tue Aug 14 01:57:11 2018 (r337734) +++ head/sys/dev/hwpmc/hwpmc_amd.c Tue Aug 14 05:18:43 2018 (r337735) @@ -458,6 +458,12 @@ amd_allocate_pmc(int cpu, int ri, struct pmc *pm, if ((pd->pd_caps & caps) != caps) return EPERM; + if (strlen(pmc_cpuid) != 0) { + pm->pm_md.pm_amd.pm_amd_evsel = + a->pm_md.pm_amd.pm_amd_config; + PMCDBG2(MDP,ALL,2,"amd-allocate ri=%d -> config=0x%x", ri, a->pm_md.pm_amd.pm_amd_config); + return (0); + } pe = a->pm_ev; @@ -884,6 +890,7 @@ pmc_amd_initialize(void) enum pmc_cputype cputype; struct pmc_mdep *pmc_mdep; enum pmc_class class; + int model; char *name; /* @@ -895,6 +902,11 @@ pmc_amd_initialize(void) */ name = NULL; + model = ((cpu_id & 0xF0000) >> 12) | ((cpu_id & 0xF0) >> 4); + if (CPUID_TO_FAMILY(cpu_id) == 0x17) + snprintf(pmc_cpuid, sizeof(pmc_cpuid), "AuthenticAMD-%d-%02X", + CPUID_TO_FAMILY(cpu_id), model); + switch (cpu_id & 0xF00) { #if defined(__i386__) case 0x600: /* Athlon(tm) processor */ @@ -912,7 +924,7 @@ pmc_amd_initialize(void) break; default: - (void) printf("pmc: Unknown AMD CPU.\n"); + (void) printf("pmc: Unknown AMD CPU %x %d-%d.\n", cpu_id, (cpu_id & 0xF00) >> 8, model); return NULL; }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201808140518.w7E5Ihp2035995>