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
29 * @(#) Copyright (c) 1983, 1992, 1993 The Regents of the University of California. All rights reserved.
30 * @(#)kgmon.c 8.1 (Berkeley) 6/6/93
31 * $FreeBSD: src/usr.sbin/kgmon/kgmon.c,v 1.9 1999/08/28 01:16:42 peter Exp $
34 #include <sys/param.h>
37 #include <sys/sysctl.h>
62 int Bflag
, bflag
, hflag
, kflag
, rflag
, pflag
;
64 int getprof(struct kvmvars
*);
65 void kern_readonly(int);
66 int openfiles(char *, char *, struct kvmvars
*);
67 void setprof(struct kvmvars
*kvp
, int state
);
68 void dumpstate(struct kvmvars
*kvp
);
69 void reset(struct kvmvars
*kvp
);
70 static void usage(void);
73 main(int argc
, char **argv
)
75 int ch
, mode
, disp
, accessmode
;
76 struct kvmvars kvmvars
;
82 while ((ch
= getopt(argc
, argv
, "M:N:Bbhpr")) != -1) {
121 #define BACKWARD_COMPATIBILITY
122 #ifdef BACKWARD_COMPATIBILITY
132 system
= (char *)getbootfile();
133 accessmode
= openfiles(system
, kmemf
, &kvmvars
);
134 mode
= getprof(&kvmvars
);
136 disp
= GMON_PROF_OFF
;
138 disp
= GMON_PROF_HIRES
;
147 if (accessmode
== O_RDWR
)
148 setprof(&kvmvars
, disp
);
149 fprintf(stdout
, "kgmon: kernel profiling is %s.\n",
150 disp
== GMON_PROF_OFF
? "off" :
151 disp
== GMON_PROF_HIRES
? "running (high resolution)" :
152 disp
== GMON_PROF_ON
? "running" :
153 disp
== GMON_PROF_BUSY
? "busy" :
154 disp
== GMON_PROF_ERROR
? "off (error)" :
155 "in an unknown state");
162 fprintf(stderr
, "usage: kgmon [-Bbhrp] [-M core] [-N system]\n");
167 * Check that profiling is enabled and open any ncessary files.
170 openfiles(char *system
, char *kmemf
, struct kvmvars
*kvp
)
172 int mib
[3], state
, openmode
;
174 char errbuf
[_POSIX2_LINE_MAX
];
179 mib
[2] = GPROF_STATE
;
181 if (sysctl(mib
, 3, &state
, &size
, NULL
, 0) < 0)
182 errx(20, "profiling not defined in kernel");
183 if (!(Bflag
|| bflag
|| hflag
|| rflag
||
185 (state
== GMON_PROF_HIRES
|| state
== GMON_PROF_ON
))))
188 if (sysctl(mib
, 3, NULL
, NULL
, &state
, size
) >= 0)
191 kern_readonly(state
);
194 openmode
= (Bflag
|| bflag
|| hflag
|| pflag
|| rflag
)
196 kvp
->kd
= kvm_openfiles(system
, kmemf
, NULL
, openmode
, errbuf
);
197 if (kvp
->kd
== NULL
) {
198 if (openmode
== O_RDWR
) {
200 kvp
->kd
= kvm_openfiles(system
, kmemf
, NULL
, O_RDONLY
,
204 errx(2, "kvm_openfiles: %s", errbuf
);
205 kern_readonly(GMON_PROF_ON
);
207 if (kvm_nlist(kvp
->kd
, nl
) < 0)
208 errx(3, "%s: no namelist", system
);
209 if (!nl
[N_GMONPARAM
].n_value
)
210 errx(20, "profiling not defined in kernel");
215 * Suppress options that require a writable kernel.
218 kern_readonly(int mode
)
220 fprintf(stderr
, "kgmon: kernel read-only: ");
221 if (pflag
&& (mode
== GMON_PROF_HIRES
|| mode
== GMON_PROF_ON
))
222 fprintf(stderr
, "data may be inconsistent\n");
224 fprintf(stderr
, "-r suppressed\n");
226 fprintf(stderr
, "-B suppressed\n");
228 fprintf(stderr
, "-b suppressed\n");
230 fprintf(stderr
, "-h suppressed\n");
231 rflag
= Bflag
= bflag
= hflag
= 0;
235 * Get the state of kernel profiling.
238 getprof(struct kvmvars
*kvp
)
244 size
= kvm_read(kvp
->kd
, nl
[N_GMONPARAM
].n_value
, &kvp
->gpm
,
249 mib
[2] = GPROF_GMONPARAM
;
250 size
= sizeof kvp
->gpm
;
251 if (sysctl(mib
, 3, &kvp
->gpm
, &size
, NULL
, 0) < 0)
254 if (size
!= sizeof kvp
->gpm
)
255 errx(4, "cannot get gmonparam: %s",
256 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
257 return (kvp
->gpm
.state
);
261 * Enable or disable kernel profiling according to the state variable.
264 setprof(struct kvmvars
*kvp
, int state
)
266 struct gmonparam
*p
= (struct gmonparam
*)nl
[N_GMONPARAM
].n_value
;
267 int mib
[3], oldstate
;
270 size
= sizeof(state
);
274 mib
[2] = GPROF_STATE
;
275 if (sysctl(mib
, 3, &oldstate
, &size
, NULL
, 0) < 0)
277 if (oldstate
== state
)
280 if (sysctl(mib
, 3, NULL
, NULL
, &state
, size
) >= 0) {
285 } else if (kvm_write(kvp
->kd
, (u_long
)&p
->state
, (void *)&state
, size
)
290 warnx("warning: cannot turn profiling %s",
291 state
== GMON_PROF_OFF
? "off" : "on");
295 * Build the gmon.out file.
298 dumpstate(struct kvmvars
*kvp
)
301 struct rawarc rawarc
;
302 struct tostruct
*tos
;
304 u_short
*froms
, *tickbuf
;
308 int fromindex
, endfrom
, toindex
;
310 setprof(kvp
, GMON_PROF_OFF
);
311 fp
= fopen("gmon.out", "w");
318 * Build the gmon header and write it to a file.
320 bzero(&h
, sizeof(h
));
321 h
.lpc
= kvp
->gpm
.lowpc
;
322 h
.hpc
= kvp
->gpm
.highpc
;
323 h
.ncnt
= kvp
->gpm
.kcountsize
+ sizeof(h
);
324 h
.version
= GMONVERSION
;
325 h
.profrate
= kvp
->gpm
.profrate
;
326 fwrite((char *)&h
, sizeof(h
), 1, fp
);
329 * Write out the tick buffer.
333 if ((tickbuf
= (u_short
*)malloc(kvp
->gpm
.kcountsize
)) == NULL
)
334 errx(5, "cannot allocate kcount space");
336 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.kcount
, (void *)tickbuf
,
337 kvp
->gpm
.kcountsize
);
339 mib
[2] = GPROF_COUNT
;
340 i
= kvp
->gpm
.kcountsize
;
341 if (sysctl(mib
, 3, tickbuf
, &i
, NULL
, 0) < 0)
344 if (i
!= kvp
->gpm
.kcountsize
)
345 errx(6, "read ticks: read %lu, got %zd: %s",
346 kvp
->gpm
.kcountsize
, i
,
347 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
348 if ((fwrite(tickbuf
, kvp
->gpm
.kcountsize
, 1, fp
)) != 1)
349 err(7, "writing tocks to gmon.out");
353 * Write out the arc info.
355 if ((froms
= (u_short
*)malloc(kvp
->gpm
.fromssize
)) == NULL
)
356 errx(8, "cannot allocate froms space");
358 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.froms
, (void *)froms
,
361 mib
[2] = GPROF_FROMS
;
362 i
= kvp
->gpm
.fromssize
;
363 if (sysctl(mib
, 3, froms
, &i
, NULL
, 0) < 0)
366 if (i
!= kvp
->gpm
.fromssize
)
367 errx(9, "read froms: read %lu, got %zd: %s",
368 kvp
->gpm
.fromssize
, i
,
369 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
370 if ((tos
= (struct tostruct
*)malloc(kvp
->gpm
.tossize
)) == NULL
)
371 errx(10, "cannot allocate tos space");
373 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.tos
, (void *)tos
,
377 i
= kvp
->gpm
.tossize
;
378 if (sysctl(mib
, 3, tos
, &i
, NULL
, 0) < 0)
381 if (i
!= kvp
->gpm
.tossize
)
382 errx(11, "read tos: read %lu, got %zd: %s",
384 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
386 warnx("lowpc 0x%tx, textsize 0x%lx",
387 kvp
->gpm
.lowpc
, kvp
->gpm
.textsize
);
388 endfrom
= kvp
->gpm
.fromssize
/ sizeof(*froms
);
389 for (fromindex
= 0; fromindex
< endfrom
; ++fromindex
) {
390 if (froms
[fromindex
] == 0)
392 frompc
= (u_long
)kvp
->gpm
.lowpc
+
393 (fromindex
* kvp
->gpm
.hashfraction
* sizeof(*froms
));
394 for (toindex
= froms
[fromindex
]; toindex
!= 0;
395 toindex
= tos
[toindex
].link
) {
397 warnx("[mcleanup] frompc 0x%lx selfpc 0x%lx count %ld",
398 frompc
, tos
[toindex
].selfpc
,
400 rawarc
.raw_frompc
= frompc
;
401 rawarc
.raw_selfpc
= (u_long
)tos
[toindex
].selfpc
;
402 rawarc
.raw_count
= tos
[toindex
].count
;
403 fwrite((char *)&rawarc
, sizeof(rawarc
), 1, fp
);
410 * Reset the kernel profiling date structures.
413 reset(struct kvmvars
*kvp
)
419 setprof(kvp
, GMON_PROF_OFF
);
421 biggest
= kvp
->gpm
.kcountsize
;
422 if (kvp
->gpm
.fromssize
> biggest
)
423 biggest
= kvp
->gpm
.fromssize
;
424 if (kvp
->gpm
.tossize
> biggest
)
425 biggest
= kvp
->gpm
.tossize
;
426 if ((zbuf
= (char *)malloc(biggest
)) == NULL
)
427 errx(12, "cannot allocate zbuf space");
428 bzero(zbuf
, biggest
);
430 if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.kcount
, zbuf
,
431 kvp
->gpm
.kcountsize
) != kvp
->gpm
.kcountsize
)
432 errx(13, "tickbuf zero: %s", kvm_geterr(kvp
->kd
));
433 if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.froms
, zbuf
,
434 kvp
->gpm
.fromssize
) != kvp
->gpm
.fromssize
)
435 errx(14, "froms zero: %s", kvm_geterr(kvp
->kd
));
436 if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.tos
, zbuf
,
437 kvp
->gpm
.tossize
) != kvp
->gpm
.tossize
)
438 errx(15, "tos zero: %s", kvm_geterr(kvp
->kd
));
444 mib
[2] = GPROF_COUNT
;
445 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.kcountsize
) < 0)
446 err(13, "tickbuf zero");
447 mib
[2] = GPROF_FROMS
;
448 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.fromssize
) < 0)
449 err(14, "froms zero");
451 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.tossize
) < 0)