]> git.ipfire.org Git - thirdparty/glibc.git/blame - gmon/gmon.c
Update.
[thirdparty/glibc.git] / gmon / gmon.c
CommitLineData
11c981a9
RM
1/*-
2 * Copyright (c) 1983, 1992, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
20 *
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
31 * SUCH DAMAGE.
32 */
11c981a9
RM
33#include <sys/param.h>
34#include <sys/time.h>
35#include <sys/gmon.h>
b20e47cb 36#include <sys/gmon_out.h>
5ae9d168 37#include <sys/uio.h>
11c981a9 38
3996f34b 39#include <errno.h>
11c981a9
RM
40#include <stdio.h>
41#include <fcntl.h>
b20e47cb
RM
42#include <unistd.h>
43
44#include <stdio.h>
11c981a9
RM
45#include <stdlib.h>
46#include <string.h>
47#include <unistd.h>
48
8f2ece69
UD
49extern char *_strerror_internal __P ((int, char *buf, size_t));
50
a68b0d31 51extern int __profile_frequency __P ((void));
d68171ed 52
b20e47cb
RM
53struct __bb *__bb_head; /* Head of basic-block list or NULL. */
54
11c981a9
RM
55struct gmonparam _gmonparam = { GMON_PROF_OFF };
56
b20e47cb
RM
57/*
58 * See profil(2) where this is described:
59 */
11c981a9 60static int s_scale;
11c981a9
RM
61#define SCALE_1_TO_1 0x10000L
62
b236e99d 63#define ERR(s) write(2, s, sizeof(s) - 1)
b20e47cb 64
11336c16 65void moncontrol __P ((int mode));
3996f34b 66void __moncontrol __P ((int mode));
11336c16
UD
67static void write_hist __P ((int fd));
68static void write_call_graph __P ((int fd));
69static void write_bb_counts __P ((int fd));
70
b20e47cb
RM
71/*
72 * Control profiling
73 * profiling is what mcount checks to see if
74 * all the data structures are ready.
75 */
76void
3996f34b 77__moncontrol (mode)
a68b0d31 78 int mode;
b20e47cb
RM
79{
80 struct gmonparam *p = &_gmonparam;
81
82 if (mode)
83 {
84 /* start */
85 profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale);
86 p->state = GMON_PROF_ON;
87 }
88 else
89 {
90 /* stop */
91 profil((void *) 0, 0, 0, 0);
92 p->state = GMON_PROF_OFF;
93 }
94}
11c981a9 95
11c981a9
RM
96
97void
3996f34b 98__monstartup (lowpc, highpc)
a68b0d31
UD
99 u_long lowpc;
100 u_long highpc;
11c981a9 101{
b20e47cb
RM
102 register int o;
103 char *cp;
104 struct gmonparam *p = &_gmonparam;
105
106 /*
107 * round lowpc and highpc to multiples of the density we're using
108 * so the rest of the scaling (here and in gprof) stays in ints.
109 */
110 p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
111 p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
112 p->textsize = p->highpc - p->lowpc;
113 p->kcountsize = p->textsize / HISTFRACTION;
114 p->hashfraction = HASHFRACTION;
115 p->log_hashfraction = -1;
116 if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) {
117 /* if HASHFRACTION is a power of two, mcount can use shifting
118 instead of integer division. Precompute shift amount. */
119 p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1;
120 }
121 p->fromssize = p->textsize / HASHFRACTION;
122 p->tolimit = p->textsize * ARCDENSITY / 100;
123 if (p->tolimit < MINARCS)
124 p->tolimit = MINARCS;
125 else if (p->tolimit > MAXARCS)
126 p->tolimit = MAXARCS;
127 p->tossize = p->tolimit * sizeof(struct tostruct);
11c981a9 128
0413b54c 129 cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1);
b20e47cb
RM
130 if (! cp)
131 {
e7fd8a39 132 ERR(_("monstartup: out of memory\n"));
b20e47cb
RM
133 return;
134 }
b20e47cb
RM
135 p->tos = (struct tostruct *)cp;
136 cp += p->tossize;
137 p->kcount = (u_short *)cp;
138 cp += p->kcountsize;
139 p->froms = (u_short *)cp;
11c981a9 140
b20e47cb
RM
141 p->tos[0].link = 0;
142
143 o = p->highpc - p->lowpc;
d68171ed 144 if (p->kcountsize < (u_long) o)
b20e47cb 145 {
11c981a9 146#ifndef hp300
b20e47cb
RM
147 s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
148#else
149 /* avoid floating point operations */
150 int quot = o / p->kcountsize;
151
152 if (quot >= 0x10000)
153 s_scale = 1;
154 else if (quot >= 0x100)
155 s_scale = 0x10000 / quot;
156 else if (o >= 0x800000)
157 s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
158 else
159 s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
11c981a9 160#endif
b20e47cb
RM
161 } else
162 s_scale = SCALE_1_TO_1;
11c981a9 163
3996f34b 164 __moncontrol(1);
11c981a9 165}
8f2ece69 166weak_alias(__monstartup, monstartup)
11c981a9 167
b20e47cb
RM
168
169static void
a68b0d31
UD
170write_hist (fd)
171 int fd;
11c981a9 172{
5ae9d168
UD
173 u_char tag = GMON_TAG_TIME_HIST;
174 struct gmon_hist_hdr thdr __attribute__ ((aligned (__alignof__ (char *))));
11c981a9 175
b20e47cb
RM
176 if (_gmonparam.kcountsize > 0)
177 {
5ae9d168
UD
178 struct iovec iov[3] =
179 {
180 { &tag, sizeof (tag) },
181 { &thdr, sizeof (struct gmon_hist_hdr) },
182 { _gmonparam.kcount, _gmonparam.kcountsize }
183 };
184
185 *(char **) thdr.low_pc = (char *) _gmonparam.lowpc;
186 *(char **) thdr.high_pc = (char *) _gmonparam.highpc;
3996f34b
UD
187 *(int32_t *) thdr.hist_size = (_gmonparam.kcountsize
188 / sizeof (HISTCOUNTER));
189 *(int32_t *) thdr.prof_rate = __profile_frequency ();
5ae9d168 190 strncpy (thdr.dimen, "seconds", sizeof (thdr.dimen));
b20e47cb 191 thdr.dimen_abbrev = 's';
11c981a9 192
5ae9d168 193 __writev (fd, iov, 3);
b20e47cb 194 }
11c981a9
RM
195}
196
b20e47cb
RM
197
198static void
a68b0d31
UD
199write_call_graph (fd)
200 int fd;
11c981a9 201{
e7fd8a39 202#define NARCS_PER_WRITEV 32
5ae9d168 203 u_char tag = GMON_TAG_CG_ARC;
e7fd8a39 204 struct gmon_cg_arc_record raw_arc[NARCS_PER_WRITEV]
5ae9d168 205 __attribute__ ((aligned (__alignof__ (char*))));
b20e47cb
RM
206 int from_index, to_index, from_len;
207 u_long frompc;
e7fd8a39
UD
208 struct iovec iov[2 * NARCS_PER_WRITEV];
209 int nfilled;
b20e47cb 210
e7fd8a39 211 for (nfilled = 0; nfilled < NARCS_PER_WRITEV; ++nfilled)
5ae9d168 212 {
e7fd8a39
UD
213 iov[2 * nfilled].iov_base = &tag;
214 iov[2 * nfilled].iov_len = sizeof (tag);
5ae9d168 215
e7fd8a39
UD
216 iov[2 * nfilled + 1].iov_base = &raw_arc[nfilled];
217 iov[2 * nfilled + 1].iov_len = sizeof (struct gmon_cg_arc_record);
218 }
219
220 nfilled = 0;
5ae9d168 221 from_len = _gmonparam.fromssize / sizeof (*_gmonparam.froms);
b20e47cb
RM
222 for (from_index = 0; from_index < from_len; ++from_index)
223 {
224 if (_gmonparam.froms[from_index] == 0)
225 continue;
226
227 frompc = _gmonparam.lowpc;
228 frompc += (from_index * _gmonparam.hashfraction
5ae9d168 229 * sizeof (*_gmonparam.froms));
b20e47cb
RM
230 for (to_index = _gmonparam.froms[from_index];
231 to_index != 0;
232 to_index = _gmonparam.tos[to_index].link)
233 {
e7fd8a39
UD
234 *(char **) raw_arc[nfilled].from_pc = (char *) frompc;
235 *(char **) raw_arc[nfilled].self_pc =
236 (char *)_gmonparam.tos[to_index].selfpc;
237 *(int *) raw_arc[nfilled].count = _gmonparam.tos[to_index].count;
238
239 if (++nfilled == NARCS_PER_WRITEV)
3e5f5557
UD
240 {
241 __writev (fd, iov, 2 * nfilled);
242 nfilled = 0;
243 }
11c981a9 244 }
b20e47cb 245 }
e7fd8a39
UD
246 if (nfilled > 0)
247 __writev (fd, iov, 2 * nfilled);
11c981a9
RM
248}
249
b20e47cb
RM
250
251static void
a68b0d31
UD
252write_bb_counts (fd)
253 int fd;
11c981a9 254{
b20e47cb 255 struct __bb *grp;
5ae9d168 256 u_char tag = GMON_TAG_BB_COUNT;
3e5f5557
UD
257 size_t ncounts;
258 size_t i;
b20e47cb 259
5ae9d168
UD
260 struct iovec bbhead[2] =
261 {
262 { &tag, sizeof (tag) },
263 { &ncounts, sizeof (ncounts) }
264 };
3e5f5557
UD
265 struct iovec bbbody[8];
266 size_t nfilled;
5ae9d168 267
3e5f5557
UD
268 for (i = 0; i < (sizeof (bbbody) / sizeof (bbbody[0])); i += 2)
269 {
270 bbbody[i].iov_len = sizeof (grp->addresses[0]);
271 bbbody[i + 1].iov_len = sizeof (grp->counts[0]);
272 }
5ae9d168 273
b20e47cb
RM
274 /* Write each group of basic-block info (all basic-blocks in a
275 compilation unit form a single group). */
276
277 for (grp = __bb_head; grp; grp = grp->next)
278 {
279 ncounts = grp->ncounts;
5ae9d168 280 __writev (fd, bbhead, 2);
e7fd8a39 281 for (nfilled = i = 0; i < ncounts; ++i)
b20e47cb 282 {
3e5f5557
UD
283 if (nfilled > (sizeof (bbbody) / sizeof (bbbody[0])) - 2)
284 {
285 __writev (fd, bbbody, nfilled);
286 nfilled = 0;
287 }
288
289 bbbody[nfilled++].iov_base = (char *) &grp->addresses[i];
290 bbbody[nfilled++].iov_base = &grp->counts[i];
b20e47cb 291 }
e7fd8a39
UD
292 if (nfilled > 0)
293 __writev (fd, bbbody, nfilled);
b20e47cb 294 }
11c981a9
RM
295}
296
297
0413b54c
UD
298static void
299write_gmon (void)
b20e47cb 300{
5ae9d168 301 struct gmon_hdr ghdr __attribute__ ((aligned (__alignof__ (int))));
b20e47cb
RM
302 int fd;
303
5ae9d168 304 fd = __open ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY, 0666);
b20e47cb
RM
305 if (fd < 0)
306 {
3996f34b
UD
307 char buf[300];
308 int errnum = errno;
309 fprintf (stderr, "_mcleanup: gmon.out: %s\n",
310 _strerror_internal (errnum, buf, sizeof buf));
b20e47cb
RM
311 return;
312 }
313
314 /* write gmon.out header: */
3996f34b 315 memset (&ghdr, '\0', sizeof (struct gmon_hdr));
5ae9d168 316 memcpy (&ghdr.cookie[0], GMON_MAGIC, sizeof (ghdr.cookie));
3996f34b 317 *(int32_t *) ghdr.version = GMON_VERSION;
5ae9d168 318 __write (fd, &ghdr, sizeof (struct gmon_hdr));
b20e47cb
RM
319
320 /* write PC histogram: */
5ae9d168 321 write_hist (fd);
b20e47cb
RM
322
323 /* write call-graph: */
5ae9d168 324 write_call_graph (fd);
b20e47cb
RM
325
326 /* write basic-block execution counts: */
5ae9d168 327 write_bb_counts (fd);
b20e47cb 328
0413b54c
UD
329 __close (fd);
330}
331
332
333void
334__write_profiling (void)
335{
336 int save = _gmonparam.state;
337 _gmonparam.state = GMON_PROF_OFF;
338 if (save == GMON_PROF_ON)
339 write_gmon ();
340 _gmonparam.state = save;
341}
342weak_alias (__write_profiling, write_profiling)
343
344
345void
346_mcleanup (void)
347{
348 __moncontrol (0);
349
350 write_gmon ();
351
ebbad4cc
UD
352 /* free the memory. */
353 free (_gmonparam.tos);
b20e47cb 354}