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 * 4. 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 * @(#)gmon.c 8.1 (Berkeley) 6/4/93
30 * $FreeBSD: src/lib/libc/gmon/gmon.c,v 1.22 2007/01/09 00:27:58 imp Exp $
31 * $DragonFly: src/lib/libc/gmon/gmon.c,v 1.8 2005/11/13 01:18:20 swildner Exp $
34 #include "namespace.h"
35 #include <sys/param.h>
38 #include <sys/sysctl.h>
46 #include "un-namespace.h"
48 #include "libc_private.h"
50 #if defined(__i386__) || defined(__sparc64__) || defined(__amd64__) || defined(__powerpc__)
51 extern char *minbrk
__asm (".minbrk");
53 extern char *minbrk
__asm ("minbrk");
56 struct gmonparam _gmonparam
= { GMON_PROF_OFF
};
59 /* see profil(2) where this is describe (incorrectly) */
60 #define SCALE_1_TO_1 0x10000L
62 #define ERR(s) _write(2, s, sizeof(s))
65 static int hertz(void);
68 monstartup(u_long lowpc
, u_long highpc
)
72 struct gmonparam
*p
= &_gmonparam
;
75 * round lowpc and highpc to multiples of the density we're using
76 * so the rest of the scaling (here and in gprof) stays in ints.
78 p
->lowpc
= ROUNDDOWN(lowpc
, HISTFRACTION
* sizeof(HISTCOUNTER
));
79 p
->highpc
= ROUNDUP(highpc
, HISTFRACTION
* sizeof(HISTCOUNTER
));
80 p
->textsize
= p
->highpc
- p
->lowpc
;
81 p
->kcountsize
= p
->textsize
/ HISTFRACTION
;
82 p
->hashfraction
= HASHFRACTION
;
83 p
->fromssize
= p
->textsize
/ HASHFRACTION
;
84 p
->tolimit
= p
->textsize
* ARCDENSITY
/ 100;
85 if (p
->tolimit
< MINARCS
)
87 else if (p
->tolimit
> MAXARCS
)
89 p
->tossize
= p
->tolimit
* sizeof(struct tostruct
);
91 cp
= sbrk(p
->kcountsize
+ p
->fromssize
+ p
->tossize
);
92 if (cp
== (char *)-1) {
93 ERR("monstartup: out of memory\n");
97 bzero(cp
, p
->kcountsize
+ p
->fromssize
+ p
->tossize
);
99 p
->tos
= (struct tostruct
*)cp
;
101 p
->kcount
= (u_short
*)cp
;
103 p
->froms
= (u_short
*)cp
;
108 o
= p
->highpc
- p
->lowpc
;
109 if (p
->kcountsize
< o
) {
111 s_scale
= ((float)p
->kcountsize
/ o
) * SCALE_1_TO_1
;
112 #else /* avoid floating point */
113 int quot
= o
/ p
->kcountsize
;
117 else if (quot
>= 0x100)
118 s_scale
= 0x10000 / quot
;
119 else if (o
>= 0x800000)
120 s_scale
= 0x1000000 / (o
/ (p
->kcountsize
>> 8));
122 s_scale
= 0x1000000 / ((o
<< 8) / p
->kcountsize
);
125 s_scale
= SCALE_1_TO_1
;
138 struct rawarc rawarc
;
139 struct gmonparam
*p
= &_gmonparam
;
140 struct gmonhdr gmonhdr
, *hdr
;
141 struct clockinfo clockinfo
;
150 if (p
->state
== GMON_PROF_ERROR
)
151 ERR("_mcleanup: tos overflow\n");
153 size
= sizeof(clockinfo
);
155 mib
[1] = KERN_CLOCKRATE
;
156 if (sysctl(mib
, 2, &clockinfo
, &size
, NULL
, 0) < 0) {
160 clockinfo
.profhz
= hertz();
161 } else if (clockinfo
.profhz
== 0) {
162 if (clockinfo
.hz
!= 0)
163 clockinfo
.profhz
= clockinfo
.hz
;
165 clockinfo
.profhz
= hertz();
169 snprintf(outname
, sizeof(outname
), "%s.gmon", _getprogname());
170 fd
= _open(outname
, O_CREAT
|O_TRUNC
|O_WRONLY
, 0666);
172 _warn("_mcleanup: %s", outname
);
176 log
= _open("gmon.log", O_CREAT
|O_TRUNC
|O_WRONLY
, 0664);
178 _warn("_mcleanup: gmon.log");
181 len
= sprintf(buf
, "[mcleanup1] kcount 0x%p ssiz %lu\n",
182 p
->kcount
, p
->kcountsize
);
183 _write(log
, buf
, len
);
185 hdr
= (struct gmonhdr
*)&gmonhdr
;
186 bzero(hdr
, sizeof(*hdr
));
188 hdr
->hpc
= p
->highpc
;
189 hdr
->ncnt
= p
->kcountsize
+ sizeof(gmonhdr
);
190 hdr
->version
= GMONVERSION
;
191 hdr
->profrate
= clockinfo
.profhz
;
192 _write(fd
, (char *)hdr
, sizeof *hdr
);
193 _write(fd
, p
->kcount
, p
->kcountsize
);
194 endfrom
= p
->fromssize
/ sizeof(*p
->froms
);
195 for (fromindex
= 0; fromindex
< endfrom
; fromindex
++) {
196 if (p
->froms
[fromindex
] == 0)
200 frompc
+= fromindex
* p
->hashfraction
* sizeof(*p
->froms
);
201 for (toindex
= p
->froms
[fromindex
]; toindex
!= 0;
202 toindex
= p
->tos
[toindex
].link
) {
205 "[mcleanup2] frompc 0x%lx selfpc 0x%lx count %lu\n" ,
206 frompc
, p
->tos
[toindex
].selfpc
,
207 p
->tos
[toindex
].count
);
208 _write(log
, buf
, len
);
210 rawarc
.raw_frompc
= frompc
;
211 rawarc
.raw_selfpc
= p
->tos
[toindex
].selfpc
;
212 rawarc
.raw_count
= p
->tos
[toindex
].count
;
213 _write(fd
, &rawarc
, sizeof rawarc
);
221 * profiling is what mcount checks to see if
222 * all the data structures are ready.
227 struct gmonparam
*p
= &_gmonparam
;
231 profil((char *)p
->kcount
, p
->kcountsize
, p
->lowpc
, s_scale
);
232 p
->state
= GMON_PROF_ON
;
235 profil(NULL
, 0, 0, 0);
236 p
->state
= GMON_PROF_OFF
;
241 * discover the tick frequency of the machine
242 * if something goes wrong, we return 0, an impossible hertz.
247 struct itimerval tim
;
249 tim
.it_interval
.tv_sec
= 0;
250 tim
.it_interval
.tv_usec
= 1;
251 tim
.it_value
.tv_sec
= 0;
252 tim
.it_value
.tv_usec
= 0;
253 setitimer(ITIMER_REAL
, &tim
, 0);
254 setitimer(ITIMER_REAL
, 0, &tim
);
255 if (tim
.it_interval
.tv_usec
< 2)
257 return (1000000 / tim
.it_interval
.tv_usec
);