Index: lib/libpmc/libpmc.c =================================================================== --- lib/libpmc/libpmc.c +++ lib/libpmc/libpmc.c @@ -58,6 +58,10 @@ static int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); #endif +#if defined(__amd64__) +static int pt_allocate_pmc(enum pmc_event _pe, char *_ctrspec, + struct pmc_op_pmcallocate *_pmc_config); +#endif #if defined(__arm__) #if defined(__XSCALE__) static int xscale_allocate_pmc(enum pmc_event _pe, char *_ctrspec, @@ -69,6 +73,8 @@ #if defined(__aarch64__) static int arm64_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); +static int coresight_allocate_pmc(enum pmc_event _pe, char *_ctrspec, + struct pmc_op_pmcallocate *_pmc_config); #endif #if defined(__mips__) static int mips_allocate_pmc(enum pmc_event _pe, char* ctrspec, @@ -186,13 +192,14 @@ PMC_CLASS_##C, __VA_ARGS__ \ } +PMC_MDEP_TABLE(kabylake, PT); PMC_MDEP_TABLE(k8, K8, PMC_CLASS_SOFT, PMC_CLASS_TSC); PMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE); PMC_MDEP_TABLE(beri, BERI, PMC_CLASS_SOFT, PMC_CLASS_BERI); PMC_MDEP_TABLE(cortex_a8, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7); PMC_MDEP_TABLE(cortex_a9, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7); -PMC_MDEP_TABLE(cortex_a53, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8); -PMC_MDEP_TABLE(cortex_a57, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8); +PMC_MDEP_TABLE(cortex_a53, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8, PMC_CLASS_CORESIGHT); +PMC_MDEP_TABLE(cortex_a57, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8, PMC_CLASS_CORESIGHT); PMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K); PMC_MDEP_TABLE(mips74k, MIPS74K, PMC_CLASS_SOFT, PMC_CLASS_MIPS74K); PMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON); @@ -206,6 +213,16 @@ __PMC_EV_TSC() }; +static const struct pmc_event_descr pt_event_table[] = +{ + __PMC_EV_PT() +}; + +static const struct pmc_event_descr coresight_event_table[] = +{ + __PMC_EV_CORESIGHT() +}; + #undef PMC_CLASS_TABLE_DESC #define PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR) \ static const struct pmc_class_descr NAME##_class_table_descr = \ @@ -225,6 +242,9 @@ #if defined(__i386__) || defined(__amd64__) PMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc); #endif +#if defined(__amd64__) +PMC_CLASS_TABLE_DESC(pt, PT, pt, pt); +#endif #if defined(__arm__) #if defined(__XSCALE__) PMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale); @@ -235,6 +255,7 @@ #if defined(__aarch64__) PMC_CLASS_TABLE_DESC(cortex_a53, ARMV8, cortex_a53, arm64); PMC_CLASS_TABLE_DESC(cortex_a57, ARMV8, cortex_a57, arm64); +PMC_CLASS_TABLE_DESC(coresight, CORESIGHT, coresight, coresight); #endif #if defined(__mips__) PMC_CLASS_TABLE_DESC(beri, BERI, beri, mips); @@ -369,6 +390,10 @@ * */ +static struct pmc_event_alias kabylake_aliases[] = { + EV_ALIAS(NULL, NULL) +}; + static struct pmc_event_alias k8_aliases[] = { EV_ALIAS("branches", "k8-fr-retired-taken-branches"), EV_ALIAS("branch-mispredicts", @@ -740,6 +765,85 @@ } #endif +#if defined(__amd64__) + +#define INTEL_PT_KW_BRANCHES "branches" +#define INTEL_PT_KW_TSC "tsc" +#define INTEL_PT_KW_MTC "mtc" +#define INTEL_PT_KW_DISRETC "disretc" +#define INTEL_PT_KW_ADDRA "addra" +#define INTEL_PT_KW_ADDRB "addrb" + +static int +pt_allocate_pmc(enum pmc_event pe, char *ctrspec, + struct pmc_op_pmcallocate *pmc_config) +{ + struct pmc_md_pt_op_pmcallocate *pm_pt; + uint64_t addr; + uint32_t addrn; + char *p, *q, *e; + + if (pe != PMC_EV_PT_PT) + return (-1); + + pm_pt = (struct pmc_md_pt_op_pmcallocate *)&pmc_config->pm_md.pm_pt; + + addrn = 0; + while ((p = strsep(&ctrspec, ",")) != NULL) { + if (KWMATCH(p, INTEL_PT_KW_BRANCHES)) { + pm_pt->flags |= INTEL_PT_FLAG_BRANCHES; + } + + if (KWMATCH(p, INTEL_PT_KW_TSC)) { + pm_pt->flags |= INTEL_PT_FLAG_TSC; + } + + if (KWMATCH(p, INTEL_PT_KW_MTC)) { + pm_pt->flags |= INTEL_PT_FLAG_MTC; + } + + if (KWMATCH(p, INTEL_PT_KW_DISRETC)) { + pm_pt->flags |= INTEL_PT_FLAG_DISRETC; + } + + if (KWPREFIXMATCH(p, INTEL_PT_KW_ADDRA "=")) { + q = strchr(p, '='); + if (*++q == '\0') /* skip '=' */ + return (-1); + + addr = strtoul(q, &e, 0); + if (e == q || *e != '\0') + return (-1); + pm_pt->ranges[addrn * 2] = addr; + } + + if (KWPREFIXMATCH(p, INTEL_PT_KW_ADDRB "=")) { + q = strchr(p, '='); + if (*++q == '\0') /* skip '=' */ + return (-1); + + addr = strtoul(q, &e, 0); + if (e == q || *e != '\0') + return (-1); + pm_pt->ranges[addrn * 2 + 1] = addr; + + if (pm_pt->ranges[addrn * 2 + 1] < pm_pt->ranges[addrn * 2]) + return (-1); + addrn += 1; + if (addrn > PT_NADDR) + return (-1); + } + }; + + pm_pt->nranges = addrn; + + pmc_config->pm_caps |= PMC_CAP_READ; + pmc_config->pm_caps &= ~PMC_CAP_WRITE; + + return (0); +} +#endif + static struct pmc_event_alias generic_aliases[] = { EV_ALIAS("instructions", "SOFT-CLOCK.HARD"), EV_ALIAS(NULL, NULL) @@ -828,6 +932,62 @@ return (0); } + +#define ARM_CORESIGHT_KW_ADDRA "addra" +#define ARM_CORESIGHT_KW_ADDRB "addrb" + +static int +coresight_allocate_pmc(enum pmc_event pe, char *ctrspec, + struct pmc_op_pmcallocate *pmc_config) +{ + struct pmc_md_coresight_op_pmcallocate *pm_coresight; + uint64_t addr; + uint32_t addrn; + char *p, *q, *e; + + if (pe != PMC_EV_CORESIGHT_CORESIGHT) + return (-1); + + pm_coresight = (struct pmc_md_coresight_op_pmcallocate *)&pmc_config->pm_md.pm_coresight; + + addrn = 0; + while ((p = strsep(&ctrspec, ",")) != NULL) { + if (KWPREFIXMATCH(p, ARM_CORESIGHT_KW_ADDRA "=")) { + q = strchr(p, '='); + if (*++q == '\0') /* skip '=' */ + return (-1); + + addr = strtoul(q, &e, 0); + if (e == q || *e != '\0') + return (-1); + pm_coresight->ranges[addrn * 2] = addr; + } + + if (KWPREFIXMATCH(p, ARM_CORESIGHT_KW_ADDRB "=")) { + q = strchr(p, '='); + if (*++q == '\0') /* skip '=' */ + return (-1); + + addr = strtoul(q, &e, 0); + if (e == q || *e != '\0') + return (-1); + pm_coresight->ranges[addrn * 2 + 1] = addr; + + if (pm_coresight->ranges[addrn * 2 + 1] < pm_coresight->ranges[addrn * 2]) + return (-1); + addrn += 1; + if (addrn > CORESIGHT_NADDR) + return (-1); + } + }; + + pm_coresight->nranges = addrn; + + pmc_config->pm_caps |= PMC_CAP_READ; + pmc_config->pm_caps &= ~PMC_CAP_WRITE; + + return (0); +} #endif #if defined(__mips__) @@ -1031,8 +1191,9 @@ retval = -1; if (mode != PMC_MODE_SS && mode != PMC_MODE_TS && - mode != PMC_MODE_SC && mode != PMC_MODE_TC) { - errno = EINVAL; + mode != PMC_MODE_SC && mode != PMC_MODE_TC && + mode != PMC_MODE_ST && mode != PMC_MODE_TT) { + return (EINVAL); goto out; } bzero(&pmc_config, sizeof(pmc_config)); @@ -1056,7 +1217,6 @@ *pmcid = pmc_config.pm_pmcid; goto out; } - errx(EX_USAGE, "ERROR: pmc_pmu_allocate failed, check for ctrname %s\n", ctrname); } else { free(spec_copy); spec_copy = NULL; @@ -1073,9 +1233,6 @@ if (spec_copy == NULL) spec_copy = strdup(ctrspec); - r = spec_copy; - ctrname = strsep(&r, ","); - /* * If a explicit class prefix was given by the user, restrict the * search for the event to the specified PMC class. @@ -1173,6 +1330,7 @@ int pmc_cpuinfo(const struct pmc_cpuinfo **pci) { + if (pmc_syscall == -1) { errno = ENXIO; return (-1); @@ -1241,6 +1399,10 @@ ev = tsc_event_table; count = PMC_EVENT_TABLE_SIZE(tsc); break; + case PMC_CLASS_PT: + ev = pt_event_table; + count = PMC_EVENT_TABLE_SIZE(pt); + break; case PMC_CLASS_K8: ev = k8_event_table; count = PMC_EVENT_TABLE_SIZE(k8); @@ -1279,6 +1441,10 @@ ev = beri_event_table; count = PMC_EVENT_TABLE_SIZE(beri); break; + case PMC_CLASS_CORESIGHT: + ev = coresight_event_table; + count = PMC_EVENT_TABLE_SIZE(coresight); + break; case PMC_CLASS_MIPS24K: ev = mips24k_event_table; count = PMC_EVENT_TABLE_SIZE(mips24k); @@ -1327,12 +1493,14 @@ int pmc_flush_logfile(void) { + return (PMC_CALL(FLUSHLOG,0)); } int pmc_close_logfile(void) { + return (PMC_CALL(CLOSELOG,0)); } @@ -1456,6 +1624,11 @@ if (cpu_info.pm_cputype != PMC_CPU_GENERIC) pmc_class_table[n++] = &tsc_class_table_descr; +#if defined(__amd64__) + if (cpu_info.pm_cputype == PMC_CPU_INTEL_KABYLAKE) + pmc_class_table[n++] = &pt_class_table_descr; +#endif + /* * Check if this CPU has fixed function counters. */ @@ -1487,7 +1660,10 @@ #if defined(__amd64__) || defined(__i386__) case PMC_CPU_AMD_K8: PMC_MDEP_INIT(k8); - pmc_class_table[n] = &k8_class_table_descr; + pmc_class_table[n++] = &k8_class_table_descr; + break; + case PMC_CPU_INTEL_KABYLAKE: + PMC_MDEP_INIT(kabylake); break; #endif case PMC_CPU_GENERIC: @@ -1512,11 +1688,13 @@ #if defined(__aarch64__) case PMC_CPU_ARMV8_CORTEX_A53: PMC_MDEP_INIT(cortex_a53); - pmc_class_table[n] = &cortex_a53_class_table_descr; + pmc_class_table[n++] = &cortex_a53_class_table_descr; + pmc_class_table[n++] = &coresight_class_table_descr; break; case PMC_CPU_ARMV8_CORTEX_A57: PMC_MDEP_INIT(cortex_a57); - pmc_class_table[n] = &cortex_a57_class_table_descr; + pmc_class_table[n++] = &cortex_a57_class_table_descr; + pmc_class_table[n++] = &coresight_class_table_descr; break; #endif #if defined(__mips__) @@ -1664,6 +1842,10 @@ } else if (pe >= PMC_EV_BERI_FIRST && pe <= PMC_EV_BERI_LAST) { ev = beri_event_table; evfence = beri_event_table + PMC_EVENT_TABLE_SIZE(beri); + } else if (pe == PMC_EV_CORESIGHT_CORESIGHT) { + ev = coresight_event_table; + evfence = coresight_event_table + + PMC_EVENT_TABLE_SIZE(coresight); } else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) { ev = mips24k_event_table; evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k); @@ -1685,6 +1867,9 @@ } else if (pe == PMC_EV_TSC_TSC) { ev = tsc_event_table; evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc); + } else if (pe == PMC_EV_PT_PT) { + ev = pt_event_table; + evfence = pt_event_table + PMC_EVENT_TABLE_SIZE(pt); } else if ((int)pe >= PMC_EV_SOFT_FIRST && (int)pe <= PMC_EV_SOFT_LAST) { ev = soft_event_table; evfence = soft_event_table + soft_event_info.pm_nevent; @@ -1801,6 +1986,68 @@ return (0); } +int +pmc_thread_wakeup(pmc_id_t pmc, pid_t pid) +{ + struct pmc_op_thread_wakeup u; + + u.pm_pmcid = pmc; + u.pm_pid = pid; + + return (PMC_CALL(THREAD_WAKEUP, &u)); +} + +int +pmc_read_trace(uint32_t cpu, pmc_id_t pmc, + pmc_value_t *cycle, pmc_value_t *offset) +{ + struct pmc_op_trace_read pmc_trace_read; + + pmc_trace_read.pm_pmcid = pmc; + pmc_trace_read.pm_cpu = cpu; + pmc_trace_read.pm_cycle = 0; + pmc_trace_read.pm_offset = 0; + + if (PMC_CALL(TRACE_READ, &pmc_trace_read) < 0) + return (-1); + + *cycle = pmc_trace_read.pm_cycle; + *offset = pmc_trace_read.pm_offset; + + return (0); +} + +int +pmc_trace_config(uint32_t cpu, pmc_id_t pmc, + uint64_t *ranges, uint32_t nranges) +{ + struct pmc_op_trace_config trc; + + trc.pm_pmcid = pmc; + trc.pm_cpu = cpu; + trc.nranges = nranges; + + if (nranges > PMC_FILTER_MAX_IP_RANGES) + return (-1); + + memcpy(&trc.ranges, ranges, sizeof(uint64_t) * 2 * nranges); + + if (PMC_CALL(TRACE_CONFIG, &trc) < 0) + return (-1); + + return (0); +} + +int +pmc_log_kmap(pmc_id_t pmc) +{ + struct pmc_op_simple pmc_log_km; + + pmc_log_km.pm_pmcid = pmc; + + return (PMC_CALL(LOG_KERNEL_MAP, &pmc_log_km)); +} + int pmc_release(pmc_id_t pmc) { Index: lib/libpmc/pmc.h =================================================================== --- lib/libpmc/pmc.h +++ lib/libpmc/pmc.h @@ -77,6 +77,7 @@ int pmc_allocate(const char *_ctrspec, enum pmc_mode _mode, uint32_t _flags, int _cpu, pmc_id_t *_pmcid, uint64_t count); int pmc_attach(pmc_id_t _pmcid, pid_t _pid); +int pmc_thread_wakeup(pmc_id_t pmc, pid_t pid); int pmc_capabilities(pmc_id_t _pmc, uint32_t *_caps); int pmc_configure_logfile(int _fd); int pmc_flush_logfile(void); @@ -88,7 +89,10 @@ int pmc_get_msr(pmc_id_t _pmc, uint32_t *_msr); int pmc_init(void); int pmc_read(pmc_id_t _pmc, pmc_value_t *_value); +int pmc_read_trace(uint32_t cpu, pmc_id_t pmc, pmc_value_t *cycle, pmc_value_t *offset); +int pmc_trace_config(uint32_t cpu, pmc_id_t pmc, uint64_t *ranges, uint32_t nranges); int pmc_release(pmc_id_t _pmc); +int pmc_log_kmap(pmc_id_t pmc); int pmc_rw(pmc_id_t _pmc, pmc_value_t _newvalue, pmc_value_t *_oldvalue); int pmc_set(pmc_id_t _pmc, pmc_value_t _value); int pmc_start(pmc_id_t _pmc); Index: lib/libpmc/pmclog.c =================================================================== --- lib/libpmc/pmclog.c +++ lib/libpmc/pmclog.c @@ -356,12 +356,16 @@ PMCLOG_READ32(le,ev->pl_u.pl_a.pl_flags); PMCLOG_READ32(le,noop); PMCLOG_READ64(le,ev->pl_u.pl_a.pl_rate); - ev->pl_u.pl_a.pl_evname = pmc_pmu_event_get_by_idx(ps->ps_cpuid, ev->pl_u.pl_a.pl_event); - if (ev->pl_u.pl_a.pl_evname != NULL) - break; - else if ((ev->pl_u.pl_a.pl_evname = + + if ((ev->pl_u.pl_a.pl_evname = _pmc_name_of_event(ev->pl_u.pl_a.pl_event, ps->ps_arch)) == NULL) { + + ev->pl_u.pl_a.pl_evname = pmc_pmu_event_get_by_idx(ps->ps_cpuid, + ev->pl_u.pl_a.pl_event); + if (ev->pl_u.pl_a.pl_evname != NULL) + break; + printf("unknown event\n"); goto error; } Index: sys/dev/hwpmc/pmc_events.h =================================================================== --- sys/dev/hwpmc/pmc_events.h +++ sys/dev/hwpmc/pmc_events.h @@ -217,6 +217,20 @@ __PMC_EV_ALIAS("unhalted-reference-cycles", IAP_ARCH_UNH_REF_CYC) \ __PMC_EV_ALIAS("unhalted-core-cycles", IAP_ARCH_UNH_COR_CYC) +/* Intel PT */ +#define __PMC_EV_PT() \ + __PMC_EV(PT, PT) + +#define PMC_EV_PT_FIRST PMC_EV_PT_PT +#define PMC_EV_PT_LAST PMC_EV_PT_PT + +/* ARM CORESIGHT */ +#define __PMC_EV_CORESIGHT() \ + __PMC_EV(CORESIGHT, CORESIGHT) + +#define PMC_EV_CORESIGHT_FIRST PMC_EV_CORESIGHT_CORESIGHT +#define PMC_EV_CORESIGHT_LAST PMC_EV_CORESIGHT_CORESIGHT + #define __PMC_EV_UCP() \ __PMC_EV(UCP, EVENT_0CH_04H_E) \ __PMC_EV(UCP, EVENT_0CH_04H_F) \ @@ -1824,6 +1838,7 @@ * START #EVENTS DESCRIPTION * 0 0x1000 Reserved * 0x1000 0x0001 TSC + * 0x1100 0x0001 PT * 0x2000 0x0080 AMD K7 events * 0x2080 0x0100 AMD K8 events * 0x10000 0x0080 INTEL architectural fixed-function events @@ -1841,11 +1856,14 @@ * 0x13300 0x00FF Freescale e500 events * 0x14000 0x0100 ARMv7 events * 0x14100 0x0100 ARMv8 events + * 0x14200 0x0001 ARM Coresight * 0x20000 0x1000 Software events */ #define __PMC_EVENTS() \ __PMC_EV_BLOCK(TSC, 0x01000) \ __PMC_EV_TSC() \ + __PMC_EV_BLOCK(PT, 0x1100) \ + __PMC_EV_PT() \ __PMC_EV_BLOCK(IAF, 0x10000) \ __PMC_EV_IAF() \ __PMC_EV_BLOCK(K7, 0x2000) \ @@ -1873,7 +1891,9 @@ __PMC_EV_BLOCK(ARMV7, 0x14000) \ __PMC_EV_ARMV7() \ __PMC_EV_BLOCK(ARMV8, 0x14100) \ - __PMC_EV_ARMV8() + __PMC_EV_ARMV8() \ + __PMC_EV_BLOCK(CORESIGHT, 0x14200) \ + __PMC_EV_CORESIGHT() #define PMC_EVENT_FIRST PMC_EV_TSC_TSC #define PMC_EVENT_LAST PMC_EV_SOFT_LAST