Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 4 Jun 2018 04:59:48 +0000 (UTC)
From:      Matt Macy <mmacy@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r334601 - in head: lib/libpmc usr.sbin/pmc
Message-ID:  <201806040459.w544xmui060101@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mmacy
Date: Mon Jun  4 04:59:48 2018
New Revision: 334601
URL: https://svnweb.freebsd.org/changeset/base/334601

Log:
  pmc: add filter command
  
  pmc filter allows the user to select event types, threads, and processes from
  a sample.
  
  % pmcstat -S unhalted_core_cycles -S llc-misses -S -S  resource_stalls.any -O pmc.log
  % pmc filter -e llc-misses pmc.log pmc-llc-misses.log
  % pmc filter -e unhalted_core_cycles -t 100339  pmc.log pmc-core-cycles.log
  etc...
  % pmcstat -R pmc-core-cycles.log -G pmc-core-cycles.stacks

Added:
  head/usr.sbin/pmc/cmd_pmc_filter.c   (contents, props changed)
Modified:
  head/lib/libpmc/libpmc_pmu_util.c   (contents, props changed)
  head/lib/libpmc/pmc.h
  head/lib/libpmc/pmclog.c
  head/lib/libpmc/pmclog.h
  head/usr.sbin/pmc/Makefile   (contents, props changed)
  head/usr.sbin/pmc/cmd_pmc.h   (contents, props changed)
  head/usr.sbin/pmc/pmc.c   (contents, props changed)

Modified: head/lib/libpmc/libpmc_pmu_util.c
==============================================================================
--- head/lib/libpmc/libpmc_pmu_util.c	Mon Jun  4 04:59:32 2018	(r334600)
+++ head/lib/libpmc/libpmc_pmu_util.c	Mon Jun  4 04:59:48 2018	(r334601)
@@ -62,8 +62,8 @@ static struct pmu_alias pmu_alias_table[] = {
 	{"BRANCH-MISSES-RETIRED", "BR_MISP_RETIRED.ALL_BRANCHES"},
 	{"cycles", "tsc-tsc"},
 	{"instructions", "inst-retired.any_p"},
-	{"branch-mispredicts", "br_misp_retired.all_branches" },
-	{"branches", "br_inst_retired.all_branches" },
+	{"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},
@@ -106,18 +106,22 @@ struct pmu_event_desc {
 };
 
 static const struct pmu_events_map *
-pmu_events_map_get(void)
+pmu_events_map_get(const char *cpuid)
 {
 	size_t s;
 	char buf[64];
 	const struct pmu_events_map *pme;
 
-	if (sysctlbyname("kern.hwpmc.cpuid", (void *)NULL, &s,
-	    (void *)NULL, 0) == -1)
-		return (NULL);
-	if (sysctlbyname("kern.hwpmc.cpuid", buf, &s,
-	    (void *)NULL, 0) == -1)
-		return (NULL);
+	if (cpuid != NULL) {
+		memcpy(buf, cpuid, 64);
+	} else {
+		if (sysctlbyname("kern.hwpmc.cpuid", (void *)NULL, &s,
+		    (void *)NULL, 0) == -1)
+			return (NULL);
+		if (sysctlbyname("kern.hwpmc.cpuid", buf, &s,
+		    (void *)NULL, 0) == -1)
+			return (NULL);
+	}
 	for (pme = pmu_events_map; pme->cpuid != NULL; pme++)
 		if (strcmp(buf, pme->cpuid) == 0)
 			return (pme);
@@ -125,13 +129,13 @@ pmu_events_map_get(void)
 }
 
 static const struct pmu_event *
-pmu_event_get(const char *event_name, int *idx)
+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()) == NULL)
+	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)
@@ -145,6 +149,18 @@ pmu_event_get(const char *event_name, int *idx)
 	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(int idx)
 {
@@ -152,7 +168,7 @@ pmc_pmu_event_get_by_idx(int idx)
 	const struct pmu_event *pe;
 	int i;
 
-	if ((pme = pmu_events_map_get()) == NULL)
+	if ((pme = pmu_events_map_get(NULL)) == NULL)
 		return (NULL);
 	for (i = 0, pe = pme->table; (pe->name || pe->desc || pe->event) && i < idx; pe++, i++);
 	return (pe->name);
@@ -218,9 +234,9 @@ pmc_pmu_sample_rate_get(const char *event_name)
 	struct pmu_event_desc ped;
 
 	event_name = pmu_alias_get(event_name);
-	if ((pe = pmu_event_get(event_name, NULL)) == NULL)
+	if ((pe = pmu_event_get(NULL, event_name, NULL)) == NULL)
 		return (DEFAULT_SAMPLE_COUNT);
-	if (pe->alias && (pe = pmu_event_get(pe->alias, NULL)) == NULL)
+	if (pe->alias && (pe = pmu_event_get(NULL, pe->alias, NULL)) == NULL)
 		return (DEFAULT_SAMPLE_COUNT);
 	if (pe->event == NULL)
 		return (DEFAULT_SAMPLE_COUNT);
@@ -233,7 +249,7 @@ int
 pmc_pmu_enabled(void)
 {
 
-	return (pmu_events_map_get() != NULL);
+	return (pmu_events_map_get(NULL) != NULL);
 }
 
 void
@@ -250,7 +266,7 @@ pmc_pmu_print_counters(const char *event_name)
 
 	if (debug != NULL && strcmp(debug, "true") == 0)
 		do_debug = 1;
-	if ((pme = pmu_events_map_get()) == NULL)
+	if ((pme = pmu_events_map_get(NULL)) == NULL)
 		return;
 	for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) {
 		if (pe->name == NULL)
@@ -269,7 +285,7 @@ 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)
+	if ((pme = pmu_events_map_get(NULL)) == NULL)
 		return;
 	for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) {
 		if (pe->name == NULL)
@@ -286,7 +302,7 @@ 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)
+	if ((pme = pmu_events_map_get(NULL)) == NULL)
 		return;
 	for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) {
 		if (pe->name == NULL)
@@ -306,7 +322,7 @@ 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)
+	if ((pme = pmu_events_map_get(NULL)) == NULL)
 		return;
 	for (pe = pme->table; pe->name || pe->desc || pe->event; pe++) {
 		if (pe->name == NULL)
@@ -350,9 +366,9 @@ pmc_pmu_pmcallocate(const char *event_name, struct pmc
 	bzero(iap, sizeof(*iap));
 	event_name = pmu_alias_get(event_name);
 	pm->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
-	if ((pe = pmu_event_get(event_name, &idx)) == NULL)
+	if ((pe = pmu_event_get(NULL, event_name, &idx)) == NULL)
 		return (ENOENT);
-	if (pe->alias && (pe = pmu_event_get(pe->alias, &idx)) == NULL)
+	if (pe->alias && (pe = pmu_event_get(NULL, pe->alias, &idx)) == NULL)
 		return (ENOENT);
 	if (pe->event == NULL)
 		return (ENOENT);
@@ -361,11 +377,11 @@ pmc_pmu_pmcallocate(const char *event_name, struct pmc
 
 
 	if (strcasestr(event_name, "UNC_") == event_name ||
-		strcasestr(event_name, "uncore") != NULL) {
+	    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)) {
+	    (ped.ped_event == 0x0 && ped.ped_umask == 0x3)) {
 		pm->pm_class = PMC_CLASS_IAF;
 	} else {
 		pm->pm_class = PMC_CLASS_IAP;
@@ -458,10 +474,17 @@ pmc_pmu_event_get_by_idx(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 *e __unused)
+{
+	return (-1);
 }
 
 #endif

Modified: head/lib/libpmc/pmc.h
==============================================================================
--- head/lib/libpmc/pmc.h	Mon Jun  4 04:59:32 2018	(r334600)
+++ head/lib/libpmc/pmc.h	Mon Jun  4 04:59:48 2018	(r334601)
@@ -121,6 +121,7 @@ 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(int idx);
+int pmc_pmu_idx_get_by_event(const char*, const char *);
 int pmc_pmu_stat_mode(const char ***);
 __END_DECLS
 

Modified: head/lib/libpmc/pmclog.c
==============================================================================
--- head/lib/libpmc/pmclog.c	Mon Jun  4 04:59:32 2018	(r334600)
+++ head/lib/libpmc/pmclog.c	Mon Jun  4 04:59:48 2018	(r334601)
@@ -78,28 +78,6 @@ __FBSDID("$FreeBSD$");
  * performance critical paths.
  */
 
-enum pmclog_parser_state {
-	PL_STATE_NEW_RECORD,		/* in-between records */
-	PL_STATE_EXPECTING_HEADER,	/* header being read */
-	PL_STATE_PARTIAL_RECORD,	/* header present but not the record */
-	PL_STATE_ERROR			/* parsing error encountered */
-};
-
-struct pmclog_parse_state {
-	enum pmclog_parser_state ps_state;
-	enum pmc_cputype	ps_arch;	/* log file architecture */
-	uint32_t		ps_version;	/* hwpmc version */
-	int			ps_initialized;	/* whether initialized */
-	int			ps_count;	/* count of records processed */
-	off_t			ps_offset;	/* stream byte offset */
-	union pmclog_entry	ps_saved;	/* saved partial log entry */
-	int			ps_svcount;	/* #bytes saved */
-	int			ps_fd;		/* active fd or -1 */
-	char			*ps_buffer;	/* scratch buffer if fd != -1 */
-	char			*ps_data;	/* current parse pointer */
-	size_t			ps_len;		/* length of buffered data */
-};
-
 #define	PMCLOG_HEADER_FROM_SAVED_STATE(PS)				\
 	(* ((uint32_t *) &(PS)->ps_saved))
 
@@ -299,7 +277,7 @@ pmclog_get_event(void *cookie, char **data, ssize_t *l
 	}
 
 	PMCLOG_INITIALIZE_READER(le, ps->ps_saved);
-
+	ev->pl_data = le;
 	PMCLOG_READ32(le,h);
 
 	if (!PMCLOG_HEADER_CHECK_MAGIC(h)) {
@@ -348,8 +326,8 @@ pmclog_get_event(void *cookie, char **data, ssize_t *l
 	case PMCLOG_TYPE_INITIALIZE:
 		PMCLOG_READ32(le,ev->pl_u.pl_i.pl_version);
 		PMCLOG_READ32(le,ev->pl_u.pl_i.pl_arch);
-		PMCLOG_READ32(le, noop);
 		PMCLOG_READSTRING(le, ev->pl_u.pl_i.pl_cpuid, PMC_CPUID_LEN);
+		memcpy(ev->pl_u.pl_i.pl_cpuid, le, PMC_CPUID_LEN);
 		ps->ps_version = ev->pl_u.pl_i.pl_version;
 		ps->ps_arch = ev->pl_u.pl_i.pl_arch;
 		ps->ps_initialized = 1;
@@ -434,6 +412,7 @@ pmclog_get_event(void *cookie, char **data, ssize_t *l
 
 	ev->pl_offset = (ps->ps_offset += evlen);
 	ev->pl_count  = (ps->ps_count += 1);
+	ev->pl_len = evlen;
 	ev->pl_state = PMCLOG_OK;
 	return 0;
 

Modified: head/lib/libpmc/pmclog.h
==============================================================================
--- head/lib/libpmc/pmclog.h	Mon Jun  4 04:59:32 2018	(r334600)
+++ head/lib/libpmc/pmclog.h	Mon Jun  4 04:59:48 2018	(r334601)
@@ -152,6 +152,8 @@ struct pmclog_ev {
 	size_t		  pl_count;	/* count of records so far */
 	struct timespec   pl_ts;	/* log entry timestamp */
 	enum pmclog_type  pl_type;	/* type of log entry */
+	void		 *pl_data;
+	int		  pl_len;
 	union { 			/* log entry data */
 		struct pmclog_ev_callchain	pl_cc;
 		struct pmclog_ev_closelog	pl_cl;
@@ -170,6 +172,28 @@ struct pmclog_ev {
 		struct pmclog_ev_sysexit	pl_se;
 		struct pmclog_ev_userdata	pl_u;
 	} pl_u;
+};
+
+enum pmclog_parser_state {
+	PL_STATE_NEW_RECORD,		/* in-between records */
+	PL_STATE_EXPECTING_HEADER,	/* header being read */
+	PL_STATE_PARTIAL_RECORD,	/* header present but not the record */
+	PL_STATE_ERROR			/* parsing error encountered */
+};
+
+struct pmclog_parse_state {
+	enum pmclog_parser_state ps_state;
+	enum pmc_cputype	ps_arch;	/* log file architecture */
+	uint32_t		ps_version;	/* hwpmc version */
+	int			ps_initialized;	/* whether initialized */
+	int			ps_count;	/* count of records processed */
+	off_t			ps_offset;	/* stream byte offset */
+	union pmclog_entry	ps_saved;	/* saved partial log entry */
+	int			ps_svcount;	/* #bytes saved */
+	int			ps_fd;		/* active fd or -1 */
+	char			*ps_buffer;	/* scratch buffer if fd != -1 */
+	char			*ps_data;	/* current parse pointer */
+	size_t			ps_len;		/* length of buffered data */
 };
 
 #define	PMCLOG_FD_NONE				(-1)

Modified: head/usr.sbin/pmc/Makefile
==============================================================================
--- head/usr.sbin/pmc/Makefile	Mon Jun  4 04:59:32 2018	(r334600)
+++ head/usr.sbin/pmc/Makefile	Mon Jun  4 04:59:48 2018	(r334601)
@@ -8,6 +8,6 @@ MAN=	
 LIBADD=	kvm pmc m ncursesw pmcstat elf
 
 SRCS=	pmc.c pmc_util.c cmd_pmc_stat.c \
-	cmd_pmc_list.c
+	cmd_pmc_list.c cmd_pmc_filter.c
 
 .include <bsd.prog.mk>

Modified: head/usr.sbin/pmc/cmd_pmc.h
==============================================================================
--- head/usr.sbin/pmc/cmd_pmc.h	Mon Jun  4 04:59:32 2018	(r334600)
+++ head/usr.sbin/pmc/cmd_pmc.h	Mon Jun  4 04:59:48 2018	(r334601)
@@ -41,6 +41,7 @@ extern struct pmcstat_args pmc_args;
 typedef int (*cmd_disp_t)(int, char **);
 
 int	cmd_pmc_stat(int, char **);
+int	cmd_pmc_filter(int, char **);
 int	cmd_pmc_stat_system(int, char **);
 int	cmd_pmc_list_events(int, char **);
 

Added: head/usr.sbin/pmc/cmd_pmc_filter.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/pmc/cmd_pmc_filter.c	Mon Jun  4 04:59:48 2018	(r334601)
@@ -0,0 +1,269 @@
+/*-
+ * 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 <stddef.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <libpmcstat.h>
+#include "cmd_pmc.h"
+
+#define LIST_MAX 64
+static struct option longopts[] = {
+	{"threads", no_argument, NULL, 't'},
+	{"pids", no_argument, NULL, 'p'},
+	{"events", no_argument, NULL, 'e'},
+	{NULL, 0, NULL, 0}
+};
+
+static void
+usage(void)
+{
+	errx(EX_USAGE,
+	    "\t filter log file\n"
+	    "\t -t <lwps>, --threads <lwps> -- comma-delimited list of lwps to filter on\n"
+	    "\t -p <pids>, --pids <pids> -- comma-delimited list of pids to filter on\n"
+	    "\t -e <events>, --events <events> -- comma-delimited list of events to filter on\n"
+	    );
+}
+
+
+static void
+parse_intlist(char *strlist, int *intlist, int *pcount, int (*fn) (const char *))
+{
+	char *token;
+	int count, tokenval;
+
+	count = 0;
+	while ((token = strsep(&strlist, ",")) != NULL &&
+	    count < LIST_MAX) {
+		if ((tokenval = fn(token)) < 0)
+			errx(EX_USAGE, "ERROR: %s not usable value", token);
+		intlist[count++] = tokenval;
+	}
+	*pcount = count;
+}
+
+static void
+parse_events(char *strlist, int *intlist, int *pcount, char *cpuid)
+{
+	char *token;
+	int count, tokenval;
+
+	count = 0;
+	while ((token = strsep(&strlist, ",")) != NULL &&
+	    count < LIST_MAX) {
+		if ((tokenval = pmc_pmu_idx_get_by_event(cpuid, token)) < 0)
+			errx(EX_USAGE, "ERROR: %s not usable value", token);
+		intlist[count++] = tokenval;
+	}
+	*pcount = count;
+}
+
+struct pmcid_ent {
+	uint32_t pe_pmcid;
+	uint32_t pe_idx;
+};
+#define	_PMCLOG_TO_HEADER(T,L)						\
+	((PMCLOG_HEADER_MAGIC << 24) |					\
+	 (PMCLOG_TYPE_ ## T << 16)   |					\
+	 ((L) & 0xFFFF))
+
+static void
+pmc_filter_handler(uint32_t *lwplist, int lwpcount, uint32_t *pidlist, int pidcount,
+    char *events, int infd, int outfd)
+{
+	struct pmclog_ev ev;
+	struct pmclog_parse_state *ps;
+	struct pmcid_ent *pe;
+	uint32_t eventlist[LIST_MAX];
+	char cpuid[PMC_CPUID_LEN];
+	int i, pmccount, copies, eventcount;
+	uint32_t idx, h;
+	off_t dstoff;
+
+	if ((ps = pmclog_open(infd)) == NULL)
+		errx(EX_OSERR, "ERROR: Cannot allocate pmclog parse state: %s\n", strerror(errno));
+
+	pmccount = 0;
+	while (pmclog_read(ps, &ev) == 0) {
+		if (ev.pl_type == PMCLOG_TYPE_INITIALIZE)
+			memcpy(cpuid, ev.pl_u.pl_i.pl_cpuid, PMC_CPUID_LEN);
+		if (ev.pl_type == PMCLOG_TYPE_PMCALLOCATE)
+			pmccount++;
+	}
+	if (events)
+		parse_events(events, eventlist, &eventcount, cpuid);
+
+	lseek(infd, 0, SEEK_SET);
+	pmclog_close(ps);
+	if ((ps = pmclog_open(infd)) == NULL)
+		errx(EX_OSERR, "ERROR: Cannot allocate pmclog parse state: %s\n", strerror(errno));
+	if ((pe = malloc(sizeof(*pe) * pmccount)) == NULL)
+		errx(EX_OSERR, "ERROR: failed to allocate pmcid map");
+	i = 0;
+	while (pmclog_read(ps, &ev) == 0 && i < pmccount) {
+		if (ev.pl_type == PMCLOG_TYPE_PMCALLOCATE) {
+			pe[i].pe_pmcid = ev.pl_u.pl_a.pl_pmcid;
+			pe[i].pe_idx = ev.pl_u.pl_a.pl_event;
+			i++;
+		}
+	}
+	lseek(infd, 0, SEEK_SET);
+	pmclog_close(ps);
+	if ((ps = pmclog_open(infd)) == NULL)
+		errx(EX_OSERR, "ERROR: Cannot allocate pmclog parse state: %s\n", strerror(errno));
+	dstoff = copies = 0;
+	while (pmclog_read(ps, &ev) == 0) {
+		dstoff += ev.pl_len;
+		h = *(uint32_t *)ev.pl_data;
+		if (ev.pl_type != PMCLOG_TYPE_CALLCHAIN) {
+			if (write(outfd, ev.pl_data, ev.pl_len) != (ssize_t)ev.pl_len)
+				errx(EX_OSERR, "ERROR: failed output write");
+			continue;
+		}
+		if (pidcount) {
+			for (i = 0; i < pidcount; i++)
+				if (pidlist[i] == ev.pl_u.pl_cc.pl_pid)
+					break;
+			if (i == pidcount)
+				continue;
+		}
+		if (lwpcount) {
+			for (i = 0; i < lwpcount; i++)
+				if (lwplist[i] == ev.pl_u.pl_cc.pl_tid)
+					break;
+			if (i == lwpcount)
+				continue;
+		}
+		if (eventcount) {
+			for (i = 0; i < pmccount; i++) {
+				if (pe[i].pe_pmcid == ev.pl_u.pl_cc.pl_pmcid)
+					break;
+			}
+			if (i == pmccount)
+				errx(EX_USAGE, "ERROR: unallocated pmcid: %d\n",
+				    ev.pl_u.pl_cc.pl_pmcid);
+
+			idx = pe[i].pe_idx;
+			for (i = 0; i < eventcount; i++) {
+				if (idx == eventlist[i])
+					break;
+			}
+			if (i == eventcount)
+				continue;
+		}
+		if (write(outfd, ev.pl_data, ev.pl_len) != (ssize_t)ev.pl_len)
+			errx(EX_OSERR, "ERROR: failed output write");
+	}
+}
+
+int
+cmd_pmc_filter(int argc, char **argv)
+{
+	char *lwps, *pids, *events;
+	uint32_t lwplist[LIST_MAX];
+	uint32_t pidlist[LIST_MAX];
+	int option, lwpcount, pidcount;
+	int prelogfd, postlogfd;
+
+	lwps = pids = events = NULL;
+	lwpcount = pidcount = 0;
+	while ((option = getopt_long(argc, argv, "t:p:e:", longopts, NULL)) != -1) {
+		switch (option) {
+		case 't':
+			lwps = strdup(optarg);
+			break;
+		case 'p':
+			pids = strdup(optarg);
+			break;
+		case 'e':
+			events = strdup(optarg);
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+	if (argc != 2)
+		usage();
+
+	if (lwps)
+		parse_intlist(lwps, lwplist, &lwpcount, atoi);
+	if (pids)
+		parse_intlist(pids, pidlist, &pidcount, atoi);
+	if ((prelogfd = open(argv[0], O_RDONLY,
+	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0)
+		errx(EX_OSERR, "ERROR: Cannot open \"%s\" for reading: %s.", argv[0],
+		    strerror(errno));
+	if ((postlogfd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC,
+	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0)
+		errx(EX_OSERR, "ERROR: Cannot open \"%s\" for writing: %s.", argv[1],
+		    strerror(errno));
+
+	pmc_filter_handler(lwplist, lwpcount, pidlist, pidcount, events,
+	    prelogfd, postlogfd);
+	return (0);
+}

Modified: head/usr.sbin/pmc/pmc.c
==============================================================================
--- head/usr.sbin/pmc/pmc.c	Mon Jun  4 04:59:32 2018	(r334600)
+++ head/usr.sbin/pmc/pmc.c	Mon Jun  4 04:59:48 2018	(r334601)
@@ -65,6 +65,7 @@ static struct cmd_handler disp_table[] = {
 	{"stat", cmd_pmc_stat},
 	{"stat-system", cmd_pmc_stat_system},
 	{"list-events", cmd_pmc_list_events},
+	{"filter", cmd_pmc_filter},
 	{NULL, NULL}
 };
 
@@ -76,6 +77,7 @@ usage(void)
 	    "\t stat <program> run program and print stats\n"
 		 "\t stat-system <program> run program and print system wide stats for duration of execution\n"
 		 "\t list-events list PMC events available on host\n"
+		 "\t filter filter records by lwp, pid, or event\n"
 	    );
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201806040459.w544xmui060101>