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.7 2008/04/20 13:44:26 swildner 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
, openmode
;
179 char errbuf
[_POSIX2_LINE_MAX
];
184 mib
[2] = GPROF_STATE
;
186 if (sysctl(mib
, 3, &state
, &size
, NULL
, 0) < 0)
187 errx(20, "profiling not defined in kernel");
188 if (!(Bflag
|| bflag
|| hflag
|| rflag
||
190 (state
== GMON_PROF_HIRES
|| state
== GMON_PROF_ON
))))
193 if (sysctl(mib
, 3, NULL
, NULL
, &state
, size
) >= 0)
196 kern_readonly(state
);
199 openmode
= (Bflag
|| bflag
|| hflag
|| pflag
|| rflag
)
201 kvp
->kd
= kvm_openfiles(system
, kmemf
, NULL
, openmode
, errbuf
);
202 if (kvp
->kd
== NULL
) {
203 if (openmode
== O_RDWR
) {
205 kvp
->kd
= kvm_openfiles(system
, kmemf
, NULL
, O_RDONLY
,
209 errx(2, "kvm_openfiles: %s", errbuf
);
210 kern_readonly(GMON_PROF_ON
);
212 if (kvm_nlist(kvp
->kd
, nl
) < 0)
213 errx(3, "%s: no namelist", system
);
214 if (!nl
[N_GMONPARAM
].n_value
)
215 errx(20, "profiling not defined in kernel");
220 * Suppress options that require a writable kernel.
223 kern_readonly(int mode
)
225 fprintf(stderr
, "kgmon: kernel read-only: ");
226 if (pflag
&& (mode
== GMON_PROF_HIRES
|| mode
== GMON_PROF_ON
))
227 fprintf(stderr
, "data may be inconsistent\n");
229 fprintf(stderr
, "-r suppressed\n");
231 fprintf(stderr
, "-B suppressed\n");
233 fprintf(stderr
, "-b suppressed\n");
235 fprintf(stderr
, "-h suppressed\n");
236 rflag
= Bflag
= bflag
= hflag
= 0;
240 * Get the state of kernel profiling.
243 getprof(struct kvmvars
*kvp
)
249 size
= kvm_read(kvp
->kd
, nl
[N_GMONPARAM
].n_value
, &kvp
->gpm
,
254 mib
[2] = GPROF_GMONPARAM
;
255 size
= sizeof kvp
->gpm
;
256 if (sysctl(mib
, 3, &kvp
->gpm
, &size
, NULL
, 0) < 0)
259 if (size
!= sizeof kvp
->gpm
)
260 errx(4, "cannot get gmonparam: %s",
261 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
262 return (kvp
->gpm
.state
);
266 * Enable or disable kernel profiling according to the state variable.
269 setprof(struct kvmvars
*kvp
, int state
)
271 struct gmonparam
*p
= (struct gmonparam
*)nl
[N_GMONPARAM
].n_value
;
272 int mib
[3], oldstate
;
275 size
= sizeof(state
);
279 mib
[2] = GPROF_STATE
;
280 if (sysctl(mib
, 3, &oldstate
, &size
, NULL
, 0) < 0)
282 if (oldstate
== state
)
285 if (sysctl(mib
, 3, NULL
, NULL
, &state
, size
) >= 0) {
290 } else if (kvm_write(kvp
->kd
, (u_long
)&p
->state
, (void *)&state
, size
)
295 warnx("warning: cannot turn profiling %s",
296 state
== GMON_PROF_OFF
? "off" : "on");
300 * Build the gmon.out file.
303 dumpstate(struct kvmvars
*kvp
)
306 struct rawarc rawarc
;
307 struct tostruct
*tos
;
309 u_short
*froms
, *tickbuf
;
313 int fromindex
, endfrom
, toindex
;
315 setprof(kvp
, GMON_PROF_OFF
);
316 fp
= fopen("gmon.out", "w");
323 * Build the gmon header and write it to a file.
325 bzero(&h
, sizeof(h
));
326 h
.lpc
= kvp
->gpm
.lowpc
;
327 h
.hpc
= kvp
->gpm
.highpc
;
328 h
.ncnt
= kvp
->gpm
.kcountsize
+ sizeof(h
);
329 h
.version
= GMONVERSION
;
330 h
.profrate
= kvp
->gpm
.profrate
;
331 fwrite((char *)&h
, sizeof(h
), 1, fp
);
334 * Write out the tick buffer.
338 if ((tickbuf
= (u_short
*)malloc(kvp
->gpm
.kcountsize
)) == NULL
)
339 errx(5, "cannot allocate kcount space");
341 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.kcount
, (void *)tickbuf
,
342 kvp
->gpm
.kcountsize
);
344 mib
[2] = GPROF_COUNT
;
345 i
= kvp
->gpm
.kcountsize
;
346 if (sysctl(mib
, 3, tickbuf
, &i
, NULL
, 0) < 0)
349 if (i
!= kvp
->gpm
.kcountsize
)
350 errx(6, "read ticks: read %u, got %d: %s",
351 kvp
->gpm
.kcountsize
, i
,
352 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
353 if ((fwrite(tickbuf
, kvp
->gpm
.kcountsize
, 1, fp
)) != 1)
354 err(7, "writing tocks to gmon.out");
358 * Write out the arc info.
360 if ((froms
= (u_short
*)malloc(kvp
->gpm
.fromssize
)) == NULL
)
361 errx(8, "cannot allocate froms space");
363 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.froms
, (void *)froms
,
366 mib
[2] = GPROF_FROMS
;
367 i
= kvp
->gpm
.fromssize
;
368 if (sysctl(mib
, 3, froms
, &i
, NULL
, 0) < 0)
371 if (i
!= kvp
->gpm
.fromssize
)
372 errx(9, "read froms: read %u, got %d: %s",
373 kvp
->gpm
.fromssize
, i
,
374 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
375 if ((tos
= (struct tostruct
*)malloc(kvp
->gpm
.tossize
)) == NULL
)
376 errx(10, "cannot allocate tos space");
378 i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.tos
, (void *)tos
,
382 i
= kvp
->gpm
.tossize
;
383 if (sysctl(mib
, 3, tos
, &i
, NULL
, 0) < 0)
386 if (i
!= kvp
->gpm
.tossize
)
387 errx(11, "read tos: read %u, got %d: %s",
389 kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
391 warnx("lowpc 0x%x, textsize 0x%x",
392 kvp
->gpm
.lowpc
, kvp
->gpm
.textsize
);
393 endfrom
= kvp
->gpm
.fromssize
/ sizeof(*froms
);
394 for (fromindex
= 0; fromindex
< endfrom
; ++fromindex
) {
395 if (froms
[fromindex
] == 0)
397 frompc
= (u_long
)kvp
->gpm
.lowpc
+
398 (fromindex
* kvp
->gpm
.hashfraction
* sizeof(*froms
));
399 for (toindex
= froms
[fromindex
]; toindex
!= 0;
400 toindex
= tos
[toindex
].link
) {
402 warnx("[mcleanup] frompc 0x%x selfpc 0x%x count %d",
403 frompc
, tos
[toindex
].selfpc
,
405 rawarc
.raw_frompc
= frompc
;
406 rawarc
.raw_selfpc
= (u_long
)tos
[toindex
].selfpc
;
407 rawarc
.raw_count
= tos
[toindex
].count
;
408 fwrite((char *)&rawarc
, sizeof(rawarc
), 1, fp
);
415 * Reset the kernel profiling date structures.
418 reset(struct kvmvars
*kvp
)
424 setprof(kvp
, GMON_PROF_OFF
);
426 biggest
= kvp
->gpm
.kcountsize
;
427 if (kvp
->gpm
.fromssize
> biggest
)
428 biggest
= kvp
->gpm
.fromssize
;
429 if (kvp
->gpm
.tossize
> biggest
)
430 biggest
= kvp
->gpm
.tossize
;
431 if ((zbuf
= (char *)malloc(biggest
)) == NULL
)
432 errx(12, "cannot allocate zbuf space");
433 bzero(zbuf
, biggest
);
435 if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.kcount
, zbuf
,
436 kvp
->gpm
.kcountsize
) != kvp
->gpm
.kcountsize
)
437 errx(13, "tickbuf zero: %s", kvm_geterr(kvp
->kd
));
438 if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.froms
, zbuf
,
439 kvp
->gpm
.fromssize
) != kvp
->gpm
.fromssize
)
440 errx(14, "froms zero: %s", kvm_geterr(kvp
->kd
));
441 if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.tos
, zbuf
,
442 kvp
->gpm
.tossize
) != kvp
->gpm
.tossize
)
443 errx(15, "tos zero: %s", kvm_geterr(kvp
->kd
));
449 mib
[2] = GPROF_COUNT
;
450 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.kcountsize
) < 0)
451 err(13, "tickbuf zero");
452 mib
[2] = GPROF_FROMS
;
453 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.fromssize
) < 0)
454 err(14, "froms zero");
456 if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.tossize
) < 0)