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 #include <sys/param.h>
32 #include <sys/gmon_out.h>
44 #include <libc-internal.h>
50 /* Head of basic-block list or NULL. */
51 struct __bb
*__bb_head attribute_hidden
;
53 struct gmonparam _gmonparam attribute_hidden
= { GMON_PROF_OFF
};
56 * See profil(2) where this is described:
59 #define SCALE_1_TO_1 0x10000L
61 #define ERR(s) __write (STDERR_FILENO, s, sizeof (s) - 1)
63 void moncontrol
__P ((int mode
));
64 void __moncontrol
__P ((int mode
));
65 static void write_hist
__P ((int fd
)) internal_function
;
66 static void write_call_graph
__P ((int fd
)) internal_function
;
67 static void write_bb_counts
__P ((int fd
)) internal_function
;
71 * profiling is what mcount checks to see if
72 * all the data structures are ready.
78 struct gmonparam
*p
= &_gmonparam
;
80 /* Don't change the state if we ran into an error. */
81 if (p
->state
== GMON_PROF_ERROR
)
87 __profil((void *) p
->kcount
, p
->kcountsize
, p
->lowpc
, s_scale
);
88 p
->state
= GMON_PROF_ON
;
93 __profil(NULL
, 0, 0, 0);
94 p
->state
= GMON_PROF_OFF
;
97 weak_alias (__moncontrol
, moncontrol
)
101 __monstartup (lowpc
, highpc
)
107 struct gmonparam
*p
= &_gmonparam
;
110 * round lowpc and highpc to multiples of the density we're using
111 * so the rest of the scaling (here and in gprof) stays in ints.
113 p
->lowpc
= ROUNDDOWN(lowpc
, HISTFRACTION
* sizeof(HISTCOUNTER
));
114 p
->highpc
= ROUNDUP(highpc
, HISTFRACTION
* sizeof(HISTCOUNTER
));
115 p
->textsize
= p
->highpc
- p
->lowpc
;
116 p
->kcountsize
= p
->textsize
/ HISTFRACTION
;
117 p
->hashfraction
= HASHFRACTION
;
118 p
->log_hashfraction
= -1;
119 /* The following test must be kept in sync with the corresponding
121 if ((HASHFRACTION
& (HASHFRACTION
- 1)) == 0) {
122 /* if HASHFRACTION is a power of two, mcount can use shifting
123 instead of integer division. Precompute shift amount. */
124 p
->log_hashfraction
= ffs(p
->hashfraction
* sizeof(*p
->froms
)) - 1;
126 p
->fromssize
= p
->textsize
/ HASHFRACTION
;
127 p
->tolimit
= p
->textsize
* ARCDENSITY
/ 100;
128 if (p
->tolimit
< MINARCS
)
129 p
->tolimit
= MINARCS
;
130 else if (p
->tolimit
> MAXARCS
)
131 p
->tolimit
= MAXARCS
;
132 p
->tossize
= p
->tolimit
* sizeof(struct tostruct
);
134 cp
= calloc (p
->kcountsize
+ p
->fromssize
+ p
->tossize
, 1);
137 ERR("monstartup: out of memory\n");
139 p
->state
= GMON_PROF_ERROR
;
142 p
->tos
= (struct tostruct
*)cp
;
144 p
->kcount
= (HISTCOUNTER
*)cp
;
146 p
->froms
= (ARCINDEX
*)cp
;
150 o
= p
->highpc
- p
->lowpc
;
151 if (p
->kcountsize
< (u_long
) o
)
154 s_scale
= ((float)p
->kcountsize
/ o
) * SCALE_1_TO_1
;
156 /* avoid floating point operations */
157 int quot
= o
/ p
->kcountsize
;
161 else if (quot
>= 0x100)
162 s_scale
= 0x10000 / quot
;
163 else if (o
>= 0x800000)
164 s_scale
= 0x1000000 / (o
/ (p
->kcountsize
>> 8));
166 s_scale
= 0x1000000 / ((o
<< 8) / p
->kcountsize
);
169 s_scale
= SCALE_1_TO_1
;
173 weak_alias(__monstartup
, monstartup
)
181 u_char tag
= GMON_TAG_TIME_HIST
;
182 struct gmon_hist_hdr thdr
__attribute__ ((aligned (__alignof__ (char *))));
184 if (_gmonparam
.kcountsize
> 0)
186 struct iovec iov
[3] =
188 { &tag
, sizeof (tag
) },
189 { &thdr
, sizeof (struct gmon_hist_hdr
) },
190 { _gmonparam
.kcount
, _gmonparam
.kcountsize
}
193 *(char **) thdr
.low_pc
= (char *) _gmonparam
.lowpc
;
194 *(char **) thdr
.high_pc
= (char *) _gmonparam
.highpc
;
195 *(int32_t *) thdr
.hist_size
= (_gmonparam
.kcountsize
196 / sizeof (HISTCOUNTER
));
197 *(int32_t *) thdr
.prof_rate
= __profile_frequency ();
198 strncpy (thdr
.dimen
, "seconds", sizeof (thdr
.dimen
));
199 thdr
.dimen_abbrev
= 's';
201 __writev (fd
, iov
, 3);
208 write_call_graph (fd
)
211 #define NARCS_PER_WRITEV 32
212 u_char tag
= GMON_TAG_CG_ARC
;
213 struct gmon_cg_arc_record raw_arc
[NARCS_PER_WRITEV
]
214 __attribute__ ((aligned (__alignof__ (char*))));
215 ARCINDEX from_index
, to_index
;
218 struct iovec iov
[2 * NARCS_PER_WRITEV
];
221 for (nfilled
= 0; nfilled
< NARCS_PER_WRITEV
; ++nfilled
)
223 iov
[2 * nfilled
].iov_base
= &tag
;
224 iov
[2 * nfilled
].iov_len
= sizeof (tag
);
226 iov
[2 * nfilled
+ 1].iov_base
= &raw_arc
[nfilled
];
227 iov
[2 * nfilled
+ 1].iov_len
= sizeof (struct gmon_cg_arc_record
);
231 from_len
= _gmonparam
.fromssize
/ sizeof (*_gmonparam
.froms
);
232 for (from_index
= 0; from_index
< from_len
; ++from_index
)
234 if (_gmonparam
.froms
[from_index
] == 0)
237 frompc
= _gmonparam
.lowpc
;
238 frompc
+= (from_index
* _gmonparam
.hashfraction
239 * sizeof (*_gmonparam
.froms
));
240 for (to_index
= _gmonparam
.froms
[from_index
];
242 to_index
= _gmonparam
.tos
[to_index
].link
)
252 arc
.frompc
= (char *) frompc
;
253 arc
.selfpc
= (char *) _gmonparam
.tos
[to_index
].selfpc
;
254 arc
.count
= _gmonparam
.tos
[to_index
].count
;
255 memcpy (raw_arc
+ nfilled
, &arc
, sizeof (raw_arc
[0]));
257 if (++nfilled
== NARCS_PER_WRITEV
)
259 __writev (fd
, iov
, 2 * nfilled
);
265 __writev (fd
, iov
, 2 * nfilled
);
275 u_char tag
= GMON_TAG_BB_COUNT
;
279 struct iovec bbhead
[2] =
281 { &tag
, sizeof (tag
) },
282 { &ncounts
, sizeof (ncounts
) }
284 struct iovec bbbody
[8];
287 for (i
= 0; i
< (sizeof (bbbody
) / sizeof (bbbody
[0])); i
+= 2)
289 bbbody
[i
].iov_len
= sizeof (grp
->addresses
[0]);
290 bbbody
[i
+ 1].iov_len
= sizeof (grp
->counts
[0]);
293 /* Write each group of basic-block info (all basic-blocks in a
294 compilation unit form a single group). */
296 for (grp
= __bb_head
; grp
; grp
= grp
->next
)
298 ncounts
= grp
->ncounts
;
299 __writev (fd
, bbhead
, 2);
300 for (nfilled
= i
= 0; i
< ncounts
; ++i
)
302 if (nfilled
> (sizeof (bbbody
) / sizeof (bbbody
[0])) - 2)
304 __writev (fd
, bbbody
, nfilled
);
308 bbbody
[nfilled
++].iov_base
= (char *) &grp
->addresses
[i
];
309 bbbody
[nfilled
++].iov_base
= &grp
->counts
[i
];
312 __writev (fd
, bbbody
, nfilled
);
320 struct gmon_hdr ghdr
__attribute__ ((aligned (__alignof__ (int))));
325 # define O_NOFOLLOW 0
328 env
= getenv ("GMON_OUT_PREFIX");
329 if (env
!= NULL
&& !__libc_enable_secure
)
331 size_t len
= strlen (env
);
333 sprintf (buf
, "%s.%u", env
, __getpid ());
334 fd
= __open (buf
, O_CREAT
|O_TRUNC
|O_WRONLY
|O_NOFOLLOW
, 0666);
339 fd
= __open ("gmon.out", O_CREAT
|O_TRUNC
|O_WRONLY
|O_NOFOLLOW
, 0666);
345 if (_IO_fwide (stderr
, 0) > 0)
346 __fwprintf (stderr
, L
"_mcleanup: gmon.out: %s\n",
347 __strerror_r (errnum
, buf
, sizeof buf
));
350 fprintf (stderr
, "_mcleanup: gmon.out: %s\n",
351 __strerror_r (errnum
, buf
, sizeof buf
));
356 /* write gmon.out header: */
357 memset (&ghdr
, '\0', sizeof (struct gmon_hdr
));
358 memcpy (&ghdr
.cookie
[0], GMON_MAGIC
, sizeof (ghdr
.cookie
));
359 *(int32_t *) ghdr
.version
= GMON_VERSION
;
360 __write (fd
, &ghdr
, sizeof (struct gmon_hdr
));
362 /* write PC histogram: */
365 /* write call-graph: */
366 write_call_graph (fd
);
368 /* write basic-block execution counts: */
369 write_bb_counts (fd
);
376 __write_profiling (void)
378 int save
= _gmonparam
.state
;
379 _gmonparam
.state
= GMON_PROF_OFF
;
380 if (save
== GMON_PROF_ON
)
382 _gmonparam
.state
= save
;
385 /* This symbol isn't used anywhere in the DSO and it is not exported.
386 This would normally mean it should be removed to get the same API
387 in static libraries. But since profiling is special in static libs
388 anyway we keep it. But not when building the DSO since some
389 quality assurance tests will otherwise trigger. */
390 weak_alias (__write_profiling
, write_profiling
)
399 if (_gmonparam
.state
!= GMON_PROF_ERROR
)
402 /* free the memory. */
403 if (_gmonparam
.tos
!= NULL
)
404 free (_gmonparam
.tos
);