svn commit: r334701 - in head: lib/libpmc share/examples/hwpmc sys/dev/hwpmc sys/sys usr.sbin/pmc usr.sbin/pmcstat

Matt Macy mmacy at FreeBSD.org
Wed Jun 6 02:48:13 UTC 2018


Author: mmacy
Date: Wed Jun  6 02:48:09 2018
New Revision: 334701
URL: https://svnweb.freebsd.org/changeset/base/334701

Log:
  hwpmc: add summary command and further metadata extensions
  
  metadata changes:
  - log pmc sample rate with pmcallocate
  - log proc flags with thread / process logging
    to identify user vs kernel threads
  
  fixes:
  - use log cpuid to translate event id to event name
  
  Implement rudimentary summary command to track sample
  counts by thread and process name within a pmc log.
  
  % make -j4 buildkernel >& /dev/null &
  % sudo pmcstat -S unhalted_core_cycles -S llc-misses -O foo sleep 15
  % pmc summary foo
  cpu_clk_unhalted.thread_p_any:
          idle: 138108207162
          clang-6.0: 105336158004
          sh: 72340108510
          make: 8642012963
          kernel: 7754011631
  longest_lat_cache.miss:
          clang-6.0: 87502625
          sh: 40901227
          make: 5500165
          kernel: 3300099
          awk: 2000060
  
  %  pmc summary -f ~/foo
  idx: 278 name: cpu_clk_unhalted.thread_p_any rate: 2000003
  idle: 69054
  clang-6.0: 52668
  sh: 36170
  make: 4321
  kernel: 3877
  hwpmc: proc(7445): 3319
  awk: 1289
  xargs: 357
  rand_harvestq: 181
  mtree: 102
  intr: 53
  zfskern: 31
  usb: 7
  pagedaemon: 4
  ntpd: 3
  syslogd: 1
  acpi_thermal: 1
  logger: 1
  syncer: 1
  snmptrapd: 1
  sleep: 1
  idx: 17 name: longest_lat_cache.miss rate: 100003
  clang-6.0: 875
  sh: 409
  make: 55
  kernel: 33
  awk: 20
  hwpmc: proc(7445): 14
  xargs: 9
  idle: 8
  intr: 3
  zfskern: 2

Added:
  head/usr.sbin/pmc/cmd_pmc_summary.cc   (contents, props changed)
Modified:
  head/lib/libpmc/libpmc.c
  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/share/examples/hwpmc/overhead.c
  head/sys/dev/hwpmc/hwpmc_logging.c
  head/sys/dev/hwpmc/hwpmc_mod.c
  head/sys/sys/pmc.h
  head/sys/sys/pmclog.h
  head/usr.sbin/pmc/Makefile   (contents, props changed)
  head/usr.sbin/pmc/cmd_pmc.h   (contents, props changed)
  head/usr.sbin/pmc/cmd_pmc_filter.cc
  head/usr.sbin/pmc/cmd_pmc_stat.c   (contents, props changed)
  head/usr.sbin/pmc/pmc.c   (contents, props changed)
  head/usr.sbin/pmcstat/pmcstat.c

Modified: head/lib/libpmc/libpmc.c
==============================================================================
--- head/lib/libpmc/libpmc.c	Wed Jun  6 01:51:05 2018	(r334700)
+++ head/lib/libpmc/libpmc.c	Wed Jun  6 02:48:09 2018	(r334701)
@@ -1007,7 +1007,8 @@ pmc_mdep_is_compatible_class(enum pmc_class pc)
 
 int
 pmc_allocate(const char *ctrspec, enum pmc_mode mode,
-    uint32_t flags, int cpu, pmc_id_t *pmcid)
+    uint32_t flags, int cpu, pmc_id_t *pmcid,
+    uint64_t count)
 {
 	size_t n;
 	int retval;
@@ -1030,6 +1031,7 @@ pmc_allocate(const char *ctrspec, enum pmc_mode mode,
 	pmc_config.pm_cpu   = cpu;
 	pmc_config.pm_mode  = mode;
 	pmc_config.pm_flags = flags;
+	pmc_config.pm_count = count;
 	if (PMC_IS_SAMPLING_MODE(mode))
 		pmc_config.pm_caps |= PMC_CAP_INTERRUPT;
 	/*

Modified: head/lib/libpmc/libpmc_pmu_util.c
==============================================================================
--- head/lib/libpmc/libpmc_pmu_util.c	Wed Jun  6 01:51:05 2018	(r334700)
+++ head/lib/libpmc/libpmc_pmu_util.c	Wed Jun  6 02:48:09 2018	(r334701)
@@ -162,13 +162,13 @@ pmc_pmu_idx_get_by_event(const char *cpuid, const char
 }
 
 const char *
-pmc_pmu_event_get_by_idx(int idx)
+pmc_pmu_event_get_by_idx(const char *cpuid, int idx)
 {
 	const struct pmu_events_map *pme;
 	const struct pmu_event *pe;
 	int i;
 
-	if ((pme = pmu_events_map_get(NULL)) == NULL)
+	if ((pme = pmu_events_map_get(cpuid)) == NULL)
 		return (NULL);
 	for (i = 0, pe = pme->table; (pe->name || pe->desc || pe->event) && i < idx; pe++, i++);
 	return (pe->name);
@@ -470,7 +470,7 @@ pmc_pmu_pmcallocate(const char *e __unused, struct pmc
 }
 
 const char *
-pmc_pmu_event_get_by_idx(int idx __unused)
+pmc_pmu_event_get_by_idx(const char *c __unused, int idx __unused)
 {
 	return (NULL);
 }

Modified: head/lib/libpmc/pmc.h
==============================================================================
--- head/lib/libpmc/pmc.h	Wed Jun  6 01:51:05 2018	(r334700)
+++ head/lib/libpmc/pmc.h	Wed Jun  6 02:48:09 2018	(r334701)
@@ -75,7 +75,7 @@ struct pmc_pmcinfo {
 
 __BEGIN_DECLS
 int	pmc_allocate(const char *_ctrspec, enum pmc_mode _mode, uint32_t _flags,
-    int _cpu, pmc_id_t *_pmcid);
+    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);
@@ -120,7 +120,7 @@ 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(int idx);
+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

Modified: head/lib/libpmc/pmclog.c
==============================================================================
--- head/lib/libpmc/pmclog.c	Wed Jun  6 01:51:05 2018	(r334700)
+++ head/lib/libpmc/pmclog.c	Wed Jun  6 02:48:09 2018	(r334701)
@@ -328,6 +328,7 @@ pmclog_get_event(void *cookie, char **data, ssize_t *l
 		PMCLOG_READ32(le,ev->pl_u.pl_i.pl_arch);
 		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_cpuid = strdup(ev->pl_u.pl_i.pl_cpuid);
 		ps->ps_version = ev->pl_u.pl_i.pl_version;
 		ps->ps_arch = ev->pl_u.pl_i.pl_arch;
 		ps->ps_initialized = 1;
@@ -347,8 +348,8 @@ pmclog_get_event(void *cookie, char **data, ssize_t *l
 		PMCLOG_READ32(le,ev->pl_u.pl_a.pl_pmcid);
 		PMCLOG_READ32(le,ev->pl_u.pl_a.pl_event);
 		PMCLOG_READ32(le,ev->pl_u.pl_a.pl_flags);
-		PMCLOG_READ32(le,noop);
-		ev->pl_u.pl_a.pl_evname = pmc_pmu_event_get_by_idx(ev->pl_u.pl_a.pl_event);
+		PMCLOG_READ64(le,ev->pl_u.pl_a.pl_rate);
+		ev->pl_u.pl_a.pl_evname = pmc_pmu_event_get_by_idx(ps->ps_cpuid, ev->pl_u.pl_a.pl_event);
 		if (ev->pl_u.pl_a.pl_evname != NULL)
 			break;
 		else if ((ev->pl_u.pl_a.pl_evname =
@@ -407,7 +408,7 @@ pmclog_get_event(void *cookie, char **data, ssize_t *l
 	case PMCLOG_TYPE_THR_CREATE:
 		PMCLOG_READ32(le,ev->pl_u.pl_tc.pl_tid);
 		PMCLOG_READ32(le,ev->pl_u.pl_tc.pl_pid);
-		PMCLOG_READ32(le,noop);
+		PMCLOG_READ32(le,ev->pl_u.pl_tc.pl_flags);
 		memcpy(ev->pl_u.pl_tc.pl_tdname, le, MAXCOMLEN+1);
 		break;
 	case PMCLOG_TYPE_THR_EXIT:
@@ -415,6 +416,8 @@ pmclog_get_event(void *cookie, char **data, ssize_t *l
 		break;
 	case PMCLOG_TYPE_PROC_CREATE:
 		PMCLOG_READ32(le,ev->pl_u.pl_pc.pl_pid);
+		PMCLOG_READ32(le,ev->pl_u.pl_pc.pl_flags);
+		PMCLOG_READ32(le,noop);
 		memcpy(ev->pl_u.pl_pc.pl_pcomm, le, MAXCOMLEN+1);
 		break;
 	default:	/* unknown record type */
@@ -553,6 +556,7 @@ pmclog_open(int fd)
 	ps->ps_count = 0;
 	ps->ps_offset = (off_t) 0;
 	bzero(&ps->ps_saved, sizeof(ps->ps_saved));
+	ps->ps_cpuid = NULL;
 	ps->ps_svcount = 0;
 	ps->ps_fd    = fd;
 	ps->ps_data  = NULL;

Modified: head/lib/libpmc/pmclog.h
==============================================================================
--- head/lib/libpmc/pmclog.h	Wed Jun  6 01:51:05 2018	(r334700)
+++ head/lib/libpmc/pmclog.h	Wed Jun  6 02:48:09 2018	(r334701)
@@ -89,15 +89,16 @@ struct pmclog_ev_pcsample {
 };
 
 struct pmclog_ev_pmcallocate {
-	uint32_t	pl_event;
 	const char *	pl_evname;
+	uint64_t	pl_rate;
+	uint32_t	pl_event;
 	uint32_t	pl_flags;
 	pmc_id_t	pl_pmcid;
 };
 
 struct pmclog_ev_pmcallocatedyn {
-	uint32_t	pl_event;
 	char 		pl_evname[PMC_NAME_MAX];
+	uint32_t	pl_event;
 	uint32_t	pl_flags;
 	pmc_id_t	pl_pmcid;
 };
@@ -122,6 +123,7 @@ struct pmclog_ev_proccsw {
 
 struct pmclog_ev_proccreate {
 	pid_t		pl_pid;
+	uint32_t	pl_flags;
 	char		pl_pcomm[MAXCOMLEN+1];
 };
 
@@ -150,6 +152,7 @@ struct pmclog_ev_sysexit {
 struct pmclog_ev_threadcreate {
 	pid_t		pl_tid;
 	pid_t		pl_pid;
+	uint32_t	pl_flags;
 	char		pl_tdname[MAXCOMLEN+1];
 };
 
@@ -211,6 +214,7 @@ struct pmclog_parse_state {
 	int			ps_fd;		/* active fd or -1 */
 	char			*ps_buffer;	/* scratch buffer if fd != -1 */
 	char			*ps_data;	/* current parse pointer */
+	char			*ps_cpuid;	/* log cpuid */
 	size_t			ps_len;		/* length of buffered data */
 };
 

Modified: head/share/examples/hwpmc/overhead.c
==============================================================================
--- head/share/examples/hwpmc/overhead.c	Wed Jun  6 01:51:05 2018	(r334700)
+++ head/share/examples/hwpmc/overhead.c	Wed Jun  6 02:48:09 2018	(r334701)
@@ -65,7 +65,7 @@ main(int argc, char **argv)
 	if (pmc_init() != 0)
 		err(EX_OSERR, "hwpmc(4) not loaded, kldload or update your kernel");
 
-	if (pmc_allocate(counter_name, PMC_MODE_SC, 0, 0, &pmcid) < 0)
+	if (pmc_allocate(counter_name, PMC_MODE_SC, 0, 0, &pmcid, 64*1024) < 0)
 		err(EX_OSERR, "failed to allocate %s as a system counter in counting mode",
 		    counter_name);
 

Modified: head/sys/dev/hwpmc/hwpmc_logging.c
==============================================================================
--- head/sys/dev/hwpmc/hwpmc_logging.c	Wed Jun  6 01:51:05 2018	(r334700)
+++ head/sys/dev/hwpmc/hwpmc_logging.c	Wed Jun  6 02:48:09 2018	(r334701)
@@ -194,7 +194,7 @@ CTASSERT(sizeof(struct pmclog_map_in) == PATH_MAX +
 CTASSERT(offsetof(struct pmclog_map_in,pl_pathname) ==
     4*4 + sizeof(uintfptr_t));
 CTASSERT(sizeof(struct pmclog_map_out) == 4*4 + 2*sizeof(uintfptr_t));
-CTASSERT(sizeof(struct pmclog_pmcallocate) == 6*4);
+CTASSERT(sizeof(struct pmclog_pmcallocate) == 8*4);
 CTASSERT(sizeof(struct pmclog_pmcattach) == 6*4 + PATH_MAX);
 CTASSERT(offsetof(struct pmclog_pmcattach,pl_pathname) == 6*4);
 CTASSERT(sizeof(struct pmclog_pmcdetach) == 6*4);
@@ -991,6 +991,7 @@ pmclog_process_pmcallocate(struct pmc *pm)
 		PMCLOG_EMIT32(pm->pm_id);
 		PMCLOG_EMIT32(pm->pm_event);
 		PMCLOG_EMIT32(pm->pm_flags);
+		PMCLOG_EMIT64(pm->pm_sc.pm_reloadcount);
 		ps = pmc_soft_ev_acquire(pm->pm_event);
 		if (ps != NULL)
 			PMCLOG_EMITSTRING(ps->ps_ev.pm_ev_name,PMC_NAME_MAX);
@@ -1004,6 +1005,7 @@ pmclog_process_pmcallocate(struct pmc *pm)
 		PMCLOG_EMIT32(pm->pm_id);
 		PMCLOG_EMIT32(pm->pm_event);
 		PMCLOG_EMIT32(pm->pm_flags);
+		PMCLOG_EMIT64(pm->pm_sc.pm_reloadcount);
 		PMCLOG_DESPATCH_SYNC(po);
 	}
 }
@@ -1050,11 +1052,15 @@ pmclog_process_proccreate(struct pmc_owner *po, struct
 	if (sync) {
 		PMCLOG_RESERVE(po, PROC_CREATE, sizeof(struct pmclog_proccreate));
 		PMCLOG_EMIT32(p->p_pid);
+		PMCLOG_EMIT32(p->p_flag);
+		PMCLOG_EMIT32(0);
 		PMCLOG_EMITSTRING(p->p_comm, MAXCOMLEN+1);
 		PMCLOG_DESPATCH_SYNC(po);
 	} else {
 		PMCLOG_RESERVE(po, PROC_CREATE, sizeof(struct pmclog_proccreate));
 		PMCLOG_EMIT32(p->p_pid);
+		PMCLOG_EMIT32(p->p_flag);
+		PMCLOG_EMIT32(0);
 		PMCLOG_EMITSTRING(p->p_comm, MAXCOMLEN+1);
 		PMCLOG_DESPATCH(po);
 	}
@@ -1163,14 +1169,14 @@ pmclog_process_threadcreate(struct pmc_owner *po, stru
 		PMCLOG_RESERVE(po, THR_CREATE, sizeof(struct pmclog_threadcreate));
 		PMCLOG_EMIT32(td->td_tid);
 		PMCLOG_EMIT32(p->p_pid);
-		PMCLOG_EMIT32(0);
+		PMCLOG_EMIT32(p->p_flag);
 		PMCLOG_EMITSTRING(td->td_name, MAXCOMLEN+1);
 		PMCLOG_DESPATCH_SYNC(po);
 	} else {
 		PMCLOG_RESERVE(po, THR_CREATE, sizeof(struct pmclog_threadcreate));
 		PMCLOG_EMIT32(td->td_tid);
 		PMCLOG_EMIT32(p->p_pid);
-		PMCLOG_EMIT32(0);
+		PMCLOG_EMIT32(p->p_flag);
 		PMCLOG_EMITSTRING(td->td_name, MAXCOMLEN+1);
 		PMCLOG_DESPATCH(po);
 	}

Modified: head/sys/dev/hwpmc/hwpmc_mod.c
==============================================================================
--- head/sys/dev/hwpmc/hwpmc_mod.c	Wed Jun  6 01:51:05 2018	(r334700)
+++ head/sys/dev/hwpmc/hwpmc_mod.c	Wed Jun  6 02:48:09 2018	(r334701)
@@ -3925,6 +3925,12 @@ pmc_syscall_handler(struct thread *td, void *syscall_a
 		pmc->pm_caps  = caps;
 		pmc->pm_flags = pa.pm_flags;
 
+		/* XXX set lower bound on sampling for process counters */
+		if (PMC_IS_SAMPLING_MODE(mode))
+			pmc->pm_sc.pm_reloadcount = pa.pm_count;
+		else
+			pmc->pm_sc.pm_initial = pa.pm_count;
+
 		/* switch thread to CPU 'cpu' */
 		pmc_save_cpu_binding(&pb);
 

Modified: head/sys/sys/pmc.h
==============================================================================
--- head/sys/sys/pmc.h	Wed Jun  6 01:51:05 2018	(r334700)
+++ head/sys/sys/pmc.h	Wed Jun  6 02:48:09 2018	(r334701)
@@ -61,8 +61,8 @@
  *
  * The patch version is incremented for every bug fix.
  */
-#define	PMC_VERSION_MAJOR	0x06
-#define	PMC_VERSION_MINOR	0x02
+#define	PMC_VERSION_MAJOR	0x07
+#define	PMC_VERSION_MINOR	0x03
 #define	PMC_VERSION_PATCH	0x0000
 
 #define	PMC_VERSION		(PMC_VERSION_MAJOR << 24 |		\
@@ -439,6 +439,7 @@ struct pmc_op_pmcallocate {
 	uint32_t	pm_flags;	/* additional modifiers PMC_F_* */
 	enum pmc_mode	pm_mode;	/* desired mode */
 	pmc_id_t	pm_pmcid;	/* [return] process pmc id */
+	pmc_value_t	pm_count;	/* initial/sample count */
 
 	union pmc_md_op_pmcallocate pm_md; /* MD layer extensions */
 };

Modified: head/sys/sys/pmclog.h
==============================================================================
--- head/sys/sys/pmclog.h	Wed Jun  6 01:51:05 2018	(r334700)
+++ head/sys/sys/pmclog.h	Wed Jun  6 02:48:09 2018	(r334701)
@@ -162,6 +162,7 @@ struct pmclog_pmcallocate {
 	uint32_t		pl_pmcid;
 	uint32_t		pl_event;
 	uint32_t		pl_flags;
+	uint64_t		pl_rate;
 } __packed;
 
 struct pmclog_pmcattach {
@@ -190,6 +191,8 @@ struct pmclog_proccsw {
 struct pmclog_proccreate {
 	PMCLOG_ENTRY_HEADER
 	uint32_t		pl_pid;
+	uint32_t		pl_flags;
+	uint32_t		pl_pad;
 	uint64_t		pl_pcomm[MAXCOMLEN+1];	/* keep 8 byte aligned */
 } __packed;
 
@@ -226,7 +229,7 @@ struct pmclog_threadcreate {
 	PMCLOG_ENTRY_HEADER
 	uint32_t		pl_tid;
 	uint32_t		pl_pid;
-	uint32_t		pl_pad;
+	uint32_t		pl_flags;
 	uint64_t		pl_tdname[MAXCOMLEN+1];	/* keep 8 byte aligned */
 } __packed;
 

Modified: head/usr.sbin/pmc/Makefile
==============================================================================
--- head/usr.sbin/pmc/Makefile	Wed Jun  6 01:51:05 2018	(r334700)
+++ head/usr.sbin/pmc/Makefile	Wed Jun  6 02:48:09 2018	(r334701)
@@ -5,11 +5,12 @@
 .include <src.opts.mk>
 PROG_CXX=	pmc
 MAN=	
-CXXFLAGS+= -O0
+CXXFLAGS+=
 
 LIBADD=	kvm pmc m ncursesw pmcstat elf
 
 SRCS=	pmc.c pmc_util.c cmd_pmc_stat.c \
-	cmd_pmc_list.c cmd_pmc_filter.cc
+	cmd_pmc_list.c cmd_pmc_filter.cc \
+	cmd_pmc_summary.cc
 
 .include <bsd.prog.mk>

Modified: head/usr.sbin/pmc/cmd_pmc.h
==============================================================================
--- head/usr.sbin/pmc/cmd_pmc.h	Wed Jun  6 01:51:05 2018	(r334700)
+++ head/usr.sbin/pmc/cmd_pmc.h	Wed Jun  6 02:48:09 2018	(r334701)
@@ -47,6 +47,7 @@ extern "C" {
 	int	cmd_pmc_filter(int, char **);
 	int	cmd_pmc_stat_system(int, char **);
 	int	cmd_pmc_list_events(int, char **);
+	int	cmd_pmc_summary(int, char **);
 #if defined(__cplusplus)
 };
 #endif

Modified: head/usr.sbin/pmc/cmd_pmc_filter.cc
==============================================================================
--- head/usr.sbin/pmc/cmd_pmc_filter.cc	Wed Jun  6 01:51:05 2018	(r334700)
+++ head/usr.sbin/pmc/cmd_pmc_filter.cc	Wed Jun  6 02:48:09 2018	(r334701)
@@ -70,13 +70,12 @@ __FBSDID("$FreeBSD$");
 
 #include <iostream>
 #include <string>
-#if _LIBCPP_STD_VER >= 11
 #include <unordered_map>
+
 using	std::unordered_map;
-#else
-#include <tr1/unordered_map>
-using	std::tr1::unordered_map;
-#endif
+typedef unordered_map <int, std::string> idmap;
+typedef std::pair <int, std::string> identry;
+
 #define LIST_MAX 64
 static struct option longopts[] = {
 	{"lwps", required_argument, NULL, 't'},
@@ -158,10 +157,6 @@ struct pmcid_ent {
 	 (PMCLOG_TYPE_ ## T << 16)   |					\
 	 ((L) & 0xFFFF))
 
-
-typedef unordered_map < int ,std::string > idmap;
-typedef std::pair < int ,std::string > identry;
-
 static bool
 pmc_find_name(idmap & map, uint32_t id, char *list[LIST_MAX], int count)
 {
@@ -234,9 +229,9 @@ pmc_filter_handler(uint32_t *lwplist, int lwpcount, ui
 	copies = 0;
 	while (pmclog_read(ps, &ev) == 0) {
 		if (ev.pl_type == PMCLOG_TYPE_THR_CREATE)
-			tidmap.insert(identry(ev.pl_u.pl_tc.pl_tid, ev.pl_u.pl_tc.pl_tdname));
+			tidmap[ev.pl_u.pl_tc.pl_tid] = ev.pl_u.pl_tc.pl_tdname;
 		if (ev.pl_type == PMCLOG_TYPE_PROC_CREATE)
-			pidmap.insert(identry(ev.pl_u.pl_pc.pl_pid, ev.pl_u.pl_pc.pl_pcomm));
+			pidmap[ev.pl_u.pl_pc.pl_pid] = ev.pl_u.pl_pc.pl_pcomm;
 		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");

Modified: head/usr.sbin/pmc/cmd_pmc_stat.c
==============================================================================
--- head/usr.sbin/pmc/cmd_pmc_stat.c	Wed Jun  6 01:51:05 2018	(r334700)
+++ head/usr.sbin/pmc/cmd_pmc_stat.c	Wed Jun  6 02:48:09 2018	(r334701)
@@ -354,7 +354,7 @@ pmc_stat_internal(int argc, char **argv, int system_mo
 
 	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) < 0)
+		    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) ?

Added: head/usr.sbin/pmc/cmd_pmc_summary.cc
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/pmc/cmd_pmc_summary.cc	Wed Jun  6 02:48:09 2018	(r334701)
@@ -0,0 +1,220 @@
+/*-
+ * 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"
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include <unordered_map>
+
+using	std::unordered_map;
+typedef unordered_map <int, std::string> idmap;
+typedef unordered_map <uint32_t, uint64_t> intmap;
+typedef unordered_map <std::string, intmap> strintmap;
+typedef std::pair<uint64_t, uint32_t> sampleid;
+typedef std::pair<uint64_t, std::string> samplename;
+typedef unordered_map <uint32_t, std::vector<samplename>> eventcountmap;
+
+#define	P_KPROC		0x00004	/* Kernel process. */
+
+static void
+usage(void)
+{
+	errx(EX_USAGE,
+	    "\t summarize log file\n"
+		 "\t -k <k>, --topk <k> show topk processes for each counter\n"
+	    );
+}
+
+static int
+pmc_summary_handler(int logfd, int k, bool do_full)
+{
+	struct pmclog_parse_state *ps;
+	struct pmclog_ev ev;
+	idmap pidmap, tidmap, eventnamemap;
+	strintmap tideventmap, pideventmap;
+	intmap eventmap, pmcidmap, ratemap;
+	intmap kerntidmap, kernpidmap;
+	eventcountmap countmap;
+
+	ps = static_cast<struct pmclog_parse_state*>(pmclog_open(logfd));
+	if (ps == NULL)
+		errx(EX_OSERR, "ERROR: Cannot allocate pmclog parse state: %s\n",
+			 strerror(errno));
+	while (pmclog_read(ps, &ev) == 0) {
+		if (ev.pl_type == PMCLOG_TYPE_PMCALLOCATE) {
+			pmcidmap[ev.pl_u.pl_a.pl_pmcid] = ev.pl_u.pl_a.pl_event;
+			ratemap[ev.pl_u.pl_a.pl_event] = ev.pl_u.pl_a.pl_rate;
+			eventnamemap[ev.pl_u.pl_a.pl_event] = ev.pl_u.pl_a.pl_evname;
+		}
+		if (ev.pl_type == PMCLOG_TYPE_THR_CREATE) {
+			tidmap[ev.pl_u.pl_tc.pl_tid] = ev.pl_u.pl_tc.pl_tdname;
+			kerntidmap[ev.pl_u.pl_tc.pl_tid] = !!(ev.pl_u.pl_tc.pl_flags & P_KPROC);
+			if (tideventmap.find(ev.pl_u.pl_tc.pl_tdname) == tideventmap.end())
+				tideventmap[ev.pl_u.pl_tc.pl_tdname] = intmap();
+		}
+		if (ev.pl_type == PMCLOG_TYPE_PROC_CREATE) {
+			pidmap[ev.pl_u.pl_pc.pl_pid] = ev.pl_u.pl_pc.pl_pcomm;
+			kernpidmap[ev.pl_u.pl_pc.pl_pid] = !!(ev.pl_u.pl_pc.pl_flags & P_KPROC);
+			if (pideventmap.find(ev.pl_u.pl_pc.pl_pcomm) == pideventmap.end())
+				pideventmap[ev.pl_u.pl_pc.pl_pcomm] = intmap();
+		}
+		if (ev.pl_type == PMCLOG_TYPE_CALLCHAIN) {
+			auto event = pmcidmap[ev.pl_u.pl_cc.pl_pmcid];
+
+			if (event == 0)
+				continue;
+			eventmap[event]++;
+			auto tidname = tidmap.find(ev.pl_u.pl_cc.pl_tid);
+			auto pidname = pidmap.find(ev.pl_u.pl_cc.pl_pid);
+			if (tidname != tidmap.end()) {
+				auto &teventmap = tideventmap[tidname->second];
+				teventmap[event]++;
+			}
+			if (pidname != pidmap.end()) {
+				auto &peventmap = pideventmap[pidname->second];
+				peventmap[event]++;
+			}
+		}
+	}
+	for (auto &pkv : pideventmap)
+		for (auto &ekv : pkv.second) {
+			auto &samplevec = countmap[ekv.first];
+			samplevec.emplace_back(ekv.second, pkv.first);
+		}
+	for (auto &kv : countmap)
+		std::sort(kv.second.begin(), kv.second.end(), [](auto &a, auto &b) {return (a.first < b.first);});
+	if (do_full) {
+		for (auto &kv : countmap) {
+			auto &name = eventnamemap[kv.first];
+			auto rate = ratemap[kv.first];
+			std::cout << "idx: " << kv.first << " name: " << name << " rate: " << rate << std::endl;
+			while (!kv.second.empty()) {
+				auto &val = kv.second.back();
+				kv.second.pop_back();
+				std::cout << val.second << ": " << val.first << std::endl;
+			}
+		}
+		return (0);
+	}
+	for (auto &kv : countmap) {
+		auto &name = eventnamemap[kv.first];
+		auto rate = ratemap[kv.first];
+		std::cout << name << ":" << std::endl;
+		for (auto i = 0; i < k; i++) {
+			auto largest = kv.second.back();
+			kv.second.pop_back();
+			std::cout << "\t" << largest.second << ": " << largest.first*rate << std::endl;
+		}
+	}
+	return (0);
+}
+
+static struct option longopts[] = {
+	{"full", no_argument, NULL, 'f'},
+	{"topk", required_argument, NULL, 'k'},
+	{NULL, 0, NULL, 0}
+};
+
+int
+cmd_pmc_summary(int argc, char **argv)
+{
+	int option, logfd, k;
+	bool do_full;
+
+	do_full = false;
+	k = 5;
+	while ((option = getopt_long(argc, argv, "k:f", longopts, NULL)) != -1) {
+		switch (option) {
+		case 'f':
+			do_full = 1;
+			break;
+		case 'k':
+			k = atoi(optarg);
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	}
+	argc -= optind;
+	argv += optind;
+	if (argc != 1) {
+		printf("argc: %d\n", argc);
+		for (int i = 0; i < argc; i++)
+			printf("%s\n", argv[i]);
+		usage();
+	}
+	if ((logfd = 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));
+
+	return (pmc_summary_handler(logfd, k, do_full));
+}

Modified: head/usr.sbin/pmc/pmc.c
==============================================================================
--- head/usr.sbin/pmc/pmc.c	Wed Jun  6 01:51:05 2018	(r334700)
+++ head/usr.sbin/pmc/pmc.c	Wed Jun  6 02:48:09 2018	(r334701)
@@ -66,6 +66,7 @@ static struct cmd_handler disp_table[] = {
 	{"stat-system", cmd_pmc_stat_system},
 	{"list-events", cmd_pmc_list_events},
 	{"filter", cmd_pmc_filter},
+	{"summary", cmd_pmc_summary},
 	{NULL, NULL}
 };
 

Modified: head/usr.sbin/pmcstat/pmcstat.c
==============================================================================
--- head/usr.sbin/pmcstat/pmcstat.c	Wed Jun  6 01:51:05 2018	(r334700)
+++ head/usr.sbin/pmcstat/pmcstat.c	Wed Jun  6 02:48:09 2018	(r334701)
@@ -1129,7 +1129,8 @@ main(int argc, char **argv)
 
 	STAILQ_FOREACH(ev, &args.pa_events, ev_next) {
 		if (pmc_allocate(ev->ev_spec, ev->ev_mode,
-		    ev->ev_flags, ev->ev_cpu, &ev->ev_pmcid) < 0)
+			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) ?


More information about the svn-src-head mailing list