hwpmc_mod.c (185363) | hwpmc_mod.c (186037) |
---|---|
1/*- 2 * Copyright (c) 2003-2008 Joseph Koshy 3 * Copyright (c) 2007 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * Portions of this software were developed by A. Joseph Koshy under 7 * sponsorship from the FreeBSD Foundation and Google, Inc. 8 * --- 16 unchanged lines hidden (view full) --- 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 */ 31 32#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2003-2008 Joseph Koshy 3 * Copyright (c) 2007 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * Portions of this software were developed by A. Joseph Koshy under 7 * sponsorship from the FreeBSD Foundation and Google, Inc. 8 * --- 16 unchanged lines hidden (view full) --- 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 */ 31 32#include <sys/cdefs.h> |
33__FBSDID("$FreeBSD: head/sys/dev/hwpmc/hwpmc_mod.c 185363 2008-11-27 09:00:47Z jkoshy $"); | 33__FBSDID("$FreeBSD: head/sys/dev/hwpmc/hwpmc_mod.c 186037 2008-12-13 13:07:12Z jkoshy $"); |
34 35#include <sys/param.h> 36#include <sys/eventhandler.h> 37#include <sys/jail.h> 38#include <sys/kernel.h> 39#include <sys/kthread.h> 40#include <sys/limits.h> 41#include <sys/lock.h> --- 1816 unchanged lines hidden (view full) --- 1858 sx_assert(&pmc_sx, SX_LOCKED); 1859 pmc_process_munmap(td, (struct pmckern_map_out *) arg); 1860 break; 1861 1862 case PMC_FN_USER_CALLCHAIN: 1863 /* 1864 * Record a call chain. 1865 */ | 34 35#include <sys/param.h> 36#include <sys/eventhandler.h> 37#include <sys/jail.h> 38#include <sys/kernel.h> 39#include <sys/kthread.h> 40#include <sys/limits.h> 41#include <sys/lock.h> --- 1816 unchanged lines hidden (view full) --- 1858 sx_assert(&pmc_sx, SX_LOCKED); 1859 pmc_process_munmap(td, (struct pmckern_map_out *) arg); 1860 break; 1861 1862 case PMC_FN_USER_CALLCHAIN: 1863 /* 1864 * Record a call chain. 1865 */ |
1866 KASSERT(td == curthread, ("[pmc,%d] td != curthread", 1867 __LINE__)); |
|
1866 pmc_capture_user_callchain(PCPU_GET(cpuid), 1867 (struct trapframe *) arg); | 1868 pmc_capture_user_callchain(PCPU_GET(cpuid), 1869 (struct trapframe *) arg); |
1870 td->td_pflags &= ~TDP_CALLCHAIN; |
|
1868 break; 1869 1870 default: 1871#ifdef DEBUG 1872 KASSERT(0, ("[pmc,%d] unknown hook %d\n", __LINE__, function)); 1873#endif 1874 break; 1875 --- 1913 unchanged lines hidden (view full) --- 3789 3790/* 3791 * Mark the thread as needing callchain capture and post an AST. The 3792 * actual callchain capture will be done in a context where it is safe 3793 * to take page faults. 3794 */ 3795 3796static void | 1871 break; 1872 1873 default: 1874#ifdef DEBUG 1875 KASSERT(0, ("[pmc,%d] unknown hook %d\n", __LINE__, function)); 1876#endif 1877 break; 1878 --- 1913 unchanged lines hidden (view full) --- 3792 3793/* 3794 * Mark the thread as needing callchain capture and post an AST. The 3795 * actual callchain capture will be done in a context where it is safe 3796 * to take page faults. 3797 */ 3798 3799static void |
3797pmc_post_callchain_ast(void) | 3800pmc_post_callchain_callback(void) |
3798{ 3799 struct thread *td; 3800 3801 td = curthread; 3802 | 3801{ 3802 struct thread *td; 3803 3804 td = curthread; 3805 |
3806 KASSERT((td->td_pflags & TDP_CALLCHAIN) == 0, 3807 ("[pmc,%d] thread %p already marked for callchain capture", 3808 __LINE__, (void *) td)); 3809 |
|
3803 /* | 3810 /* |
3804 * Mark this thread as needing processing in ast(). 3805 * td->td_pflags will be safe to touch as the process was in 3806 * user space when it was interrupted. | 3811 * Mark this thread as needing callchain capture. 3812 * `td->td_pflags' will be safe to touch because this thread 3813 * was in user space when it was interrupted. |
3807 */ 3808 td->td_pflags |= TDP_CALLCHAIN; 3809 3810 /* | 3814 */ 3815 td->td_pflags |= TDP_CALLCHAIN; 3816 3817 /* |
3811 * Again, since we've entered this function directly from 3812 * userland, `td' is guaranteed to be not locked by this CPU, 3813 * so its safe to try acquire the thread lock even though we 3814 * are executing in an NMI context. We need to acquire this 3815 * lock before touching `td_flags' because other CPUs may be 3816 * in the process of touching this field. | 3818 * Don't let this thread migrate between CPUs until callchain 3819 * capture completes. |
3817 */ | 3820 */ |
3818 thread_lock(td); 3819 td->td_flags |= TDF_ASTPENDING; 3820 thread_unlock(td); | 3821 sched_pin(); |
3821 3822 return; 3823} 3824 3825/* 3826 * Interrupt processing. 3827 * 3828 * Find a free slot in the per-cpu array of samples and capture the --- 35 unchanged lines hidden (view full) --- 3864 3865 3866 /* Fill in entry. */ 3867 PMCDBG(SAM,INT,1,"cpu=%d pm=%p tf=%p um=%d wr=%d rd=%d", cpu, pm, 3868 (void *) tf, inuserspace, 3869 (int) (psb->ps_write - psb->ps_samples), 3870 (int) (psb->ps_read - psb->ps_samples)); 3871 | 3822 3823 return; 3824} 3825 3826/* 3827 * Interrupt processing. 3828 * 3829 * Find a free slot in the per-cpu array of samples and capture the --- 35 unchanged lines hidden (view full) --- 3865 3866 3867 /* Fill in entry. */ 3868 PMCDBG(SAM,INT,1,"cpu=%d pm=%p tf=%p um=%d wr=%d rd=%d", cpu, pm, 3869 (void *) tf, inuserspace, 3870 (int) (psb->ps_write - psb->ps_samples), 3871 (int) (psb->ps_read - psb->ps_samples)); 3872 |
3873 KASSERT(pm->pm_runcount >= 0, 3874 ("[pmc,%d] pm=%p runcount %d", __LINE__, (void *) pm, 3875 pm->pm_runcount)); 3876 |
|
3872 atomic_add_rel_32(&pm->pm_runcount, 1); /* hold onto PMC */ 3873 ps->ps_pmc = pm; 3874 if ((td = curthread) && td->td_proc) 3875 ps->ps_pid = td->td_proc->p_pid; 3876 else 3877 ps->ps_pid = -1; 3878 ps->ps_cpu = cpu; | 3877 atomic_add_rel_32(&pm->pm_runcount, 1); /* hold onto PMC */ 3878 ps->ps_pmc = pm; 3879 if ((td = curthread) && td->td_proc) 3880 ps->ps_pid = td->td_proc->p_pid; 3881 else 3882 ps->ps_pid = -1; 3883 ps->ps_cpu = cpu; |
3884 ps->ps_td = td; |
|
3879 ps->ps_flags = inuserspace ? PMC_CC_F_USERSPACE : 0; 3880 3881 callchaindepth = (pm->pm_flags & PMC_F_CALLCHAIN) ? 3882 pmc_callchaindepth : 1; 3883 3884 if (callchaindepth == 1) 3885 ps->ps_pc[0] = PMC_TRAPFRAME_TO_PC(tf); 3886 else { 3887 /* 3888 * Kernel stack traversals can be done immediately, 3889 * while we defer to an AST for user space traversals. 3890 */ 3891 if (!inuserspace) 3892 callchaindepth = 3893 pmc_save_kernel_callchain(ps->ps_pc, 3894 callchaindepth, tf); 3895 else { | 3885 ps->ps_flags = inuserspace ? PMC_CC_F_USERSPACE : 0; 3886 3887 callchaindepth = (pm->pm_flags & PMC_F_CALLCHAIN) ? 3888 pmc_callchaindepth : 1; 3889 3890 if (callchaindepth == 1) 3891 ps->ps_pc[0] = PMC_TRAPFRAME_TO_PC(tf); 3892 else { 3893 /* 3894 * Kernel stack traversals can be done immediately, 3895 * while we defer to an AST for user space traversals. 3896 */ 3897 if (!inuserspace) 3898 callchaindepth = 3899 pmc_save_kernel_callchain(ps->ps_pc, 3900 callchaindepth, tf); 3901 else { |
3896 pmc_post_callchain_ast(); | 3902 pmc_post_callchain_callback(); |
3897 callchaindepth = PMC_SAMPLE_INUSE; 3898 } 3899 } 3900 3901 ps->ps_nsamples = callchaindepth; /* mark entry as in use */ 3902 3903 /* increment write pointer, modulo ring buffer size */ 3904 ps++; --- 15 unchanged lines hidden (view full) --- 3920 * rescheduled. 3921 */ 3922 3923static void 3924pmc_capture_user_callchain(int cpu, struct trapframe *tf) 3925{ 3926 int i; 3927 struct pmc *pm; | 3903 callchaindepth = PMC_SAMPLE_INUSE; 3904 } 3905 } 3906 3907 ps->ps_nsamples = callchaindepth; /* mark entry as in use */ 3908 3909 /* increment write pointer, modulo ring buffer size */ 3910 ps++; --- 15 unchanged lines hidden (view full) --- 3926 * rescheduled. 3927 */ 3928 3929static void 3930pmc_capture_user_callchain(int cpu, struct trapframe *tf) 3931{ 3932 int i; 3933 struct pmc *pm; |
3934 struct thread *td; |
|
3928 struct pmc_sample *ps; 3929 struct pmc_samplebuffer *psb; | 3935 struct pmc_sample *ps; 3936 struct pmc_samplebuffer *psb; |
3937#ifdef INVARIANTS 3938 int ncallchains; 3939#endif |
|
3930 | 3940 |
3941 sched_unpin(); /* Can migrate safely now. */ 3942 |
|
3931 psb = pmc_pcpu[cpu]->pc_sb; | 3943 psb = pmc_pcpu[cpu]->pc_sb; |
3944 td = curthread; |
|
3932 | 3945 |
3946 KASSERT(td->td_pflags & TDP_CALLCHAIN, 3947 ("[pmc,%d] Retrieving callchain for thread that doesn't want it", 3948 __LINE__)); 3949 3950#ifdef INVARIANTS 3951 ncallchains = 0; 3952#endif 3953 |
|
3933 /* 3934 * Iterate through all deferred callchain requests. 3935 */ 3936 | 3954 /* 3955 * Iterate through all deferred callchain requests. 3956 */ 3957 |
3937 for (i = 0; i < pmc_nsamples; i++) { | 3958 ps = psb->ps_samples; 3959 for (i = 0; i < pmc_nsamples; i++, ps++) { |
3938 | 3960 |
3939 ps = &psb->ps_samples[i]; | |
3940 if (ps->ps_nsamples != PMC_SAMPLE_INUSE) 3941 continue; | 3961 if (ps->ps_nsamples != PMC_SAMPLE_INUSE) 3962 continue; |
3963 if (ps->ps_td != td) 3964 continue; |
|
3942 | 3965 |
3966 KASSERT(ps->ps_cpu == cpu, 3967 ("[pmc,%d] cpu mismatch ps_cpu=%d pcpu=%d", __LINE__, 3968 ps->ps_cpu, PCPU_GET(cpuid))); 3969 |
|
3943 pm = ps->ps_pmc; 3944 3945 KASSERT(pm->pm_flags & PMC_F_CALLCHAIN, 3946 ("[pmc,%d] Retrieving callchain for PMC that doesn't " 3947 "want it", __LINE__)); 3948 | 3970 pm = ps->ps_pmc; 3971 3972 KASSERT(pm->pm_flags & PMC_F_CALLCHAIN, 3973 ("[pmc,%d] Retrieving callchain for PMC that doesn't " 3974 "want it", __LINE__)); 3975 |
3976 KASSERT(pm->pm_runcount > 0, 3977 ("[pmc,%d] runcount %d", __LINE__, pm->pm_runcount)); 3978 |
|
3949 /* 3950 * Retrieve the callchain and mark the sample buffer 3951 * as 'processable' by the timer tick sweep code. 3952 */ 3953 ps->ps_nsamples = pmc_save_user_callchain(ps->ps_pc, 3954 pmc_callchaindepth, tf); | 3979 /* 3980 * Retrieve the callchain and mark the sample buffer 3981 * as 'processable' by the timer tick sweep code. 3982 */ 3983 ps->ps_nsamples = pmc_save_user_callchain(ps->ps_pc, 3984 pmc_callchaindepth, tf); |
3985 3986#ifdef INVARIANTS 3987 ncallchains++; 3988#endif 3989 |
|
3955 } 3956 | 3990 } 3991 |
3992 KASSERT(ncallchains > 0, 3993 ("[pmc,%d] cpu %d didn't find a sample to collect", __LINE__, 3994 cpu)); 3995 |
|
3957 return; 3958} 3959 3960 3961/* 3962 * Process saved PC samples. 3963 */ 3964 --- 21 unchanged lines hidden (view full) --- 3986 break; 3987 if (ps->ps_nsamples == PMC_SAMPLE_INUSE) { 3988 /* Need a rescan at a later time. */ 3989 atomic_set_rel_int(&pmc_cpumask, (1 << cpu)); 3990 break; 3991 } 3992 3993 pm = ps->ps_pmc; | 3996 return; 3997} 3998 3999 4000/* 4001 * Process saved PC samples. 4002 */ 4003 --- 21 unchanged lines hidden (view full) --- 4025 break; 4026 if (ps->ps_nsamples == PMC_SAMPLE_INUSE) { 4027 /* Need a rescan at a later time. */ 4028 atomic_set_rel_int(&pmc_cpumask, (1 << cpu)); 4029 break; 4030 } 4031 4032 pm = ps->ps_pmc; |
4033 4034 KASSERT(pm->pm_runcount > 0, 4035 ("[pmc,%d] pm=%p runcount %d", __LINE__, (void *) pm, 4036 pm->pm_runcount)); 4037 |
|
3994 po = pm->pm_owner; 3995 3996 KASSERT(PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)), 3997 ("[pmc,%d] pmc=%p non-sampling mode=%d", __LINE__, 3998 pm, PMC_TO_MODE(pm))); 3999 4000 /* Ignore PMCs that have been switched off */ 4001 if (pm->pm_state != PMC_STATE_RUNNING) --- 736 unchanged lines hidden --- | 4038 po = pm->pm_owner; 4039 4040 KASSERT(PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)), 4041 ("[pmc,%d] pmc=%p non-sampling mode=%d", __LINE__, 4042 pm, PMC_TO_MODE(pm))); 4043 4044 /* Ignore PMCs that have been switched off */ 4045 if (pm->pm_state != PMC_STATE_RUNNING) --- 736 unchanged lines hidden --- |