]>
git.saurik.com Git - apple/system_cmds.git/blob - kgmon.tproj/kgmon.c
2 * Copyright (c) 1983, 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
33 static const char copyright
[] =
34 "@(#) Copyright (c) 1983, 1992, 1993\n\
35 The Regents of the University of California. All rights reserved.\n";
40 static char sccsid
[] = "@(#)kgmon.c 8.1 (Berkeley) 6/6/93";
42 static const char rcsid
[] =
43 "$FreeBSD: src/usr.sbin/kgmon/kgmon.c,v 1.14 2004/08/30 03:11:46 marcel Exp $";
45 #endif /* !__APPLE__ */
47 #include <sys/param.h>
50 #include <sys/sysctl.h>
78 int Bflag
, bflag
, hflag
, kflag
, rflag
, pflag
;
80 int getprof(struct kvmvars
*);
81 int getprofhz(struct kvmvars
*);
82 void kern_readonly(int);
83 int openfiles(char *, char *, struct kvmvars
*);
84 void setprof(struct kvmvars
*kvp
, int state
);
85 void dumpstate(struct kvmvars
*kvp
);
86 void reset(struct kvmvars
*kvp
);
87 static void usage(void);
90 main(int argc
, char **argv
)
96 int ch
, mode
, disp
, accessmode
;
97 struct kvmvars kvmvars
;
104 while ((ch
= getopt(argc
, argv
, "M:N:bhpr")) != -1) {
106 while ((ch
= getopt(argc
, argv
, "M:N:Bbhpr")) != -1) {
148 #define BACKWARD_COMPATIBILITY
149 #ifdef BACKWARD_COMPATIBILITY
162 system
= (char *)getbootfile();
164 accessmode
= openfiles(system
, kmemf
, &kvmvars
);
165 mode
= getprof(&kvmvars
);
167 disp
= GMON_PROF_OFF
;
170 disp
= GMON_PROF_HIRES
;
180 if (accessmode
== O_RDWR
)
181 setprof(&kvmvars
, disp
);
182 (void)fprintf(stdout
, "kgmon: kernel profiling is %s.\n",
184 disp
== GMON_PROF_OFF
? "off" :
185 disp
== GMON_PROF_HIRES
? "running (high resolution)" :
186 disp
== GMON_PROF_ON
? "running" :
187 disp
== GMON_PROF_BUSY
? "busy" :
188 disp
== GMON_PROF_ERROR
? "off (error)" :
189 "in an unknown state");
191 disp
== GMON_PROF_OFF
? "off" : "running");
192 #endif /* __APPLE__ */
200 fprintf(stderr
, "usage: kgmon [-bhrp]\n");
202 fprintf(stderr
, "usage: kgmon [-Bbhrp] [-M core] [-N system]\n");
208 * Check that profiling is enabled and open any ncessary files.
211 openfiles(system
, kmemf
, kvp
)
217 int mib
[3], state
, openmode
;
218 char errbuf
[_POSIX2_LINE_MAX
];
223 mib
[2] = GPROF_STATE
;
225 if (sysctl(mib
, 3, &state
, &size
, NULL
, 0) < 0)
226 errx(20, "profiling not defined in kernel");
228 if (!(bflag
|| hflag
|| rflag
||
229 (pflag
&& (state
== GMON_PROF_ON
))))
232 if (!(Bflag
|| bflag
|| hflag
|| rflag
||
234 (state
== GMON_PROF_HIRES
|| state
== GMON_PROF_ON
))))
238 if (sysctl(mib
, 3, NULL
, NULL
, &state
, size
) >= 0)
240 (void)seteuid(getuid());
241 kern_readonly(state
);
245 openmode
= (bflag
|| hflag
|| pflag
|| rflag
)
247 openmode
= (Bflag
|| bflag
|| hflag
|| pflag
|| rflag
)
250 kvp
->kd
= kvm_openfiles(system
, kmemf
, NULL
, openmode
, errbuf
);
251 if (kvp
->kd
== NULL
) {
252 if (openmode
== O_RDWR
) {
254 kvp
->kd
= kvm_openfiles(system
, kmemf
, NULL
, O_RDONLY
,
258 errx(2, "kvm_openfiles: %s", errbuf
);
259 kern_readonly(GMON_PROF_ON
);
261 if (kvm_nlist(kvp
->kd
, nl
) < 0)
262 errx(3, "%s: no namelist", system
);
263 if (!nl
[N_GMONPARAM
].n_value
)
264 errx(20, "profiling not defined in kernel");
269 * Suppress options that require a writable kernel.
276 (void)fprintf(stderr
, "kgmon: kernel read-only: ");
278 if (pflag
&& mode
== GMON_PROF_ON
)
280 if (pflag
&& (mode
== GMON_PROF_HIRES
|| mode
== GMON_PROF_ON
))
282 (void)fprintf(stderr
, "data may be inconsistent\n");
284 (void)fprintf(stderr
, "-r supressed\n");
287 (void)fprintf(stderr
, "-B supressed\n");
290 (void)fprintf(stderr
, "-b supressed\n");
292 (void)fprintf(stderr
, "-h supressed\n");
294 rflag
= bflag
= hflag
= 0;
296 rflag
= Bflag
= bflag
= hflag
= 0;
301 * Get the state of kernel profiling.
311 size
= kvm_read(kvp
->kd
, nl
[N_GMONPARAM
].n_value
, &kvp
->gpm
,
316 mib
[2] = GPROF_GMONPARAM
;
317 size
= sizeof kvp
->gpm
;
318 if (sysctl(mib
, 3, &kvp
->gpm
, &size
, NULL
, 0) < 0)
323 if (size
!= sizeof kvp
->gpm
)
324 errx(4, "cannot get gmonparam: %s",
325 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
326 #else /* __APPLE__ */
328 * Accept certain undersized "structs" from old kernels. We need
329 * everything up to hashfraction, and want profrate and
330 * histcounter_type. Assume that the kernel doesn't put garbage
331 * in any padding that is returned instead of profrate and
332 * histcounter_type. This is a bad assumption for dead kernels,
333 * since kvm_read() will normally return garbage for bytes beyond
334 * the end of the actual kernel struct, if any.
336 if (size
< offsetof(struct gmonparam
, hashfraction
) +
337 sizeof(kvp
->gpm
.hashfraction
) || size
> sizeof(kvp
->gpm
))
338 errx(4, "cannot get gmonparam: %s",
339 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
340 bzero((char *)&kvp
->gpm
+ size
, sizeof(kvp
->gpm
) - size
);
341 if (kvp
->gpm
.profrate
== 0)
342 kvp
->gpm
.profrate
= getprofhz(kvp
);
344 if (kvp
->gpm
.histcounter_type
== 0) {
346 * This fixup only works for not-so-old i386 kernels. The
347 * magic 16 is the kernel FUNCTION_ALIGNMENT. 64-bit
348 * counters are signed; smaller counters are unsigned.
350 kvp
->gpm
.histcounter_type
= 16 /
351 (kvp
->gpm
.textsize
/ kvp
->gpm
.kcountsize
) * CHAR_BIT
;
352 if (kvp
->gpm
.histcounter_type
== 64)
353 kvp
->gpm
.histcounter_type
= -64;
356 #endif /* __APPLE__ */
358 return (kvp
->gpm
.state
);
362 * Enable or disable kernel profiling according to the state variable.
369 struct gmonparam
*p
= (struct gmonparam
*)nl
[N_GMONPARAM
].n_value
;
371 int mib
[3], oldstate
;
377 mib
[2] = GPROF_STATE
;
378 if (sysctl(mib
, 3, &oldstate
, &sz
, NULL
, 0) < 0)
380 if (oldstate
== state
)
383 if (sysctl(mib
, 3, NULL
, NULL
, &state
, sz
) >= 0) {
384 (void)seteuid(getuid());
387 (void)seteuid(getuid());
388 } else if (kvm_write(kvp
->kd
, (u_long
)&p
->state
, (void *)&state
, sz
)
392 warnx("warning: cannot turn profiling %s",
393 state
== GMON_PROF_OFF
? "off" : "on");
397 * Build the gmon.out file.
404 struct rawarc rawarc
;
405 struct tostruct
*tos
;
407 u_short
*froms
, *tickbuf
;
411 int fromindex
, endfrom
, toindex
;
413 setprof(kvp
, GMON_PROF_OFF
);
414 fp
= fopen("gmon.out", "w");
421 * Build the gmon header and write it to a file.
423 bzero(&h
, sizeof(h
));
424 h
.lpc
= kvp
->gpm
.lowpc
;
425 h
.hpc
= kvp
->gpm
.highpc
;
426 h
.ncnt
= kvp
->gpm
.kcountsize
+ sizeof(h
);
427 h
.version
= GMONVERSION
;
429 h
.profrate
= getprofhz(kvp
);
431 h
.profrate
= kvp
->gpm
.profrate
;
432 h
.histcounter_type
= kvp
->gpm
.histcounter_type
;
434 fwrite((char *)&h
, sizeof(h
), 1, fp
);
437 * Write out the tick buffer.
441 if ((tickbuf
= (u_short
*)malloc(kvp
->gpm
.kcountsize
)) == NULL
)
442 errx(5, "cannot allocate kcount space");
444 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.kcount
, (void *)tickbuf
,
445 kvp
->gpm
.kcountsize
);
447 mib
[2] = GPROF_COUNT
;
448 i
= kvp
->gpm
.kcountsize
;
449 if (sysctl(mib
, 3, tickbuf
, &i
, NULL
, 0) < 0)
452 if (i
!= kvp
->gpm
.kcountsize
)
453 errx(6, "read ticks: read %lu, got %ld: %s",
454 kvp
->gpm
.kcountsize
, (long)i
,
455 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
456 if ((fwrite(tickbuf
, kvp
->gpm
.kcountsize
, 1, fp
)) != 1)
457 err(7, "writing tocks to gmon.out");
461 * Write out the arc info.
463 if ((froms
= (u_short
*)malloc(kvp
->gpm
.fromssize
)) == NULL
)
464 errx(8, "cannot allocate froms space");
466 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.froms
, (void *)froms
,
469 mib
[2] = GPROF_FROMS
;
470 i
= kvp
->gpm
.fromssize
;
471 if (sysctl(mib
, 3, froms
, &i
, NULL
, 0) < 0)
474 if (i
!= kvp
->gpm
.fromssize
)
475 errx(9, "read froms: read %lu, got %ld: %s",
476 kvp
->gpm
.fromssize
, (long)i
,
477 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
478 if ((tos
= (struct tostruct
*)malloc(kvp
->gpm
.tossize
)) == NULL
)
479 errx(10, "cannot allocate tos space");
481 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.tos
, (void *)tos
,
485 i
= kvp
->gpm
.tossize
;
486 if (sysctl(mib
, 3, tos
, &i
, NULL
, 0) < 0)
489 if (i
!= kvp
->gpm
.tossize
)
490 errx(11, "read tos: read %lu, got %ld: %s",
491 kvp
->gpm
.tossize
, (long)i
,
492 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
494 warnx("lowpc 0x%lx, textsize 0x%lx",
495 (unsigned long)kvp
->gpm
.lowpc
, kvp
->gpm
.textsize
);
496 endfrom
= kvp
->gpm
.fromssize
/ sizeof(*froms
);
497 for (fromindex
= 0; fromindex
< endfrom
; ++fromindex
) {
498 if (froms
[fromindex
] == 0)
500 frompc
= (u_long
)kvp
->gpm
.lowpc
+
501 (fromindex
* kvp
->gpm
.hashfraction
* sizeof(*froms
));
502 for (toindex
= froms
[fromindex
]; toindex
!= 0;
503 toindex
= tos
[toindex
].link
) {
505 warnx("[mcleanup] frompc 0x%lx selfpc 0x%lx "
506 "count %ld", frompc
, tos
[toindex
].selfpc
,
508 rawarc
.raw_frompc
= frompc
;
509 rawarc
.raw_selfpc
= (u_long
)tos
[toindex
].selfpc
;
510 rawarc
.raw_count
= tos
[toindex
].count
;
511 fwrite((char *)&rawarc
, sizeof(rawarc
), 1, fp
);
518 * Get the profiling rate.
525 int mib
[2], profrate
;
526 struct clockinfo clockrate
;
530 if (kvm_read(kvp
->kd
, nl
[N_PROFHZ
].n_value
, &profrate
,
531 sizeof profrate
) != sizeof profrate
)
532 warnx("get clockrate: %s", kvm_geterr(kvp
->kd
));
536 mib
[1] = KERN_CLOCKRATE
;
537 clockrate
.profhz
= 1;
538 size
= sizeof clockrate
;
539 if (sysctl(mib
, 2, &clockrate
, &size
, NULL
, 0) < 0)
540 warn("get clockrate: %s", strerror(errno
));
541 return (clockrate
.profhz
);
545 * Reset the kernel profiling date structures.
555 setprof(kvp
, GMON_PROF_OFF
);
557 biggest
= kvp
->gpm
.kcountsize
;
558 if (kvp
->gpm
.fromssize
> biggest
)
559 biggest
= kvp
->gpm
.fromssize
;
560 if (kvp
->gpm
.tossize
> biggest
)
561 biggest
= kvp
->gpm
.tossize
;
562 if ((zbuf
= (char *)malloc(biggest
)) == NULL
)
563 errx(12, "cannot allocate zbuf space");
564 bzero(zbuf
, biggest
);
566 if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.kcount
, zbuf
,
567 kvp
->gpm
.kcountsize
) != kvp
->gpm
.kcountsize
)
568 errx(13, "tickbuf zero: %s", kvm_geterr(kvp
->kd
));
569 if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.froms
, zbuf
,
570 kvp
->gpm
.fromssize
) != kvp
->gpm
.fromssize
)
571 errx(14, "froms zero: %s", kvm_geterr(kvp
->kd
));
572 if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.tos
, zbuf
,
573 kvp
->gpm
.tossize
) != kvp
->gpm
.tossize
)
574 errx(15, "tos zero: %s", kvm_geterr(kvp
->kd
));
580 mib
[2] = GPROF_COUNT
;
581 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.kcountsize
) < 0)
582 errx(13, "tickbuf zero: %s", strerror(errno
));
583 mib
[2] = GPROF_FROMS
;
584 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.fromssize
) < 0)
585 errx(14, "froms zero: %s", strerror(errno
));
587 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.tossize
) < 0)
588 errx(15, "tos zero: %s", strerror(errno
));
589 (void)seteuid(getuid());