]>
git.saurik.com Git - apple/system_cmds.git/blob - kgmon.tproj/kgmon.c
47161c0c4b8decab2d02c5878156e7cc873bb00d
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * Copyright (c) 1983, 1992, 1993
26 * The Regents of the University of California. All rights reserved.
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 static char copyright
[] =
59 "@(#) Copyright (c) 1983, 1992, 1993\n\
60 The Regents of the University of California. All rights reserved.\n";
64 static char sccsid
[] = "@(#)kgmon.c 8.1 (Berkeley) 6/6/93";
67 #include <sys/param.h>
69 #include <sys/sysctl.h>
94 int bflag
, hflag
, kflag
, rflag
, pflag
;
96 void setprof
__P((struct kvmvars
*kvp
, int state
));
97 void dumpstate
__P((struct kvmvars
*kvp
));
98 void reset
__P((struct kvmvars
*kvp
));
101 main(int argc
, char **argv
)
105 int ch
, mode
, disp
, accessmode
;
106 struct kvmvars kvmvars
;
107 char *system
, *kmemf
;
112 while ((ch
= getopt(argc
, argv
, "M:N:bhpr")) != EOF
) {
141 (void)fprintf(stderr
,
142 "usage: kgmon [-bhrp] [-M core] [-N system]\n");
149 #define BACKWARD_COMPATIBILITY
150 #ifdef BACKWARD_COMPATIBILITY
161 accessmode
= openfiles(system
, kmemf
, &kvmvars
);
162 mode
= getprof(&kvmvars
);
164 disp
= GMON_PROF_OFF
;
173 if (accessmode
== O_RDWR
)
174 setprof(&kvmvars
, disp
);
175 (void)fprintf(stdout
, "kgmon: kernel profiling is %s.\n",
176 disp
== GMON_PROF_OFF
? "off" : "running");
181 * Check that profiling is enabled and open any ncessary files.
183 openfiles(system
, kmemf
, kvp
)
188 int mib
[3], state
, size
, openmode
;
189 char errbuf
[_POSIX2_LINE_MAX
];
194 mib
[2] = GPROF_STATE
;
196 if (sysctl(mib
, 3, &state
, &size
, NULL
, 0) < 0) {
197 (void)fprintf(stderr
,
198 "kgmon: profiling not defined in kernel.\n");
201 if (!(bflag
|| hflag
|| rflag
||
202 (pflag
&& state
== GMON_PROF_ON
)))
205 if (sysctl(mib
, 3, NULL
, NULL
, &state
, size
) >= 0)
207 (void)seteuid(getuid());
208 kern_readonly(state
);
211 openmode
= (bflag
|| hflag
|| pflag
|| rflag
) ? O_RDWR
: O_RDONLY
;
212 kvp
->kd
= kvm_openfiles(system
, kmemf
, NULL
, openmode
, errbuf
);
213 if (kvp
->kd
== NULL
) {
214 if (openmode
== O_RDWR
) {
216 kvp
->kd
= kvm_openfiles(system
, kmemf
, NULL
, O_RDONLY
,
219 if (kvp
->kd
== NULL
) {
220 (void)fprintf(stderr
, "kgmon: kvm_openfiles: %s\n",
224 kern_readonly(GMON_PROF_ON
);
226 if (kvm_nlist(kvp
->kd
, nl
) < 0) {
227 (void)fprintf(stderr
, "kgmon: %s: no namelist\n", system
);
230 if (!nl
[N_GMONPARAM
].n_value
) {
231 (void)fprintf(stderr
,
232 "kgmon: profiling not defined in kernel.\n");
239 * Suppress options that require a writable kernel.
245 (void)fprintf(stderr
, "kgmon: kernel read-only: ");
246 if (pflag
&& mode
== GMON_PROF_ON
)
247 (void)fprintf(stderr
, "data may be inconsistent\n");
249 (void)fprintf(stderr
, "-r supressed\n");
251 (void)fprintf(stderr
, "-b supressed\n");
253 (void)fprintf(stderr
, "-h supressed\n");
254 rflag
= bflag
= hflag
= 0;
258 * Get the state of kernel profiling.
266 size
= kvm_read(kvp
->kd
, nl
[N_GMONPARAM
].n_value
, &kvp
->gpm
,
271 mib
[2] = GPROF_GMONPARAM
;
272 size
= sizeof kvp
->gpm
;
273 if (sysctl(mib
, 3, &kvp
->gpm
, &size
, NULL
, 0) < 0)
276 if (size
!= sizeof kvp
->gpm
) {
277 (void)fprintf(stderr
, "kgmon: cannot get gmonparam: %s\n",
278 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
281 return (kvp
->gpm
.state
);
285 * Enable or disable kernel profiling according to the state variable.
292 struct gmonparam
*p
= (struct gmonparam
*)nl
[N_GMONPARAM
].n_value
;
293 int mib
[3], sz
, oldstate
;
299 mib
[2] = GPROF_STATE
;
300 if (sysctl(mib
, 3, &oldstate
, &sz
, NULL
, 0) < 0)
302 if (oldstate
== state
)
305 if (sysctl(mib
, 3, NULL
, NULL
, &state
, sz
) >= 0) {
306 (void)seteuid(getuid());
309 (void)seteuid(getuid());
310 } else if (kvm_write(kvp
->kd
, (u_long
)&p
->state
, (void *)&state
, sz
)
314 (void)fprintf(stderr
, "kgmon: warning: cannot turn profiling %s\n",
315 state
== GMON_PROF_OFF
? "off" : "on");
319 * Build the gmon.out file.
326 struct rawarc rawarc
;
327 struct tostruct
*tos
;
329 u_short
*froms
, *tickbuf
;
332 int fromindex
, endfrom
, toindex
;
334 setprof(kvp
, GMON_PROF_OFF
);
335 fp
= fopen("gmon.out", "w");
342 * Build the gmon header and write it to a file.
344 bzero(&h
, sizeof(h
));
345 h
.lpc
= kvp
->gpm
.lowpc
;
346 h
.hpc
= kvp
->gpm
.highpc
;
347 h
.ncnt
= kvp
->gpm
.kcountsize
+ sizeof(h
);
348 h
.version
= GMONVERSION
;
349 h
.profrate
= getprofhz(kvp
);
350 fwrite((char *)&h
, sizeof(h
), 1, fp
);
353 * Write out the tick buffer.
357 if ((tickbuf
= (u_short
*)malloc(kvp
->gpm
.kcountsize
)) == NULL
) {
358 fprintf(stderr
, "kgmon: cannot allocate kcount space\n");
362 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.kcount
, (void *)tickbuf
,
363 kvp
->gpm
.kcountsize
);
365 mib
[2] = GPROF_COUNT
;
366 i
= kvp
->gpm
.kcountsize
;
367 if (sysctl(mib
, 3, tickbuf
, &i
, NULL
, 0) < 0)
370 if (i
!= kvp
->gpm
.kcountsize
) {
371 (void)fprintf(stderr
, "kgmon: read ticks: read %u, got %d: %s",
372 kvp
->gpm
.kcountsize
, i
,
373 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
376 if ((fwrite(tickbuf
, kvp
->gpm
.kcountsize
, 1, fp
)) != 1) {
377 perror("kgmon: writing tocks to gmon.out");
383 * Write out the arc info.
385 if ((froms
= (u_short
*)malloc(kvp
->gpm
.fromssize
)) == NULL
) {
386 fprintf(stderr
, "kgmon: cannot allocate froms space\n");
390 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.froms
, (void *)froms
,
393 mib
[2] = GPROF_FROMS
;
394 i
= kvp
->gpm
.fromssize
;
395 if (sysctl(mib
, 3, froms
, &i
, NULL
, 0) < 0)
398 if (i
!= kvp
->gpm
.fromssize
) {
399 (void)fprintf(stderr
, "kgmon: read froms: read %u, got %d: %s",
400 kvp
->gpm
.fromssize
, i
,
401 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
404 if ((tos
= (struct tostruct
*)malloc(kvp
->gpm
.tossize
)) == NULL
) {
405 fprintf(stderr
, "kgmon: cannot allocate tos space\n");
409 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.tos
, (void *)tos
,
413 i
= kvp
->gpm
.tossize
;
414 if (sysctl(mib
, 3, tos
, &i
, NULL
, 0) < 0)
417 if (i
!= kvp
->gpm
.tossize
) {
418 (void)fprintf(stderr
, "kgmon: read tos: read %u, got %d: %s",
420 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
424 (void)fprintf(stderr
, "kgmon: lowpc 0x%x, textsize 0x%x\n",
425 kvp
->gpm
.lowpc
, kvp
->gpm
.textsize
);
426 endfrom
= kvp
->gpm
.fromssize
/ sizeof(*froms
);
427 for (fromindex
= 0; fromindex
< endfrom
; ++fromindex
) {
428 if (froms
[fromindex
] == 0)
430 frompc
= (u_long
)kvp
->gpm
.lowpc
+
431 (fromindex
* kvp
->gpm
.hashfraction
* sizeof(*froms
));
432 for (toindex
= froms
[fromindex
]; toindex
!= 0;
433 toindex
= tos
[toindex
].link
) {
435 (void)fprintf(stderr
,
436 "%s: [mcleanup] frompc 0x%x selfpc 0x%x count %d\n",
437 "kgmon", frompc
, tos
[toindex
].selfpc
,
439 rawarc
.raw_frompc
= frompc
;
440 rawarc
.raw_selfpc
= (u_long
)tos
[toindex
].selfpc
;
441 rawarc
.raw_count
= tos
[toindex
].count
;
442 fwrite((char *)&rawarc
, sizeof(rawarc
), 1, fp
);
449 * Get the profiling rate.
455 int mib
[2], size
, profrate
;
456 struct clockinfo clockrate
;
460 if (kvm_read(kvp
->kd
, nl
[N_PROFHZ
].n_value
, &profrate
,
461 sizeof profrate
) != sizeof profrate
)
462 (void)fprintf(stderr
, "kgmon: get clockrate: %s\n",
463 kvm_geterr(kvp
->kd
));
467 mib
[1] = KERN_CLOCKRATE
;
468 clockrate
.profhz
= 1;
469 size
= sizeof clockrate
;
470 if (sysctl(mib
, 2, &clockrate
, &size
, NULL
, 0) < 0)
471 (void)fprintf(stderr
, "kgmon: get clockrate: %s\n",
473 return (clockrate
.profhz
);
477 * Reset the kernel profiling date structures.
487 setprof(kvp
, GMON_PROF_OFF
);
489 biggest
= kvp
->gpm
.kcountsize
;
490 if (kvp
->gpm
.fromssize
> biggest
)
491 biggest
= kvp
->gpm
.fromssize
;
492 if (kvp
->gpm
.tossize
> biggest
)
493 biggest
= kvp
->gpm
.tossize
;
494 if ((zbuf
= (char *)malloc(biggest
)) == NULL
) {
495 fprintf(stderr
, "kgmon: cannot allocate zbuf space\n");
498 bzero(zbuf
, biggest
);
500 if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.kcount
, zbuf
,
501 kvp
->gpm
.kcountsize
) != kvp
->gpm
.kcountsize
) {
502 (void)fprintf(stderr
, "kgmon: tickbuf zero: %s\n",
503 kvm_geterr(kvp
->kd
));
506 if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.froms
, zbuf
,
507 kvp
->gpm
.fromssize
) != kvp
->gpm
.fromssize
) {
508 (void)fprintf(stderr
, "kgmon: froms zero: %s\n",
509 kvm_geterr(kvp
->kd
));
512 if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.tos
, zbuf
,
513 kvp
->gpm
.tossize
) != kvp
->gpm
.tossize
) {
514 (void)fprintf(stderr
, "kgmon: tos zero: %s\n",
515 kvm_geterr(kvp
->kd
));
523 mib
[2] = GPROF_COUNT
;
524 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.kcountsize
) < 0) {
525 (void)fprintf(stderr
, "kgmon: tickbuf zero: %s\n",
529 mib
[2] = GPROF_FROMS
;
530 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.fromssize
) < 0) {
531 (void)fprintf(stderr
, "kgmon: froms zero: %s\n",
536 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.tossize
) < 0) {
537 (void)fprintf(stderr
, "kgmon: tos zero: %s\n",
541 (void)seteuid(getuid());