* Copyright (c) 1983, 1992, 1993
* The Regents of the University of California. All rights reserved.
* %sccs.include.redist.c%
static char copyright
[] =
"@(#) Copyright (c) 1983, 1992, 1993\n\
The Regents of the University of California. All rights reserved.\n";
static char sccsid
[] = "@(#)kgmon.c 8.1 (Berkeley) %G%";
int bflag
, hflag
, kflag
, rflag
, pflag
;
void setprof
__P((struct kvmvars
*kvp
, int state
));
void dumpstate
__P((struct kvmvars
*kvp
));
void reset
__P((struct kvmvars
*kvp
));
main(int argc
, char **argv
)
int ch
, mode
, disp
, accessmode
;
while ((ch
= getopt(argc
, argv
, "M:N:bhpr")) != EOF
) {
"usage: kgmon [-bhrp] [-M core] [-N system]\n");
#define BACKWARD_COMPATIBILITY
#ifdef BACKWARD_COMPATIBILITY
accessmode
= openfiles(system
, kmemf
, &kvmvars
);
mode
= getprof(&kvmvars
);
if (accessmode
== O_RDWR
)
(void)fprintf(stdout
, "kgmon: kernel profiling is %s.\n",
disp
== GMON_PROF_OFF
? "off" : "running");
* Check that profiling is enabled and open any ncessary files.
openfiles(system
, kmemf
, kvp
)
int mib
[3], state
, size
, openmode
;
char errbuf
[_POSIX2_LINE_MAX
];
if (sysctl(mib
, 3, &state
, &size
, NULL
, 0) < 0) {
"kgmon: profiling not defined in kernel.\n");
if (!(bflag
|| hflag
|| rflag
||
(pflag
&& state
== GMON_PROF_ON
)))
if (sysctl(mib
, 3, NULL
, NULL
, &state
, size
) >= 0)
openmode
= (bflag
|| hflag
|| pflag
|| rflag
) ? O_RDWR
: O_RDONLY
;
kvp
->kd
= kvm_openfiles(system
, kmemf
, NULL
, openmode
, errbuf
);
if (openmode
== O_RDWR
) {
kvp
->kd
= kvm_openfiles(system
, kmemf
, NULL
, O_RDONLY
,
(void)fprintf(stderr
, "kgmon: kvm_openfiles: %s\n",
kern_readonly(GMON_PROF_ON
);
if (kvm_nlist(kvp
->kd
, nl
) < 0) {
(void)fprintf(stderr
, "kgmon: %s: no namelist\n", system
);
if (!nl
[N_GMONPARAM
].n_value
) {
"kgmon: profiling not defined in kernel.\n");
* Suppress options that require a writable kernel.
(void)fprintf(stderr
, "kgmon: kernel read-only: ");
if (pflag
&& mode
== GMON_PROF_ON
)
(void)fprintf(stderr
, "data may be inconsistent\n");
(void)fprintf(stderr
, "-r supressed\n");
(void)fprintf(stderr
, "-b supressed\n");
(void)fprintf(stderr
, "-h supressed\n");
rflag
= bflag
= hflag
= 0;
* Get the state of kernel profiling.
size
= kvm_read(kvp
->kd
, nl
[N_GMONPARAM
].n_value
, &kvp
->gpm
,
mib
[2] = GPROF_GMONPARAM
;
if (sysctl(mib
, 3, &kvp
->gpm
, &size
, NULL
, 0) < 0)
if (size
!= sizeof kvp
->gpm
) {
(void)fprintf(stderr
, "kgmon: cannot get gmonparam: %s\n",
kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
* Enable or disable kernel profiling according to the state variable.
struct gmonparam
*p
= (struct gmonparam
*)nl
[N_GMONPARAM
].n_value
;
int mib
[3], sz
, oldstate
;
if (sysctl(mib
, 3, &oldstate
, &sz
, NULL
, 0) < 0)
if (sysctl(mib
, 3, NULL
, NULL
, &state
, sz
) >= 0) {
} else if (kvm_write(kvp
->kd
, (u_long
)&p
->state
, (void *)&state
, sz
)
(void)fprintf(stderr
, "kgmon: warning: cannot turn profiling %s\n",
state
== GMON_PROF_OFF
? "off" : "on");
* Build the gmon.out file.
u_short
*froms
, *tickbuf
;
int fromindex
, endfrom
, toindex
;
setprof(kvp
, GMON_PROF_OFF
);
fp
= fopen("gmon.out", "w");
* Build the gmon header and write it to a file.
h
.ncnt
= kvp
->gpm
.kcountsize
+ sizeof(h
);
h
.profrate
= getprofhz(kvp
);
fwrite((char *)&h
, sizeof(h
), 1, fp
);
* Write out the tick buffer.
if ((tickbuf
= (u_short
*)malloc(kvp
->gpm
.kcountsize
)) == NULL
) {
fprintf(stderr
, "kgmon: cannot allocate kcount space\n");
i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.kcount
, (void *)tickbuf
,
if (sysctl(mib
, 3, tickbuf
, &i
, NULL
, 0) < 0)
if (i
!= kvp
->gpm
.kcountsize
) {
(void)fprintf(stderr
, "kgmon: read ticks: read %u, got %d: %s",
kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
if ((fwrite(tickbuf
, kvp
->gpm
.kcountsize
, 1, fp
)) != 1) {
perror("kgmon: writing tocks to gmon.out");
* Write out the arc info.
if ((froms
= (u_short
*)malloc(kvp
->gpm
.fromssize
)) == NULL
) {
fprintf(stderr
, "kgmon: cannot allocate froms space\n");
i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.froms
, (void *)froms
,
if (sysctl(mib
, 3, froms
, &i
, NULL
, 0) < 0)
if (i
!= kvp
->gpm
.fromssize
) {
(void)fprintf(stderr
, "kgmon: read froms: read %u, got %d: %s",
kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
if ((tos
= (struct tostruct
*)malloc(kvp
->gpm
.tossize
)) == NULL
) {
fprintf(stderr
, "kgmon: cannot allocate tos space\n");
i
= kvm_read(kvp
->kd
, (u_long
)kvp
->gpm
.tos
, (void *)tos
,
if (sysctl(mib
, 3, tos
, &i
, NULL
, 0) < 0)
if (i
!= kvp
->gpm
.tossize
) {
(void)fprintf(stderr
, "kgmon: read tos: read %u, got %d: %s",
kflag
? kvm_geterr(kvp
->kd
) : strerror(errno
));
(void)fprintf(stderr
, "kgmon: lowpc 0x%x, textsize 0x%x\n",
kvp
->gpm
.lowpc
, kvp
->gpm
.textsize
);
endfrom
= kvp
->gpm
.fromssize
/ sizeof(*froms
);
for (fromindex
= 0; fromindex
< endfrom
; ++fromindex
) {
if (froms
[fromindex
] == 0)
frompc
= (u_long
)kvp
->gpm
.lowpc
+
(fromindex
* kvp
->gpm
.hashfraction
* sizeof(*froms
));
for (toindex
= froms
[fromindex
]; toindex
!= 0;
toindex
= tos
[toindex
].link
) {
"%s: [mcleanup] frompc 0x%x selfpc 0x%x count %d\n",
"kgmon", frompc
, tos
[toindex
].selfpc
,
rawarc
.raw_frompc
= frompc
;
rawarc
.raw_selfpc
= (u_long
)tos
[toindex
].selfpc
;
rawarc
.raw_count
= tos
[toindex
].count
;
fwrite((char *)&rawarc
, sizeof(rawarc
), 1, fp
);
* Get the profiling rate.
int mib
[2], size
, profrate
;
struct clockinfo clockrate
;
if (kvm_read(kvp
->kd
, nl
[N_PROFHZ
].n_value
, &profrate
,
sizeof profrate
) != sizeof profrate
)
(void)fprintf(stderr
, "kgmon: get clockrate: %s\n",
if (sysctl(mib
, 2, &clockrate
, &size
, NULL
, 0) < 0)
(void)fprintf(stderr
, "kgmon: get clockrate: %s\n",
return (clockrate
.profhz
);
* Reset the kernel profiling date structures.
setprof(kvp
, GMON_PROF_OFF
);
biggest
= kvp
->gpm
.kcountsize
;
if (kvp
->gpm
.fromssize
> biggest
)
biggest
= kvp
->gpm
.fromssize
;
if (kvp
->gpm
.tossize
> biggest
)
biggest
= kvp
->gpm
.tossize
;
if ((zbuf
= (char *)malloc(biggest
)) == NULL
) {
fprintf(stderr
, "kgmon: cannot allocate zbuf space\n");
if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.kcount
, zbuf
,
kvp
->gpm
.kcountsize
) != kvp
->gpm
.kcountsize
) {
(void)fprintf(stderr
, "kgmon: tickbuf zero: %s\n",
if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.froms
, zbuf
,
kvp
->gpm
.fromssize
) != kvp
->gpm
.fromssize
) {
(void)fprintf(stderr
, "kgmon: froms zero: %s\n",
if (kvm_write(kvp
->kd
, (u_long
)kvp
->gpm
.tos
, zbuf
,
kvp
->gpm
.tossize
) != kvp
->gpm
.tossize
) {
(void)fprintf(stderr
, "kgmon: tos zero: %s\n",
if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.kcountsize
) < 0) {
(void)fprintf(stderr
, "kgmon: tickbuf zero: %s\n",
if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.fromssize
) < 0) {
(void)fprintf(stderr
, "kgmon: froms zero: %s\n",
if (sysctl(mib
, 3, NULL
, NULL
, zbuf
, kvp
->gpm
.tossize
) < 0) {
(void)fprintf(stderr
, "kgmon: tos zero: %s\n",