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. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * @(#) Copyright (c) 1983, 1992, 1993 The Regents of the University of California. All rights reserved.
34 * @(#)kgmon.c 8.1 (Berkeley) 6/6/93
35 * $FreeBSD: src/usr.sbin/kgmon/kgmon.c,v 1.9 1999/08/28 01:16:42 peter Exp $
36 * $DragonFly: src/usr.sbin/kgmon/kgmon.c,v 1.6 2004/12/22 01:28:39 joerg Exp $
39 #include <sys/param.h>
42 #include <sys/sysctl.h>
67 int Bflag
, bflag
, hflag
, kflag
, rflag
, pflag
;
69 int getprof(struct kvmvars
*);
70 void kern_readonly(int);
71 int openfiles(char *, char *, struct kvmvars
*);
72 void setprof(struct kvmvars
*kvp
, int state
);
73 void dumpstate(struct kvmvars
*kvp
);
74 void reset(struct kvmvars
*kvp
);
75 static void usage(void);
78 main(int argc
, char **argv
)
80 int ch
, mode
, disp
, accessmode
;
81 struct kvmvars kvmvars
;
87 while ((ch
= getopt(argc
, argv
, "M:N:Bbhpr")) != -1) {
126 #define BACKWARD_COMPATIBILITY
127 #ifdef BACKWARD_COMPATIBILITY
137 system
= (char *)getbootfile();
138 accessmode
= openfiles(system
, kmemf
, &kvmvars
);
139 mode
= getprof(&kvmvars
);
141 disp
= GMON_PROF_OFF
;
143 disp
= GMON_PROF_HIRES
;
152 if (accessmode
== O_RDWR
)
153 setprof(&kvmvars
, disp
);
154 fprintf(stdout
, "kgmon: kernel profiling is %s.\n",
155 disp
== GMON_PROF_OFF
? "off" :
156 disp
== GMON_PROF_HIRES
? "running (high resolution)" :
157 disp
== GMON_PROF_ON
? "running" :
158 disp
== GMON_PROF_BUSY
? "busy" :
159 disp
== GMON_PROF_ERROR
? "off (error)" :
160 "in an unknown state");
167 fprintf(stderr
, "usage: kgmon [-Bbhrp] [-M core] [-N system]\n");
172 * Check that profiling is enabled and open any ncessary files.
175 openfiles(char *system
, char *kmemf
, struct kvmvars
*kvp
)
177 int mib
[3], state
, size
, openmode
;
178 char errbuf
[_POSIX2_LINE_MAX
];
183 mib
[2] = GPROF_STATE
;
185 if (sysctl(mib
, 3, &state
, &size
, NULL
, 0) < 0)
186 errx(20, "profiling not defined in kernel");
187 if (!(Bflag
|| bflag
|| hflag
|| rflag
||
189 (state
== GMON_PROF_HIRES
|| state
== GMON_PROF_ON
))))
192 if (sysctl(mib
, 3, NULL
, NULL
, &state
, size
) >= 0)
195 kern_readonly(state
);
198 openmode
= (Bflag
|| bflag
|| hflag
|| pflag
|| rflag
)
200 kvp
->kd
= kvm_openfiles(system
, kmemf
, NULL
, openmode
, errbuf
);
201 if (kvp
->kd
== NULL
) {
202 if (openmode
== O_RDWR
) {
204 kvp
->kd
= kvm_openfiles(system
, kmemf
, NULL
, O_RDONLY
,
208 errx(2, "kvm_openfiles: %s", errbuf
);
209 kern_readonly(GMON_PROF_ON
);
211 if (kvm_nlist(kvp
->kd
, nl
) < 0)
212 errx(3, "%s: no namelist", system
);
213 if (!nl
[N_GMONPARAM
].n_value
)
214 errx(20, "profiling not defined in kernel");
219 * Suppress options that require a writable kernel.
222 kern_readonly(int mode
)
224 fprintf(stderr
, "kgmon: kernel read-only: ");
225 if (pflag
&& (mode
== GMON_PROF_HIRES
|| mode
== GMON_PROF_ON
))
226 fprintf(stderr
, "data may be inconsistent\n");
228 fprintf(stderr
, "-r supressed\n");
230 fprintf(stderr
, "-B supressed\n");
232 fprintf(stderr
, "-b supressed\n");
234 fprintf(stderr
, "-h supressed\n");
235 rflag
= Bflag
= bflag
= hflag
= 0;
239 * Get the state of kernel profiling.
242 getprof(struct kvmvars
*kvp
)
247 size
= kvm_read(kvp
->kd
, nl
[N_GMONPARAM
].n_value
, &kvp
->gpm
,
252 mib
[2] = GPROF_GMONPARAM
;
253 size
= sizeof kvp
->gpm
;
254 if (sysctl(mib
, 3, &kvp
->gpm
, &size
, NULL
, 0) < 0)
257 if (size
!= sizeof kvp
->gpm
)
258 errx(4, "cannot get gmonparam: %s",
259 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
260 return (kvp
->gpm
.state
);
264 * Enable or disable kernel profiling according to the state variable.
267 setprof(struct kvmvars
*kvp
, int state
)
269 struct gmonparam
*p
= (struct gmonparam
*)nl
[N_GMONPARAM
].n_value
;
270 int mib
[3], sz
, oldstate
;
276 mib
[2] = GPROF_STATE
;
277 if (sysctl(mib
, 3, &oldstate
, &sz
, NULL
, 0) < 0)
279 if (oldstate
== state
)
282 if (sysctl(mib
, 3, NULL
, NULL
, &state
, sz
) >= 0) {
287 } else if (kvm_write(kvp
->kd
, (u_long
)&p
->state
, (void *)&state
, sz
)
291 warnx("warning: cannot turn profiling %s",
292 state
== GMON_PROF_OFF
? "off" : "on");
296 * Build the gmon.out file.
299 dumpstate(struct kvmvars
*kvp
)
302 struct rawarc rawarc
;
303 struct tostruct
*tos
;
305 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 %u, got %d: %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 %u, got %d: %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 %u, got %d: %s",
384 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
386 warnx("lowpc 0x%x, textsize 0x%x",
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%x selfpc 0x%x count %d",
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)