]> git.ipfire.org Git - thirdparty/glibc.git/blame - gmon/gmon.c
Remove trailing whitespace from localedata.
[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
fbb37d25 61#define ERR(s) write_not_cancel (STDERR_FILENO, s, sizeof (s) - 1)
b20e47cb 62
79937577
UD
63void moncontrol (int mode);
64void __moncontrol (int mode);
65static void write_hist (int fd) internal_function;
66static void write_call_graph (int fd) internal_function;
67static void write_bb_counts (int fd) internal_function;
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
3996f34b 75__moncontrol (mode)
a68b0d31 76 int mode;
b20e47cb
RM
77{
78 struct gmonparam *p = &_gmonparam;
79
14e9dd67
UD
80 /* Don't change the state if we ran into an error. */
81 if (p->state == GMON_PROF_ERROR)
82 return;
83
b20e47cb
RM
84 if (mode)
85 {
86 /* start */
9a0a462c 87 __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale);
b20e47cb
RM
88 p->state = GMON_PROF_ON;
89 }
90 else
91 {
92 /* stop */
9a0a462c 93 __profil(NULL, 0, 0, 0);
b20e47cb
RM
94 p->state = GMON_PROF_OFF;
95 }
96}
69173865 97weak_alias (__moncontrol, moncontrol)
11c981a9 98
11c981a9
RM
99
100void
3996f34b 101__monstartup (lowpc, highpc)
a68b0d31
UD
102 u_long lowpc;
103 u_long highpc;
11c981a9 104{
b20e47cb
RM
105 register int o;
106 char *cp;
107 struct gmonparam *p = &_gmonparam;
108
109 /*
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.
112 */
113 p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
114 p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
115 p->textsize = p->highpc - p->lowpc;
69ac9d07 116 p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms));
b20e47cb
RM
117 p->hashfraction = HASHFRACTION;
118 p->log_hashfraction = -1;
9a0a462c
UD
119 /* The following test must be kept in sync with the corresponding
120 test in mcount.c. */
b20e47cb
RM
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;
125 }
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);
11c981a9 133
0413b54c 134 cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1);
b20e47cb
RM
135 if (! cp)
136 {
14e9dd67
UD
137 ERR("monstartup: out of memory\n");
138 p->tos = NULL;
139 p->state = GMON_PROF_ERROR;
b20e47cb
RM
140 return;
141 }
b20e47cb
RM
142 p->tos = (struct tostruct *)cp;
143 cp += p->tossize;
be5b0fbc 144 p->kcount = (HISTCOUNTER *)cp;
b20e47cb 145 cp += p->kcountsize;
be5b0fbc 146 p->froms = (ARCINDEX *)cp;
11c981a9 147
b20e47cb
RM
148 p->tos[0].link = 0;
149
150 o = p->highpc - p->lowpc;
d68171ed 151 if (p->kcountsize < (u_long) o)
b20e47cb 152 {
11c981a9 153#ifndef hp300
b20e47cb
RM
154 s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
155#else
156 /* avoid floating point operations */
157 int quot = o / p->kcountsize;
158
159 if (quot >= 0x10000)
160 s_scale = 1;
161 else if (quot >= 0x100)
162 s_scale = 0x10000 / quot;
163 else if (o >= 0x800000)
164 s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
165 else
166 s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
11c981a9 167#endif
b20e47cb
RM
168 } else
169 s_scale = SCALE_1_TO_1;
11c981a9 170
3996f34b 171 __moncontrol(1);
11c981a9 172}
1ab18a5b 173weak_alias (__monstartup, monstartup)
11c981a9 174
b20e47cb
RM
175
176static void
dfd2257a 177internal_function
a68b0d31
UD
178write_hist (fd)
179 int fd;
11c981a9 180{
5ae9d168 181 u_char tag = GMON_TAG_TIME_HIST;
11c981a9 182
b20e47cb
RM
183 if (_gmonparam.kcountsize > 0)
184 {
f521be31
UD
185 struct real_gmon_hist_hdr
186 {
187 char *low_pc;
188 char *high_pc;
189 int32_t hist_size;
190 int32_t prof_rate;
191 char dimen[15];
192 char dimen_abbrev;
193 } thdr;
5ae9d168 194 struct iovec iov[3] =
3ce1f295 195 {
5ae9d168
UD
196 { &tag, sizeof (tag) },
197 { &thdr, sizeof (struct gmon_hist_hdr) },
198 { _gmonparam.kcount, _gmonparam.kcountsize }
199 };
200
f521be31
UD
201 if (sizeof (thdr) != sizeof (struct gmon_hist_hdr)
202 || (offsetof (struct real_gmon_hist_hdr, low_pc)
203 != offsetof (struct gmon_hist_hdr, low_pc))
204 || (offsetof (struct real_gmon_hist_hdr, high_pc)
205 != offsetof (struct gmon_hist_hdr, high_pc))
206 || (offsetof (struct real_gmon_hist_hdr, hist_size)
207 != offsetof (struct gmon_hist_hdr, hist_size))
208 || (offsetof (struct real_gmon_hist_hdr, prof_rate)
209 != offsetof (struct gmon_hist_hdr, prof_rate))
210 || (offsetof (struct real_gmon_hist_hdr, dimen)
211 != offsetof (struct gmon_hist_hdr, dimen))
212 || (offsetof (struct real_gmon_hist_hdr, dimen_abbrev)
213 != offsetof (struct gmon_hist_hdr, dimen_abbrev)))
214 abort ();
215
216 thdr.low_pc = (char *) _gmonparam.lowpc;
217 thdr.high_pc = (char *) _gmonparam.highpc;
218 thdr.hist_size = _gmonparam.kcountsize / sizeof (HISTCOUNTER);
219 thdr.prof_rate = __profile_frequency ();
5ae9d168 220 strncpy (thdr.dimen, "seconds", sizeof (thdr.dimen));
b20e47cb 221 thdr.dimen_abbrev = 's';
11c981a9 222
fbb37d25 223 writev_not_cancel_no_status (fd, iov, 3);
b20e47cb 224 }
11c981a9
RM
225}
226
b20e47cb
RM
227
228static void
dfd2257a 229internal_function
a68b0d31
UD
230write_call_graph (fd)
231 int fd;
11c981a9 232{
e7fd8a39 233#define NARCS_PER_WRITEV 32
5ae9d168 234 u_char tag = GMON_TAG_CG_ARC;
e7fd8a39 235 struct gmon_cg_arc_record raw_arc[NARCS_PER_WRITEV]
5ae9d168 236 __attribute__ ((aligned (__alignof__ (char*))));
be5b0fbc 237 ARCINDEX from_index, to_index;
eb64f8cb 238 u_long from_len;
b20e47cb 239 u_long frompc;
e7fd8a39
UD
240 struct iovec iov[2 * NARCS_PER_WRITEV];
241 int nfilled;
b20e47cb 242
e7fd8a39 243 for (nfilled = 0; nfilled < NARCS_PER_WRITEV; ++nfilled)
5ae9d168 244 {
e7fd8a39
UD
245 iov[2 * nfilled].iov_base = &tag;
246 iov[2 * nfilled].iov_len = sizeof (tag);
5ae9d168 247
e7fd8a39
UD
248 iov[2 * nfilled + 1].iov_base = &raw_arc[nfilled];
249 iov[2 * nfilled + 1].iov_len = sizeof (struct gmon_cg_arc_record);
250 }
251
252 nfilled = 0;
5ae9d168 253 from_len = _gmonparam.fromssize / sizeof (*_gmonparam.froms);
b20e47cb
RM
254 for (from_index = 0; from_index < from_len; ++from_index)
255 {
256 if (_gmonparam.froms[from_index] == 0)
257 continue;
258
259 frompc = _gmonparam.lowpc;
260 frompc += (from_index * _gmonparam.hashfraction
5ae9d168 261 * sizeof (*_gmonparam.froms));
b20e47cb
RM
262 for (to_index = _gmonparam.froms[from_index];
263 to_index != 0;
264 to_index = _gmonparam.tos[to_index].link)
265 {
328c5f65
UD
266 struct arc
267 {
268 char *frompc;
269 char *selfpc;
270 int32_t count;
271 }
272 arc;
273
274 arc.frompc = (char *) frompc;
275 arc.selfpc = (char *) _gmonparam.tos[to_index].selfpc;
276 arc.count = _gmonparam.tos[to_index].count;
277 memcpy (raw_arc + nfilled, &arc, sizeof (raw_arc [0]));
e7fd8a39
UD
278
279 if (++nfilled == NARCS_PER_WRITEV)
3e5f5557 280 {
fbb37d25 281 writev_not_cancel_no_status (fd, iov, 2 * nfilled);
3e5f5557
UD
282 nfilled = 0;
283 }
11c981a9 284 }
b20e47cb 285 }
e7fd8a39 286 if (nfilled > 0)
fbb37d25 287 writev_not_cancel_no_status (fd, iov, 2 * nfilled);
11c981a9
RM
288}
289
b20e47cb
RM
290
291static void
dfd2257a 292internal_function
a68b0d31
UD
293write_bb_counts (fd)
294 int fd;
11c981a9 295{
b20e47cb 296 struct __bb *grp;
5ae9d168 297 u_char tag = GMON_TAG_BB_COUNT;
3e5f5557
UD
298 size_t ncounts;
299 size_t i;
b20e47cb 300
5ae9d168
UD
301 struct iovec bbhead[2] =
302 {
303 { &tag, sizeof (tag) },
304 { &ncounts, sizeof (ncounts) }
305 };
3e5f5557
UD
306 struct iovec bbbody[8];
307 size_t nfilled;
5ae9d168 308
3e5f5557
UD
309 for (i = 0; i < (sizeof (bbbody) / sizeof (bbbody[0])); i += 2)
310 {
311 bbbody[i].iov_len = sizeof (grp->addresses[0]);
312 bbbody[i + 1].iov_len = sizeof (grp->counts[0]);
313 }
5ae9d168 314
b20e47cb
RM
315 /* Write each group of basic-block info (all basic-blocks in a
316 compilation unit form a single group). */
317
318 for (grp = __bb_head; grp; grp = grp->next)
319 {
320 ncounts = grp->ncounts;
fbb37d25 321 writev_not_cancel_no_status (fd, bbhead, 2);
e7fd8a39 322 for (nfilled = i = 0; i < ncounts; ++i)
b20e47cb 323 {
3e5f5557
UD
324 if (nfilled > (sizeof (bbbody) / sizeof (bbbody[0])) - 2)
325 {
fbb37d25 326 writev_not_cancel_no_status (fd, bbbody, nfilled);
3e5f5557
UD
327 nfilled = 0;
328 }
329
330 bbbody[nfilled++].iov_base = (char *) &grp->addresses[i];
331 bbbody[nfilled++].iov_base = &grp->counts[i];
b20e47cb 332 }
e7fd8a39 333 if (nfilled > 0)
fbb37d25 334 writev_not_cancel_no_status (fd, bbbody, nfilled);
b20e47cb 335 }
11c981a9
RM
336}
337
338
0413b54c
UD
339static void
340write_gmon (void)
b20e47cb 341{
14c44e2e
UD
342 int fd = -1;
343 char *env;
b20e47cb 344
b7eb7b0f
UD
345#ifndef O_NOFOLLOW
346# define O_NOFOLLOW 0
347#endif
348
14c44e2e
UD
349 env = getenv ("GMON_OUT_PREFIX");
350 if (env != NULL && !__libc_enable_secure)
b20e47cb 351 {
14c44e2e
UD
352 size_t len = strlen (env);
353 char buf[len + 20];
4c5b09ed 354 __snprintf (buf, sizeof (buf), "%s.%u", env, __getpid ());
fbb37d25 355 fd = open_not_cancel (buf, O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0666);
14c44e2e
UD
356 }
357
358 if (fd == -1)
359 {
fbb37d25
UD
360 fd = open_not_cancel ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW,
361 0666);
14c44e2e
UD
362 if (fd < 0)
363 {
364 char buf[300];
365 int errnum = errno;
df6f8969 366 __fxprintf (NULL, "_mcleanup: gmon.out: %s\n",
df6f8969 367 __strerror_r (errnum, buf, sizeof buf));
14c44e2e
UD
368 return;
369 }
b20e47cb
RM
370 }
371
372 /* write gmon.out header: */
f521be31
UD
373 struct real_gmon_hdr
374 {
375 char cookie[4];
376 int32_t version;
377 char spare[3 * 4];
378 } ghdr;
379 if (sizeof (ghdr) != sizeof (struct gmon_hdr)
380 || (offsetof (struct real_gmon_hdr, cookie)
381 != offsetof (struct gmon_hdr, cookie))
382 || (offsetof (struct real_gmon_hdr, version)
383 != offsetof (struct gmon_hdr, version)))
384 abort ();
5ae9d168 385 memcpy (&ghdr.cookie[0], GMON_MAGIC, sizeof (ghdr.cookie));
f521be31
UD
386 ghdr.version = GMON_VERSION;
387 memset (ghdr.spare, '\0', sizeof (ghdr.spare));
fbb37d25 388 write_not_cancel (fd, &ghdr, sizeof (struct gmon_hdr));
b20e47cb
RM
389
390 /* write PC histogram: */
5ae9d168 391 write_hist (fd);
b20e47cb
RM
392
393 /* write call-graph: */
5ae9d168 394 write_call_graph (fd);
b20e47cb
RM
395
396 /* write basic-block execution counts: */
5ae9d168 397 write_bb_counts (fd);
b20e47cb 398
fbb37d25 399 close_not_cancel_no_status (fd);
0413b54c
UD
400}
401
402
403void
404__write_profiling (void)
405{
406 int save = _gmonparam.state;
407 _gmonparam.state = GMON_PROF_OFF;
408 if (save == GMON_PROF_ON)
409 write_gmon ();
410 _gmonparam.state = save;
411}
f5bf21a7
UD
412#ifndef SHARED
413/* This symbol isn't used anywhere in the DSO and it is not exported.
414 This would normally mean it should be removed to get the same API
415 in static libraries. But since profiling is special in static libs
416 anyway we keep it. But not when building the DSO since some
417 quality assurance tests will otherwise trigger. */
0413b54c 418weak_alias (__write_profiling, write_profiling)
f5bf21a7 419#endif
0413b54c
UD
420
421
422void
423_mcleanup (void)
424{
14e9dd67 425 __moncontrol (0);
0413b54c 426
14e9dd67 427 if (_gmonparam.state != GMON_PROF_ERROR)
0413b54c
UD
428 write_gmon ();
429
14e9dd67 430 /* free the memory. */
72e6cdfa 431 free (_gmonparam.tos);
b20e47cb 432}