From owner-svn-src-all@FreeBSD.ORG Sun Jun 7 10:00:35 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id C951F106568D; Sun, 7 Jun 2009 10:00:35 +0000 (UTC) (envelope-from fabient@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id B184C8FC21; Sun, 7 Jun 2009 10:00:35 +0000 (UTC) (envelope-from fabient@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n57A0Z48089383; Sun, 7 Jun 2009 10:00:35 GMT (envelope-from fabient@svn.freebsd.org) Received: (from fabient@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n57A0Zem089380; Sun, 7 Jun 2009 10:00:35 GMT (envelope-from fabient@svn.freebsd.org) Message-Id: <200906071000.n57A0Zem089380@svn.freebsd.org> From: Fabien Thomas Date: Sun, 7 Jun 2009 10:00:35 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r193634 - in stable/7: lib/libpmc share/man/man4 sys/amd64/amd64 sys/amd64/include sys/conf sys/dev/hwpmc sys/i386/i386 sys/i386/include sys/kern sys/modules/hwpmc sys/sys usr.sbin usr.... X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 07 Jun 2009 10:00:36 -0000 Author: fabient Date: Sun Jun 7 10:00:35 2009 New Revision: 193634 URL: http://svn.freebsd.org/changeset/base/193634 Log: MFC hwpmc framework: - capture with callchain - Intel Core 2 support - Intel Core i7 support - source code annotate (pmcannotate) - bug fixes Reviewed by: jkoshy (mentor) Approved by: re (gnn) Added: stable/7/lib/libpmc/libpmcinternal.h (contents, props changed) stable/7/lib/libpmc/pmc.atom.3 (contents, props changed) stable/7/lib/libpmc/pmc.core.3 (contents, props changed) stable/7/lib/libpmc/pmc.core2.3 (contents, props changed) stable/7/lib/libpmc/pmc.iaf.3 (contents, props changed) stable/7/lib/libpmc/pmc.k7.3 (contents, props changed) stable/7/lib/libpmc/pmc.k8.3 (contents, props changed) stable/7/lib/libpmc/pmc.p4.3 (contents, props changed) stable/7/lib/libpmc/pmc.p5.3 (contents, props changed) stable/7/lib/libpmc/pmc.p6.3 (contents, props changed) stable/7/lib/libpmc/pmc.tsc.3 (contents, props changed) stable/7/lib/libpmc/pmc_allocate.3 (contents, props changed) stable/7/lib/libpmc/pmc_attach.3 (contents, props changed) stable/7/lib/libpmc/pmc_capabilities.3 (contents, props changed) stable/7/lib/libpmc/pmc_configure_logfile.3 (contents, props changed) stable/7/lib/libpmc/pmc_disable.3 (contents, props changed) stable/7/lib/libpmc/pmc_event_names_of_class.3 (contents, props changed) stable/7/lib/libpmc/pmc_get_driver_stats.3 (contents, props changed) stable/7/lib/libpmc/pmc_get_msr.3 (contents, props changed) stable/7/lib/libpmc/pmc_init.3 (contents, props changed) stable/7/lib/libpmc/pmc_name_of_capability.3 (contents, props changed) stable/7/lib/libpmc/pmc_read.3 (contents, props changed) stable/7/lib/libpmc/pmc_set.3 (contents, props changed) stable/7/lib/libpmc/pmc_start.3 (contents, props changed) stable/7/sys/dev/hwpmc/hwpmc_core.c (contents, props changed) stable/7/sys/dev/hwpmc/hwpmc_core.h (contents, props changed) stable/7/sys/dev/hwpmc/hwpmc_intel.c (contents, props changed) stable/7/sys/dev/hwpmc/hwpmc_tsc.c (contents, props changed) stable/7/sys/dev/hwpmc/hwpmc_tsc.h (contents, props changed) stable/7/usr.sbin/pmcannotate/ stable/7/usr.sbin/pmcannotate/Makefile (contents, props changed) stable/7/usr.sbin/pmcannotate/pmcannotate.8 (contents, props changed) stable/7/usr.sbin/pmcannotate/pmcannotate.c (contents, props changed) Modified: stable/7/lib/libpmc/Makefile stable/7/lib/libpmc/libpmc.c stable/7/lib/libpmc/pmc.3 stable/7/lib/libpmc/pmclog.c stable/7/lib/libpmc/pmclog.h stable/7/share/man/man4/hwpmc.4 stable/7/sys/amd64/amd64/exception.S stable/7/sys/amd64/amd64/genassym.c stable/7/sys/amd64/amd64/machdep.c stable/7/sys/amd64/amd64/mp_machdep.c stable/7/sys/amd64/amd64/trap.c stable/7/sys/amd64/include/intr_machdep.h stable/7/sys/amd64/include/pmc_mdep.h stable/7/sys/conf/Makefile.amd64 stable/7/sys/conf/Makefile.i386 stable/7/sys/conf/files.amd64 stable/7/sys/conf/files.i386 stable/7/sys/conf/files.pc98 stable/7/sys/dev/hwpmc/hwpmc_amd.c stable/7/sys/dev/hwpmc/hwpmc_amd.h stable/7/sys/dev/hwpmc/hwpmc_arm.c stable/7/sys/dev/hwpmc/hwpmc_ia64.c stable/7/sys/dev/hwpmc/hwpmc_logging.c stable/7/sys/dev/hwpmc/hwpmc_mod.c stable/7/sys/dev/hwpmc/hwpmc_pentium.c stable/7/sys/dev/hwpmc/hwpmc_pentium.h stable/7/sys/dev/hwpmc/hwpmc_piv.c stable/7/sys/dev/hwpmc/hwpmc_piv.h stable/7/sys/dev/hwpmc/hwpmc_powerpc.c stable/7/sys/dev/hwpmc/hwpmc_ppro.c stable/7/sys/dev/hwpmc/hwpmc_ppro.h stable/7/sys/dev/hwpmc/hwpmc_sparc64.c stable/7/sys/dev/hwpmc/hwpmc_x86.c stable/7/sys/dev/hwpmc/pmc_events.h stable/7/sys/i386/i386/exception.s stable/7/sys/i386/i386/genassym.c stable/7/sys/i386/i386/trap.c stable/7/sys/i386/include/pmc_mdep.h stable/7/sys/kern/kern_pmc.c stable/7/sys/modules/hwpmc/Makefile stable/7/sys/sys/pmc.h stable/7/sys/sys/pmckern.h stable/7/sys/sys/pmclog.h stable/7/sys/sys/proc.h stable/7/usr.sbin/Makefile stable/7/usr.sbin/pmccontrol/pmccontrol.8 stable/7/usr.sbin/pmccontrol/pmccontrol.c stable/7/usr.sbin/pmcstat/Makefile stable/7/usr.sbin/pmcstat/pmcstat.8 stable/7/usr.sbin/pmcstat/pmcstat.c stable/7/usr.sbin/pmcstat/pmcstat.h stable/7/usr.sbin/pmcstat/pmcstat_log.c Modified: stable/7/lib/libpmc/Makefile ============================================================================== --- stable/7/lib/libpmc/Makefile Sun Jun 7 09:23:50 2009 (r193633) +++ stable/7/lib/libpmc/Makefile Sun Jun 7 10:00:35 2009 (r193634) @@ -7,40 +7,54 @@ INCS= pmc.h pmclog.h WARNS?= 6 -MAN= pmc.3 pmclog.3 +MAN= pmc.3 +MAN+= pmc_allocate.3 +MAN+= pmc_attach.3 +MAN+= pmc_capabilities.3 +MAN+= pmc_configure_logfile.3 +MAN+= pmc_disable.3 +MAN+= pmc_event_names_of_class.3 +MAN+= pmc_get_driver_stats.3 +MAN+= pmc_get_msr.3 +MAN+= pmc_init.3 +MAN+= pmc_name_of_capability.3 +MAN+= pmc_read.3 +MAN+= pmc_set.3 +MAN+= pmc_start.3 +MAN+= pmclog.3 + +# PMC-dependent manual pages +MAN+= pmc.atom.3 +MAN+= pmc.core.3 +MAN+= pmc.core2.3 +MAN+= pmc.iaf.3 +MAN+= pmc.k7.3 +MAN+= pmc.k8.3 +MAN+= pmc.p4.3 +MAN+= pmc.p5.3 +MAN+= pmc.p6.3 +MAN+= pmc.tsc.3 MLINKS+= \ - pmc.3 pmc_allocate.3 \ - pmc.3 pmc_attach.3 \ - pmc.3 pmc_capabilities.3 \ - pmc.3 pmc_configure_logfile.3 \ - pmc.3 pmc_cpuinfo.3 \ - pmc.3 pmc_detach.3 \ - pmc.3 pmc_disable.3 \ - pmc.3 pmc_enable.3 \ - pmc.3 pmc_event_names_of_class.3 \ - pmc.3 pmc_flush_logfile.3 \ - pmc.3 pmc_get_driver_stats.3 \ - pmc.3 pmc_init.3 \ - pmc.3 pmc_name_of_capability.3 \ - pmc.3 pmc_name_of_class.3 \ - pmc.3 pmc_name_of_cputype.3 \ - pmc.3 pmc_name_of_event.3 \ - pmc.3 pmc_name_of_mode.3 \ - pmc.3 pmc_name_of_state.3 \ - pmc.3 pmc_ncpu.3 \ - pmc.3 pmc_npmc.3 \ - pmc.3 pmc_pmcinfo.3 \ - pmc.3 pmc_read.3 \ - pmc.3 pmc_release.3 \ - pmc.3 pmc_rw.3 \ - pmc.3 pmc_set.3 \ - pmc.3 pmc_start.3 \ - pmc.3 pmc_stop.3 \ - pmc.3 pmc_width.3 \ - pmc.3 pmc_write.3 \ - pmc.3 pmc_writelog.3 \ - pmc.3 pmc_x86_get_msr.3 + pmc_allocate.3 pmc_release.3 \ + pmc_attach.3 pmc_detach.3 \ + pmc_capabilities.3 pmc_ncpu.3 \ + pmc_capabilities.3 pmc_npmc.3 \ + pmc_capabilities.3 pmc_pmcinfo.3 \ + pmc_capabilities.3 pmc_cpuinfo.3 \ + pmc_capabilities.3 pmc_width.3 \ + pmc_configure_logfile.3 pmc_flush_logfile.3 \ + pmc_configure_logfile.3 pmc_writelog.3 \ + pmc_disable.3 pmc_enable.3 \ + pmc_name_of_capability.3 pmc_name_of_class.3 \ + pmc_name_of_capability.3 pmc_name_of_cputype.3 \ + pmc_name_of_capability.3 pmc_name_of_disposition.3 \ + pmc_name_of_capability.3 pmc_name_of_event.3 \ + pmc_name_of_capability.3 pmc_name_of_mode.3 \ + pmc_name_of_capability.3 pmc_name_of_state.3 \ + pmc_read.3 pmc_rw.3 \ + pmc_read.3 pmc_write.3 \ + pmc_start.3 pmc_stop.3 MLINKS+= \ pmclog.3 pmclog_open.3 \ Modified: stable/7/lib/libpmc/libpmc.c ============================================================================== --- stable/7/lib/libpmc/libpmc.c Sun Jun 7 09:23:50 2009 (r193633) +++ stable/7/lib/libpmc/libpmc.c Sun Jun 7 10:00:35 2009 (r193634) @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003-2006 Joseph Koshy + * Copyright (c) 2003-2008 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,12 +42,18 @@ __FBSDID("$FreeBSD$"); #include #include +#include "libpmcinternal.h" + /* Function prototypes */ #if defined(__i386__) static int k7_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); #endif #if defined(__amd64__) || defined(__i386__) +static int iaf_allocate_pmc(enum pmc_event _pe, char *_ctrspec, + struct pmc_op_pmcallocate *_pmc_config); +static int iap_allocate_pmc(enum pmc_event _pe, char *_ctrspec, + struct pmc_op_pmcallocate *_pmc_config); static int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); static int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec, @@ -59,6 +65,10 @@ static int p5_allocate_pmc(enum pmc_even static int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec, struct pmc_op_pmcallocate *_pmc_config); #endif +#if defined(__amd64__) || defined(__i386__) +static int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec, + struct pmc_op_pmcallocate *_pmc_config); +#endif #define PMC_CALL(cmd, params) \ syscall(pmc_syscall, PMC_OP_##cmd, (params)) @@ -69,7 +79,6 @@ static int p6_allocate_pmc(enum pmc_even * mapped to the appropriate canonical event descriptions using a * lookup table. */ - struct pmc_event_alias { const char *pm_alias; const char *pm_spec; @@ -78,25 +87,145 @@ struct pmc_event_alias { static const struct pmc_event_alias *pmc_mdep_event_aliases; /* - * The pmc_event_descr table maps symbolic names known to the user + * The pmc_event_descr structure maps symbolic names known to the user * to integer codes used by the PMC KLD. */ - struct pmc_event_descr { const char *pm_ev_name; enum pmc_event pm_ev_code; - enum pmc_class pm_ev_class; }; -static const struct pmc_event_descr -pmc_event_table[] = +/* + * The pmc_class_descr structure maps class name prefixes for + * event names to event tables and other PMC class data. + */ +struct pmc_class_descr { + const char *pm_evc_name; + size_t pm_evc_name_size; + enum pmc_class pm_evc_class; + const struct pmc_event_descr *pm_evc_event_table; + size_t pm_evc_event_table_size; + int (*pm_evc_allocate_pmc)(enum pmc_event _pe, + char *_ctrspec, struct pmc_op_pmcallocate *_pa); +}; + +#define PMC_TABLE_SIZE(N) (sizeof(N)/sizeof(N[0])) +#define PMC_EVENT_TABLE_SIZE(N) PMC_TABLE_SIZE(N##_event_table) + +#undef __PMC_EV +#define __PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N }, + +/* + * PMC_CLASSDEP_TABLE(NAME, CLASS) + * + * Define a table mapping event names and aliases to HWPMC event IDs. + */ +#define PMC_CLASSDEP_TABLE(N, C) \ + static const struct pmc_event_descr N##_event_table[] = \ + { \ + __PMC_EV_##C() \ + } + +PMC_CLASSDEP_TABLE(iaf, IAF); +PMC_CLASSDEP_TABLE(k7, K7); +PMC_CLASSDEP_TABLE(k8, K8); +PMC_CLASSDEP_TABLE(p4, P4); +PMC_CLASSDEP_TABLE(p5, P5); +PMC_CLASSDEP_TABLE(p6, P6); + +#undef __PMC_EV_ALIAS +#define __PMC_EV_ALIAS(N,CODE) { N, PMC_EV_##CODE }, + +static const struct pmc_event_descr atom_event_table[] = +{ + __PMC_EV_ALIAS_ATOM() +}; + +static const struct pmc_event_descr core_event_table[] = { -#undef __PMC_EV -#define __PMC_EV(C,N,EV) { #EV, PMC_EV_ ## C ## _ ## N, PMC_CLASS_ ## C }, - __PMC_EVENTS() + __PMC_EV_ALIAS_CORE() +}; + + +static const struct pmc_event_descr core2_event_table[] = +{ + __PMC_EV_ALIAS_CORE2() +}; + +static const struct pmc_event_descr corei7_event_table[] = +{ + __PMC_EV_ALIAS_COREI7() }; /* + * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...) + * + * Map a CPU to the PMC classes it supports. + */ +#define PMC_MDEP_TABLE(N,C,...) \ + static const enum pmc_class N##_pmc_classes[] = { \ + PMC_CLASS_##C, __VA_ARGS__ \ + } + +PMC_MDEP_TABLE(atom, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC); +PMC_MDEP_TABLE(core, IAP, PMC_CLASS_TSC); +PMC_MDEP_TABLE(core2, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC); +PMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC); +PMC_MDEP_TABLE(k7, K7, PMC_CLASS_TSC); +PMC_MDEP_TABLE(k8, K8, PMC_CLASS_TSC); +PMC_MDEP_TABLE(p4, P4, PMC_CLASS_TSC); +PMC_MDEP_TABLE(p5, P5, PMC_CLASS_TSC); +PMC_MDEP_TABLE(p6, P6, PMC_CLASS_TSC); + +static const struct pmc_event_descr tsc_event_table[] = +{ + __PMC_EV_TSC() +}; + +#undef PMC_CLASS_TABLE_DESC +#define PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR) \ +static const struct pmc_class_descr NAME##_class_table_descr = \ + { \ + .pm_evc_name = #CLASS "-", \ + .pm_evc_name_size = sizeof(#CLASS "-") - 1, \ + .pm_evc_class = PMC_CLASS_##CLASS , \ + .pm_evc_event_table = EVENTS##_event_table , \ + .pm_evc_event_table_size = \ + PMC_EVENT_TABLE_SIZE(EVENTS), \ + .pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc \ + } + +#if defined(__i386__) || defined(__amd64__) +PMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf); +PMC_CLASS_TABLE_DESC(atom, IAP, atom, iap); +PMC_CLASS_TABLE_DESC(core, IAP, core, iap); +PMC_CLASS_TABLE_DESC(core2, IAP, core2, iap); +PMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap); +#endif +#if defined(__i386__) +PMC_CLASS_TABLE_DESC(k7, K7, k7, k7); +#endif +#if defined(__i386__) || defined(__amd64__) +PMC_CLASS_TABLE_DESC(k8, K8, k8, k8); +PMC_CLASS_TABLE_DESC(p4, P4, p4, p4); +#endif +#if defined(__i386__) +PMC_CLASS_TABLE_DESC(p5, P5, p5, p5); +PMC_CLASS_TABLE_DESC(p6, P6, p6, p6); +#endif +#if defined(__i386__) || defined(__amd64__) +PMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc); +#endif + +#undef PMC_CLASS_TABLE_DESC + +static const struct pmc_class_descr **pmc_class_table; +#define PMC_CLASS_TABLE_SIZE cpu_info.pm_nclass + +static const enum pmc_class *pmc_mdep_class_list; +static size_t pmc_mdep_class_list_size; + +/* * Mapping tables, mapping enumeration values to human readable * strings. */ @@ -113,9 +242,14 @@ static const char * pmc_class_names[] = __PMC_CLASSES() }; -static const char * pmc_cputype_names[] = { +struct pmc_cputype_map { + enum pmc_class pm_cputype; + const char *pm_name; +}; + +static const struct pmc_cputype_map pmc_cputype_names[] = { #undef __PMC_CPU -#define __PMC_CPU(S, D) #S , +#define __PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } , __PMC_CPUS() }; @@ -141,11 +275,6 @@ static int pmc_syscall = -1; /* filled static struct pmc_cpuinfo cpu_info; /* filled in by pmc_init() */ - -/* Architecture dependent event parsing */ -static int (*pmc_mdep_allocate_pmc)(enum pmc_event _pe, char *_ctrspec, - struct pmc_op_pmcallocate *_pmc_config); - /* Event masks for events */ struct pmc_masks { const char *pm_name; @@ -163,20 +292,21 @@ pmc_parse_mask(const struct pmc_masks *p int c; if (pmask == NULL) /* no mask keywords */ - return -1; - q = strchr(p, '='); /* skip '=' */ + return (-1); + q = strchr(p, '='); /* skip '=' */ if (*++q == '\0') /* no more data */ - return -1; + return (-1); c = 0; /* count of mask keywords seen */ while ((r = strsep(&q, "+")) != NULL) { - for (pm = pmask; pm->pm_name && strcmp(r, pm->pm_name); pm++) + for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name); + pm++) ; if (pm->pm_name == NULL) /* not found */ - return -1; + return (-1); *evmask |= pm->pm_value; c++; } - return c; + return (c); } #endif @@ -194,7 +324,7 @@ static struct pmc_event_alias k7_aliases EV_ALIAS("branches", "k7-retired-branches"), EV_ALIAS("branch-mispredicts", "k7-retired-branches-mispredicted"), EV_ALIAS("cycles", "tsc"), - EV_ALIAS("dc-misses", "k7-dc-misses,mask=moesi"), + EV_ALIAS("dc-misses", "k7-dc-misses"), EV_ALIAS("ic-misses", "k7-ic-misses"), EV_ALIAS("instructions", "k7-retired-instructions"), EV_ALIAS("interrupts", "k7-hardware-interrupts"), @@ -212,19 +342,12 @@ static int k7_allocate_pmc(enum pmc_event pe, char *ctrspec, struct pmc_op_pmcallocate *pmc_config) { - char *e, *p, *q; - int c, has_unitmask; + char *e, *p, *q; + int c, has_unitmask; uint32_t count, unitmask; pmc_config->pm_md.pm_amd.pm_amd_config = 0; - pmc_config->pm_caps |= PMC_CAP_READ; - - if (pe == PMC_EV_TSC_TSC) { - /* TSC events must be unqualified. */ - if (ctrspec && *ctrspec != '\0') - return -1; - return 0; - } + pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 || pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM || @@ -234,17 +357,15 @@ k7_allocate_pmc(enum pmc_event pe, char } else unitmask = has_unitmask = 0; - pmc_config->pm_caps |= PMC_CAP_WRITE; - while ((p = strsep(&ctrspec, ",")) != NULL) { if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) { q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ - return -1; + return (-1); count = strtol(q, &e, 0); if (e == q || *e != '\0') - return -1; + return (-1); pmc_config->pm_caps |= PMC_CAP_THRESHOLD; pmc_config->pm_md.pm_amd.pm_amd_config |= @@ -258,11 +379,11 @@ k7_allocate_pmc(enum pmc_event pe, char pmc_config->pm_caps |= PMC_CAP_SYSTEM; } else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) { if (has_unitmask == 0) - return -1; + return (-1); unitmask = 0; q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ - return -1; + return (-1); while ((c = tolower(*q++)) != 0) if (c == 'm') @@ -278,15 +399,15 @@ k7_allocate_pmc(enum pmc_event pe, char else if (c == '+') continue; else - return -1; + return (-1); if (unitmask == 0) - return -1; + return (-1); } else if (KWMATCH(p, K7_KW_USR)) { pmc_config->pm_caps |= PMC_CAP_USER; } else - return -1; + return (-1); } if (has_unitmask) { @@ -295,7 +416,7 @@ k7_allocate_pmc(enum pmc_event pe, char AMD_PMC_TO_UNITMASK(unitmask); } - return 0; + return (0); } @@ -304,6 +425,240 @@ k7_allocate_pmc(enum pmc_event pe, char #if defined(__amd64__) || defined(__i386__) /* + * Intel Core (Family 6, Model E) PMCs. + */ + +static struct pmc_event_alias core_aliases[] = { + EV_ALIAS("branches", "iap-br-instr-ret"), + EV_ALIAS("branch-mispredicts", "iap-br-mispred-ret"), + EV_ALIAS("cycles", "tsc-tsc"), + EV_ALIAS("ic-misses", "iap-icache-misses"), + EV_ALIAS("instructions", "iap-instr-ret"), + EV_ALIAS("interrupts", "iap-core-hw-int-rx"), + EV_ALIAS("unhalted-cycles", "iap-unhalted-core-cycles"), + EV_ALIAS(NULL, NULL) +}; + +/* + * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H) + * and Atom (Family 6, model 1CH) PMCs. + */ + +static struct pmc_event_alias core2_aliases[] = { + EV_ALIAS("branches", "iap-br-inst-retired.any"), + EV_ALIAS("branch-mispredicts", "iap-br-inst-retired.mispred"), + EV_ALIAS("cycles", "tsc-tsc"), + EV_ALIAS("ic-misses", "iap-l1i-misses"), + EV_ALIAS("instructions", "iaf-instr-retired.any"), + EV_ALIAS("interrupts", "iap-hw-int-rcv"), + EV_ALIAS("unhalted-cycles", "iaf-cpu-clk-unhalted.core"), + EV_ALIAS(NULL, NULL) +}; +#define atom_aliases core2_aliases +#define corei7_aliases core2_aliases + +#define IAF_KW_OS "os" +#define IAF_KW_USR "usr" +#define IAF_KW_ANYTHREAD "anythread" + +/* + * Parse an event specifier for Intel fixed function counters. + */ +static int +iaf_allocate_pmc(enum pmc_event pe, char *ctrspec, + struct pmc_op_pmcallocate *pmc_config) +{ + char *p; + + (void) pe; + + pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); + pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0; + + while ((p = strsep(&ctrspec, ",")) != NULL) { + if (KWMATCH(p, IAF_KW_OS)) + pmc_config->pm_caps |= PMC_CAP_SYSTEM; + else if (KWMATCH(p, IAF_KW_USR)) + pmc_config->pm_caps |= PMC_CAP_USER; + else if (KWMATCH(p, IAF_KW_ANYTHREAD)) + pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY; + else + return (-1); + } + + return (0); +} + +/* + * Core/Core2 support. + */ + +#define IAP_KW_AGENT "agent" +#define IAP_KW_ANYTHREAD "anythread" +#define IAP_KW_CACHESTATE "cachestate" +#define IAP_KW_CMASK "cmask" +#define IAP_KW_CORE "core" +#define IAP_KW_EDGE "edge" +#define IAP_KW_INV "inv" +#define IAP_KW_OS "os" +#define IAP_KW_PREFETCH "prefetch" +#define IAP_KW_SNOOPRESPONSE "snoopresponse" +#define IAP_KW_SNOOPTYPE "snooptype" +#define IAP_KW_TRANSITION "trans" +#define IAP_KW_USR "usr" + +static struct pmc_masks iap_core_mask[] = { + PMCMASK(all, (0x3 << 14)), + PMCMASK(this, (0x1 << 14)), + NULLMASK +}; + +static struct pmc_masks iap_agent_mask[] = { + PMCMASK(this, 0), + PMCMASK(any, (0x1 << 13)), + NULLMASK +}; + +static struct pmc_masks iap_prefetch_mask[] = { + PMCMASK(both, (0x3 << 12)), + PMCMASK(only, (0x1 << 12)), + PMCMASK(exclude, 0), + NULLMASK +}; + +static struct pmc_masks iap_cachestate_mask[] = { + PMCMASK(i, (1 << 8)), + PMCMASK(s, (1 << 9)), + PMCMASK(e, (1 << 10)), + PMCMASK(m, (1 << 11)), + NULLMASK +}; + +static struct pmc_masks iap_snoopresponse_mask[] = { + PMCMASK(clean, (1 << 8)), + PMCMASK(hit, (1 << 9)), + PMCMASK(hitm, (1 << 11)), + NULLMASK +}; + +static struct pmc_masks iap_snooptype_mask[] = { + PMCMASK(cmp2s, (1 << 8)), + PMCMASK(cmp2i, (1 << 9)), + NULLMASK +}; + +static struct pmc_masks iap_transition_mask[] = { + PMCMASK(any, 0x00), + PMCMASK(frequency, 0x10), + NULLMASK +}; + +static int +iap_allocate_pmc(enum pmc_event pe, char *ctrspec, + struct pmc_op_pmcallocate *pmc_config) +{ + char *e, *p, *q; + uint32_t cachestate, evmask; + int count, n; + + pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE | + PMC_CAP_QUALIFIER); + pmc_config->pm_md.pm_iap.pm_iap_config = 0; + + cachestate = evmask = 0; + + /* Parse additional modifiers if present */ + while ((p = strsep(&ctrspec, ",")) != NULL) { + + n = 0; + if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) { + q = strchr(p, '='); + if (*++q == '\0') /* skip '=' */ + return (-1); + count = strtol(q, &e, 0); + if (e == q || *e != '\0') + return (-1); + pmc_config->pm_caps |= PMC_CAP_THRESHOLD; + pmc_config->pm_md.pm_iap.pm_iap_config |= + IAP_CMASK(count); + } else if (KWMATCH(p, IAP_KW_EDGE)) { + pmc_config->pm_caps |= PMC_CAP_EDGE; + } else if (KWMATCH(p, IAP_KW_INV)) { + pmc_config->pm_caps |= PMC_CAP_INVERT; + } else if (KWMATCH(p, IAP_KW_OS)) { + pmc_config->pm_caps |= PMC_CAP_SYSTEM; + } else if (KWMATCH(p, IAP_KW_USR)) { + pmc_config->pm_caps |= PMC_CAP_USER; + } else if (KWMATCH(p, IAP_KW_ANYTHREAD)) { + pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY; + } else if (KWMATCH(p, IAP_KW_CORE)) { + n = pmc_parse_mask(iap_core_mask, p, &evmask); + if (n != 1) + return (-1); + } else if (KWMATCH(p, IAP_KW_AGENT)) { + n = pmc_parse_mask(iap_agent_mask, p, &evmask); + if (n != 1) + return (-1); + } else if (KWMATCH(p, IAP_KW_PREFETCH)) { + n = pmc_parse_mask(iap_prefetch_mask, p, &evmask); + if (n != 1) + return (-1); + } else if (KWMATCH(p, IAP_KW_CACHESTATE)) { + n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate); + } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE && + KWMATCH(p, IAP_KW_TRANSITION)) { + n = pmc_parse_mask(iap_transition_mask, p, &evmask); + if (n != 1) + return (-1); + } else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM || + cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 || + cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME || + cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7) { + if (KWMATCH(p, IAP_KW_SNOOPRESPONSE)) { + n = pmc_parse_mask(iap_snoopresponse_mask, p, + &evmask); + } else if (KWMATCH(p, IAP_KW_SNOOPTYPE)) { + n = pmc_parse_mask(iap_snooptype_mask, p, + &evmask); + } else + return (-1); + } else + return (-1); + + if (n < 0) /* Parsing failed. */ + return (-1); + } + + pmc_config->pm_md.pm_iap.pm_iap_config |= evmask; + + /* + * If the event requires a 'cachestate' qualifier but was not + * specified by the user, use a sensible default. + */ + switch (pe) { + case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */ + case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */ + case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */ + case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */ + case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */ + case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */ + case PMC_EV_IAP_EVENT_32H: /* Core */ + case PMC_EV_IAP_EVENT_40H: /* Core */ + case PMC_EV_IAP_EVENT_41H: /* Core */ + case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */ + case PMC_EV_IAP_EVENT_77H: /* Core */ + if (cachestate == 0) + cachestate = (0xF << 8); + default: + break; + } + + pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate; + + return (0); +} + +/* * AMD K8 PMCs. * * These are very similar to AMD K7 PMCs, but support more kinds of @@ -317,7 +672,7 @@ static struct pmc_event_alias k8_aliases EV_ALIAS("cycles", "tsc"), EV_ALIAS("dc-misses", "k8-dc-miss"), EV_ALIAS("ic-misses", "k8-ic-miss"), - EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), + EV_ALIAS("instructions", "k8-fr-retired-x86-instructions"), EV_ALIAS("interrupts", "k8-fr-taken-hardware-interrupts"), EV_ALIAS("unhalted-cycles", "k8-bu-cpu-clk-unhalted"), EV_ALIAS(NULL, NULL) @@ -492,7 +847,7 @@ static const struct pmc_masks k8_mask_np /* nb hypertransport bus bandwidth */ static const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */ __K8MASK(command, 0), - __K8MASK(data, 1), + __K8MASK(data, 1), __K8MASK(buffer-release, 2), __K8MASK(nop, 3), NULLMASK @@ -511,21 +866,14 @@ static int k8_allocate_pmc(enum pmc_event pe, char *ctrspec, struct pmc_op_pmcallocate *pmc_config) { - char *e, *p, *q; - int n; + char *e, *p, *q; + int n; uint32_t count, evmask; const struct pmc_masks *pm, *pmask; - pmc_config->pm_caps |= PMC_CAP_READ; + pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); pmc_config->pm_md.pm_amd.pm_amd_config = 0; - if (pe == PMC_EV_TSC_TSC) { - /* TSC events must be unqualified. */ - if (ctrspec && *ctrspec != '\0') - return -1; - return 0; - } - pmask = NULL; evmask = 0; @@ -599,17 +947,15 @@ k8_allocate_pmc(enum pmc_event pe, char break; /* no options defined */ } - pmc_config->pm_caps |= PMC_CAP_WRITE; - while ((p = strsep(&ctrspec, ",")) != NULL) { if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) { q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ - return -1; + return (-1); count = strtol(q, &e, 0); if (e == q || *e != '\0') - return -1; + return (-1); pmc_config->pm_caps |= PMC_CAP_THRESHOLD; pmc_config->pm_md.pm_amd.pm_amd_config |= @@ -621,18 +967,17 @@ k8_allocate_pmc(enum pmc_event pe, char pmc_config->pm_caps |= PMC_CAP_INVERT; } else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) { if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) - return -1; + return (-1); pmc_config->pm_caps |= PMC_CAP_QUALIFIER; } else if (KWMATCH(p, K8_KW_OS)) { pmc_config->pm_caps |= PMC_CAP_SYSTEM; } else if (KWMATCH(p, K8_KW_USR)) { pmc_config->pm_caps |= PMC_CAP_USER; } else - return -1; + return (-1); } /* other post processing */ - switch (pe) { case PMC_EV_K8_FP_DISPATCHED_FPU_OPS: case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED: @@ -648,7 +993,7 @@ k8_allocate_pmc(enum pmc_event pe, char case PMC_EV_K8_LS_LOCKED_OPERATION: /* XXX CPU Rev A,B evmask is to be zero */ if (evmask & (evmask - 1)) /* > 1 bit set */ - return -1; + return (-1); if (evmask == 0) { evmask = 0x01; /* Rev C and later: #instrs */ pmc_config->pm_caps |= PMC_CAP_QUALIFIER; @@ -666,7 +1011,7 @@ k8_allocate_pmc(enum pmc_event pe, char pmc_config->pm_md.pm_amd.pm_amd_config = AMD_PMC_TO_UNITMASK(evmask); - return 0; + return (0); } #endif @@ -1008,25 +1353,17 @@ p4_allocate_pmc(enum pmc_event pe, char uint32_t evmask, cccractivemask; const struct pmc_masks *pm, *pmask; - pmc_config->pm_caps |= PMC_CAP_READ; + pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); pmc_config->pm_md.pm_p4.pm_p4_cccrconfig = pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0; - if (pe == PMC_EV_TSC_TSC) { - /* TSC must not be further qualified */ - if (ctrspec && *ctrspec != '\0') - return -1; - return 0; - } - pmask = NULL; evmask = 0; cccractivemask = 0x3; has_tag = has_busreqtype = 0; - pmc_config->pm_caps |= PMC_CAP_WRITE; #define __P4SETMASK(M) do { \ - pmask = p4_mask_##M; \ + pmask = p4_mask_##M; \ } while (0) switch (pe) { @@ -1159,7 +1496,7 @@ p4_allocate_pmc(enum pmc_event pe, char __P4SETMASK(machclr); break; default: - return -1; + return (-1); } /* process additional flags */ @@ -1167,30 +1504,30 @@ p4_allocate_pmc(enum pmc_event pe, char if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) { q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ - return -1; + return (-1); - if (strcmp(q, P4_KW_ACTIVE_NONE) == 0) + if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0) cccractivemask = 0x0; - else if (strcmp(q, P4_KW_ACTIVE_SINGLE) == 0) + else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0) cccractivemask = 0x1; - else if (strcmp(q, P4_KW_ACTIVE_BOTH) == 0) + else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0) cccractivemask = 0x2; - else if (strcmp(q, P4_KW_ACTIVE_ANY) == 0) + else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0) cccractivemask = 0x3; else - return -1; + return (-1); } else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) { if (has_busreqtype == 0) - return -1; + return (-1); q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ - return -1; + return (-1); count = strtol(q, &e, 0); if (e == q || *e != '\0') - return -1; + return (-1); evmask = (evmask & ~0x1F) | (count & 0x1F); } else if (KWMATCH(p, P4_KW_CASCADE)) pmc_config->pm_caps |= PMC_CAP_CASCADE; @@ -1200,7 +1537,7 @@ p4_allocate_pmc(enum pmc_event pe, char pmc_config->pm_caps |= PMC_CAP_INVERT; else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) { if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0) - return -1; + return (-1); pmc_config->pm_caps |= PMC_CAP_QUALIFIER; } else if (KWMATCH(p, P4_KW_OS)) pmc_config->pm_caps |= PMC_CAP_SYSTEM; @@ -1208,15 +1545,15 @@ p4_allocate_pmc(enum pmc_event pe, char pmc_config->pm_caps |= PMC_CAP_PRECISE; else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) { if (has_tag == 0) - return -1; + return (-1); q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ - return -1; + return (-1); count = strtol(q, &e, 0); if (e == q || *e != '\0') - return -1; + return (-1); pmc_config->pm_caps |= PMC_CAP_TAGGING; pmc_config->pm_md.pm_p4.pm_p4_escrconfig |= @@ -1224,11 +1561,11 @@ p4_allocate_pmc(enum pmc_event pe, char } else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) { q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ - return -1; + return (-1); count = strtol(q, &e, 0); if (e == q || *e != '\0') - return -1; + return (-1); pmc_config->pm_caps |= PMC_CAP_THRESHOLD; pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &= @@ -1238,7 +1575,7 @@ p4_allocate_pmc(enum pmc_event pe, char } else if (KWMATCH(p, P4_KW_USR)) pmc_config->pm_caps |= PMC_CAP_USER; else - return -1; + return (-1); } /* other post processing */ @@ -1258,16 +1595,16 @@ p4_allocate_pmc(enum pmc_event pe, char case PMC_EV_P4_FSB_DATA_ACTIVITY: if ((evmask & 0x06) == 0x06 || (evmask & 0x18) == 0x18) - return -1; /* can't have own+other bits together */ + return (-1); /* can't have own+other bits together */ if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */ evmask = 0x1D; break; case PMC_EV_P4_MACHINE_CLEAR: /* only one bit is allowed to be set */ if ((evmask & (evmask - 1)) != 0) - return -1; + return (-1); if (evmask == 0) { - evmask = 0x1; /* 'CLEAR' */ + evmask = 0x1; /* 'CLEAR' */ pmc_config->pm_caps |= PMC_CAP_QUALIFIER; } break; @@ -1282,7 +1619,7 @@ p4_allocate_pmc(enum pmc_event pe, char pmc_config->pm_md.pm_p4.pm_p4_escrconfig = P4_ESCR_TO_EVENT_MASK(evmask); - return 0; + return (0); } #endif @@ -1294,7 +1631,14 @@ p4_allocate_pmc(enum pmc_event pe, char */ static struct pmc_event_alias p5_aliases[] = { - EV_ALIAS("cycles", "tsc"), + EV_ALIAS("branches", "p5-taken-branches"), + EV_ALIAS("cycles", "tsc"), + EV_ALIAS("dc-misses", "p5-data-read-miss-or-write-miss"), + EV_ALIAS("ic-misses", "p5-code-cache-miss"), + EV_ALIAS("instructions", "p5-instructions-executed"), + EV_ALIAS("interrupts", "p5-hardware-interrupts"), + EV_ALIAS("unhalted-cycles", + "p5-number-of-cycles-not-in-halt-state"), EV_ALIAS(NULL, NULL) }; @@ -1302,7 +1646,7 @@ static int p5_allocate_pmc(enum pmc_event pe, char *ctrspec, struct pmc_op_pmcallocate *pmc_config) { - return -1 || pe || ctrspec || pmc_config; /* shut up gcc */ + return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */ } /* @@ -1438,22 +1782,15 @@ p6_allocate_pmc(enum pmc_event pe, char int count, n; const struct pmc_masks *pm, *pmask; - pmc_config->pm_caps |= PMC_CAP_READ; + pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE); pmc_config->pm_md.pm_ppro.pm_ppro_config = 0; - if (pe == PMC_EV_TSC_TSC) { - if (ctrspec && *ctrspec != '\0') - return -1; - return 0; - } - - pmc_config->pm_caps |= PMC_CAP_WRITE; evmask = 0; #define P6MASKSET(M) pmask = p6_mask_ ## M switch(pe) { - case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; + case PMC_EV_P6_L2_IFETCH: P6MASKSET(mesi); break; case PMC_EV_P6_L2_LD: P6MASKSET(mesi); break; case PMC_EV_P6_L2_ST: P6MASKSET(mesi); break; case PMC_EV_P6_L2_RQSTS: P6MASKSET(mesi); break; @@ -1513,10 +1850,10 @@ p6_allocate_pmc(enum pmc_event pe, char if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) { q = strchr(p, '='); if (*++q == '\0') /* skip '=' */ - return -1; + return (-1); count = strtol(q, &e, 0); if (e == q || *e != '\0') - return -1; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***