diff --git a/lib/libpmc/libpmc_pmu_util.c b/lib/libpmc/libpmc_pmu_util.c
index 1b2c10e07368..a525a0067822 100644
--- a/lib/libpmc/libpmc_pmu_util.c
+++ b/lib/libpmc/libpmc_pmu_util.c
@@ -1,626 +1,604 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright (c) 2018, Matthew Macy
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * $FreeBSD$
  *
  */
 
 #include <sys/types.h>
 #include <sys/errno.h>
 #include <sys/pmc.h>
 #include <sys/sysctl.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <limits.h>
 #include <regex.h>
 #include <string.h>
 #include <pmc.h>
 #include <pmclog.h>
 #include <assert.h>
 #include <libpmcstat.h>
 #include "pmu-events/pmu-events.h"
 
 #if defined(__amd64__) || defined(__i386__)
 struct pmu_alias {
 	const char *pa_alias;
 	const char *pa_name;
 };
 
 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"},
 	{"LLC-MISSES", "LONGEST_LAT_CACHE.MISS"},
 	{"LLC_REFERENCE", "LONGEST_LAT_CACHE.REFERENCE"},
 	{"LLC-REFERENCE", "LONGEST_LAT_CACHE.REFERENCE"},
 	{"LLC_MISS_RHITM", "mem_load_l3_miss_retired.remote_hitm"},
 	{"LLC-MISS-RHITM", "mem_load_l3_miss_retired.remote_hitm"},
 	{"RESOURCE_STALL", "RESOURCE_STALLS.ANY"},
 	{"RESOURCE_STALLS_ANY", "RESOURCE_STALLS.ANY"},
 	{"BRANCH_INSTRUCTION_RETIRED", "BR_INST_RETIRED.ALL_BRANCHES"},
 	{"BRANCH-INSTRUCTION-RETIRED", "BR_INST_RETIRED.ALL_BRANCHES"},
 	{"BRANCH_MISSES_RETIRED", "BR_MISP_RETIRED.ALL_BRANCHES"},
 	{"BRANCH-MISSES-RETIRED", "BR_MISP_RETIRED.ALL_BRANCHES"},
 	{"cycles", "tsc-tsc"},
 	{"unhalted-cycles", "CPU_CLK_UNHALTED.THREAD_P_ANY"},
 	{"instructions", "inst_retired.any_p"},
 	{"branch-mispredicts", "br_misp_retired.all_branches"},
 	{"branches", "br_inst_retired.all_branches"},
 	{"interrupts", "hw_interrupts.received"},
 	{"ic-misses", "frontend_retired.l1i_miss"},
 	{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[PMC_CPUID_LEN];
 	size_t s = sizeof(buf);
 	pmu_mfr_t mfr;
 
 	if (sysctlbyname("kern.hwpmc.cpuid", buf, &s,
 	    (void *)NULL, 0) == -1)
 		return (PMU_INVALID);
 	if (strcasestr(buf, "AuthenticAMD") != NULL ||
 	    strcasestr(buf, "HygonGenuine") != NULL)
 		mfr = PMU_AMD;
 	else if (strcasestr(buf, "GenuineIntel") != NULL)
 		mfr = PMU_INTEL;
 	else
 		mfr = PMU_INVALID;
 	return (mfr);
 }
 
 /*
  *  The Intel fixed mode counters are:
  *	"inst_retired.any",
  *	"cpu_clk_unhalted.thread",
  *	"cpu_clk_unhalted.thread_any",
  *	"cpu_clk_unhalted.ref_tsc",
  *
  */
 
 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);
 }
 
 struct pmu_event_desc {
 	uint64_t ped_period;
 	uint64_t ped_offcore_rsp;
 	uint64_t ped_l3_thread;
 	uint64_t ped_l3_slice;
 	uint32_t ped_event;
 	uint32_t ped_frontend;
 	uint32_t ped_ldlat;
 	uint32_t ped_config1;
 	int16_t	ped_umask;
 	uint8_t	ped_cmask;
 	uint8_t	ped_any;
 	uint8_t	ped_inv;
 	uint8_t	ped_edge;
 	uint8_t	ped_fc_mask;
 	uint8_t	ped_ch_mask;
 };
 
 static const struct pmu_events_map *
 pmu_events_map_get(const char *cpuid)
 {
 	regex_t re;
 	regmatch_t pmatch[1];
 	char buf[PMC_CPUID_LEN];
 	size_t s = sizeof(buf);
 	int match;
 	const struct pmu_events_map *pme;
 
 	if (cpuid != NULL) {
 		strlcpy(buf, cpuid, s);
 	} else {
 		if (sysctlbyname("kern.hwpmc.cpuid", buf, &s,
 		    (void *)NULL, 0) == -1)
 			return (NULL);
 	}
 	for (pme = pmu_events_map; pme->cpuid != NULL; pme++) {
 		if (regcomp(&re, pme->cpuid, REG_EXTENDED) != 0) {
 			printf("regex '%s' failed to compile, ignoring\n",
 			    pme->cpuid);
 			continue;
 		}
 		match = regexec(&re, buf, 1, pmatch, 0);
 		regfree(&re);
 		if (match == 0) {
 			if (pmatch[0].rm_so == 0 && (buf[pmatch[0].rm_eo] == 0
 			    || buf[pmatch[0].rm_eo] == '-'))
 				return (pme);
 		}
 	}
 	return (NULL);
 }
 
 static const struct pmu_event *
 pmu_event_get(const char *cpuid, const char *event_name, int *idx)
 {
 	const struct pmu_events_map *pme;
 	const struct pmu_event *pe;
 	int i;
 
 	if ((pme = pmu_events_map_get(cpuid)) == NULL)
 		return (NULL);
 	for (i = 0, pe = pme->table; pe->name || pe->desc || pe->event; pe++, i++) {
 		if (pe->name == NULL)
 			continue;
 		if (strcasecmp(pe->name, event_name) == 0) {
 			if (idx)
 				*idx = i;
 			return (pe);
 		}
 	}
 	return (NULL);
 }
 
 int
 pmc_pmu_idx_get_by_event(const char *cpuid, const char *event)
 {
 	int idx;
 	const char *realname;
 
 	realname = pmu_alias_get(event);
 	if (pmu_event_get(cpuid, realname, &idx) == NULL)
 		return (-1);
 	return (idx);
 }
 
 const char *
 pmc_pmu_event_get_by_idx(const char *cpuid, int idx)
 {
 	const struct pmu_events_map *pme;
 
 	if ((pme = pmu_events_map_get(cpuid)) == NULL)
 		return (NULL);
 	assert(pme->table[idx].name);
 	return (pme->table[idx].name);
 }
 
 static int
 pmu_parse_event(struct pmu_event_desc *ped, const char *eventin)
 {
 	char *event;
 	char *kvp, *key, *value, *r;
 	char *debug;
 
 	if ((event = strdup(eventin)) == NULL)
 		return (ENOMEM);
 	r = event;
 	bzero(ped, sizeof(*ped));
 	ped->ped_period = DEFAULT_SAMPLE_COUNT;
 	ped->ped_umask = -1;
 	while ((kvp = strsep(&event, ",")) != NULL) {
 		key = strsep(&kvp, "=");
 		if (key == NULL)
 			abort();
 		value = kvp;
 		if (strcmp(key, "umask") == 0)
 			ped->ped_umask = strtol(value, NULL, 16);
 		else if (strcmp(key, "event") == 0)
 			ped->ped_event = strtol(value, NULL, 16);
 		else if (strcmp(key, "period") == 0)
 			ped->ped_period = strtol(value, NULL, 10);
 		else if (strcmp(key, "offcore_rsp") == 0)
 			ped->ped_offcore_rsp = strtol(value, NULL, 16);
 		else if (strcmp(key, "any") == 0)
 			ped->ped_any = strtol(value, NULL, 10);
 		else if (strcmp(key, "cmask") == 0)
 			ped->ped_cmask = strtol(value, NULL, 10);
 		else if (strcmp(key, "inv") == 0)
 			ped->ped_inv = strtol(value, NULL, 10);
 		else if (strcmp(key, "edge") == 0)
 			ped->ped_edge = strtol(value, NULL, 10);
 		else if (strcmp(key, "frontend") == 0)
 			ped->ped_frontend = strtol(value, NULL, 16);
 		else if (strcmp(key, "ldlat") == 0)
 			ped->ped_ldlat = strtol(value, NULL, 16);
 		else if (strcmp(key, "fc_mask") == 0)
 			ped->ped_fc_mask = strtol(value, NULL, 16);
 		else if (strcmp(key, "ch_mask") == 0)
 			ped->ped_ch_mask = strtol(value, NULL, 16);
 		else if (strcmp(key, "config1") == 0)
 			ped->ped_config1 = strtol(value, NULL, 16);
 		else if (strcmp(key, "l3_thread_mask") == 0)
 			ped->ped_l3_thread = strtol(value, NULL, 16);
 		else if (strcmp(key, "l3_slice_mask") == 0)
 			ped->ped_l3_slice = strtol(value, NULL, 16);
 		else {
 			debug = getenv("PMUDEBUG");
 			if (debug != NULL && strcmp(debug, "true") == 0 && value != NULL)
 				printf("unrecognized kvpair: %s:%s\n", key, value);
 		}
 	}
 	free(r);
 	return (0);
 }
 
 uint64_t
 pmc_pmu_sample_rate_get(const char *event_name)
 {
 	const struct pmu_event *pe;
 	struct pmu_event_desc ped;
 
 	event_name = pmu_alias_get(event_name);
 	if ((pe = pmu_event_get(NULL, event_name, NULL)) == NULL)
 		return (DEFAULT_SAMPLE_COUNT);
 	if (pe->alias && (pe = pmu_event_get(NULL, pe->alias, NULL)) == NULL)
 		return (DEFAULT_SAMPLE_COUNT);
 	if (pe->event == NULL)
 		return (DEFAULT_SAMPLE_COUNT);
 	if (pmu_parse_event(&ped, pe->event))
 		return (DEFAULT_SAMPLE_COUNT);
 	return (ped.ped_period);
 }
 
 int
 pmc_pmu_enabled(void)
 {
 
 	return (pmu_events_map_get(NULL) != NULL);
 }
 
 void
 pmc_pmu_print_counters(const char *event_name)
 {
 	const struct pmu_events_map *pme;
 	const struct pmu_event *pe;
 	struct pmu_event_desc ped;
 	char *debug;
 	int do_debug;
 
 	debug = getenv("PMUDEBUG");
 	do_debug = 0;
 
 	if (debug != NULL && strcmp(debug, "true") == 0)
 		do_debug = 1;
 	if ((pme = pmu_events_map_get(NULL)) == NULL)
 		return;
 	for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) {
 		if (pe->name == NULL)
 			continue;
 		if (event_name != NULL && strcasestr(pe->name, event_name) == NULL)
 			continue;
 		printf("\t%s\n", pe->name);
 		if (do_debug)
 			pmu_parse_event(&ped, pe->event);
 	}
 }
 
 void
 pmc_pmu_print_counter_desc(const char *ev)
 {
 	const struct pmu_events_map *pme;
 	const struct pmu_event *pe;
 
 	if ((pme = pmu_events_map_get(NULL)) == NULL)
 		return;
 	for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) {
 		if (pe->name == NULL)
 			continue;
 		if (strcasestr(pe->name, ev) != NULL &&
 		    pe->desc != NULL)
 			printf("%s:\t%s\n", pe->name, pe->desc);
 	}
 }
 
 void
 pmc_pmu_print_counter_desc_long(const char *ev)
 {
 	const struct pmu_events_map *pme;
 	const struct pmu_event *pe;
 
 	if ((pme = pmu_events_map_get(NULL)) == NULL)
 		return;
 	for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) {
 		if (pe->name == NULL)
 			continue;
 		if (strcasestr(pe->name, ev) != NULL) {
 			if (pe->long_desc != NULL)
 				printf("%s:\n%s\n", pe->name, pe->long_desc);
 			else if (pe->desc != NULL)
 				printf("%s:\t%s\n", pe->name, pe->desc);
 		}
 	}
 }
 
 void
 pmc_pmu_print_counter_full(const char *ev)
 {
 	const struct pmu_events_map *pme;
 	const struct pmu_event *pe;
 
 	if ((pme = pmu_events_map_get(NULL)) == NULL)
 		return;
 	for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) {
 		if (pe->name == NULL)
 			continue;
 		if (strcasestr(pe->name, ev) == NULL)
 			continue;
 		printf("name: %s\n", pe->name);
 		if (pe->long_desc != NULL)
 			printf("desc: %s\n", pe->long_desc);
 		else if (pe->desc != NULL)
 			printf("desc: %s\n", pe->desc);
 		if (pe->event != NULL)
 			printf("event: %s\n", pe->event);
 		if (pe->topic != NULL)
 			printf("topic: %s\n", pe->topic);
 		if (pe->pmu != NULL)
 			printf("pmu: %s\n", pe->pmu);
 		if (pe->unit != NULL)
 			printf("unit: %s\n", pe->unit);
 		if (pe->perpkg != NULL)
 			printf("perpkg: %s\n", pe->perpkg);
 		if (pe->metric_expr != NULL)
 			printf("metric_expr: %s\n", pe->metric_expr);
 		if (pe->metric_name != NULL)
 			printf("metric_name: %s\n", pe->metric_name);
 		if (pe->metric_group != NULL)
 			printf("metric_group: %s\n", pe->metric_group);
 	}
 }
 
 static int
 pmc_pmu_amd_pmcallocate(const char *event_name, struct pmc_op_pmcallocate *pm,
 	struct pmu_event_desc *ped)
 {
 	struct pmc_md_amd_op_pmcallocate *amd;
 	const struct pmu_event *pe;
 	int idx = -1;
 
 	amd = &pm->pm_md.pm_amd;
 	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;
 	pe = pmu_event_get(NULL, event_name, &idx);
 
 	if (strcmp("l3cache", pe->topic) == 0){
 		amd->pm_amd_config |= AMD_PMC_TO_EVENTMASK(ped->ped_event);
 		amd->pm_amd_sub_class = PMC_AMD_SUB_CLASS_L3_CACHE;
 		amd->pm_amd_config |= AMD_PMC_TO_L3SLICE(ped->ped_l3_slice);
 		amd->pm_amd_config |= AMD_PMC_TO_L3CORE(ped->ped_l3_thread);
 	}
 	else if (strcmp("data fabric", pe->topic) == 0){
 
 		amd->pm_amd_config |= AMD_PMC_TO_EVENTMASK_DF(ped->ped_event);
 		amd->pm_amd_sub_class = PMC_AMD_SUB_CLASS_DATA_FABRIC;
 	}
 	else{
 		amd->pm_amd_config |= AMD_PMC_TO_EVENTMASK(ped->ped_event);
 		amd->pm_amd_sub_class = PMC_AMD_SUB_CLASS_CORE;
 		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;
 
 	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)) {
 		pm->pm_class = PMC_CLASS_IAF;
 	} else {
 		pm->pm_class = PMC_CLASS_IAP;
 		pm->pm_caps |= PMC_CAP_QUALIFIER;
 	}
 	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;
 
 	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)
 		iap->pm_iap_config |= IAP_ANY;
 	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));
 }
 
-/*
- * Ultimately rely on AMD calling theirs the same
- */
-static const char *stat_mode_cntrs[] = {
-	"cpu_clk_unhalted.thread",
-	"inst_retired.any",
-	"br_inst_retired.all_branches",
-	"br_misp_retired.all_branches",
-	"longest_lat_cache.reference",
-	"longest_lat_cache.miss",
-};
-
-int
-pmc_pmu_stat_mode(const char ***cntrs)
-{
-	if (pmc_pmu_enabled()) {
-		*cntrs = stat_mode_cntrs;
-		return (0);
-	}
-	return (EOPNOTSUPP);
-}
-
 #else
 
 uint64_t
 pmc_pmu_sample_rate_get(const char *event_name __unused)
 {
 	return (DEFAULT_SAMPLE_COUNT);
 }
 
 void
 pmc_pmu_print_counters(const char *event_name __unused)
 {
 }
 
 void
 pmc_pmu_print_counter_desc(const char *e __unused)
 {
 }
 
 void
 pmc_pmu_print_counter_desc_long(const char *e __unused)
 {
 }
 
 void
 pmc_pmu_print_counter_full(const char *e __unused)
 {
 
 }
 
 int
 pmc_pmu_enabled(void)
 {
 	return (0);
 }
 
 int
 pmc_pmu_pmcallocate(const char *e __unused, struct pmc_op_pmcallocate *p __unused)
 {
 	return (EOPNOTSUPP);
 }
 
 const char *
 pmc_pmu_event_get_by_idx(const char *c __unused, int idx __unused)
 {
 	return (NULL);
 }
 
 int
 pmc_pmu_stat_mode(const char ***a __unused)
 {
 	return (EOPNOTSUPP);
 }
 
 int
 pmc_pmu_idx_get_by_event(const char *c __unused, const char *e __unused)
 {
 	return (-1);
 }
 
 #endif
diff --git a/lib/libpmc/pmc.h b/lib/libpmc/pmc.h
index 9d12085364e5..7579f93a42b1 100644
--- a/lib/libpmc/pmc.h
+++ b/lib/libpmc/pmc.h
@@ -1,128 +1,127 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright (c) 2003,2004 Joseph Koshy
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * $FreeBSD$
  */
 
 #ifndef _PMC_H_
 #define _PMC_H_
 
 #include <sys/cdefs.h>
 #include <sys/types.h>
 #include <sys/pmc.h>
 
 /*
  * Driver statistics.
  */
 struct pmc_driverstats {
 	unsigned int	pm_intr_ignored;	/* #interrupts ignored */
 	unsigned int	pm_intr_processed;	/* #interrupts processed */
 	unsigned int	pm_intr_bufferfull;	/* #interrupts with ENOSPC */
 	unsigned int	pm_syscalls;		/* #syscalls */
 	unsigned int	pm_syscall_errors;	/* #syscalls with errors */
 	unsigned int	pm_buffer_requests;	/* #buffer requests */
 	unsigned int	pm_buffer_requests_failed; /* #failed buffer requests */
 	unsigned int	pm_log_sweeps;		/* #sample buffer processing
 						   passes */
 };
 
 /*
  * CPU information.
  */
 struct pmc_cpuinfo {
 	enum pmc_cputype pm_cputype;	/* the kind of CPU */
 	uint32_t	pm_ncpu;	/* number of CPUs */
 	uint32_t	pm_npmc;	/* #PMCs per CPU */
 	uint32_t	pm_nclass;	/* #classes of PMCs */
 	struct pmc_classinfo pm_classes[PMC_CLASS_MAX];
 };
 
 /*
  * Current PMC state.
  */
 struct pmc_pmcinfo {
 	int32_t		pm_cpu;		/* CPU number */
 	struct pmc_info	pm_pmcs[];	/* NPMC structs */
 };
 
 /*
  * Prototypes
  */
 
 __BEGIN_DECLS
 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_capabilities(pmc_id_t _pmc, uint32_t *_caps);
 int	pmc_configure_logfile(int _fd);
 int	pmc_flush_logfile(void);
 int	pmc_close_logfile(void);
 int	pmc_detach(pmc_id_t _pmcid, pid_t _pid);
 int	pmc_disable(int _cpu, int _pmc);
 int	pmc_enable(int _cpu, int _pmc);
 int	pmc_get_driver_stats(struct pmc_driverstats *_gms);
 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_release(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);
 int	pmc_stop(pmc_id_t _pmc);
 int	pmc_width(pmc_id_t _pmc, uint32_t *_width);
 int	pmc_write(pmc_id_t _pmc, pmc_value_t _value);
 int	pmc_writelog(uint32_t _udata);
 
 int	pmc_ncpu(void);
 int	pmc_npmc(int _cpu);
 int	pmc_cpuinfo(const struct pmc_cpuinfo **_cpu_info);
 int	pmc_pmcinfo(int _cpu, struct pmc_pmcinfo **_pmc_info);
 
 const char	*pmc_name_of_capability(enum pmc_caps _c);
 const char	*pmc_name_of_class(enum pmc_class _pc);
 const char	*pmc_name_of_cputype(enum pmc_cputype _cp);
 const char	*pmc_name_of_disposition(enum pmc_disp _pd);
 const char	*pmc_name_of_event(enum pmc_event _pe);
 const char	*pmc_name_of_mode(enum pmc_mode _pm);
 const char	*pmc_name_of_state(enum pmc_state _ps);
 
 int	pmc_event_names_of_class(enum pmc_class _cl, const char ***_eventnames,
     int *_nevents);
 
 int pmc_pmu_enabled(void);
 void pmc_pmu_print_counters(const char *);
 void pmc_pmu_print_counter_desc(const char *);
 void pmc_pmu_print_counter_desc_long(const char *);
 void pmc_pmu_print_counter_full(const char *);
 uint64_t pmc_pmu_sample_rate_get(const char *);
 int pmc_pmu_pmcallocate(const char *, struct pmc_op_pmcallocate *);
 const char *pmc_pmu_event_get_by_idx(const char *, int idx);
 int pmc_pmu_idx_get_by_event(const char*, const char *);
-int pmc_pmu_stat_mode(const char ***);
 __END_DECLS
 
 #endif
diff --git a/usr.sbin/pmc/cmd_pmc_stat.c b/usr.sbin/pmc/cmd_pmc_stat.c
index 44ca7b92dea7..55d1f1ca7a3b 100644
--- a/usr.sbin/pmc/cmd_pmc_stat.c
+++ b/usr.sbin/pmc/cmd_pmc_stat.c
@@ -1,489 +1,496 @@
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright (c) 2018, Matthew Macy
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  */
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/cpuset.h>
 #include <sys/event.h>
 #include <sys/queue.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/sysctl.h>
 #include <sys/time.h>
 #include <sys/ttycom.h>
 #include <sys/user.h>
 #include <sys/wait.h>
 
 #include <assert.h>
 #include <curses.h>
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <getopt.h>
 #include <kvm.h>
 #include <libgen.h>
 #include <limits.h>
 #include <locale.h>
 #include <math.h>
 #include <pmc.h>
 #include <pmclog.h>
 #include <regex.h>
 #include <signal.h>
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sysexits.h>
 #include <unistd.h>
 
 #include <libpmcstat.h>
 #include "cmd_pmc.h"
 
 /*
  * Return the frequency of the kernel's statistics clock.
  */
 static int
 getstathz(void)
 {
 	int mib[2];
 	size_t size;
 	struct clockinfo clockrate;
 
 	mib[0] = CTL_KERN;
 	mib[1] = KERN_CLOCKRATE;
 	size = sizeof clockrate;
 	if (sysctl(mib, 2, &clockrate, &size, NULL, 0) == -1)
 		err(1, "sysctl kern.clockrate");
 	return clockrate.stathz;
 }
 
 #define STAT_MODE_NPMCS 6
 #define FIXED_MODE_NPMCS 2
 static struct timespec before_ts;
 #define CYCLES		0
 #define INST		1
 #define BR		2
 #define IAP_START	BR
 #define BR_MISS	3
 #define CACHE	4
 #define CACHE_MISS	5
 static const char *pmc_stat_mode_names[] = {
 	"cycles",
 	"instructions",
 	"branches",
 	"branch-misses",
 	"cache-references",
 	"cache-misses",
 };
 
+/* Common aliases for the desired stat counter */
+static const char *pmc_stat_mode_aliases[] = {
+	"unhalted-cycles",
+	"instructions",
+	"branches",
+	"branch-mispredicts",
+	"LLC-REFERENCE",
+	"LLC-MISSES",
+};
+
 static int pmcstat_sockpair[NSOCKPAIRFD];
 
 static void __dead2
 usage(void)
 {
 	errx(EX_USAGE,
 	    "\t get basic stats from command line program\n"
 	    "\t -j <eventlist>, --events <eventlist> comma-delimited list of event specifiers\n"
 	    );
 }
 
 static void
 showtime(FILE *out, struct timespec *before, struct timespec *after,
     struct rusage *ru)
 {
 	char decimal_point;
 	uint64_t real, user, sys;
 
 	(void)setlocale(LC_NUMERIC, "");
 	decimal_point = localeconv()->decimal_point[0];
 
 	after->tv_sec -= before->tv_sec;
 	after->tv_nsec -= before->tv_nsec;
 	if (after->tv_nsec < 0) {
 		after->tv_sec--;
 		after->tv_nsec += 1000000000;
 	}
 
 	real = (after->tv_sec * 1000000000 + after->tv_nsec) / 1000;
 	user = ru->ru_utime.tv_sec * 1000000 + ru->ru_utime.tv_usec;
 	sys = ru->ru_stime.tv_sec * 1000000 + ru->ru_stime.tv_usec;
 	fprintf(out, "%13jd%c%02ld  real\t\t\t#\t%2.02f%% cpu\n",
 	    (intmax_t)after->tv_sec, decimal_point,
 	    after->tv_nsec / 10000000, 100 * (double)(sys + user + 1) / (double)(real + 1));
 	fprintf(out, "%13jd%c%02ld  user\t\t\t#\t%2.2f%% cpu\n",
 	    (intmax_t)ru->ru_utime.tv_sec, decimal_point,
 	    ru->ru_utime.tv_usec / 10000, 100 * (double)(user + 1) / (double)(real + 1));
 	fprintf(out, "%13jd%c%02ld  sys\t\t\t#\t%2.02f%% cpu\n",
 	    (intmax_t)ru->ru_stime.tv_sec, decimal_point,
 	    ru->ru_stime.tv_usec / 10000, 100 * (double)(sys + 1) / (double)(real + 1));
 }
 
 static const char *stat_mode_cntrs[STAT_MODE_NPMCS];
 static const char *stat_mode_names[STAT_MODE_NPMCS];
 
 static void
 pmc_stat_setup_stat(int system_mode, const char *arg)
 {
 	const char *new_cntrs[STAT_MODE_NPMCS];
-	static const char **pmc_stat_mode_cntrs;
 	struct pmcstat_ev *ev;
 	char *counters, *counter;
 	int i, c, start, newcnt;
 	cpuset_t cpumask, rootmask;
 
 	if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
 	    sizeof(rootmask), &rootmask) == -1)
 		err(EX_OSERR, "ERROR: Cannot determine the root set of CPUs");
 	CPU_COPY(&rootmask, &cpumask);
 
-	if (pmc_pmu_stat_mode(&pmc_stat_mode_cntrs) != 0)
-		errx(EX_USAGE, "ERROR: hwmpc.ko not loaded or stat not supported on host.");
 	if (system_mode && geteuid() != 0)
 		errx(EX_USAGE, "ERROR: system mode counters can only be used as root");
 	counters = NULL;
 	for (i = 0; i < STAT_MODE_NPMCS; i++) {
-		stat_mode_cntrs[i] = pmc_stat_mode_cntrs[i];
+		stat_mode_cntrs[i] = pmc_stat_mode_aliases[i];
 		stat_mode_names[i] = pmc_stat_mode_names[i];
 	}
 	if (arg) {
 		counters = strdup(arg);
 		newcnt = 0;
 		while ((counter = strsep(&counters, ",")) != NULL &&
 		    newcnt < STAT_MODE_NPMCS - IAP_START) {
 			new_cntrs[newcnt++] = counter;
 			if (pmc_pmu_sample_rate_get(counter) == DEFAULT_SAMPLE_COUNT)
 				errx(EX_USAGE, "ERROR: %s not recognized on host", counter);
 		}
 		start = IAP_START + STAT_MODE_NPMCS - FIXED_MODE_NPMCS - newcnt;
 		for (i = 0; i < newcnt; i++) {
 			stat_mode_cntrs[start + i] = new_cntrs[i];
 			stat_mode_names[start + i] = new_cntrs[i];
 		}
 	}
 	if (system_mode)
 		pmc_args.pa_flags |= FLAG_HAS_SYSTEM_PMCS;
 	else
 		pmc_args.pa_flags |= FLAG_HAS_PROCESS_PMCS;
 	pmc_args.pa_flags |= FLAG_HAS_COUNTING_PMCS;
 	pmc_args.pa_flags |= FLAG_HAS_COMMANDLINE | FLAG_HAS_TARGET;
 	pmc_args.pa_flags |= FLAG_HAS_PIPE;
 	pmc_args.pa_required |= FLAG_HAS_COMMANDLINE | FLAG_HAS_TARGET | FLAG_HAS_OUTPUT_LOGFILE;
 	pmc_args.pa_outputpath = strdup("/dev/null");
 	pmc_args.pa_logfd = pmcstat_open_log(pmc_args.pa_outputpath,
 	    PMCSTAT_OPEN_FOR_WRITE);
 	for (i = 0; i < STAT_MODE_NPMCS; i++) {
 		if ((ev = malloc(sizeof(*ev))) == NULL)
 			errx(EX_SOFTWARE, "ERROR: Out of memory.");
 		if (system_mode)
 			ev->ev_mode = PMC_MODE_SC;
 		else
 			ev->ev_mode = PMC_MODE_TC;
 		ev->ev_spec = strdup(stat_mode_cntrs[i]);
 		if (ev->ev_spec == NULL)
 			errx(EX_SOFTWARE, "ERROR: Out of memory.");
 		c = strcspn(strdup(stat_mode_cntrs[i]), ", \t");
 		ev->ev_name = malloc(c + 1);
 		if (ev->ev_name == NULL)
 			errx(EX_SOFTWARE, "ERROR: Out of memory.");
 		(void)strncpy(ev->ev_name, stat_mode_cntrs[i], c);
 		*(ev->ev_name + c) = '\0';
 
 		ev->ev_count = -1;
 		ev->ev_flags = 0;
 		ev->ev_flags |= PMC_F_DESCENDANTS;
 		ev->ev_cumulative = 1;
 
 		ev->ev_saved = 0LL;
 		ev->ev_pmcid = PMC_ID_INVALID;
 		STAILQ_INSERT_TAIL(&pmc_args.pa_events, ev, ev_next);
 		if (system_mode) {
 			ev->ev_cpu = CPU_FFS(&cpumask) - 1;
 			CPU_CLR(ev->ev_cpu, &cpumask);
 			pmcstat_clone_event_descriptor(ev, &cpumask, &pmc_args);
 			CPU_SET(ev->ev_cpu, &cpumask);
 		} else
 			ev->ev_cpu = PMC_CPU_ANY;
 
 	}
 	if (clock_gettime(CLOCK_MONOTONIC, &before_ts))
 		err(1, "clock_gettime");
 }
 
 static void
 pmc_stat_print_stat(struct rusage *ru)
 {
 	struct pmcstat_ev *ev;
 	struct timespec after;
 	uint64_t cvals[STAT_MODE_NPMCS];
 	uint64_t ticks, value;
 	int hz, i;
 
 	if (ru) {
 		hz = getstathz();
 		ticks = hz * (ru->ru_utime.tv_sec + ru->ru_stime.tv_sec) +
 			hz * (ru->ru_utime.tv_usec + ru->ru_stime.tv_usec) / 1000000;
 		if (clock_gettime(CLOCK_MONOTONIC, &after))
 			err(1, "clock_gettime");
 		/*
 		 * If our round-off on the tick calculation still puts us at 0,
 		 * then always assume at least one tick.
 		 */
 		if (ticks == 0)
 			ticks = 1;
 		fprintf(pmc_args.pa_printfile, "%16ld  %s\t\t#\t%02.03f M/sec\n",
 			ru->ru_minflt, "page faults", ((double)ru->ru_minflt / (double)ticks) / hz);
 		fprintf(pmc_args.pa_printfile, "%16ld  %s\t\t#\t%02.03f M/sec\n",
 			ru->ru_nvcsw, "voluntary csw", ((double)ru->ru_nvcsw / (double)ticks) / hz);
 		fprintf(pmc_args.pa_printfile, "%16ld  %s\t#\t%02.03f M/sec\n",
 			ru->ru_nivcsw, "involuntary csw", ((double)ru->ru_nivcsw / (double)ticks) / hz);
 	}
 
 	bzero(&cvals, sizeof(cvals));
 	STAILQ_FOREACH(ev, &pmc_args.pa_events, ev_next) {
 		if (pmc_read(ev->ev_pmcid, &value) < 0)
 			err(EX_OSERR, "ERROR: Cannot read pmc \"%s\"",
 			    ev->ev_name);
 		for (i = 0; i < STAT_MODE_NPMCS; i++)
 			if (strcmp(ev->ev_name, stat_mode_cntrs[i]) == 0)
 				cvals[i] += value;
 	}
 
 	fprintf(pmc_args.pa_printfile, "%16jd  %s\n", (uintmax_t)cvals[CYCLES], stat_mode_names[CYCLES]);
 	fprintf(pmc_args.pa_printfile, "%16jd  %s\t\t#\t%01.03f inst/cycle\n", (uintmax_t)cvals[INST], stat_mode_names[INST],
 	    (double)cvals[INST] / cvals[CYCLES]);
 	fprintf(pmc_args.pa_printfile, "%16jd  %s\n", (uintmax_t)cvals[BR], stat_mode_names[BR]);
 	if (stat_mode_names[BR_MISS] == pmc_stat_mode_names[BR_MISS])
 		fprintf(pmc_args.pa_printfile, "%16jd  %s\t\t#\t%.03f%%\n",
 		    (uintmax_t)cvals[BR_MISS], stat_mode_names[BR_MISS],
 		    100 * ((double)cvals[BR_MISS] / cvals[BR]));
 	else
 		fprintf(pmc_args.pa_printfile, "%16jd  %s\n",
 		    (uintmax_t)cvals[BR_MISS], stat_mode_names[BR_MISS]);
 	fprintf(pmc_args.pa_printfile, "%16jd  %s%s", (uintmax_t)cvals[CACHE], stat_mode_names[CACHE],
 	    stat_mode_names[CACHE] != pmc_stat_mode_names[CACHE] ? "\n" : "");
 	if (stat_mode_names[CACHE] == pmc_stat_mode_names[CACHE])
 		fprintf(pmc_args.pa_printfile, "\t#\t%.03f refs/inst\n",
 		    ((double)cvals[CACHE] / cvals[INST]));
 	fprintf(pmc_args.pa_printfile, "%16jd  %s%s", (uintmax_t)cvals[CACHE_MISS], stat_mode_names[CACHE_MISS],
 	    stat_mode_names[CACHE_MISS] != pmc_stat_mode_names[CACHE_MISS] ? "\n" : "");
 	if (stat_mode_names[CACHE_MISS] == pmc_stat_mode_names[CACHE_MISS])
 		fprintf(pmc_args.pa_printfile, "\t\t#\t%.03f%%\n",
 		    100 * ((double)cvals[CACHE_MISS] / cvals[CACHE]));
 
 	if (ru)
 		showtime(pmc_args.pa_printfile, &before_ts, &after, ru);
 }
 
 static struct option longopts[] = {
 	{"events", required_argument, NULL, 'j'},
 	{NULL, 0, NULL, 0}
 };
 
 static int
 pmc_stat_internal(int argc, char **argv, int system_mode)
 {
 	char *event, *r;
 	struct sigaction sa;
 	struct kevent kev;
 	struct rusage ru;
 	struct winsize ws;
 	struct pmcstat_ev *ev;
 	int c, option, runstate;
 	int waitstatus, ru_valid, do_debug;
 
 	do_debug = ru_valid = 0;
 	r = event = NULL;
 	while ((option = getopt_long(argc, argv, "dj:", longopts, NULL)) != -1) {
 		switch (option) {
 		case 'j':
 			r = event = strdup(optarg);
 			break;
 		case 'd':
 			do_debug = 1;
 			break;
 		case '?':
 		default:
 			usage();
 		}
 	}
 	pmc_args.pa_argc = (argc -= optind);
 	pmc_args.pa_argv = (argv += optind);
 	if (argc == 0)
 		usage();
 	pmc_args.pa_flags |= FLAG_HAS_COMMANDLINE;
 	pmc_stat_setup_stat(system_mode, event);
 	free(r);
 	bzero(&ru, sizeof(ru));
 	EV_SET(&kev, SIGINT, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
 	if (kevent(pmc_kq, &kev, 1, NULL, 0, NULL) < 0)
 		err(EX_OSERR, "ERROR: Cannot register kevent for SIGINT");
 
 	EV_SET(&kev, SIGIO, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
 	if (kevent(pmc_kq, &kev, 1, NULL, 0, NULL) < 0)
 		err(EX_OSERR, "ERROR: Cannot register kevent for SIGIO");
 	EV_SET(&kev, 0, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
 	if (kevent(pmc_kq, &kev, 1, NULL, 0, NULL) < 0)
 		err(EX_OSERR,
 			"ERROR: Cannot register kevent for timer");
 
 	STAILQ_FOREACH(ev, &pmc_args.pa_events, ev_next) {
 		if (pmc_allocate(ev->ev_spec, ev->ev_mode,
 		    ev->ev_flags, ev->ev_cpu, &ev->ev_pmcid, ev->ev_count) < 0)
 			err(EX_OSERR,
 			    "ERROR: Cannot allocate %s-mode pmc with specification \"%s\"",
 			    PMC_IS_SYSTEM_MODE(ev->ev_mode) ?
 			    "system" : "process", ev->ev_spec);
 
 		if (PMC_IS_SAMPLING_MODE(ev->ev_mode) &&
 		    pmc_set(ev->ev_pmcid, ev->ev_count) < 0)
 			err(EX_OSERR,
 			    "ERROR: Cannot set sampling count for PMC \"%s\"",
 			    ev->ev_name);
 	}
 
 	/*
 	 * An exec() failure of a forked child is signalled by the
 	 * child sending the parent a SIGCHLD.  We don't register an
 	 * actual signal handler for SIGCHLD, but instead use our
 	 * kqueue to pick up the signal.
 	 */
 	EV_SET(&kev, SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
 	if (kevent(pmc_kq, &kev, 1, NULL, 0, NULL) < 0)
 		err(EX_OSERR, "ERROR: Cannot register kevent for SIGCHLD");
 
 	pmcstat_create_process(pmcstat_sockpair, &pmc_args, pmc_kq);
 
 	if (SLIST_EMPTY(&pmc_args.pa_targets))
 		errx(EX_DATAERR,
 		    "ERROR: No matching target processes.");
 	if (pmc_args.pa_flags & FLAG_HAS_PROCESS_PMCS)
 		pmcstat_attach_pmcs(&pmc_args);
 
 	/* start the pmcs */
 	pmc_util_start_pmcs(&pmc_args);
 
 	/* start the (commandline) process if needed */
 	pmcstat_start_process(pmcstat_sockpair);
 
 	/* Handle SIGINT using the kqueue loop */
 	sa.sa_handler = SIG_IGN;
 	sa.sa_flags = 0;
 	(void)sigemptyset(&sa.sa_mask);
 
 	if (sigaction(SIGINT, &sa, NULL) < 0)
 		err(EX_OSERR, "ERROR: Cannot install signal handler");
 
 	/*
  * loop till either the target process (if any) exits, or we
  * are killed by a SIGINT or we reached the time duration.
  */
 	runstate = PMCSTAT_RUNNING;
 	do {
 		if ((c = kevent(pmc_kq, NULL, 0, &kev, 1, NULL)) <= 0) {
 			if (errno != EINTR)
 				err(EX_OSERR, "ERROR: kevent failed");
 			else
 				continue;
 		}
 		if (kev.flags & EV_ERROR)
 			errc(EX_OSERR, kev.data, "ERROR: kevent failed");
 
 		switch (kev.filter) {
 		case EVFILT_PROC:	/* target has exited */
 			if (wait4(pmc_util_get_pid(&pmc_args), &waitstatus, 0, &ru) > 0) {
 				getrusage(RUSAGE_CHILDREN, &ru);
 				ru_valid = 1;
 			}
 			break;
 
 		case EVFILT_READ:	/* log file data is present */
 			break;
 		case EVFILT_TIMER:
 			if (do_debug)
 				pmc_stat_print_stat(NULL);
 			break;
 		case EVFILT_SIGNAL:
 			if (kev.ident == SIGCHLD) {
 				/*
 				 * The child process sends us a
 				 * SIGCHLD if its exec() failed.  We
 				 * wait for it to exit and then exit
 				 * ourselves.
 				 */
 				(void)wait(&c);
 				runstate = PMCSTAT_FINISHED;
 			} else if (kev.ident == SIGIO) {
 				/*
 				 * We get a SIGIO if a PMC loses all
 				 * of its targets, or if logfile
 				 * writes encounter an error.
 				 */
 				if (wait4(pmc_util_get_pid(&pmc_args), &waitstatus, 0, &ru) > 0) {
 					getrusage(RUSAGE_CHILDREN, &ru);
 					ru_valid = 1;
 				}
 				runstate = pmcstat_close_log(&pmc_args);
 			} else if (kev.ident == SIGINT) {
 				/* Kill the child process if we started it */
 				if (pmc_args.pa_flags & FLAG_HAS_COMMANDLINE)
 					pmc_util_kill_process(&pmc_args);
 				runstate = pmcstat_close_log(&pmc_args);
 			} else if (kev.ident == SIGWINCH) {
 				if (ioctl(fileno(pmc_args.pa_printfile),
 				    TIOCGWINSZ, &ws) < 0)
 					err(EX_OSERR,
 					    "ERROR: Cannot determine window size");
 				pmc_displayheight = ws.ws_row - 1;
 				pmc_displaywidth = ws.ws_col - 1;
 			} else
 				assert(0);
 
 			break;
 		}
 	} while (runstate != PMCSTAT_FINISHED);
 	if (!ru_valid)
 		warnx("couldn't get rusage");
 	pmc_stat_print_stat(&ru);
 	pmc_util_cleanup(&pmc_args);
 	return (0);
 }
 
 int
 cmd_pmc_stat(int argc, char **argv)
 {
 	return (pmc_stat_internal(argc, argv, 0));
 }
 
 int
 cmd_pmc_stat_system(int argc, char **argv)
 {
 	return (pmc_stat_internal(argc, argv, 1));
 }