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
30 #if !defined(lint) && defined(LIBC_SCCS)
31 static char rcsid
[] = "$OpenBSD: gmon.c,v 1.8 1997/07/23 21:11:27 kstailey Exp $";
35 * This file is taken from Cygwin distribution. Please keep it in sync.
36 * The differences should be within __MINGW32__ guard.
44 #include <sys/param.h>
46 #include <sys/types.h>
51 //extern char *minbrk __asm ("minbrk");
54 #define MINUS_ONE_P (-1LL)
56 #define MINUS_ONE_P (-1)
60 #define bzero(ptr,size) memset (ptr, 0, size);
62 struct gmonparam _gmonparam
= { GMON_PROF_OFF
, NULL
, 0, NULL
, 0, NULL
, 0, 0L,
66 /* see profil(2) where this is describe (incorrectly) */
67 #define SCALE_1_TO_1 0x10000L
69 #define ERR(s) write(2, s, sizeof(s))
71 void moncontrol
__P((int));
76 void *rv
= malloc(size
);
80 return (void *) MINUS_ONE_P
;
83 void monstartup (size_t, size_t);
86 monstartup (size_t lowpc
, size_t highpc
)
90 struct gmonparam
*p
= &_gmonparam
;
93 * round lowpc and highpc to multiples of the density we're using
94 * so the rest of the scaling (here and in gprof) stays in ints.
96 p
->lowpc
= ROUNDDOWN(lowpc
, HISTFRACTION
* sizeof(HISTCOUNTER
));
97 p
->highpc
= ROUNDUP(highpc
, HISTFRACTION
* sizeof(HISTCOUNTER
));
98 p
->textsize
= p
->highpc
- p
->lowpc
;
99 p
->kcountsize
= p
->textsize
/ HISTFRACTION
;
100 p
->hashfraction
= HASHFRACTION
;
101 p
->fromssize
= p
->textsize
/ p
->hashfraction
;
102 p
->tolimit
= p
->textsize
* ARCDENSITY
/ 100;
103 if (p
->tolimit
< MINARCS
)
104 p
->tolimit
= MINARCS
;
105 else if (p
->tolimit
> MAXARCS
)
106 p
->tolimit
= MAXARCS
;
107 p
->tossize
= p
->tolimit
* sizeof(struct tostruct
);
109 cp
= fake_sbrk(p
->kcountsize
+ p
->fromssize
+ p
->tossize
);
110 if (cp
== (char *)MINUS_ONE_P
) {
111 ERR("monstartup: out of memory\n");
115 /* zero out cp as value will be added there */
116 bzero(cp
, p
->kcountsize
+ p
->fromssize
+ p
->tossize
);
118 p
->tos
= (struct tostruct
*)cp
;
120 p
->kcount
= (u_int16_t
*)cp
;
122 p
->froms
= (u_int16_t
*)cp
;
124 /* XXX minbrk needed? */
125 //minbrk = fake_sbrk(0);
128 o
= p
->highpc
- p
->lowpc
;
129 if (p
->kcountsize
< o
) {
131 s_scale
= ((float)p
->kcountsize
/ o
) * SCALE_1_TO_1
;
132 #else /* avoid floating point */
133 int quot
= o
/ p
->kcountsize
;
137 else if (quot
>= 0x100)
138 s_scale
= 0x10000 / quot
;
139 else if (o
>= 0x800000)
140 s_scale
= 0x1000000 / (o
/ (p
->kcountsize
>> 8));
142 s_scale
= 0x1000000 / ((o
<< 8) / p
->kcountsize
);
145 s_scale
= SCALE_1_TO_1
;
150 void _mcleanup (void);
160 struct rawarc rawarc
;
161 struct gmonparam
*p
= &_gmonparam
;
162 struct gmonhdr gmonhdr
, *hdr
;
163 char *filename
= (char *) "gmon.out";
170 if (p
->state
== GMON_PROF_ERROR
)
171 ERR("_mcleanup: tos overflow\n");
176 /* We copy an undocumented glibc feature: customizing the profiler's
177 output file name somewhat, depending on the env var GMON_OUT_PREFIX.
178 if GMON_OUT_PREFIX is unspecified, the file's name is "gmon.out".
180 if GMON_OUT_PREFIX is specified with at least one character, the
181 file's name is computed as "$GMON_OUT_PREFIX.$pid".
183 if GMON_OUT_PREFIX is specified but contains no characters, the
184 file's name is computed as "gmon.out.$pid". Cygwin-specific.
186 if ((prefix
= getenv("GMON_OUT_PREFIX")) != NULL
) {
188 /* Covers positive pid_t values. */
189 int32_t divisor
= 1000*1000*1000;
190 pid_t pid
= getpid();
191 size_t len
= strlen(prefix
);
194 len
= strlen(prefix
= filename
);
195 buf
= alloca(len
+ 13);// allow for '.', 10-digit pid, NUL, +1
197 memcpy(buf
, prefix
, len
);
200 while (divisor
> pid
) // skip leading zeroes
202 do { // convert pid to digits and store 'em
203 buf
[len
++] = (pid
/ divisor
) + '0';
205 } while (divisor
/= 10);
211 fd
= open(filename
, O_CREAT
|O_TRUNC
|O_WRONLY
|O_BINARY
, 0666);
217 log
= open("gmon.log", O_CREAT
|O_TRUNC
|O_WRONLY
, 0664);
219 perror("mcount: gmon.log");
222 len
= sprintf(dbuf
, "[mcleanup1] kcount 0x%x ssiz %d\n",
223 p
->kcount
, p
->kcountsize
);
224 write(log
, dbuf
, len
);
226 hdr
= (struct gmonhdr
*)&gmonhdr
;
227 bzero(hdr
, sizeof *hdr
);
229 hdr
->hpc
= p
->highpc
;
230 hdr
->ncnt
= p
->kcountsize
+ sizeof(gmonhdr
);
231 hdr
->version
= GMONVERSION
;
233 write(fd
, (char *)hdr
, sizeof *hdr
);
234 write(fd
, p
->kcount
, p
->kcountsize
);
235 endfrom
= p
->fromssize
/ sizeof(*p
->froms
);
236 for (fromindex
= 0; fromindex
< endfrom
; fromindex
++) {
237 if (p
->froms
[fromindex
] == 0)
241 frompc
+= fromindex
* p
->hashfraction
* sizeof(*p
->froms
);
242 for (toindex
= p
->froms
[fromindex
]; toindex
!= 0;
243 toindex
= p
->tos
[toindex
].link
) {
246 "[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" ,
247 frompc
, p
->tos
[toindex
].selfpc
,
248 p
->tos
[toindex
].count
);
249 write(log
, dbuf
, len
);
251 rawarc
.raw_frompc
= frompc
;
252 rawarc
.raw_selfpc
= p
->tos
[toindex
].selfpc
;
253 rawarc
.raw_count
= p
->tos
[toindex
].count
;
254 write(fd
, &rawarc
, sizeof rawarc
);
262 * profiling is what mcount checks to see if
263 * all the data structures are ready.
268 struct gmonparam
*p
= &_gmonparam
;
272 profil((char *)p
->kcount
, p
->kcountsize
, p
->lowpc
,
274 p
->state
= GMON_PROF_ON
;
277 profil((char *)0, 0, 0, 0);
278 p
->state
= GMON_PROF_OFF
;