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....
Fabien Thomas
fabient at FreeBSD.org
Sun Jun 7 10:00:36 UTC 2009
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 <strings.h>
#include <unistd.h>
+#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 ***
More information about the svn-src-stable-7
mailing list