summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Macy <mmacy@FreeBSD.org>2018-06-05 04:26:40 +0000
committerMatt Macy <mmacy@FreeBSD.org>2018-06-05 04:26:40 +0000
commitebfaf69cc0a741100c3ef6ec6960d3a3ba0d1168 (patch)
tree43428d2c3cb5da86f51cf6b8a2bffa67d47f84d8
parenta12a06fae282272577b48a4c8b722f659bbf053e (diff)
Notes
-rw-r--r--lib/libpmc/pmclog.c13
-rw-r--r--lib/libpmc/pmclog.h18
-rw-r--r--sys/dev/hwpmc/hwpmc_logging.c69
-rw-r--r--sys/dev/hwpmc/hwpmc_mod.c92
-rw-r--r--sys/kern/kern_kthread.c15
-rw-r--r--sys/kern/kern_thr.c6
-rw-r--r--sys/kern/kern_thread.c3
-rw-r--r--sys/sys/pmc.h2
-rw-r--r--sys/sys/pmckern.h3
-rw-r--r--sys/sys/pmclog.h32
-rw-r--r--usr.sbin/Makefile2
-rw-r--r--usr.sbin/pmc/Makefile6
-rw-r--r--usr.sbin/pmc/cmd_pmc.h15
-rw-r--r--usr.sbin/pmc/cmd_pmc_filter.cc (renamed from usr.sbin/pmc/cmd_pmc_filter.c)137
14 files changed, 355 insertions, 58 deletions
diff --git a/lib/libpmc/pmclog.c b/lib/libpmc/pmclog.c
index 4ed65ebad75b9..cfa11118c60c2 100644
--- a/lib/libpmc/pmclog.c
+++ b/lib/libpmc/pmclog.c
@@ -404,6 +404,19 @@ pmclog_get_event(void *cookie, char **data, ssize_t *len,
case PMCLOG_TYPE_USERDATA:
PMCLOG_READ32(le,ev->pl_u.pl_u.pl_userdata);
break;
+ 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);
+ memcpy(ev->pl_u.pl_tc.pl_tdname, le, MAXCOMLEN+1);
+ break;
+ case PMCLOG_TYPE_THR_EXIT:
+ PMCLOG_READ32(le,ev->pl_u.pl_te.pl_tid);
+ break;
+ case PMCLOG_TYPE_PROC_CREATE:
+ PMCLOG_READ32(le,ev->pl_u.pl_pc.pl_pid);
+ memcpy(ev->pl_u.pl_pc.pl_pcomm, le, MAXCOMLEN+1);
+ break;
default: /* unknown record type */
ps->ps_state = PL_STATE_ERROR;
ev->pl_state = PMCLOG_ERROR;
diff --git a/lib/libpmc/pmclog.h b/lib/libpmc/pmclog.h
index 0d2c7d0f8b4cc..0f324ced6bc8c 100644
--- a/lib/libpmc/pmclog.h
+++ b/lib/libpmc/pmclog.h
@@ -120,6 +120,11 @@ struct pmclog_ev_proccsw {
pmc_value_t pl_value;
};
+struct pmclog_ev_proccreate {
+ pid_t pl_pid;
+ char pl_pcomm[MAXCOMLEN+1];
+};
+
struct pmclog_ev_procexec {
pid_t pl_pid;
pmc_id_t pl_pmcid;
@@ -142,6 +147,16 @@ struct pmclog_ev_sysexit {
pid_t pl_pid;
};
+struct pmclog_ev_threadcreate {
+ pid_t pl_tid;
+ pid_t pl_pid;
+ char pl_tdname[MAXCOMLEN+1];
+};
+
+struct pmclog_ev_threadexit {
+ pid_t pl_tid;
+};
+
struct pmclog_ev_userdata {
uint32_t pl_userdata;
};
@@ -166,10 +181,13 @@ struct pmclog_ev {
struct pmclog_ev_pmcattach pl_t;
struct pmclog_ev_pmcdetach pl_d;
struct pmclog_ev_proccsw pl_c;
+ struct pmclog_ev_proccreate pl_pc;
struct pmclog_ev_procexec pl_x;
struct pmclog_ev_procexit pl_e;
struct pmclog_ev_procfork pl_f;
struct pmclog_ev_sysexit pl_se;
+ struct pmclog_ev_threadcreate pl_tc;
+ struct pmclog_ev_threadexit pl_te;
struct pmclog_ev_userdata pl_u;
} pl_u;
};
diff --git a/sys/dev/hwpmc/hwpmc_logging.c b/sys/dev/hwpmc/hwpmc_logging.c
index 482c91e460315..49996229480b9 100644
--- a/sys/dev/hwpmc/hwpmc_logging.c
+++ b/sys/dev/hwpmc/hwpmc_logging.c
@@ -229,7 +229,7 @@ static void pmclog_loop(void *arg);
static void pmclog_release(struct pmc_owner *po);
static uint32_t *pmclog_reserve(struct pmc_owner *po, int length);
static void pmclog_schedule_io(struct pmc_owner *po, int wakeup);
-static void pmclog_schedule_all(struct pmc_owner *po);
+static void pmclog_schedule_all(struct pmc_owner *po, int force);
static void pmclog_stop_kthread(struct pmc_owner *po);
/*
@@ -808,7 +808,7 @@ pmclog_deconfigure_log(struct pmc_owner *po)
*/
int
-pmclog_flush(struct pmc_owner *po)
+pmclog_flush(struct pmc_owner *po, int force)
{
int error;
@@ -832,7 +832,7 @@ pmclog_flush(struct pmc_owner *po)
goto error;
}
- pmclog_schedule_all(po);
+ pmclog_schedule_all(po, force);
error:
mtx_unlock(&pmc_kthread_mtx);
@@ -840,9 +840,8 @@ pmclog_flush(struct pmc_owner *po)
}
static void
-pmclog_schedule_one_cond(void *arg)
+pmclog_schedule_one_cond(struct pmc_owner *po, int force)
{
- struct pmc_owner *po = arg;
struct pmclog_buffer *plb;
int cpu;
@@ -851,7 +850,8 @@ pmclog_schedule_one_cond(void *arg)
/* tell hardclock not to run again */
if (PMC_CPU_HAS_SAMPLES(cpu))
PMC_CALL_HOOK_UNLOCKED(curthread, PMC_FN_DO_SAMPLES, NULL);
- pmc_flush_samples(cpu);
+ if (force)
+ pmc_flush_samples(cpu);
plb = po->po_curbuf[cpu];
if (plb && plb->plb_ptr != plb->plb_base)
pmclog_schedule_io(po, 1);
@@ -859,7 +859,7 @@ pmclog_schedule_one_cond(void *arg)
}
static void
-pmclog_schedule_all(struct pmc_owner *po)
+pmclog_schedule_all(struct pmc_owner *po, int force)
{
/*
* Schedule the current buffer if any and not empty.
@@ -868,7 +868,7 @@ pmclog_schedule_all(struct pmc_owner *po)
thread_lock(curthread);
sched_bind(curthread, i);
thread_unlock(curthread);
- pmclog_schedule_one_cond(po);
+ pmclog_schedule_one_cond(po, force);
}
thread_lock(curthread);
sched_unbind(curthread);
@@ -895,7 +895,7 @@ pmclog_close(struct pmc_owner *po)
/*
* Schedule the current buffer.
*/
- pmclog_schedule_all(po);
+ pmclog_schedule_all(po, 0);
wakeup_one(po);
mtx_unlock(&pmc_kthread_mtx);
@@ -1044,6 +1044,22 @@ pmclog_process_pmcdetach(struct pmc *pm, pid_t pid)
PMCLOG_DESPATCH_SYNC(po);
}
+void
+pmclog_process_proccreate(struct pmc_owner *po, struct proc *p, int sync)
+{
+ if (sync) {
+ PMCLOG_RESERVE(po, PROC_CREATE, sizeof(struct pmclog_proccreate));
+ PMCLOG_EMIT32(p->p_pid);
+ 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_EMITSTRING(p->p_comm, MAXCOMLEN+1);
+ PMCLOG_DESPATCH(po);
+ }
+}
+
/*
* Log a context switch event to the log file.
*/
@@ -1079,14 +1095,13 @@ pmclog_process_procexec(struct pmc_owner *po, pmc_id_t pmid, pid_t pid,
pathlen = strlen(path) + 1; /* #bytes for the path */
recordlen = offsetof(struct pmclog_procexec, pl_pathname) + pathlen;
-
PMCLOG_RESERVE(po, PROCEXEC, recordlen);
PMCLOG_EMIT32(pid);
PMCLOG_EMIT32(pmid);
PMCLOG_EMIT32(0);
PMCLOG_EMITADDR(startaddr);
PMCLOG_EMITSTRING(path,pathlen);
- PMCLOG_DESPATCH(po);
+ PMCLOG_DESPATCH_SYNC(po);
}
/*
@@ -1138,6 +1153,38 @@ pmclog_process_sysexit(struct pmc_owner *po, pid_t pid)
PMCLOG_DESPATCH(po);
}
+void
+pmclog_process_threadcreate(struct pmc_owner *po, struct thread *td, int sync)
+{
+ struct proc *p;
+
+ p = td->td_proc;
+ if (sync) {
+ PMCLOG_RESERVE(po, THR_CREATE, sizeof(struct pmclog_threadcreate));
+ PMCLOG_EMIT32(td->td_tid);
+ PMCLOG_EMIT32(p->p_pid);
+ PMCLOG_EMIT32(0);
+ 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_EMITSTRING(td->td_name, MAXCOMLEN+1);
+ PMCLOG_DESPATCH(po);
+ }
+}
+
+void
+pmclog_process_threadexit(struct pmc_owner *po, struct thread *td)
+{
+
+ PMCLOG_RESERVE(po, THR_EXIT, sizeof(struct pmclog_threadexit));
+ PMCLOG_EMIT32(td->td_tid);
+ PMCLOG_DESPATCH(po);
+}
+
/*
* Write a user log entry.
*/
diff --git a/sys/dev/hwpmc/hwpmc_mod.c b/sys/dev/hwpmc/hwpmc_mod.c
index e9c47881894ef..191f2554ee60e 100644
--- a/sys/dev/hwpmc/hwpmc_mod.c
+++ b/sys/dev/hwpmc/hwpmc_mod.c
@@ -269,6 +269,11 @@ static int generic_switch_out(struct pmc_cpu *pc, struct pmc_process *pp);
static struct pmc_mdep *pmc_generic_cpu_initialize(void);
static void pmc_generic_cpu_finalize(struct pmc_mdep *md);
static void pmc_post_callchain_callback(void);
+static void pmc_process_threadcreate(struct thread *td);
+static void pmc_process_threadexit(struct thread *td);
+static void pmc_process_proccreate(struct proc *p);
+static void pmc_process_allproc(struct pmc *pm);
+
/*
* Kernel tunables and sysctl(8) interface.
*/
@@ -2049,6 +2054,9 @@ const char *pmc_hooknames[] = {
"THR-CREATE",
"THR-EXIT",
"THR-USERRET",
+ "THR-CREATE-LOG",
+ "THR-EXIT-LOG",
+ "PROC-CREATE-LOG"
};
#endif
@@ -2225,6 +2233,10 @@ pmc_hook_handler(struct thread *td, int function, void *arg)
pmc_process_munmap(td, (struct pmckern_map_out *) arg);
break;
+ case PMC_FN_PROC_CREATE_LOG:
+ pmc_process_proccreate((struct proc *)arg);
+ break;
+
case PMC_FN_USER_CALLCHAIN:
/*
* Record a call chain.
@@ -2270,14 +2282,22 @@ pmc_hook_handler(struct thread *td, int function, void *arg)
case PMC_FN_THR_CREATE:
pmc_process_thread_add(td);
+ pmc_process_threadcreate(td);
+ break;
+
+ case PMC_FN_THR_CREATE_LOG:
+ pmc_process_threadcreate(td);
break;
case PMC_FN_THR_EXIT:
KASSERT(td == curthread, ("[pmc,%d] td != curthread",
__LINE__));
pmc_process_thread_delete(td);
+ pmc_process_threadexit(td);
+ break;
+ case PMC_FN_THR_EXIT_LOG:
+ pmc_process_threadexit(td);
break;
-
case PMC_FN_THR_USERRET:
KASSERT(td == curthread, ("[pmc,%d] td != curthread",
__LINE__));
@@ -2697,9 +2717,9 @@ pmc_wait_for_pmc_idle(struct pmc *pm)
* Loop (with a forced context switch) till the PMC's runcount
* comes down to zero.
*/
- pmclog_flush(pm->pm_owner);
+ pmclog_flush(pm->pm_owner, 1);
while (counter_u64_fetch(pm->pm_runcount) > 0) {
- pmclog_flush(pm->pm_owner);
+ pmclog_flush(pm->pm_owner, 1);
#ifdef HWPMC_DEBUG
maxloop--;
KASSERT(maxloop > 0,
@@ -3439,7 +3459,7 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
break;
}
- error = pmclog_flush(po);
+ error = pmclog_flush(po, 0);
}
break;
@@ -4015,6 +4035,8 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
pmc = NULL;
break;
}
+ if (mode == PMC_MODE_SS)
+ pmc_process_allproc(pmc);
/*
* Return the allocated index.
@@ -5216,8 +5238,10 @@ pmc_process_fork(void *arg __unused, struct proc *p1, struct proc *newproc,
*/
epoch_enter_preempt(global_epoch_preempt);
CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext)
- if (po->po_flags & PMC_PO_OWNS_LOGFILE)
+ if (po->po_flags & PMC_PO_OWNS_LOGFILE) {
pmclog_process_procfork(po, p1->p_pid, newproc->p_pid);
+ pmclog_process_proccreate(po, newproc, 1);
+ }
epoch_exit_preempt(global_epoch_preempt);
if (!is_using_hwpmcs)
@@ -5280,6 +5304,64 @@ pmc_process_fork(void *arg __unused, struct proc *p1, struct proc *newproc,
}
static void
+pmc_process_threadcreate(struct thread *td)
+{
+ struct pmc_owner *po;
+
+ epoch_enter_preempt(global_epoch_preempt);
+ CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext)
+ if (po->po_flags & PMC_PO_OWNS_LOGFILE)
+ pmclog_process_threadcreate(po, td, 1);
+ epoch_exit_preempt(global_epoch_preempt);
+}
+
+static void
+pmc_process_threadexit(struct thread *td)
+{
+ struct pmc_owner *po;
+
+ epoch_enter_preempt(global_epoch_preempt);
+ CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext)
+ if (po->po_flags & PMC_PO_OWNS_LOGFILE)
+ pmclog_process_threadexit(po, td);
+ epoch_exit_preempt(global_epoch_preempt);
+}
+
+static void
+pmc_process_proccreate(struct proc *p)
+{
+ struct pmc_owner *po;
+
+ epoch_enter_preempt(global_epoch_preempt);
+ CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext)
+ if (po->po_flags & PMC_PO_OWNS_LOGFILE)
+ pmclog_process_proccreate(po, p, 1 /* sync */);
+ epoch_exit_preempt(global_epoch_preempt);
+}
+
+static void
+pmc_process_allproc(struct pmc *pm)
+{
+ struct pmc_owner *po;
+ struct thread *td;
+ struct proc *p;
+
+ po = pm->pm_owner;
+ if ((po->po_flags & PMC_PO_OWNS_LOGFILE) == 0)
+ return;
+ sx_slock(&allproc_lock);
+ FOREACH_PROC_IN_SYSTEM(p) {
+ pmclog_process_proccreate(po, p, 0 /* sync */);
+ PROC_LOCK(p);
+ FOREACH_THREAD_IN_PROC(p, td)
+ pmclog_process_threadcreate(po, td, 0 /* sync */);
+ PROC_UNLOCK(p);
+ }
+ sx_sunlock(&allproc_lock);
+ pmclog_flush(po, 0);
+}
+
+static void
pmc_kld_load(void *arg __unused, linker_file_t lf)
{
struct pmc_owner *po;
diff --git a/sys/kern/kern_kthread.c b/sys/kern/kern_kthread.c
index 2554572d88f83..19b7df110641b 100644
--- a/sys/kern/kern_kthread.c
+++ b/sys/kern/kern_kthread.c
@@ -126,6 +126,12 @@ kproc_create(void (*func)(void *), void *arg,
sched_clear_tdname(td);
#endif
TSTHREAD(td, td->td_name);
+#ifdef HWPMC_HOOKS
+ if (PMC_SYSTEM_SAMPLING_ACTIVE()) {
+ PMC_CALL_HOOK_UNLOCKED(td, PMC_FN_PROC_CREATE_LOG, p2);
+ PMC_CALL_HOOK_UNLOCKED(td, PMC_FN_THR_CREATE_LOG, NULL);
+ }
+#endif
/* call the processes' main()... */
cpu_fork_kthread_handler(td, func, arg);
@@ -310,7 +316,10 @@ kthread_add(void (*func)(void *), void *arg, struct proc *p,
/* Avoid inheriting affinity from a random parent. */
cpuset_kernthread(newtd);
-
+#ifdef HWPMC_HOOKS
+ if (PMC_SYSTEM_SAMPLING_ACTIVE())
+ PMC_CALL_HOOK_UNLOCKED(td, PMC_FN_THR_CREATE_LOG, NULL);
+#endif
/* Delay putting it on the run queue until now. */
if (!(flags & RFSTOPPED)) {
thread_lock(newtd);
@@ -331,6 +340,10 @@ kthread_exit(void)
td = curthread;
p = td->td_proc;
+#ifdef HWPMC_HOOKS
+ if (PMC_SYSTEM_SAMPLING_ACTIVE())
+ PMC_CALL_HOOK_UNLOCKED(td, PMC_FN_THR_EXIT_LOG, NULL);
+#endif
/* A module may be waiting for us to exit. */
wakeup(td);
diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c
index 5e817cdfaad71..915b552706a36 100644
--- a/sys/kern/kern_thr.c
+++ b/sys/kern/kern_thr.c
@@ -265,6 +265,8 @@ thread_create(struct thread *td, struct rtprio *rtp,
#ifdef HWPMC_HOOKS
if (PMC_PROC_IS_USING_PMCS(p))
PMC_CALL_HOOK(newtd, PMC_FN_THR_CREATE, NULL);
+ else if (PMC_SYSTEM_SAMPLING_ACTIVE())
+ PMC_CALL_HOOK_UNLOCKED(newtd, PMC_FN_THR_CREATE_LOG, NULL);
#endif
tidhash_add(newtd);
@@ -592,6 +594,10 @@ sys_thr_set_name(struct thread *td, struct thr_set_name_args *uap)
if (ttd == NULL)
return (ESRCH);
strcpy(ttd->td_name, name);
+#ifdef HWPMC_HOOKS
+ if (PMC_PROC_IS_USING_PMCS(p) || PMC_SYSTEM_SAMPLING_ACTIVE())
+ PMC_CALL_HOOK_UNLOCKED(ttd, PMC_FN_THR_CREATE_LOG, NULL);
+#endif
#ifdef KTR
sched_clear_tdname(ttd);
#endif
diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c
index 86bcdc90bfa0e..a3a6e87d2c4aa 100644
--- a/sys/kern/kern_thread.c
+++ b/sys/kern/kern_thread.c
@@ -589,7 +589,8 @@ thread_exit(void)
if (PMC_PROC_IS_USING_PMCS(td->td_proc)) {
PMC_SWITCH_CONTEXT(td, PMC_FN_CSW_OUT);
PMC_CALL_HOOK_UNLOCKED(td, PMC_FN_THR_EXIT, NULL);
- }
+ } else if (PMC_SYSTEM_SAMPLING_ACTIVE())
+ PMC_CALL_HOOK_UNLOCKED(td, PMC_FN_THR_EXIT_LOG, NULL);
#endif
PROC_UNLOCK(p);
PROC_STATLOCK(p);
diff --git a/sys/sys/pmc.h b/sys/sys/pmc.h
index b78ee0581bae8..35183bc8dba64 100644
--- a/sys/sys/pmc.h
+++ b/sys/sys/pmc.h
@@ -62,7 +62,7 @@
* The patch version is incremented for every bug fix.
*/
#define PMC_VERSION_MAJOR 0x06
-#define PMC_VERSION_MINOR 0x01
+#define PMC_VERSION_MINOR 0x02
#define PMC_VERSION_PATCH 0x0000
#define PMC_VERSION (PMC_VERSION_MAJOR << 24 | \
diff --git a/sys/sys/pmckern.h b/sys/sys/pmckern.h
index d0a19161483a3..aa4961ede1324 100644
--- a/sys/sys/pmckern.h
+++ b/sys/sys/pmckern.h
@@ -63,6 +63,9 @@
#define PMC_FN_THR_CREATE 12
#define PMC_FN_THR_EXIT 13
#define PMC_FN_THR_USERRET 14
+#define PMC_FN_THR_CREATE_LOG 15
+#define PMC_FN_THR_EXIT_LOG 16
+#define PMC_FN_PROC_CREATE_LOG 17
#define PMC_HR 0 /* Hardware ring buffer */
#define PMC_SR 1 /* Software ring buffer */
diff --git a/sys/sys/pmclog.h b/sys/sys/pmclog.h
index 8d170cd3ded34..9e37985d93b4d 100644
--- a/sys/sys/pmclog.h
+++ b/sys/sys/pmclog.h
@@ -67,7 +67,13 @@ enum pmclog_type {
*
* New variant of PMCLOG_TYPE_PMCALLOCATE for dynamic event.
*/
- PMCLOG_TYPE_PMCALLOCATEDYN = 17
+ PMCLOG_TYPE_PMCALLOCATEDYN = 17,
+ /*
+ * V6 ABI
+ */
+ PMCLOG_TYPE_THR_CREATE = 18,
+ PMCLOG_TYPE_THR_EXIT = 19,
+ PMCLOG_TYPE_PROC_CREATE = 20
};
/*
@@ -181,6 +187,12 @@ struct pmclog_proccsw {
uint32_t pl_tid;
} __packed;
+struct pmclog_proccreate {
+ PMCLOG_ENTRY_HEADER
+ uint32_t pl_pid;
+ uint64_t pl_pcomm[MAXCOMLEN+1]; /* keep 8 byte aligned */
+} __packed;
+
struct pmclog_procexec {
PMCLOG_ENTRY_HEADER
uint32_t pl_pid;
@@ -210,6 +222,19 @@ struct pmclog_sysexit {
uint32_t pl_pid;
} __packed;
+struct pmclog_threadcreate {
+ PMCLOG_ENTRY_HEADER
+ uint32_t pl_tid;
+ uint32_t pl_pid;
+ uint32_t pl_pad;
+ uint64_t pl_tdname[MAXCOMLEN+1]; /* keep 8 byte aligned */
+} __packed;
+
+struct pmclog_threadexit {
+ PMCLOG_ENTRY_HEADER
+ uint32_t pl_tid;
+} __packed;
+
struct pmclog_userdata {
PMCLOG_ENTRY_HEADER
uint32_t pl_userdata;
@@ -261,7 +286,7 @@ union pmclog_entry { /* only used to size scratch areas */
int pmclog_configure_log(struct pmc_mdep *_md, struct pmc_owner *_po,
int _logfd);
int pmclog_deconfigure_log(struct pmc_owner *_po);
-int pmclog_flush(struct pmc_owner *_po);
+int pmclog_flush(struct pmc_owner *_po, int force);
int pmclog_close(struct pmc_owner *_po);
void pmclog_initialize(void);
int pmclog_proc_create(struct thread *td, void **handlep);
@@ -283,6 +308,9 @@ void pmclog_process_procexec(struct pmc_owner *_po, pmc_id_t _pmid, pid_t _pid,
void pmclog_process_procexit(struct pmc *_pm, struct pmc_process *_pp);
void pmclog_process_procfork(struct pmc_owner *_po, pid_t _oldpid, pid_t _newpid);
void pmclog_process_sysexit(struct pmc_owner *_po, pid_t _pid);
+void pmclog_process_threadcreate(struct pmc_owner *_po, struct thread *td, int sync);
+void pmclog_process_threadexit(struct pmc_owner *_po, struct thread *td);
+void pmclog_process_proccreate(struct pmc_owner *_po, struct proc *p, int sync);
int pmclog_process_userlog(struct pmc_owner *_po,
struct pmc_op_writelog *_wl);
void pmclog_shutdown(void);
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
index afc6f3021d9b1..af327d42e97ad 100644
--- a/usr.sbin/Makefile
+++ b/usr.sbin/Makefile
@@ -179,7 +179,9 @@ SUBDIR.${MK_OPENSSL}+= keyserv
SUBDIR.${MK_PC_SYSINSTALL}+= pc-sysinstall
SUBDIR.${MK_PF}+= ftp-proxy
SUBDIR.${MK_PKGBOOTSTRAP}+= pkg
+.if (${COMPILER_TYPE} == "clang" || (${COMPILER_TYPE} == "gcc" && ${COMPILER_VERSION} >= 60100))
SUBDIR.${MK_PMC}+= pmc
+.endif
SUBDIR.${MK_PMC}+= pmcannotate
SUBDIR.${MK_PMC}+= pmccontrol
SUBDIR.${MK_PMC}+= pmcstat
diff --git a/usr.sbin/pmc/Makefile b/usr.sbin/pmc/Makefile
index 6a0438452822a..481670118b305 100644
--- a/usr.sbin/pmc/Makefile
+++ b/usr.sbin/pmc/Makefile
@@ -2,12 +2,14 @@
# $FreeBSD$
#
-PROG= pmc
+.include <src.opts.mk>
+PROG_CXX= pmc
MAN=
+CXXFLAGS+= -O0
LIBADD= kvm pmc m ncursesw pmcstat elf
SRCS= pmc.c pmc_util.c cmd_pmc_stat.c \
- cmd_pmc_list.c cmd_pmc_filter.c
+ cmd_pmc_list.c cmd_pmc_filter.cc
.include <bsd.prog.mk>
diff --git a/usr.sbin/pmc/cmd_pmc.h b/usr.sbin/pmc/cmd_pmc.h
index 463c30b0fb877..46a253cc8713a 100644
--- a/usr.sbin/pmc/cmd_pmc.h
+++ b/usr.sbin/pmc/cmd_pmc.h
@@ -40,11 +40,16 @@ 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 **);
-
+#if defined(__cplusplus)
+extern "C" {
+#endif
+ 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 **);
+#if defined(__cplusplus)
+};
+#endif
int pmc_util_get_pid(struct pmcstat_args *);
void pmc_util_start_pmcs(struct pmcstat_args *);
void pmc_util_cleanup(struct pmcstat_args *);
diff --git a/usr.sbin/pmc/cmd_pmc_filter.c b/usr.sbin/pmc/cmd_pmc_filter.cc
index c4dbe2a2fe7d3..b35bb2bee3bdd 100644
--- a/usr.sbin/pmc/cmd_pmc_filter.c
+++ b/usr.sbin/pmc/cmd_pmc_filter.cc
@@ -68,11 +68,22 @@ __FBSDID("$FreeBSD$");
#include <libpmcstat.h>
#include "cmd_pmc.h"
+#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
#define LIST_MAX 64
static struct option longopts[] = {
- {"threads", no_argument, NULL, 't'},
- {"pids", no_argument, NULL, 'p'},
- {"events", no_argument, NULL, 'e'},
+ {"lwps", required_argument, NULL, 't'},
+ {"pids", required_argument, NULL, 'p'},
+ {"threads", required_argument, NULL, 'T'},
+ {"processes", required_argument, NULL, 'P'},
+ {"events", required_argument, NULL, 'e'},
{NULL, 0, NULL, 0}
};
@@ -81,15 +92,18 @@ 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"
+ "\t -p <pids>, --pids <pids> -- comma-delimited list of pids to filter on\n"
+ "\t -P <processes>, --processes <processes> -- comma-delimited list of process names to filter on\n"
+ "\t -t <lwps>, --lwps <lwps> -- comma-delimited list of lwps to filter on\n"
+ "\t -T <threads>, --threads <threads> -- comma-delimited list of thread names to filter on\n"
+ "\t -x -- toggle inclusive filtering\n"
);
}
static void
-parse_intlist(char *strlist, int *intlist, int *pcount, int (*fn) (const char *))
+parse_intlist(char *strlist, uint32_t *intlist, int *pcount, int (*fn) (const char *))
{
char *token;
int count, tokenval;
@@ -105,7 +119,7 @@ parse_intlist(char *strlist, int *intlist, int *pcount, int (*fn) (const char *)
}
static void
-parse_events(char *strlist, int *intlist, int *pcount, char *cpuid)
+parse_events(char *strlist, uint32_t intlist[LIST_MAX], int *pcount, char *cpuid)
{
char *token;
int count, tokenval;
@@ -120,6 +134,21 @@ parse_events(char *strlist, int *intlist, int *pcount, char *cpuid)
*pcount = count;
}
+static void
+parse_names(char *strlist, char *namelist[LIST_MAX], int *pcount)
+{
+ char *token;
+ int count;
+
+ count = 0;
+ while ((token = strsep(&strlist, ",")) != NULL &&
+ count < LIST_MAX) {
+ namelist[count++] = token;
+ }
+ *pcount = count;
+}
+
+
struct pmcid_ent {
uint32_t pe_pmcid;
uint32_t pe_idx;
@@ -129,23 +158,52 @@ 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)
+{
+ int i;
+
+ auto kvpair = map.find(id);
+ if (kvpair == map.end()) {
+ printf("unknown id: %d\n", id);
+ return (false);
+ }
+ auto p = list;
+ for (i = 0; i < count; i++, p++) {
+ if (strstr(kvpair->second.c_str(), *p) != NULL)
+ return (true);
+ }
+ return (false);
+}
+
static void
pmc_filter_handler(uint32_t *lwplist, int lwpcount, uint32_t *pidlist, int pidcount,
- char *events, int infd, int outfd)
+ char *events, char *processes, char *threads, bool exclusive, 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;
+ char *proclist[LIST_MAX];
+ char *threadlist[LIST_MAX];
+ int i, pmccount, copies, eventcount, proccount, threadcount;
+ uint32_t idx;
+ idmap pidmap, tidmap;
- if ((ps = pmclog_open(infd)) == NULL)
+ if ((ps = static_cast < struct pmclog_parse_state *>(pmclog_open(infd)))== NULL)
errx(EX_OSERR, "ERROR: Cannot allocate pmclog parse state: %s\n", strerror(errno));
- eventcount = pmccount = 0;
+ proccount = eventcount = pmccount = 0;
+ if (processes)
+ parse_names(processes, proclist, &proccount);
+ if (threads)
+ parse_names(threads, threadlist, &threadcount);
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);
@@ -157,9 +215,9 @@ pmc_filter_handler(uint32_t *lwplist, int lwpcount, uint32_t *pidlist, int pidco
lseek(infd, 0, SEEK_SET);
pmclog_close(ps);
- if ((ps = pmclog_open(infd)) == NULL)
+ if ((ps = static_cast < struct pmclog_parse_state *>(pmclog_open(infd)))== NULL)
errx(EX_OSERR, "ERROR: Cannot allocate pmclog parse state: %s\n", strerror(errno));
- if ((pe = malloc(sizeof(*pe) * pmccount)) == NULL)
+ if ((pe = (typeof(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) {
@@ -171,12 +229,14 @@ pmc_filter_handler(uint32_t *lwplist, int lwpcount, uint32_t *pidlist, int pidco
}
lseek(infd, 0, SEEK_SET);
pmclog_close(ps);
- if ((ps = pmclog_open(infd)) == NULL)
+ if ((ps = static_cast < struct pmclog_parse_state *>(pmclog_open(infd)))== NULL)
errx(EX_OSERR, "ERROR: Cannot allocate pmclog parse state: %s\n", strerror(errno));
- dstoff = copies = 0;
+ copies = 0;
while (pmclog_read(ps, &ev) == 0) {
- dstoff += ev.pl_len;
- h = *(uint32_t *)ev.pl_data;
+ 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));
+ 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));
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");
@@ -186,14 +246,14 @@ pmc_filter_handler(uint32_t *lwplist, int lwpcount, uint32_t *pidlist, int pidco
for (i = 0; i < pidcount; i++)
if (pidlist[i] == ev.pl_u.pl_cc.pl_pid)
break;
- if (i == pidcount)
+ if ((i == pidcount) == exclusive)
continue;
}
if (lwpcount) {
for (i = 0; i < lwpcount; i++)
if (lwplist[i] == ev.pl_u.pl_cc.pl_tid)
break;
- if (i == lwpcount)
+ if ((i == lwpcount) == exclusive)
continue;
}
if (eventcount) {
@@ -210,9 +270,15 @@ pmc_filter_handler(uint32_t *lwplist, int lwpcount, uint32_t *pidlist, int pidco
if (idx == eventlist[i])
break;
}
- if (i == eventcount)
+ if ((i == eventcount) == exclusive)
continue;
}
+ if (proccount &&
+ pmc_find_name(pidmap, ev.pl_u.pl_cc.pl_pid, proclist, proccount) == exclusive)
+ continue;
+ if (threadcount &&
+ pmc_find_name(tidmap, ev.pl_u.pl_cc.pl_tid, threadlist, threadcount) == exclusive)
+ continue;
if (write(outfd, ev.pl_data, ev.pl_len) != (ssize_t)ev.pl_len)
errx(EX_OSERR, "ERROR: failed output write");
}
@@ -221,24 +287,35 @@ pmc_filter_handler(uint32_t *lwplist, int lwpcount, uint32_t *pidlist, int pidco
int
cmd_pmc_filter(int argc, char **argv)
{
- char *lwps, *pids, *events;
+ char *lwps, *pids, *events, *processes, *threads;
uint32_t lwplist[LIST_MAX];
uint32_t pidlist[LIST_MAX];
int option, lwpcount, pidcount;
int prelogfd, postlogfd;
+ bool exclusive;
- lwps = pids = events = NULL;
+ threads = processes = lwps = pids = events = NULL;
lwpcount = pidcount = 0;
- while ((option = getopt_long(argc, argv, "t:p:e:", longopts, NULL)) != -1) {
+ exclusive = false;
+ while ((option = getopt_long(argc, argv, "e:p:t:xP:T:", longopts, NULL)) != -1) {
switch (option) {
- case 't':
- lwps = strdup(optarg);
+ case 'e':
+ events = strdup(optarg);
break;
case 'p':
pids = strdup(optarg);
break;
- case 'e':
- events = strdup(optarg);
+ case 'P':
+ processes = strdup(optarg);
+ break;
+ case 't':
+ lwps = strdup(optarg);
+ break;
+ case 'T':
+ threads = strdup(optarg);
+ break;
+ case 'x':
+ exclusive = !exclusive;
break;
case '?':
default:
@@ -264,6 +341,6 @@ cmd_pmc_filter(int argc, char **argv)
strerror(errno));
pmc_filter_handler(lwplist, lwpcount, pidlist, pidcount, events,
- prelogfd, postlogfd);
+ processes, threads, exclusive, prelogfd, postlogfd);
return (0);
}