xref: /freebsd/sys/kern/subr_prof.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1df8bae1dSRodney W. Grimes /*-
251369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni  *
4df8bae1dSRodney W. Grimes  * Copyright (c) 1982, 1986, 1993
5df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
6df8bae1dSRodney W. Grimes  *
7df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
8df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
9df8bae1dSRodney W. Grimes  * are met:
10df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
11df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
12df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
13df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
14df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
1569a28758SEd Maste  * 3. Neither the name of the University nor the names of its contributors
16df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
17df8bae1dSRodney W. Grimes  *    without specific prior written permission.
18df8bae1dSRodney W. Grimes  *
19df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
30df8bae1dSRodney W. Grimes  */
31df8bae1dSRodney W. Grimes 
32df8bae1dSRodney W. Grimes #include <sys/param.h>
33df8bae1dSRodney W. Grimes #include <sys/systm.h>
34d2d3e875SBruce Evans #include <sys/sysproto.h>
359e420850SBruce Evans #include <sys/kernel.h>
36fb919e4dSMark Murray #include <sys/lock.h>
37fb919e4dSMark Murray #include <sys/mutex.h>
38df8bae1dSRodney W. Grimes #include <sys/proc.h>
392baeef32SBruce Evans #include <sys/resourcevar.h>
409e420850SBruce Evans #include <sys/sysctl.h>
41b5e8ce9fSBruce Evans 
42df8bae1dSRodney W. Grimes #include <machine/cpu.h>
43df8bae1dSRodney W. Grimes 
44df8bae1dSRodney W. Grimes /*
45df8bae1dSRodney W. Grimes  * Profiling system call.
46df8bae1dSRodney W. Grimes  *
47df8bae1dSRodney W. Grimes  * The scale factor is a fixed point number with 16 bits of fraction, so that
48df8bae1dSRodney W. Grimes  * 1.0 is represented as 0x10000.  A scale factor of 0 turns off profiling.
49df8bae1dSRodney W. Grimes  */
50d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
51df8bae1dSRodney W. Grimes struct profil_args {
52df8bae1dSRodney W. Grimes 	caddr_t	samples;
53134e06feSBruce Evans 	size_t	size;
54134e06feSBruce Evans 	size_t	offset;
55df8bae1dSRodney W. Grimes 	u_int	scale;
56df8bae1dSRodney W. Grimes };
57d2d3e875SBruce Evans #endif
58df8bae1dSRodney W. Grimes /* ARGSUSED */
5926f9a767SRodney W. Grimes int
sys_profil(struct thread * td,struct profil_args * uap)608451d0ddSKip Macy sys_profil(struct thread *td, struct profil_args *uap)
61df8bae1dSRodney W. Grimes {
62a282253aSJulian Elischer 	struct uprof *upp;
639752f794SJohn Baldwin 	struct proc *p;
64df8bae1dSRodney W. Grimes 
659752f794SJohn Baldwin 	if (uap->scale > (1 << 16))
669752f794SJohn Baldwin 		return (EINVAL);
676f1e8c18SMatthew Dillon 
689752f794SJohn Baldwin 	p = td->td_proc;
69df8bae1dSRodney W. Grimes 	if (uap->scale == 0) {
70a3a70178SJohn Baldwin 		PROC_LOCK(p);
71a3a70178SJohn Baldwin 		stopprofclock(p);
72a3a70178SJohn Baldwin 		PROC_UNLOCK(p);
739752f794SJohn Baldwin 		return (0);
74df8bae1dSRodney W. Grimes 	}
75a3a70178SJohn Baldwin 	PROC_LOCK(p);
76b40ce416SJulian Elischer 	upp = &td->td_proc->p_stats->p_prof;
775c7bebf9SKonstantin Belousov 	PROC_PROFLOCK(p);
78df8bae1dSRodney W. Grimes 	upp->pr_off = uap->offset;
79df8bae1dSRodney W. Grimes 	upp->pr_scale = uap->scale;
80df8bae1dSRodney W. Grimes 	upp->pr_base = uap->samples;
81df8bae1dSRodney W. Grimes 	upp->pr_size = uap->size;
825c7bebf9SKonstantin Belousov 	PROC_PROFUNLOCK(p);
839752f794SJohn Baldwin 	startprofclock(p);
849752f794SJohn Baldwin 	PROC_UNLOCK(p);
85df8bae1dSRodney W. Grimes 
869752f794SJohn Baldwin 	return (0);
87df8bae1dSRodney W. Grimes }
88df8bae1dSRodney W. Grimes 
89df8bae1dSRodney W. Grimes /*
90df8bae1dSRodney W. Grimes  * Scale is a fixed-point number with the binary point 16 bits
91df8bae1dSRodney W. Grimes  * into the value, and is <= 1.0.  pc is at most 32 bits, so the
92df8bae1dSRodney W. Grimes  * intermediate result is at most 48 bits.
93df8bae1dSRodney W. Grimes  */
94df8bae1dSRodney W. Grimes #define	PC_TO_INDEX(pc, prof) \
95df8bae1dSRodney W. Grimes 	((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
96df8bae1dSRodney W. Grimes 	    (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
97df8bae1dSRodney W. Grimes 
98df8bae1dSRodney W. Grimes /*
99df8bae1dSRodney W. Grimes  * Collect user-level profiling statistics; called on a profiling tick,
100df8bae1dSRodney W. Grimes  * when a process is running in user-mode.  This routine may be called
101cee61c8cSBrooks Davis  * from an interrupt context.  We perform the update with an AST
102cee61c8cSBrooks Davis  * that will vector us to trap() with a context in which copyin and
103cee61c8cSBrooks Davis  * copyout will work.  Trap will then call addupc_task().
104df8bae1dSRodney W. Grimes  *
105df8bae1dSRodney W. Grimes  * Note that we may (rarely) not get around to the AST soon enough, and
106df8bae1dSRodney W. Grimes  * lose profile ticks when the next tick overwrites this one, but in this
107df8bae1dSRodney W. Grimes  * case the system is overloaded and the profile is probably already
108df8bae1dSRodney W. Grimes  * inaccurate.
109df8bae1dSRodney W. Grimes  */
110df8bae1dSRodney W. Grimes void
addupc_intr(struct thread * td,uintfptr_t pc,u_int ticks)111cb49fcd1SJohn Baldwin addupc_intr(struct thread *td, uintfptr_t pc, u_int ticks)
112df8bae1dSRodney W. Grimes {
113a282253aSJulian Elischer 	struct uprof *prof;
114df8bae1dSRodney W. Grimes 
115df8bae1dSRodney W. Grimes 	if (ticks == 0)
116df8bae1dSRodney W. Grimes 		return;
1174a338afdSJulian Elischer 	prof = &td->td_proc->p_stats->p_prof;
1185c7bebf9SKonstantin Belousov 	PROC_PROFLOCK(td->td_proc);
119cee61c8cSBrooks Davis 	if (pc < prof->pr_off || PC_TO_INDEX(pc, prof) >= prof->pr_size) {
1205c7bebf9SKonstantin Belousov 		PROC_PROFUNLOCK(td->td_proc);
121df8bae1dSRodney W. Grimes 		return;			/* out of range; ignore */
122a3a70178SJohn Baldwin 	}
123df8bae1dSRodney W. Grimes 
1245c7bebf9SKonstantin Belousov 	PROC_PROFUNLOCK(td->td_proc);
12552eb8464SJohn Baldwin 	td->td_profil_addr = pc;
12652eb8464SJohn Baldwin 	td->td_profil_ticks = ticks;
12752eb8464SJohn Baldwin 	td->td_pflags |= TDP_OWEUPC;
128*c6d31b83SKonstantin Belousov 	ast_sched(td, TDA_OWEUPC);
129df8bae1dSRodney W. Grimes }
130df8bae1dSRodney W. Grimes 
131df8bae1dSRodney W. Grimes /*
132cee61c8cSBrooks Davis  * Actually update the profiling statistics.  If the update fails, we
133cee61c8cSBrooks Davis  * simply turn off profiling.
134df8bae1dSRodney W. Grimes  */
135037d027cSBruce Evans void
addupc_task(struct thread * td,uintfptr_t pc,u_int ticks)136cb49fcd1SJohn Baldwin addupc_task(struct thread *td, uintfptr_t pc, u_int ticks)
137df8bae1dSRodney W. Grimes {
1384a338afdSJulian Elischer 	struct proc *p = td->td_proc;
139a282253aSJulian Elischer 	struct uprof *prof;
140a282253aSJulian Elischer 	caddr_t addr;
141a282253aSJulian Elischer 	u_int i;
142df8bae1dSRodney W. Grimes 	u_short v;
143a282253aSJulian Elischer 	int stop = 0;
144df8bae1dSRodney W. Grimes 
14548fd1f38SJohn Baldwin 	if (ticks == 0)
146df8bae1dSRodney W. Grimes 		return;
147df8bae1dSRodney W. Grimes 
148a282253aSJulian Elischer 	PROC_LOCK(p);
1499752f794SJohn Baldwin 	if (!(p->p_flag & P_PROFIL)) {
150a282253aSJulian Elischer 		PROC_UNLOCK(p);
151a282253aSJulian Elischer 		return;
152a282253aSJulian Elischer 	}
153a282253aSJulian Elischer 	p->p_profthreads++;
154df8bae1dSRodney W. Grimes 	prof = &p->p_stats->p_prof;
1555c7bebf9SKonstantin Belousov 	PROC_PROFLOCK(p);
156df8bae1dSRodney W. Grimes 	if (pc < prof->pr_off ||
157a282253aSJulian Elischer 	    (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size) {
1585c7bebf9SKonstantin Belousov 		PROC_PROFUNLOCK(p);
159a282253aSJulian Elischer 		goto out;
160a282253aSJulian Elischer 	}
161df8bae1dSRodney W. Grimes 
162df8bae1dSRodney W. Grimes 	addr = prof->pr_base + i;
1635c7bebf9SKonstantin Belousov 	PROC_PROFUNLOCK(p);
164a3a70178SJohn Baldwin 	PROC_UNLOCK(p);
16501609114SAlfred Perlstein 	if (copyin(addr, &v, sizeof(v)) == 0) {
166df8bae1dSRodney W. Grimes 		v += ticks;
167a3a70178SJohn Baldwin 		if (copyout(&v, addr, sizeof(v)) == 0) {
168a3a70178SJohn Baldwin 			PROC_LOCK(p);
169a282253aSJulian Elischer 			goto out;
170df8bae1dSRodney W. Grimes 		}
171a3a70178SJohn Baldwin 	}
172a282253aSJulian Elischer 	stop = 1;
173a3a70178SJohn Baldwin 	PROC_LOCK(p);
174a282253aSJulian Elischer 
175a282253aSJulian Elischer out:
176a282253aSJulian Elischer 	if (--p->p_profthreads == 0) {
1779752f794SJohn Baldwin 		if (p->p_flag & P_STOPPROF) {
178a282253aSJulian Elischer 			wakeup(&p->p_profthreads);
1790436fcb8SKonstantin Belousov 			p->p_flag &= ~P_STOPPROF;
180a282253aSJulian Elischer 			stop = 0;
181a282253aSJulian Elischer 		}
182a282253aSJulian Elischer 	}
183a282253aSJulian Elischer 	if (stop)
184df8bae1dSRodney W. Grimes 		stopprofclock(p);
185a282253aSJulian Elischer 	PROC_UNLOCK(p);
186df8bae1dSRodney W. Grimes }
187