aboutsummaryrefslogtreecommitdiff
path: root/lib/libpmc/libpmc.c
diff options
context:
space:
mode:
authorFabien Thomas <fabient@FreeBSD.org>2012-03-28 20:58:30 +0000
committerFabien Thomas <fabient@FreeBSD.org>2012-03-28 20:58:30 +0000
commitf5f9340b9807d44d200658ba1bbbbbb57ab72e07 (patch)
treefadff08d26576c3d5c1cef9d47abd784602b237a /lib/libpmc/libpmc.c
parent1faacf5d0925fb593d0d5a17dbd3b0d705bdd478 (diff)
downloadsrc-f5f9340b9807d44d200658ba1bbbbbb57ab72e07.tar.gz
src-f5f9340b9807d44d200658ba1bbbbbb57ab72e07.zip
Add software PMC support.
New kernel events can be added at various location for sampling or counting. This will for example allow easy system profiling whatever the processor is with known tools like pmcstat(8). Simultaneous usage of software PMC and hardware PMC is possible, for example looking at the lock acquire failure, page fault while sampling on instructions. Sponsored by: NETASQ MFC after: 1 month
Notes
Notes: svn path=/head/; revision=233628
Diffstat (limited to 'lib/libpmc/libpmc.c')
-rw-r--r--lib/libpmc/libpmc.c118
1 files changed, 92 insertions, 26 deletions
diff --git a/lib/libpmc/libpmc.c b/lib/libpmc/libpmc.c
index 4323171e7443..3b7dc376ed27 100644
--- a/lib/libpmc/libpmc.c
+++ b/lib/libpmc/libpmc.c
@@ -77,11 +77,12 @@ static int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
static int xscale_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,
struct pmc_op_pmcallocate *_pmc_config);
#endif /* __mips__ */
+static int soft_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
+ struct pmc_op_pmcallocate *_pmc_config);
#if defined(__powerpc__)
static int ppc7450_allocate_pmc(enum pmc_event _pe, char* ctrspec,
@@ -156,6 +157,8 @@ PMC_CLASSDEP_TABLE(octeon, OCTEON);
PMC_CLASSDEP_TABLE(ucf, UCF);
PMC_CLASSDEP_TABLE(ppc7450, PPC7450);
+static struct pmc_event_descr soft_event_table[PMC_EV_DYN_COUNT];
+
#undef __PMC_EV_ALIAS
#define __PMC_EV_ALIAS(N,CODE) { N, PMC_EV_##CODE },
@@ -215,21 +218,22 @@ static const struct pmc_event_descr westmereuc_event_table[] =
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_CLASS_UCF, PMC_CLASS_UCP);
-PMC_MDEP_TABLE(sandybridge, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
-PMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
-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);
-PMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_XSCALE);
-PMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_MIPS24K);
-PMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_OCTEON);
-PMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_PPC7450);
+PMC_MDEP_TABLE(atom, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(core, IAP, PMC_CLASS_SOFT, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(core2, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
+PMC_MDEP_TABLE(sandybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
+PMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
+PMC_MDEP_TABLE(k7, K7, PMC_CLASS_SOFT, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(k8, K8, PMC_CLASS_SOFT, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(p4, P4, PMC_CLASS_SOFT, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(p5, P5, PMC_CLASS_SOFT, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(p6, P6, PMC_CLASS_SOFT, PMC_CLASS_TSC);
+PMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE);
+PMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K);
+PMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON);
+PMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450);
+PMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT);
static const struct pmc_event_descr tsc_event_table[] =
{
@@ -279,16 +283,24 @@ PMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc);
#if defined(__XSCALE__)
PMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale);
#endif
-
#if defined(__mips__)
PMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips);
PMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips);
#endif /* __mips__ */
-
#if defined(__powerpc__)
PMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, ppc7450);
#endif
+static struct pmc_class_descr soft_class_table_descr =
+{
+ .pm_evc_name = "SOFT-",
+ .pm_evc_name_size = sizeof("SOFT-") - 1,
+ .pm_evc_class = PMC_CLASS_SOFT,
+ .pm_evc_event_table = NULL,
+ .pm_evc_event_table_size = 0,
+ .pm_evc_allocate_pmc = soft_allocate_pmc
+};
+
#undef PMC_CLASS_TABLE_DESC
static const struct pmc_class_descr **pmc_class_table;
@@ -343,9 +355,12 @@ static const char * pmc_state_names[] = {
__PMC_STATES()
};
-static int pmc_syscall = -1; /* filled in by pmc_init() */
-
-static struct pmc_cpuinfo cpu_info; /* filled in by pmc_init() */
+/*
+ * Filled in by pmc_init().
+ */
+static int pmc_syscall = -1;
+static struct pmc_cpuinfo cpu_info;
+static struct pmc_op_getdyneventinfo soft_event_info;
/* Event masks for events */
struct pmc_masks {
@@ -2179,6 +2194,25 @@ tsc_allocate_pmc(enum pmc_event pe, char *ctrspec,
}
#endif
+static struct pmc_event_alias generic_aliases[] = {
+ EV_ALIAS("instructions", "SOFT-CLOCK.HARD"),
+ EV_ALIAS(NULL, NULL)
+};
+
+static int
+soft_allocate_pmc(enum pmc_event pe, char *ctrspec,
+ struct pmc_op_pmcallocate *pmc_config)
+{
+ (void)ctrspec;
+ (void)pmc_config;
+
+ if (pe < PMC_EV_SOFT_FIRST || pe > PMC_EV_SOFT_LAST)
+ return (-1);
+
+ pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
+ return (0);
+}
+
#if defined(__XSCALE__)
static struct pmc_event_alias xscale_aliases[] = {
@@ -2663,6 +2697,10 @@ pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames,
ev = ppc7450_event_table;
count = PMC_EVENT_TABLE_SIZE(ppc7450);
break;
+ case PMC_CLASS_SOFT:
+ ev = soft_event_table;
+ count = soft_event_info.pm_nevent;
+ break;
default:
errno = EINVAL;
return (-1);
@@ -2676,6 +2714,7 @@ pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames,
for (;count--; ev++, names++)
*names = ev->pm_ev_name;
+
return (0);
}
@@ -2780,11 +2819,34 @@ pmc_init(void)
pmc_class_table[n] = NULL;
/*
+ * Get soft events list.
+ */
+ soft_event_info.pm_class = PMC_CLASS_SOFT;
+ if (PMC_CALL(GETDYNEVENTINFO, &soft_event_info) < 0)
+ return (pmc_syscall = -1);
+
+ /* Map soft events to static list. */
+ for (n = 0; n < soft_event_info.pm_nevent; n++) {
+ soft_event_table[n].pm_ev_name =
+ soft_event_info.pm_events[n].pm_ev_name;
+ soft_event_table[n].pm_ev_code =
+ soft_event_info.pm_events[n].pm_ev_code;
+ }
+ soft_class_table_descr.pm_evc_event_table_size = \
+ soft_event_info.pm_nevent;
+ soft_class_table_descr.pm_evc_event_table = \
+ soft_event_table;
+
+ /*
* Fill in the class table.
*/
n = 0;
+
+ /* Fill soft events information. */
+ pmc_class_table[n++] = &soft_class_table_descr;
#if defined(__amd64__) || defined(__i386__)
- pmc_class_table[n++] = &tsc_class_table_descr;
+ if (cpu_info.pm_cputype != PMC_CPU_GENERIC)
+ pmc_class_table[n++] = &tsc_class_table_descr;
/*
* Check if this CPU has fixed function counters.
@@ -2867,6 +2929,9 @@ pmc_init(void)
pmc_class_table[n] = &p4_class_table_descr;
break;
#endif
+ case PMC_CPU_GENERIC:
+ PMC_MDEP_INIT(generic);
+ break;
#if defined(__XSCALE__)
case PMC_CPU_INTEL_XSCALE:
PMC_MDEP_INIT(xscale);
@@ -3035,18 +3100,19 @@ _pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu)
evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale);
} 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
-);
+ evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k);
} else if (pe >= PMC_EV_OCTEON_FIRST && pe <= PMC_EV_OCTEON_LAST) {
ev = octeon_event_table;
evfence = octeon_event_table + PMC_EVENT_TABLE_SIZE(octeon);
} else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) {
ev = ppc7450_event_table;
- evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450
-);
+ evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450);
} 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_SOFT_FIRST && pe <= PMC_EV_SOFT_LAST) {
+ ev = soft_event_table;
+ evfence = soft_event_table + soft_event_info.pm_nevent;
}
for (; ev != evfence; ev++)