]>
git.saurik.com Git - apple/system_cmds.git/blob - kgmon.tproj/kgmon.c
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 1983, 1992, 1993
27 * The Regents of the University of California. All rights reserved.
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 static char copyright
[] =
60 "@(#) Copyright (c) 1983, 1992, 1993\n\
61 The Regents of the University of California. All rights reserved.\n";
65 static char sccsid
[] = "@(#)kgmon.c 8.1 (Berkeley) 6/6/93";
68 #include <sys/param.h>
70 #include <sys/sysctl.h>
95 int bflag
, hflag
, kflag
, rflag
, pflag
;
97 void setprof
__P((struct kvmvars
*kvp
, int state
));
98 void dumpstate
__P((struct kvmvars
*kvp
));
99 void reset
__P((struct kvmvars
*kvp
));
102 main(int argc
, char **argv
)
106 int ch
, mode
, disp
, accessmode
;
107 struct kvmvars kvmvars
;
108 char *system
, *kmemf
;
113 while ((ch
= getopt(argc
, argv
, "M:N:bhpr")) != EOF
) {
142 (void)fprintf(stderr
,
143 "usage: kgmon [-bhrp] [-M core] [-N system]\n");
150 #define BACKWARD_COMPATIBILITY
151 #ifdef BACKWARD_COMPATIBILITY
162 accessmode
= openfiles(system
, kmemf
, &kvmvars
);
163 mode
= getprof(&kvmvars
);
165 disp
= GMON_PROF_OFF
;
174 if (accessmode
== O_RDWR
)
175 setprof(&kvmvars
, disp
);
176 (void)fprintf(stdout
, "kgmon: kernel profiling is %s.\n",
177 disp
== GMON_PROF_OFF
? "off" : "running");
182 * Check that profiling is enabled and open any ncessary files.
184 openfiles(system
, kmemf
, kvp
)
189 int mib
[3], state
, size
, openmode
;
190 char errbuf
[_POSIX2_LINE_MAX
];
195 mib
[2] = GPROF_STATE
;
197 if (sysctl(mib
, 3, &state
, &size
, NULL
, 0) < 0) {
198 (void)fprintf(stderr
,
199 "kgmon: profiling not defined in kernel.\n");
202 if (!(bflag
|| hflag
|| rflag
||
203 (pflag
&& state
== GMON_PROF_ON
)))
206 if (sysctl(mib
, 3, NULL
, NULL
, &state
, size
) >= 0)
208 (void)seteuid(getuid());
209 kern_readonly(state
);
212 openmode
= (bflag
|| hflag
|| pflag
|| rflag
) ? O_RDWR
: O_RDONLY
;
213 kvp
->kd
= kvm_openfiles(system
, kmemf
, NULL
, openmode
, errbuf
);
214 if (kvp
->kd
== NULL
) {
215 if (openmode
== O_RDWR
) {
217 kvp
->kd
= kvm_openfiles(system
, kmemf
, NULL
, O_RDONLY
,
220 if (kvp
->kd
== NULL
) {
221 (void)fprintf(stderr
, "kgmon: kvm_openfiles: %s\n",
225 kern_readonly(GMON_PROF_ON
);
227 if (kvm_nlist(kvp
->kd
, nl
) < 0) {
228 (void)fprintf(stderr
, "kgmon: %s: no namelist\n", system
);
231 if (!nl
[N_GMONPARAM
].n_value
) {
232 (void)fprintf(stderr
,
233 "kgmon: profiling not defined in kernel.\n");
240 * Suppress options that require a writable kernel.
246 (void)fprintf(stderr
, "kgmon: kernel read-only: ");
247 if (pflag
&& mode
== GMON_PROF_ON
)
248 (void)fprintf(stderr
, "data may be inconsistent\n");
250 (void)fprintf(stderr
, "-r supressed\n");
252 (void)fprintf(stderr
, "-b supressed\n");
254 (void)fprintf(stderr
, "-h supressed\n");
255 rflag
= bflag
= hflag
= 0;
259 * Get the state of kernel profiling.
267 size
= kvm_read(kvp
->kd
, nl
[N_GMONPARAM
].n_value
, &kvp
->gpm
,
272 mib
[2] = GPROF_GMONPARAM
;
273 size
= sizeof kvp
->gpm
;
274 if (sysctl(mib
, 3, &kvp
->gpm
, &size
, NULL
, 0) < 0)
277 if (size
!= sizeof kvp
->gpm
) {
278 (void)fprintf(stderr
, "kgmon: cannot get gmonparam: %s\n",
279 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
282 return (kvp
->gpm
.state
);
286 * Enable or disable kernel profiling according to the state variable.
293 struct gmonparam
*p
= (struct gmonparam
*)nl
[N_GMONPARAM
].n_value
;
294 int mib
[3], sz
, oldstate
;
300 mib
[2] = GPROF_STATE
;
301 if (sysctl(mib
, 3, &oldstate
, &sz
, NULL
, 0) < 0)
303 if (oldstate
== state
)
306 if (sysctl(mib
, 3, NULL
, NULL
, &state
, sz
) >= 0) {
307 (void)seteuid(getuid());
310 (void)seteuid(getuid());
311 } else if (kvm_write(kvp
->kd
, (u_long
)&p
->state
, (void *)&state
, sz
)
315 (void)fprintf(stderr
, "kgmon: warning: cannot turn profiling %s\n",
316 state
== GMON_PROF_OFF
? "off" : "on");
320 * Build the gmon.out file.
327 struct rawarc rawarc
;
328 struct tostruct
*tos
;
330 u_short
*froms
, *tickbuf
;
333 int fromindex
, endfrom
, toindex
;
335 setprof(kvp
, GMON_PROF_OFF
);
336 fp
= fopen("gmon.out", "w");
343 * Build the gmon header and write it to a file.
345 bzero(&h
, sizeof(h
));
346 h
.lpc
= kvp
->gpm
.lowpc
;
347 h
.hpc
= kvp
->gpm
.highpc
;
348 h
.ncnt
= kvp
->gpm
.kcountsize
+ sizeof(h
);
349 h
.version
= GMONVERSION
;
350 h
.profrate
= getprofhz(kvp
);
351 fwrite((char *)&h
, sizeof(h
), 1, fp
);
354 * Write out the tick buffer.
358 if ((tickbuf
= (u_short
*)malloc(kvp
->gpm
.kcountsize
)) == NULL
) {
359 fprintf(stderr
, "kgmon: cannot allocate kcount space\n");
363 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.kcount
, (void *)tickbuf
,
364 kvp
->gpm
.kcountsize
);
366 mib
[2] = GPROF_COUNT
;
367 i
= kvp
->gpm
.kcountsize
;
368 if (sysctl(mib
, 3, tickbuf
, &i
, NULL
, 0) < 0)
371 if (i
!= kvp
->gpm
.kcountsize
) {
372 (void)fprintf(stderr
, "kgmon: read ticks: read %u, got %d: %s",
373 kvp
->gpm
.kcountsize
, i
,
374 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
377 if ((fwrite(tickbuf
, kvp
->gpm
.kcountsize
, 1, fp
)) != 1) {
378 perror("kgmon: writing tocks to gmon.out");
384 * Write out the arc info.
386 if ((froms
= (u_short
*)malloc(kvp
->gpm
.fromssize
)) == NULL
) {
387 fprintf(stderr
, "kgmon: cannot allocate froms space\n");
391 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.froms
, (void *)froms
,
394 mib
[2] = GPROF_FROMS
;
395 i
= kvp
->gpm
.fromssize
;
396 if (sysctl(mib
, 3, froms
, &i
, NULL
, 0) < 0)
399 if (i
!= kvp
->gpm
.fromssize
) {
400 (void)fprintf(stderr
, "kgmon: read froms: read %u, got %d: %s",
401 kvp
->gpm
.fromssize
, i
,
402 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
405 if ((tos
= (struct tostruct
*)malloc(kvp
->gpm
.tossize
)) == NULL
) {
406 fprintf(stderr
, "kgmon: cannot allocate tos space\n");
410 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.tos
, (void *)tos
,
414 i
= kvp
->gpm
.tossize
;
415 if (sysctl(mib
, 3, tos
, &i
, NULL
, 0) < 0)
418 if (i
!= kvp
->gpm
.tossize
) {
419 (void)fprintf(stderr
, "kgmon: read tos: read %u, got %d: %s",
421 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
425 (void)fprintf(stderr
, "kgmon: lowpc 0x%x, textsize 0x%x\n",
426 kvp
->gpm
.lowpc
, kvp
->gpm
.textsize
);
427 endfrom
= kvp
->gpm
.fromssize
/ sizeof(*froms
);
428 for (fromindex
= 0; fromindex
< endfrom
; ++fromindex
) {
429 if (froms
[fromindex
] == 0)
431 frompc
= (u_long
)kvp
->gpm
.lowpc
+
432 (fromindex
* kvp
->gpm
.hashfraction
* sizeof(*froms
));
433 for (toindex
= froms
[fromindex
]; toindex
!= 0;
434 toindex
= tos
[toindex
].link
) {
436 (void)fprintf(stderr
,
437 "%s: [mcleanup] frompc 0x%x selfpc 0x%x count %d\n",
438 "kgmon", frompc
, tos
[toindex
].selfpc
,
440 rawarc
.raw_frompc
= frompc
;
441 rawarc
.raw_selfpc
= (u_long
)tos
[toindex
].selfpc
;
442 rawarc
.raw_count
= tos
[toindex
].count
;
443 fwrite((char *)&rawarc
, sizeof(rawarc
), 1, fp
);
450 * Get the profiling rate.
456 int mib
[2], size
, profrate
;
457 struct clockinfo clockrate
;
461 if (kvm_read(kvp
->kd
, nl
[N_PROFHZ
].n_value
, &profrate
,
462 sizeof profrate
) != sizeof profrate
)
463 (void)fprintf(stderr
, "kgmon: get clockrate: %s\n",
464 kvm_geterr(kvp
->kd
));
468 mib
[1] = KERN_CLOCKRATE
;
469 clockrate
.profhz
= 1;
470 size
= sizeof clockrate
;
471 if (sysctl(mib
, 2, &clockrate
, &size
, NULL
, 0) < 0)
472 (void)fprintf(stderr
, "kgmon: get clockrate: %s\n",
474 return (clockrate
.profhz
);
478 * Reset the kernel profiling date structures.
488 setprof(kvp
, GMON_PROF_OFF
);
490 biggest
= kvp
->gpm
.kcountsize
;
491 if (kvp
->gpm
.fromssize
> biggest
)
492 biggest
= kvp
->gpm
.fromssize
;
493 if (kvp
->gpm
.tossize
> biggest
)
494 biggest
= kvp
->gpm
.tossize
;
495 if ((zbuf
= (char *)malloc(biggest
)) == NULL
) {
496 fprintf(stderr
, "kgmon: cannot allocate zbuf space\n");
499 bzero(zbuf
, biggest
);
501 if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.kcount
, zbuf
,
502 kvp
->gpm
.kcountsize
) != kvp
->gpm
.kcountsize
) {
503 (void)fprintf(stderr
, "kgmon: tickbuf zero: %s\n",
504 kvm_geterr(kvp
->kd
));
507 if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.froms
, zbuf
,
508 kvp
->gpm
.fromssize
) != kvp
->gpm
.fromssize
) {
509 (void)fprintf(stderr
, "kgmon: froms zero: %s\n",
510 kvm_geterr(kvp
->kd
));
513 if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.tos
, zbuf
,
514 kvp
->gpm
.tossize
) != kvp
->gpm
.tossize
) {
515 (void)fprintf(stderr
, "kgmon: tos zero: %s\n",
516 kvm_geterr(kvp
->kd
));
524 mib
[2] = GPROF_COUNT
;
525 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.kcountsize
) < 0) {
526 (void)fprintf(stderr
, "kgmon: tickbuf zero: %s\n",
530 mib
[2] = GPROF_FROMS
;
531 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.fromssize
) < 0) {
532 (void)fprintf(stderr
, "kgmon: froms zero: %s\n",
537 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.tossize
) < 0) {
538 (void)fprintf(stderr
, "kgmon: tos zero: %s\n",
542 (void)seteuid(getuid());