diff options
| author | Joseph Koshy <jkoshy@FreeBSD.org> | 2005-05-30 06:29:29 +0000 |
|---|---|---|
| committer | Joseph Koshy <jkoshy@FreeBSD.org> | 2005-05-30 06:29:29 +0000 |
| commit | 36c0fd9d0fb62e50ec668ba7c50c5bffaf9464d6 (patch) | |
| tree | 7e883bbffeb74552930e9883202ed3d7c3123a4a /sys | |
| parent | 95eca142ec1e8547a26a4a18d14842f36dcf9fc5 (diff) | |
Notes
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/amd64/amd64/trap.c | 16 | ||||
| -rw-r--r-- | sys/dev/hwpmc/hwpmc_amd.c | 4 | ||||
| -rw-r--r-- | sys/dev/hwpmc/hwpmc_piv.c | 3 | ||||
| -rw-r--r-- | sys/dev/hwpmc/hwpmc_ppro.c | 2 | ||||
| -rw-r--r-- | sys/i386/i386/trap.c | 17 | ||||
| -rw-r--r-- | sys/kern/kern_clock.c | 9 | ||||
| -rw-r--r-- | sys/kern/kern_pmc.c | 6 | ||||
| -rw-r--r-- | sys/sys/pmc.h | 2 | ||||
| -rw-r--r-- | sys/sys/pmckern.h | 41 |
9 files changed, 78 insertions, 22 deletions
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index 56ab882f9b146..7c8da2df7fe4b 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -70,6 +70,9 @@ __FBSDID("$FreeBSD$"); #ifdef KTRACE #include <sys/ktrace.h> #endif +#ifdef HWPMC_HOOKS +#include <sys/pmckern.h> +#endif #include <vm/vm.h> #include <vm/vm_param.h> @@ -180,6 +183,19 @@ trap(frame) } #endif +#ifdef HWPMC_HOOKS + /* + * CPU PMCs interrupt using an NMI. If the PMC module is + * active, pass the 'rip' value to the PMC module's interrupt + * handler. A return value of '1' from the handler means that + * the NMI was handled by it and we can return immediately. + */ + if (type == T_NMI && pmc_intr && + (*pmc_intr)(PCPU_GET(cpuid), (uintptr_t) frame.tf_rip, + TRAPF_USERMODE(&frame))) + goto out; +#endif + if ((frame.tf_rflags & PSL_I) == 0) { /* * Buggy application or kernel code has disabled diff --git a/sys/dev/hwpmc/hwpmc_amd.c b/sys/dev/hwpmc/hwpmc_amd.c index cd3db049e09b5..1eb987dba806b 100644 --- a/sys/dev/hwpmc/hwpmc_amd.c +++ b/sys/dev/hwpmc/hwpmc_amd.c @@ -739,7 +739,7 @@ amd_stop_pmc(int cpu, int ri) */ static int -amd_intr(int cpu, uintptr_t eip) +amd_intr(int cpu, uintptr_t eip, int usermode) { int i, retval; enum pmc_mode mode; @@ -748,6 +748,8 @@ amd_intr(int cpu, uintptr_t eip) struct pmc_cpu *pc; struct pmc_hw *phw; + (void) usermode; + KASSERT(cpu >= 0 && cpu < mp_ncpus, ("[amd,%d] out of range CPU %d", __LINE__, cpu)); diff --git a/sys/dev/hwpmc/hwpmc_piv.c b/sys/dev/hwpmc/hwpmc_piv.c index e81e4e45012ef..c9ade03edd056 100644 --- a/sys/dev/hwpmc/hwpmc_piv.c +++ b/sys/dev/hwpmc/hwpmc_piv.c @@ -1452,7 +1452,7 @@ p4_lapic_enable_pmc_interrupt(void) static int -p4_intr(int cpu, uintptr_t eip) +p4_intr(int cpu, uintptr_t eip, int usermode) { int i, pmc_interrupted; uint32_t cccrval, pmi_ovf_mask; @@ -1462,6 +1462,7 @@ p4_intr(int cpu, uintptr_t eip) pmc_value_t v; (void) eip; + (void) usermode; PMCDBG(MDP,INT, 1, "cpu=%d eip=%x pcint=0x%x", cpu, eip, lapic->lvt_pcint); diff --git a/sys/dev/hwpmc/hwpmc_ppro.c b/sys/dev/hwpmc/hwpmc_ppro.c index 13f91956ca000..370e6e575ff12 100644 --- a/sys/dev/hwpmc/hwpmc_ppro.c +++ b/sys/dev/hwpmc/hwpmc_ppro.c @@ -672,7 +672,7 @@ p6_stop_pmc(int cpu, int ri) } static int -p6_intr(int cpu, uintptr_t eip) +p6_intr(int cpu, uintptr_t eip, int usermode) { (void) cpu; (void) eip; diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index 2bca06889a930..bb02052c3b5cb 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -72,6 +72,9 @@ __FBSDID("$FreeBSD$"); #ifdef KTRACE #include <sys/ktrace.h> #endif +#ifdef HWPMC_HOOKS +#include <sys/pmckern.h> +#endif #include <vm/vm.h> #include <vm/vm_param.h> @@ -198,6 +201,20 @@ trap(frame) } #endif +#ifdef HWPMC_HOOKS + /* + * CPU PMCs interrupt using an NMI so we check for that first. + * If the HWPMC module is active, 'pmc_hook' will point to + * the function to be called. A return value of '1' from the + * hook means that the NMI was handled by it and that we can + * return immediately. + */ + if (type == T_NMI && pmc_intr && + (*pmc_intr)(PCPU_GET(cpuid), (uintptr_t) frame.tf_eip, + TRAPF_USERMODE(&frame))) + goto out; +#endif + if ((frame.tf_eflags & PSL_I) == 0) { /* * Buggy application or kernel code has disabled diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c index 4ac211df140c2..070d459cfc1e5 100644 --- a/sys/kern/kern_clock.c +++ b/sys/kern/kern_clock.c @@ -69,6 +69,10 @@ __FBSDID("$FreeBSD$"); #include <sys/gmon.h> #endif +#ifdef HWPMC_HOOKS +#include <sys/pmckern.h> +#endif + #ifdef DEVICE_POLLING extern void hardclock_device_poll(void); #endif /* DEVICE_POLLING */ @@ -191,6 +195,11 @@ hardclock_process(frame) } } mtx_unlock_spin_flags(&sched_lock, MTX_QUIET); + +#ifdef HWPMC_HOOKS + if (PMC_CPU_HAS_SAMPLES(PCPU_GET(cpuid))) + PMC_CALL_HOOK_UNLOCKED(curthread, PMC_FN_DO_SAMPLES, NULL); +#endif } /* diff --git a/sys/kern/kern_pmc.c b/sys/kern/kern_pmc.c index c6fbb45d29288..ee0f8ec6fcb5a 100644 --- a/sys/kern/kern_pmc.c +++ b/sys/kern/kern_pmc.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003 Joseph Koshy + * Copyright (c) 2003-2005, Joseph Koshy * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,7 +35,9 @@ struct sx pmc_sx; int (*pmc_hook)(struct thread *td, int function, void *arg) = NULL; /* Interrupt handler */ -int (*pmc_intr)(int cpu, uintptr_t pc) = NULL; +int (*pmc_intr)(int cpu, uintptr_t pc, int usermode) = NULL; + +cpumask_t pmc_cpumask; /* * Since PMC(4) may not be loaded in the current kernel, the diff --git a/sys/sys/pmc.h b/sys/sys/pmc.h index 745469d1c5195..ae1d1245eb7bb 100644 --- a/sys/sys/pmc.h +++ b/sys/sys/pmc.h @@ -1347,7 +1347,7 @@ struct pmc_mdep { int (*pmd_stop_pmc)(int _cpu, int _ri); /* handle a PMC interrupt */ - int (*pmd_intr)(int _cpu, uintptr_t _pc); + int (*pmd_intr)(int _cpu, uintptr_t _pc, int _usermode); int (*pmd_describe)(int _cpu, int _ri, struct pmc_info *_pi, struct pmc **_ppmc); diff --git a/sys/sys/pmckern.h b/sys/sys/pmckern.h index 3c11172554de5..7a222da3b4dc9 100644 --- a/sys/sys/pmckern.h +++ b/sys/sys/pmckern.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003, Joseph Koshy + * Copyright (c) 2003-2005, Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,20 +39,25 @@ #include <sys/proc.h> #include <sys/sx.h> -#define PMC_FN_PROCESS_EXIT 1 -#define PMC_FN_PROCESS_EXEC 2 -#define PMC_FN_PROCESS_FORK 3 -#define PMC_FN_CSW_IN 4 -#define PMC_FN_CSW_OUT 5 +#define PMC_FN_PROCESS_EXEC 1 +#define PMC_FN_CSW_IN 2 +#define PMC_FN_CSW_OUT 3 +#define PMC_FN_DO_SAMPLES 4 + +#define PMC_FN_PROCESS_EXIT 5 /* obsolete */ +#define PMC_FN_PROCESS_FORK 6 /* obsolete */ /* hook */ extern int (*pmc_hook)(struct thread *_td, int _function, void *_arg); -extern int (*pmc_intr)(int cpu, uintptr_t pc); +extern int (*pmc_intr)(int _cpu, uintptr_t _pc, int _usermode); /* SX lock protecting the hook */ extern struct sx pmc_sx; -/* hook invocation; for use within the kernel */ +/* Per-cpu flags indicating availability of sampling data */ +extern cpumask_t pmc_cpumask; + +/* Hook invocation; for use within the kernel */ #define PMC_CALL_HOOK(t, cmd, arg) \ do { \ sx_slock(&pmc_sx); \ @@ -61,7 +66,7 @@ do { \ sx_sunlock(&pmc_sx); \ } while (0) -/* hook invocation that needs an exclusive lock */ +/* Hook invocation that needs an exclusive lock */ #define PMC_CALL_HOOK_X(t, cmd, arg) \ do { \ sx_xlock(&pmc_sx); \ @@ -70,22 +75,26 @@ do { \ sx_xunlock(&pmc_sx); \ } while (0) -/* context switches cannot take locks */ -#define PMC_SWITCH_CONTEXT(t, cmd) \ +/* + * Some hook invocations (e.g., from context switch and clock handling + * code) need to be lock-free. + */ +#define PMC_CALL_HOOK_UNLOCKED(t, cmd, arg) \ do { \ if (pmc_hook != NULL) \ - (pmc_hook)((t), (cmd), NULL); \ + (pmc_hook)((t), (cmd), (arg)); \ } while (0) +#define PMC_SWITCH_CONTEXT(t,cmd) PMC_CALL_HOOK_UNLOCKED(t,cmd,NULL) -/* - * check if a process is using HWPMCs. - */ - +/* Check if a process is using HWPMCs.*/ #define PMC_PROC_IS_USING_PMCS(p) \ (__predict_false(atomic_load_acq_int(&(p)->p_flag) & \ P_HWPMC)) +/* Check if a CPU has recorded samples. */ +#define PMC_CPU_HAS_SAMPLES(C) (__predict_false(pmc_cpumask & (1 << (C)))) + /* helper functions */ int pmc_cpu_is_disabled(int _cpu); int pmc_cpu_is_logical(int _cpu); |
