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