Home | History | Annotate | Line # | Download | only in tprof
tprof_x86_intel.c revision 1.5.2.1
      1  1.5.2.1   martin /*	$NetBSD: tprof_x86_intel.c,v 1.5.2.1 2023/06/21 22:34:51 martin Exp $	*/
      2      1.1     maxv 
      3      1.1     maxv /*
      4      1.1     maxv  * Copyright (c) 2018 The NetBSD Foundation, Inc.
      5      1.1     maxv  * All rights reserved.
      6      1.1     maxv  *
      7      1.1     maxv  * This code is derived from software contributed to The NetBSD Foundation
      8      1.1     maxv  * by Maxime Villard.
      9      1.1     maxv  *
     10      1.1     maxv  * Redistribution and use in source and binary forms, with or without
     11      1.1     maxv  * modification, are permitted provided that the following conditions
     12      1.1     maxv  * are met:
     13      1.1     maxv  * 1. Redistributions of source code must retain the above copyright
     14      1.1     maxv  *    notice, this list of conditions and the following disclaimer.
     15      1.1     maxv  * 2. Redistributions in binary form must reproduce the above copyright
     16      1.1     maxv  *    notice, this list of conditions and the following disclaimer in the
     17      1.1     maxv  *    documentation and/or other materials provided with the distribution.
     18      1.1     maxv  *
     19      1.1     maxv  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20      1.1     maxv  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21      1.1     maxv  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22      1.1     maxv  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23      1.1     maxv  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24      1.1     maxv  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25      1.1     maxv  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26      1.1     maxv  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27      1.1     maxv  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28      1.1     maxv  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29      1.1     maxv  * POSSIBILITY OF SUCH DAMAGE.
     30      1.1     maxv  */
     31      1.1     maxv 
     32      1.1     maxv /*
     33      1.1     maxv  * Copyright (c)2008,2009 YAMAMOTO Takashi,
     34      1.1     maxv  * All rights reserved.
     35      1.1     maxv  *
     36      1.1     maxv  * Redistribution and use in source and binary forms, with or without
     37      1.1     maxv  * modification, are permitted provided that the following conditions
     38      1.1     maxv  * are met:
     39      1.1     maxv  * 1. Redistributions of source code must retain the above copyright
     40      1.1     maxv  *    notice, this list of conditions and the following disclaimer.
     41      1.1     maxv  * 2. Redistributions in binary form must reproduce the above copyright
     42      1.1     maxv  *    notice, this list of conditions and the following disclaimer in the
     43      1.1     maxv  *    documentation and/or other materials provided with the distribution.
     44      1.1     maxv  *
     45      1.1     maxv  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     46      1.1     maxv  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     47      1.1     maxv  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     48      1.1     maxv  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     49      1.1     maxv  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     50      1.1     maxv  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     51      1.1     maxv  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     52      1.1     maxv  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     53      1.1     maxv  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     54      1.1     maxv  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     55      1.1     maxv  * SUCH DAMAGE.
     56      1.1     maxv  */
     57      1.1     maxv 
     58      1.1     maxv #include <sys/cdefs.h>
     59  1.5.2.1   martin __KERNEL_RCSID(0, "$NetBSD: tprof_x86_intel.c,v 1.5.2.1 2023/06/21 22:34:51 martin Exp $");
     60      1.1     maxv 
     61      1.1     maxv #include <sys/param.h>
     62      1.1     maxv #include <sys/systm.h>
     63      1.1     maxv #include <sys/kernel.h>
     64      1.1     maxv #include <sys/module.h>
     65      1.1     maxv 
     66      1.1     maxv #include <sys/cpu.h>
     67      1.5      ryo #include <sys/percpu.h>
     68      1.1     maxv #include <sys/xcall.h>
     69      1.1     maxv 
     70      1.1     maxv #include <dev/tprof/tprof.h>
     71      1.1     maxv 
     72      1.1     maxv #include <uvm/uvm.h>		/* VM_MIN_KERNEL_ADDRESS */
     73      1.1     maxv 
     74      1.1     maxv #include <x86/nmi.h>
     75      1.1     maxv 
     76      1.1     maxv #include <machine/cpufunc.h>
     77      1.1     maxv #include <machine/cputypes.h>	/* CPUVENDOR_* */
     78      1.1     maxv #include <machine/cpuvar.h>	/* cpu_vendor */
     79      1.1     maxv #include <machine/i82489reg.h>
     80      1.1     maxv #include <machine/i82489var.h>
     81      1.1     maxv 
     82      1.5      ryo static u_int counter_bitwidth;
     83      1.5      ryo 
     84      1.5      ryo #define	PERFEVTSEL(i)		(MSR_EVNTSEL0 + (i))
     85      1.5      ryo #define	PERFCTR(i)		(MSR_PERFCTR0 + (i))
     86      1.5      ryo 
     87      1.1     maxv #define	PERFEVTSEL_EVENT_SELECT	__BITS(0, 7)
     88      1.1     maxv #define	PERFEVTSEL_UNIT_MASK	__BITS(8, 15)
     89      1.1     maxv #define	PERFEVTSEL_USR		__BIT(16)
     90      1.1     maxv #define	PERFEVTSEL_OS		__BIT(17)
     91      1.1     maxv #define	PERFEVTSEL_E		__BIT(18)
     92      1.1     maxv #define	PERFEVTSEL_PC		__BIT(19)
     93      1.1     maxv #define	PERFEVTSEL_INT		__BIT(20)
     94      1.1     maxv #define	PERFEVTSEL_EN		__BIT(22)
     95      1.1     maxv #define	PERFEVTSEL_INV		__BIT(23)
     96      1.1     maxv #define	PERFEVTSEL_COUNTER_MASK	__BITS(24, 31)
     97      1.1     maxv 
     98      1.1     maxv static uint32_t intel_lapic_saved[MAXCPUS];
     99      1.1     maxv static nmi_handler_t *intel_nmi_handle;
    100      1.5      ryo 
    101      1.5      ryo static uint32_t
    102      1.5      ryo tprof_intel_ncounters(void)
    103      1.5      ryo {
    104  1.5.2.1   martin 	uint32_t descs[4];
    105  1.5.2.1   martin 
    106  1.5.2.1   martin 	if (cpuid_level < 0x0a)
    107  1.5.2.1   martin 		return 0;
    108  1.5.2.1   martin 
    109  1.5.2.1   martin 	x86_cpuid(0x0a, descs);
    110  1.5.2.1   martin 
    111  1.5.2.1   martin 	return __SHIFTOUT(descs[0], CPUID_PERF_NGPPC);
    112      1.5      ryo }
    113      1.5      ryo 
    114      1.5      ryo static u_int
    115      1.5      ryo tprof_intel_counter_bitwidth(u_int counter)
    116      1.5      ryo {
    117  1.5.2.1   martin 
    118      1.5      ryo 	return counter_bitwidth;
    119      1.5      ryo }
    120      1.5      ryo 
    121      1.5      ryo static inline void
    122      1.5      ryo tprof_intel_counter_write(u_int counter, uint64_t val)
    123      1.5      ryo {
    124  1.5.2.1   martin 
    125      1.5      ryo 	wrmsr(PERFCTR(counter), val);
    126      1.5      ryo }
    127      1.5      ryo 
    128      1.5      ryo static inline uint64_t
    129      1.5      ryo tprof_intel_counter_read(u_int counter)
    130      1.5      ryo {
    131  1.5.2.1   martin 
    132      1.5      ryo 	return rdmsr(PERFCTR(counter));
    133      1.5      ryo }
    134      1.1     maxv 
    135      1.1     maxv static void
    136      1.5      ryo tprof_intel_configure_event(u_int counter, const tprof_param_t *param)
    137      1.1     maxv {
    138      1.1     maxv 	uint64_t evtval;
    139      1.1     maxv 
    140      1.1     maxv 	evtval =
    141      1.5      ryo 	    __SHIFTIN(param->p_event, PERFEVTSEL_EVENT_SELECT) |
    142      1.5      ryo 	    __SHIFTIN(param->p_unit, PERFEVTSEL_UNIT_MASK) |
    143      1.5      ryo 	    ((param->p_flags & TPROF_PARAM_USER) ? PERFEVTSEL_USR : 0) |
    144      1.5      ryo 	    ((param->p_flags & TPROF_PARAM_KERN) ? PERFEVTSEL_OS : 0) |
    145      1.5      ryo 	    PERFEVTSEL_INT;
    146      1.5      ryo 	wrmsr(PERFEVTSEL(counter), evtval);
    147      1.1     maxv 
    148  1.5.2.1   martin 	/* Reset the counter */
    149      1.5      ryo 	tprof_intel_counter_write(counter, param->p_value);
    150      1.5      ryo }
    151      1.1     maxv 
    152      1.5      ryo static void
    153      1.5      ryo tprof_intel_start(tprof_countermask_t runmask)
    154      1.5      ryo {
    155      1.5      ryo 	int bit;
    156      1.5      ryo 
    157      1.5      ryo 	while ((bit = ffs(runmask)) != 0) {
    158      1.5      ryo 		bit--;
    159      1.5      ryo 		CLR(runmask, __BIT(bit));
    160      1.5      ryo 		wrmsr(PERFEVTSEL(bit), rdmsr(PERFEVTSEL(bit)) | PERFEVTSEL_EN);
    161      1.5      ryo 	}
    162      1.1     maxv }
    163      1.1     maxv 
    164      1.1     maxv static void
    165      1.5      ryo tprof_intel_stop(tprof_countermask_t stopmask)
    166      1.1     maxv {
    167      1.5      ryo 	int bit;
    168      1.1     maxv 
    169      1.5      ryo 	while ((bit = ffs(stopmask)) != 0) {
    170      1.5      ryo 		bit--;
    171      1.5      ryo 		CLR(stopmask, __BIT(bit));
    172  1.5.2.1   martin 		wrmsr(PERFEVTSEL(bit), rdmsr(PERFEVTSEL(bit)) &
    173  1.5.2.1   martin 		    ~PERFEVTSEL_EN);
    174      1.5      ryo 	}
    175      1.1     maxv }
    176      1.1     maxv 
    177      1.1     maxv static int
    178      1.5      ryo tprof_intel_nmi(const struct trapframe *tf, void *arg)
    179      1.1     maxv {
    180      1.5      ryo 	tprof_backend_softc_t *sc = arg;
    181      1.5      ryo 	tprof_frame_info_t tfi;
    182      1.1     maxv 	uint32_t pcint;
    183      1.5      ryo 	int bit;
    184      1.1     maxv 
    185      1.5      ryo 	uint64_t *counters_offset =
    186      1.5      ryo 	    percpu_getptr_remote(sc->sc_ctr_offset_percpu, curcpu());
    187      1.5      ryo 	tprof_countermask_t mask = sc->sc_ctr_ovf_mask;
    188      1.5      ryo 	while ((bit = ffs(mask)) != 0) {
    189      1.5      ryo 		bit--;
    190      1.5      ryo 		CLR(mask, __BIT(bit));
    191      1.5      ryo 
    192      1.5      ryo 		/* If the highest bit is non zero, then it's not for us. */
    193      1.5      ryo 		uint64_t ctr = tprof_intel_counter_read(bit);
    194      1.5      ryo 		if ((ctr & __BIT(counter_bitwidth - 1)) != 0)
    195      1.5      ryo 			continue;	/* not overflowed */
    196      1.5      ryo 
    197      1.5      ryo 		if (ISSET(sc->sc_ctr_prof_mask, __BIT(bit))) {
    198  1.5.2.1   martin 			/* Account for the counter, and reset */
    199      1.5      ryo 			tprof_intel_counter_write(bit,
    200      1.5      ryo 			    sc->sc_count[bit].ctr_counter_reset_val);
    201      1.5      ryo 			counters_offset[bit] +=
    202      1.5      ryo 			    sc->sc_count[bit].ctr_counter_val + ctr;
    203      1.1     maxv 
    204  1.5.2.1   martin 			/* Record a sample */
    205      1.1     maxv #if defined(__x86_64__)
    206      1.5      ryo 			tfi.tfi_pc = tf->tf_rip;
    207      1.1     maxv #else
    208      1.5      ryo 			tfi.tfi_pc = tf->tf_eip;
    209      1.1     maxv #endif
    210      1.5      ryo 			tfi.tfi_counter = bit;
    211      1.5      ryo 			tfi.tfi_inkernel = tfi.tfi_pc >= VM_MIN_KERNEL_ADDRESS;
    212      1.5      ryo 			tprof_sample(NULL, &tfi);
    213      1.5      ryo 		} else {
    214  1.5.2.1   martin 			/* Not profiled, but require to consider overflow */
    215      1.5      ryo 			counters_offset[bit] += __BIT(counter_bitwidth);
    216      1.5      ryo 		}
    217      1.5      ryo 	}
    218      1.1     maxv 
    219  1.5.2.1   martin 	/* Unmask PMI */
    220      1.3  msaitoh 	pcint = lapic_readreg(LAPIC_LVT_PCINT);
    221      1.1     maxv 	KASSERT((pcint & LAPIC_LVT_MASKED) != 0);
    222      1.3  msaitoh 	lapic_writereg(LAPIC_LVT_PCINT, pcint & ~LAPIC_LVT_MASKED);
    223      1.1     maxv 
    224      1.1     maxv 	return 1;
    225      1.1     maxv }
    226      1.1     maxv 
    227      1.1     maxv static uint64_t
    228      1.5      ryo tprof_intel_counter_estimate_freq(u_int counter)
    229      1.1     maxv {
    230  1.5.2.1   martin 
    231      1.5      ryo 	return curcpu()->ci_data.cpu_cc_freq;
    232      1.1     maxv }
    233      1.1     maxv 
    234      1.1     maxv static uint32_t
    235      1.1     maxv tprof_intel_ident(void)
    236      1.1     maxv {
    237      1.1     maxv 	uint32_t descs[4];
    238      1.1     maxv 
    239  1.5.2.1   martin 	if (cpu_vendor != CPUVENDOR_INTEL)
    240      1.1     maxv 		return TPROF_IDENT_NONE;
    241      1.1     maxv 
    242  1.5.2.1   martin 	if (cpuid_level < 0x0a)
    243      1.1     maxv 		return TPROF_IDENT_NONE;
    244  1.5.2.1   martin 
    245  1.5.2.1   martin 	x86_cpuid(0x0a, descs);
    246  1.5.2.1   martin 	if ((descs[0] & CPUID_PERF_VERSION) == 0)
    247      1.1     maxv 		return TPROF_IDENT_NONE;
    248  1.5.2.1   martin 
    249  1.5.2.1   martin 	if ((descs[0] & CPUID_PERF_NGPPC) == 0)
    250      1.1     maxv 		return TPROF_IDENT_NONE;
    251      1.1     maxv 
    252      1.4  msaitoh 	counter_bitwidth = __SHIFTOUT(descs[0], CPUID_PERF_NBWGPPC);
    253      1.1     maxv 
    254      1.1     maxv 	return TPROF_IDENT_INTEL_GENERIC;
    255      1.1     maxv }
    256      1.1     maxv 
    257      1.5      ryo static void
    258      1.5      ryo tprof_intel_establish_cpu(void *arg1, void *arg2)
    259      1.5      ryo {
    260      1.5      ryo 	struct cpu_info * const ci = curcpu();
    261      1.5      ryo 
    262      1.5      ryo 	intel_lapic_saved[cpu_index(ci)] = lapic_readreg(LAPIC_LVT_PCINT);
    263      1.5      ryo 	lapic_writereg(LAPIC_LVT_PCINT, LAPIC_DLMODE_NMI);
    264      1.5      ryo }
    265      1.5      ryo 
    266      1.5      ryo static void
    267      1.5      ryo tprof_intel_disestablish_cpu(void *arg1, void *arg2)
    268      1.5      ryo {
    269      1.5      ryo 	struct cpu_info * const ci = curcpu();
    270      1.5      ryo 
    271      1.5      ryo 	lapic_writereg(LAPIC_LVT_PCINT, intel_lapic_saved[cpu_index(ci)]);
    272      1.5      ryo }
    273      1.5      ryo 
    274      1.1     maxv static int
    275      1.5      ryo tprof_intel_establish(tprof_backend_softc_t *sc)
    276      1.1     maxv {
    277      1.1     maxv 	uint64_t xc;
    278      1.1     maxv 
    279  1.5.2.1   martin 	if (tprof_intel_ident() == TPROF_IDENT_NONE)
    280      1.1     maxv 		return ENOTSUP;
    281      1.1     maxv 
    282      1.1     maxv 	KASSERT(intel_nmi_handle == NULL);
    283      1.5      ryo 	intel_nmi_handle = nmi_establish(tprof_intel_nmi, sc);
    284      1.1     maxv 
    285      1.5      ryo 	xc = xc_broadcast(0, tprof_intel_establish_cpu, sc, NULL);
    286      1.1     maxv 	xc_wait(xc);
    287      1.1     maxv 
    288      1.1     maxv 	return 0;
    289      1.1     maxv }
    290      1.1     maxv 
    291      1.1     maxv static void
    292      1.5      ryo tprof_intel_disestablish(tprof_backend_softc_t *sc)
    293      1.1     maxv {
    294      1.1     maxv 	uint64_t xc;
    295      1.1     maxv 
    296      1.5      ryo 	xc = xc_broadcast(0, tprof_intel_disestablish_cpu, sc, NULL);
    297      1.1     maxv 	xc_wait(xc);
    298      1.1     maxv 
    299      1.1     maxv 	KASSERT(intel_nmi_handle != NULL);
    300      1.1     maxv 	nmi_disestablish(intel_nmi_handle);
    301      1.1     maxv 	intel_nmi_handle = NULL;
    302      1.1     maxv }
    303      1.1     maxv 
    304      1.2     maxv const tprof_backend_ops_t tprof_intel_ops = {
    305      1.1     maxv 	.tbo_ident = tprof_intel_ident,
    306      1.5      ryo 	.tbo_ncounters = tprof_intel_ncounters,
    307      1.5      ryo 	.tbo_counter_bitwidth = tprof_intel_counter_bitwidth,
    308      1.5      ryo 	.tbo_counter_read = tprof_intel_counter_read,
    309      1.5      ryo 	.tbo_counter_estimate_freq = tprof_intel_counter_estimate_freq,
    310      1.5      ryo 	.tbo_valid_event = NULL,
    311      1.5      ryo 	.tbo_configure_event = tprof_intel_configure_event,
    312      1.1     maxv 	.tbo_start = tprof_intel_start,
    313      1.1     maxv 	.tbo_stop = tprof_intel_stop,
    314      1.5      ryo 	.tbo_establish = tprof_intel_establish,
    315      1.5      ryo 	.tbo_disestablish = tprof_intel_disestablish,
    316      1.1     maxv };
    317