subr_prof.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /* $OpenBSD: subr_prof.c,v 1.28 2015/03/14 03:38:50 jsg Exp $ */
  2. /* $NetBSD: subr_prof.c,v 1.12 1996/04/22 01:38:50 christos Exp $ */
  3. /*-
  4. * Copyright (c) 1982, 1986, 1993
  5. * The Regents of the University of California. All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the name of the University nor the names of its contributors
  16. * may be used to endorse or promote products derived from this software
  17. * without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  20. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  23. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  25. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  28. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29. * SUCH DAMAGE.
  30. *
  31. * @(#)subr_prof.c 8.3 (Berkeley) 9/23/93
  32. */
  33. #include <sys/param.h>
  34. #include <sys/systm.h>
  35. #include <sys/proc.h>
  36. #include <sys/resourcevar.h>
  37. #include <sys/mount.h>
  38. #include <sys/sysctl.h>
  39. #include <sys/syscallargs.h>
  40. #ifdef GPROF
  41. #include <sys/malloc.h>
  42. #include <sys/gmon.h>
  43. #include <uvm/uvm_extern.h>
  44. /*
  45. * Flag to prevent CPUs from executing the mcount() monitor function
  46. * until we're sure they are in a sane state.
  47. */
  48. int gmoninit = 0;
  49. extern char etext[];
  50. void
  51. kmstartup(void)
  52. {
  53. CPU_INFO_ITERATOR cii;
  54. struct cpu_info *ci;
  55. struct gmonparam *p;
  56. u_long lowpc, highpc, textsize;
  57. u_long kcountsize, fromssize, tossize;
  58. long tolimit;
  59. char *cp;
  60. int size;
  61. /*
  62. * Round lowpc and highpc to multiples of the density we're using
  63. * so the rest of the scaling (here and in gprof) stays in ints.
  64. */
  65. lowpc = ROUNDDOWN(KERNBASE, HISTFRACTION * sizeof(HISTCOUNTER));
  66. highpc = ROUNDUP((u_long)etext, HISTFRACTION * sizeof(HISTCOUNTER));
  67. textsize = highpc - lowpc;
  68. printf("Profiling kernel, textsize=%ld [%lx..%lx]\n",
  69. textsize, lowpc, highpc);
  70. kcountsize = textsize / HISTFRACTION;
  71. fromssize = textsize / HASHFRACTION;
  72. tolimit = textsize * ARCDENSITY / 100;
  73. if (tolimit < MINARCS)
  74. tolimit = MINARCS;
  75. else if (tolimit > MAXARCS)
  76. tolimit = MAXARCS;
  77. tossize = tolimit * sizeof(struct tostruct);
  78. size = sizeof(*p) + kcountsize + fromssize + tossize;
  79. /* Allocate and initialize one profiling buffer per CPU. */
  80. CPU_INFO_FOREACH(cii, ci) {
  81. cp = km_alloc(round_page(size), &kv_any, &kp_zero, &kd_nowait);
  82. if (cp == NULL) {
  83. printf("No memory for profiling.\n");
  84. return;
  85. }
  86. p = (struct gmonparam *)cp;
  87. cp += sizeof(*p);
  88. p->tos = (struct tostruct *)cp;
  89. cp += tossize;
  90. p->kcount = (u_short *)cp;
  91. cp += kcountsize;
  92. p->froms = (u_short *)cp;
  93. p->state = GMON_PROF_OFF;
  94. p->lowpc = lowpc;
  95. p->highpc = highpc;
  96. p->textsize = textsize;
  97. p->hashfraction = HASHFRACTION;
  98. p->kcountsize = kcountsize;
  99. p->fromssize = fromssize;
  100. p->tolimit = tolimit;
  101. p->tossize = tossize;
  102. ci->ci_gmon = p;
  103. }
  104. }
  105. /*
  106. * Return kernel profiling information.
  107. */
  108. int
  109. sysctl_doprof(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
  110. size_t newlen)
  111. {
  112. CPU_INFO_ITERATOR cii;
  113. struct cpu_info *ci;
  114. struct gmonparam *gp = NULL;
  115. int error, cpuid, op;
  116. /* all sysctl names at this level are name and field */
  117. if (namelen != 2)
  118. return (ENOTDIR); /* overloaded */
  119. op = name[0];
  120. cpuid = name[1];
  121. CPU_INFO_FOREACH(cii, ci) {
  122. if (cpuid == CPU_INFO_UNIT(ci)) {
  123. gp = ci->ci_gmon;
  124. break;
  125. }
  126. }
  127. if (gp == NULL)
  128. return (EOPNOTSUPP);
  129. /* Assume that if we're here it is safe to execute profiling. */
  130. gmoninit = 1;
  131. switch (op) {
  132. case GPROF_STATE:
  133. error = sysctl_int(oldp, oldlenp, newp, newlen, &gp->state);
  134. if (error)
  135. return (error);
  136. if (gp->state == GMON_PROF_OFF)
  137. stopprofclock(&process0);
  138. else
  139. startprofclock(&process0);
  140. return (0);
  141. case GPROF_COUNT:
  142. return (sysctl_struct(oldp, oldlenp, newp, newlen,
  143. gp->kcount, gp->kcountsize));
  144. case GPROF_FROMS:
  145. return (sysctl_struct(oldp, oldlenp, newp, newlen,
  146. gp->froms, gp->fromssize));
  147. case GPROF_TOS:
  148. return (sysctl_struct(oldp, oldlenp, newp, newlen,
  149. gp->tos, gp->tossize));
  150. case GPROF_GMONPARAM:
  151. return (sysctl_rdstruct(oldp, oldlenp, newp, gp, sizeof *gp));
  152. default:
  153. return (EOPNOTSUPP);
  154. }
  155. /* NOTREACHED */
  156. }
  157. #endif /* GPROF */
  158. /*
  159. * Profiling system call.
  160. *
  161. * The scale factor is a fixed point number with 16 bits of fraction, so that
  162. * 1.0 is represented as 0x10000. A scale factor of 0 turns off profiling.
  163. */
  164. /* ARGSUSED */
  165. int
  166. sys_profil(struct proc *p, void *v, register_t *retval)
  167. {
  168. struct sys_profil_args /* {
  169. syscallarg(caddr_t) samples;
  170. syscallarg(size_t) size;
  171. syscallarg(u_long) offset;
  172. syscallarg(u_int) scale;
  173. } */ *uap = v;
  174. struct process *pr = p->p_p;
  175. struct uprof *upp;
  176. int s;
  177. if (SCARG(uap, scale) > (1 << 16))
  178. return (EINVAL);
  179. if (SCARG(uap, scale) == 0) {
  180. stopprofclock(pr);
  181. return (0);
  182. }
  183. upp = &pr->ps_prof;
  184. /* Block profile interrupts while changing state. */
  185. s = splstatclock();
  186. upp->pr_off = SCARG(uap, offset);
  187. upp->pr_scale = SCARG(uap, scale);
  188. upp->pr_base = (caddr_t)SCARG(uap, samples);
  189. upp->pr_size = SCARG(uap, size);
  190. startprofclock(pr);
  191. splx(s);
  192. return (0);
  193. }
  194. /*
  195. * Scale is a fixed-point number with the binary point 16 bits
  196. * into the value, and is <= 1.0. pc is at most 32 bits, so the
  197. * intermediate result is at most 48 bits.
  198. */
  199. #define PC_TO_INDEX(pc, prof) \
  200. ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
  201. (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
  202. /*
  203. * Collect user-level profiling statistics; called on a profiling tick,
  204. * when a process is running in user-mode. This routine may be called
  205. * from an interrupt context. Schedule an AST that will vector us to
  206. * trap() with a context in which copyin and copyout will work.
  207. * Trap will then call addupc_task().
  208. */
  209. void
  210. addupc_intr(struct proc *p, u_long pc)
  211. {
  212. struct uprof *prof;
  213. prof = &p->p_p->ps_prof;
  214. if (pc < prof->pr_off || PC_TO_INDEX(pc, prof) >= prof->pr_size)
  215. return; /* out of range; ignore */
  216. p->p_prof_addr = pc;
  217. p->p_prof_ticks++;
  218. atomic_setbits_int(&p->p_flag, P_OWEUPC);
  219. need_proftick(p);
  220. }
  221. /*
  222. * Much like before, but we can afford to take faults here. If the
  223. * update fails, we simply turn off profiling.
  224. */
  225. void
  226. addupc_task(struct proc *p, u_long pc, u_int nticks)
  227. {
  228. struct process *pr = p->p_p;
  229. struct uprof *prof;
  230. caddr_t addr;
  231. u_int i;
  232. u_short v;
  233. /* Testing PS_PROFIL may be unnecessary, but is certainly safe. */
  234. if ((pr->ps_flags & PS_PROFIL) == 0 || nticks == 0)
  235. return;
  236. prof = &pr->ps_prof;
  237. if (pc < prof->pr_off ||
  238. (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
  239. return;
  240. addr = prof->pr_base + i;
  241. if (copyin(addr, (caddr_t)&v, sizeof(v)) == 0) {
  242. v += nticks;
  243. if (copyout((caddr_t)&v, addr, sizeof(v)) == 0)
  244. return;
  245. }
  246. stopprofclock(pr);
  247. }