]> git.ipfire.org Git - thirdparty/glibc.git/blame - gmon/gmon.c
gmon: Remove internal_function attribute
[thirdparty/glibc.git] / gmon / gmon.c
CommitLineData
11c981a9 1/*-
3ce1f295 2 * Copyright (c) 1983, 1992, 1993, 2011
11c981a9
RM
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.
11c981a9
RM
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.
16 *
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
27 * SUCH DAMAGE.
28 */
11c981a9
RM
29#include <sys/param.h>
30#include <sys/time.h>
31#include <sys/gmon.h>
b20e47cb 32#include <sys/gmon_out.h>
5ae9d168 33#include <sys/uio.h>
11c981a9 34
3996f34b 35#include <errno.h>
11c981a9
RM
36#include <stdio.h>
37#include <fcntl.h>
b20e47cb 38#include <unistd.h>
3ce1f295 39#include <wchar.h>
b20e47cb
RM
40
41#include <stdio.h>
11c981a9
RM
42#include <stdlib.h>
43#include <string.h>
f521be31 44#include <stddef.h>
11c981a9 45#include <unistd.h>
66539a73 46#include <libc-internal.h>
fbb37d25 47#include <not-cancel.h>
d68171ed 48
8dcc6a3f 49
100351c3
UD
50/* Head of basic-block list or NULL. */
51struct __bb *__bb_head attribute_hidden;
b20e47cb 52
0e47dbd0 53struct gmonparam _gmonparam attribute_hidden = { GMON_PROF_OFF };
11c981a9 54
b20e47cb
RM
55/*
56 * See profil(2) where this is described:
57 */
11c981a9 58static int s_scale;
11c981a9
RM
59#define SCALE_1_TO_1 0x10000L
60
c647fb88 61#define ERR(s) __write_nocancel (STDERR_FILENO, s, sizeof (s) - 1)
b20e47cb 62
79937577
UD
63void moncontrol (int mode);
64void __moncontrol (int mode);
8d2f9410
FW
65static void write_hist (int fd);
66static void write_call_graph (int fd);
67static void write_bb_counts (int fd);
11336c16 68
b20e47cb
RM
69/*
70 * Control profiling
71 * profiling is what mcount checks to see if
72 * all the data structures are ready.
73 */
74void
9d46370c 75__moncontrol (int mode)
b20e47cb
RM
76{
77 struct gmonparam *p = &_gmonparam;
78
14e9dd67
UD
79 /* Don't change the state if we ran into an error. */
80 if (p->state == GMON_PROF_ERROR)
81 return;
82
b20e47cb
RM
83 if (mode)
84 {
85 /* start */
9a0a462c 86 __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale);
b20e47cb
RM
87 p->state = GMON_PROF_ON;
88 }
89 else
90 {
91 /* stop */
9a0a462c 92 __profil(NULL, 0, 0, 0);
b20e47cb
RM
93 p->state = GMON_PROF_OFF;
94 }
95}
69173865 96weak_alias (__moncontrol, moncontrol)
11c981a9 97
11c981a9
RM
98
99void
9d46370c 100__monstartup (u_long lowpc, u_long highpc)
11c981a9 101{
2e09a79a 102 int o;
b20e47cb
RM
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;
69ac9d07 113 p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms));
b20e47cb
RM
114 p->hashfraction = HASHFRACTION;
115 p->log_hashfraction = -1;
9a0a462c
UD
116 /* The following test must be kept in sync with the corresponding
117 test in mcount.c. */
b20e47cb
RM
118 if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) {
119 /* if HASHFRACTION is a power of two, mcount can use shifting
120 instead of integer division. Precompute shift amount. */
121 p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1;
122 }
123 p->fromssize = p->textsize / HASHFRACTION;
124 p->tolimit = p->textsize * ARCDENSITY / 100;
125 if (p->tolimit < MINARCS)
126 p->tolimit = MINARCS;
127 else if (p->tolimit > MAXARCS)
128 p->tolimit = MAXARCS;
129 p->tossize = p->tolimit * sizeof(struct tostruct);
11c981a9 130
0413b54c 131 cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1);
b20e47cb
RM
132 if (! cp)
133 {
14e9dd67
UD
134 ERR("monstartup: out of memory\n");
135 p->tos = NULL;
136 p->state = GMON_PROF_ERROR;
b20e47cb
RM
137 return;
138 }
b20e47cb
RM
139 p->tos = (struct tostruct *)cp;
140 cp += p->tossize;
be5b0fbc 141 p->kcount = (HISTCOUNTER *)cp;
b20e47cb 142 cp += p->kcountsize;
be5b0fbc 143 p->froms = (ARCINDEX *)cp;
11c981a9 144
b20e47cb
RM
145 p->tos[0].link = 0;
146
147 o = p->highpc - p->lowpc;
d68171ed 148 if (p->kcountsize < (u_long) o)
b20e47cb 149 {
11c981a9 150#ifndef hp300
b20e47cb
RM
151 s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
152#else
153 /* avoid floating point operations */
154 int quot = o / p->kcountsize;
155
156 if (quot >= 0x10000)
157 s_scale = 1;
158 else if (quot >= 0x100)
159 s_scale = 0x10000 / quot;
160 else if (o >= 0x800000)
161 s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
162 else
163 s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
11c981a9 164#endif
b20e47cb
RM
165 } else
166 s_scale = SCALE_1_TO_1;
11c981a9 167
3996f34b 168 __moncontrol(1);
11c981a9 169}
1ab18a5b 170weak_alias (__monstartup, monstartup)
11c981a9 171
b20e47cb
RM
172
173static void
9d46370c 174write_hist (int fd)
11c981a9 175{
5ae9d168 176 u_char tag = GMON_TAG_TIME_HIST;
11c981a9 177
b20e47cb
RM
178 if (_gmonparam.kcountsize > 0)
179 {
f521be31
UD
180 struct real_gmon_hist_hdr
181 {
182 char *low_pc;
183 char *high_pc;
184 int32_t hist_size;
185 int32_t prof_rate;
186 char dimen[15];
187 char dimen_abbrev;
188 } thdr;
5ae9d168 189 struct iovec iov[3] =
3ce1f295 190 {
5ae9d168
UD
191 { &tag, sizeof (tag) },
192 { &thdr, sizeof (struct gmon_hist_hdr) },
193 { _gmonparam.kcount, _gmonparam.kcountsize }
194 };
195
f521be31
UD
196 if (sizeof (thdr) != sizeof (struct gmon_hist_hdr)
197 || (offsetof (struct real_gmon_hist_hdr, low_pc)
198 != offsetof (struct gmon_hist_hdr, low_pc))
199 || (offsetof (struct real_gmon_hist_hdr, high_pc)
200 != offsetof (struct gmon_hist_hdr, high_pc))
201 || (offsetof (struct real_gmon_hist_hdr, hist_size)
202 != offsetof (struct gmon_hist_hdr, hist_size))
203 || (offsetof (struct real_gmon_hist_hdr, prof_rate)
204 != offsetof (struct gmon_hist_hdr, prof_rate))
205 || (offsetof (struct real_gmon_hist_hdr, dimen)
206 != offsetof (struct gmon_hist_hdr, dimen))
207 || (offsetof (struct real_gmon_hist_hdr, dimen_abbrev)
208 != offsetof (struct gmon_hist_hdr, dimen_abbrev)))
209 abort ();
210
211 thdr.low_pc = (char *) _gmonparam.lowpc;
212 thdr.high_pc = (char *) _gmonparam.highpc;
213 thdr.hist_size = _gmonparam.kcountsize / sizeof (HISTCOUNTER);
214 thdr.prof_rate = __profile_frequency ();
5ae9d168 215 strncpy (thdr.dimen, "seconds", sizeof (thdr.dimen));
b20e47cb 216 thdr.dimen_abbrev = 's';
11c981a9 217
19926de9 218 __writev_nocancel_nostatus (fd, iov, 3);
b20e47cb 219 }
11c981a9
RM
220}
221
b20e47cb
RM
222
223static void
9d46370c 224write_call_graph (int fd)
11c981a9 225{
e7fd8a39 226#define NARCS_PER_WRITEV 32
5ae9d168 227 u_char tag = GMON_TAG_CG_ARC;
e7fd8a39 228 struct gmon_cg_arc_record raw_arc[NARCS_PER_WRITEV]
5ae9d168 229 __attribute__ ((aligned (__alignof__ (char*))));
be5b0fbc 230 ARCINDEX from_index, to_index;
eb64f8cb 231 u_long from_len;
b20e47cb 232 u_long frompc;
e7fd8a39
UD
233 struct iovec iov[2 * NARCS_PER_WRITEV];
234 int nfilled;
b20e47cb 235
e7fd8a39 236 for (nfilled = 0; nfilled < NARCS_PER_WRITEV; ++nfilled)
5ae9d168 237 {
e7fd8a39
UD
238 iov[2 * nfilled].iov_base = &tag;
239 iov[2 * nfilled].iov_len = sizeof (tag);
5ae9d168 240
e7fd8a39
UD
241 iov[2 * nfilled + 1].iov_base = &raw_arc[nfilled];
242 iov[2 * nfilled + 1].iov_len = sizeof (struct gmon_cg_arc_record);
243 }
244
245 nfilled = 0;
5ae9d168 246 from_len = _gmonparam.fromssize / sizeof (*_gmonparam.froms);
b20e47cb
RM
247 for (from_index = 0; from_index < from_len; ++from_index)
248 {
249 if (_gmonparam.froms[from_index] == 0)
250 continue;
251
252 frompc = _gmonparam.lowpc;
253 frompc += (from_index * _gmonparam.hashfraction
5ae9d168 254 * sizeof (*_gmonparam.froms));
b20e47cb
RM
255 for (to_index = _gmonparam.froms[from_index];
256 to_index != 0;
257 to_index = _gmonparam.tos[to_index].link)
258 {
328c5f65
UD
259 struct arc
260 {
261 char *frompc;
262 char *selfpc;
263 int32_t count;
264 }
265 arc;
266
267 arc.frompc = (char *) frompc;
268 arc.selfpc = (char *) _gmonparam.tos[to_index].selfpc;
269 arc.count = _gmonparam.tos[to_index].count;
270 memcpy (raw_arc + nfilled, &arc, sizeof (raw_arc [0]));
e7fd8a39
UD
271
272 if (++nfilled == NARCS_PER_WRITEV)
3e5f5557 273 {
19926de9 274 __writev_nocancel_nostatus (fd, iov, 2 * nfilled);
3e5f5557
UD
275 nfilled = 0;
276 }
11c981a9 277 }
b20e47cb 278 }
e7fd8a39 279 if (nfilled > 0)
19926de9 280 __writev_nocancel_nostatus (fd, iov, 2 * nfilled);
11c981a9
RM
281}
282
b20e47cb
RM
283
284static void
9d46370c 285write_bb_counts (int fd)
11c981a9 286{
b20e47cb 287 struct __bb *grp;
5ae9d168 288 u_char tag = GMON_TAG_BB_COUNT;
3e5f5557
UD
289 size_t ncounts;
290 size_t i;
b20e47cb 291
5ae9d168
UD
292 struct iovec bbhead[2] =
293 {
294 { &tag, sizeof (tag) },
295 { &ncounts, sizeof (ncounts) }
296 };
3e5f5557
UD
297 struct iovec bbbody[8];
298 size_t nfilled;
5ae9d168 299
3e5f5557
UD
300 for (i = 0; i < (sizeof (bbbody) / sizeof (bbbody[0])); i += 2)
301 {
302 bbbody[i].iov_len = sizeof (grp->addresses[0]);
303 bbbody[i + 1].iov_len = sizeof (grp->counts[0]);
304 }
5ae9d168 305
b20e47cb
RM
306 /* Write each group of basic-block info (all basic-blocks in a
307 compilation unit form a single group). */
308
309 for (grp = __bb_head; grp; grp = grp->next)
310 {
311 ncounts = grp->ncounts;
19926de9 312 __writev_nocancel_nostatus (fd, bbhead, 2);
e7fd8a39 313 for (nfilled = i = 0; i < ncounts; ++i)
b20e47cb 314 {
3e5f5557
UD
315 if (nfilled > (sizeof (bbbody) / sizeof (bbbody[0])) - 2)
316 {
19926de9 317 __writev_nocancel_nostatus (fd, bbbody, nfilled);
3e5f5557
UD
318 nfilled = 0;
319 }
320
321 bbbody[nfilled++].iov_base = (char *) &grp->addresses[i];
322 bbbody[nfilled++].iov_base = &grp->counts[i];
b20e47cb 323 }
e7fd8a39 324 if (nfilled > 0)
19926de9 325 __writev_nocancel_nostatus (fd, bbbody, nfilled);
b20e47cb 326 }
11c981a9
RM
327}
328
329
0413b54c
UD
330static void
331write_gmon (void)
b20e47cb 332{
14c44e2e
UD
333 int fd = -1;
334 char *env;
b20e47cb 335
14c44e2e
UD
336 env = getenv ("GMON_OUT_PREFIX");
337 if (env != NULL && !__libc_enable_secure)
b20e47cb 338 {
14c44e2e
UD
339 size_t len = strlen (env);
340 char buf[len + 20];
4c5b09ed 341 __snprintf (buf, sizeof (buf), "%s.%u", env, __getpid ());
c2284574 342 fd = __open_nocancel (buf, O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0666);
14c44e2e
UD
343 }
344
345 if (fd == -1)
346 {
c2284574 347 fd = __open_nocancel ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW,
fbb37d25 348 0666);
14c44e2e
UD
349 if (fd < 0)
350 {
351 char buf[300];
352 int errnum = errno;
df6f8969 353 __fxprintf (NULL, "_mcleanup: gmon.out: %s\n",
df6f8969 354 __strerror_r (errnum, buf, sizeof buf));
14c44e2e
UD
355 return;
356 }
b20e47cb
RM
357 }
358
359 /* write gmon.out header: */
f521be31
UD
360 struct real_gmon_hdr
361 {
362 char cookie[4];
363 int32_t version;
364 char spare[3 * 4];
365 } ghdr;
366 if (sizeof (ghdr) != sizeof (struct gmon_hdr)
367 || (offsetof (struct real_gmon_hdr, cookie)
368 != offsetof (struct gmon_hdr, cookie))
369 || (offsetof (struct real_gmon_hdr, version)
370 != offsetof (struct gmon_hdr, version)))
371 abort ();
5ae9d168 372 memcpy (&ghdr.cookie[0], GMON_MAGIC, sizeof (ghdr.cookie));
f521be31
UD
373 ghdr.version = GMON_VERSION;
374 memset (ghdr.spare, '\0', sizeof (ghdr.spare));
c647fb88 375 __write_nocancel (fd, &ghdr, sizeof (struct gmon_hdr));
b20e47cb
RM
376
377 /* write PC histogram: */
5ae9d168 378 write_hist (fd);
b20e47cb
RM
379
380 /* write call-graph: */
5ae9d168 381 write_call_graph (fd);
b20e47cb
RM
382
383 /* write basic-block execution counts: */
5ae9d168 384 write_bb_counts (fd);
b20e47cb 385
c181840c 386 __close_nocancel_nostatus (fd);
0413b54c
UD
387}
388
389
390void
391__write_profiling (void)
392{
393 int save = _gmonparam.state;
394 _gmonparam.state = GMON_PROF_OFF;
395 if (save == GMON_PROF_ON)
396 write_gmon ();
397 _gmonparam.state = save;
398}
f5bf21a7
UD
399#ifndef SHARED
400/* This symbol isn't used anywhere in the DSO and it is not exported.
401 This would normally mean it should be removed to get the same API
402 in static libraries. But since profiling is special in static libs
403 anyway we keep it. But not when building the DSO since some
404 quality assurance tests will otherwise trigger. */
0413b54c 405weak_alias (__write_profiling, write_profiling)
f5bf21a7 406#endif
0413b54c
UD
407
408
409void
410_mcleanup (void)
411{
14e9dd67 412 __moncontrol (0);
0413b54c 413
14e9dd67 414 if (_gmonparam.state != GMON_PROF_ERROR)
0413b54c
UD
415 write_gmon ();
416
14e9dd67 417 /* free the memory. */
72e6cdfa 418 free (_gmonparam.tos);
b20e47cb 419}