]> git.ipfire.org Git - thirdparty/glibc.git/blame - gmon/gmon.c
Consolidate non cancellable close call
[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);
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
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
dfd2257a 174internal_function
9d46370c 175write_hist (int fd)
11c981a9 176{
5ae9d168 177 u_char tag = GMON_TAG_TIME_HIST;
11c981a9 178
b20e47cb
RM
179 if (_gmonparam.kcountsize > 0)
180 {
f521be31
UD
181 struct real_gmon_hist_hdr
182 {
183 char *low_pc;
184 char *high_pc;
185 int32_t hist_size;
186 int32_t prof_rate;
187 char dimen[15];
188 char dimen_abbrev;
189 } thdr;
5ae9d168 190 struct iovec iov[3] =
3ce1f295 191 {
5ae9d168
UD
192 { &tag, sizeof (tag) },
193 { &thdr, sizeof (struct gmon_hist_hdr) },
194 { _gmonparam.kcount, _gmonparam.kcountsize }
195 };
196
f521be31
UD
197 if (sizeof (thdr) != sizeof (struct gmon_hist_hdr)
198 || (offsetof (struct real_gmon_hist_hdr, low_pc)
199 != offsetof (struct gmon_hist_hdr, low_pc))
200 || (offsetof (struct real_gmon_hist_hdr, high_pc)
201 != offsetof (struct gmon_hist_hdr, high_pc))
202 || (offsetof (struct real_gmon_hist_hdr, hist_size)
203 != offsetof (struct gmon_hist_hdr, hist_size))
204 || (offsetof (struct real_gmon_hist_hdr, prof_rate)
205 != offsetof (struct gmon_hist_hdr, prof_rate))
206 || (offsetof (struct real_gmon_hist_hdr, dimen)
207 != offsetof (struct gmon_hist_hdr, dimen))
208 || (offsetof (struct real_gmon_hist_hdr, dimen_abbrev)
209 != offsetof (struct gmon_hist_hdr, dimen_abbrev)))
210 abort ();
211
212 thdr.low_pc = (char *) _gmonparam.lowpc;
213 thdr.high_pc = (char *) _gmonparam.highpc;
214 thdr.hist_size = _gmonparam.kcountsize / sizeof (HISTCOUNTER);
215 thdr.prof_rate = __profile_frequency ();
5ae9d168 216 strncpy (thdr.dimen, "seconds", sizeof (thdr.dimen));
b20e47cb 217 thdr.dimen_abbrev = 's';
11c981a9 218
fbb37d25 219 writev_not_cancel_no_status (fd, iov, 3);
b20e47cb 220 }
11c981a9
RM
221}
222
b20e47cb
RM
223
224static void
dfd2257a 225internal_function
9d46370c 226write_call_graph (int fd)
11c981a9 227{
e7fd8a39 228#define NARCS_PER_WRITEV 32
5ae9d168 229 u_char tag = GMON_TAG_CG_ARC;
e7fd8a39 230 struct gmon_cg_arc_record raw_arc[NARCS_PER_WRITEV]
5ae9d168 231 __attribute__ ((aligned (__alignof__ (char*))));
be5b0fbc 232 ARCINDEX from_index, to_index;
eb64f8cb 233 u_long from_len;
b20e47cb 234 u_long frompc;
e7fd8a39
UD
235 struct iovec iov[2 * NARCS_PER_WRITEV];
236 int nfilled;
b20e47cb 237
e7fd8a39 238 for (nfilled = 0; nfilled < NARCS_PER_WRITEV; ++nfilled)
5ae9d168 239 {
e7fd8a39
UD
240 iov[2 * nfilled].iov_base = &tag;
241 iov[2 * nfilled].iov_len = sizeof (tag);
5ae9d168 242
e7fd8a39
UD
243 iov[2 * nfilled + 1].iov_base = &raw_arc[nfilled];
244 iov[2 * nfilled + 1].iov_len = sizeof (struct gmon_cg_arc_record);
245 }
246
247 nfilled = 0;
5ae9d168 248 from_len = _gmonparam.fromssize / sizeof (*_gmonparam.froms);
b20e47cb
RM
249 for (from_index = 0; from_index < from_len; ++from_index)
250 {
251 if (_gmonparam.froms[from_index] == 0)
252 continue;
253
254 frompc = _gmonparam.lowpc;
255 frompc += (from_index * _gmonparam.hashfraction
5ae9d168 256 * sizeof (*_gmonparam.froms));
b20e47cb
RM
257 for (to_index = _gmonparam.froms[from_index];
258 to_index != 0;
259 to_index = _gmonparam.tos[to_index].link)
260 {
328c5f65
UD
261 struct arc
262 {
263 char *frompc;
264 char *selfpc;
265 int32_t count;
266 }
267 arc;
268
269 arc.frompc = (char *) frompc;
270 arc.selfpc = (char *) _gmonparam.tos[to_index].selfpc;
271 arc.count = _gmonparam.tos[to_index].count;
272 memcpy (raw_arc + nfilled, &arc, sizeof (raw_arc [0]));
e7fd8a39
UD
273
274 if (++nfilled == NARCS_PER_WRITEV)
3e5f5557 275 {
fbb37d25 276 writev_not_cancel_no_status (fd, iov, 2 * nfilled);
3e5f5557
UD
277 nfilled = 0;
278 }
11c981a9 279 }
b20e47cb 280 }
e7fd8a39 281 if (nfilled > 0)
fbb37d25 282 writev_not_cancel_no_status (fd, iov, 2 * nfilled);
11c981a9
RM
283}
284
b20e47cb
RM
285
286static void
dfd2257a 287internal_function
9d46370c 288write_bb_counts (int fd)
11c981a9 289{
b20e47cb 290 struct __bb *grp;
5ae9d168 291 u_char tag = GMON_TAG_BB_COUNT;
3e5f5557
UD
292 size_t ncounts;
293 size_t i;
b20e47cb 294
5ae9d168
UD
295 struct iovec bbhead[2] =
296 {
297 { &tag, sizeof (tag) },
298 { &ncounts, sizeof (ncounts) }
299 };
3e5f5557
UD
300 struct iovec bbbody[8];
301 size_t nfilled;
5ae9d168 302
3e5f5557
UD
303 for (i = 0; i < (sizeof (bbbody) / sizeof (bbbody[0])); i += 2)
304 {
305 bbbody[i].iov_len = sizeof (grp->addresses[0]);
306 bbbody[i + 1].iov_len = sizeof (grp->counts[0]);
307 }
5ae9d168 308
b20e47cb
RM
309 /* Write each group of basic-block info (all basic-blocks in a
310 compilation unit form a single group). */
311
312 for (grp = __bb_head; grp; grp = grp->next)
313 {
314 ncounts = grp->ncounts;
fbb37d25 315 writev_not_cancel_no_status (fd, bbhead, 2);
e7fd8a39 316 for (nfilled = i = 0; i < ncounts; ++i)
b20e47cb 317 {
3e5f5557
UD
318 if (nfilled > (sizeof (bbbody) / sizeof (bbbody[0])) - 2)
319 {
fbb37d25 320 writev_not_cancel_no_status (fd, bbbody, nfilled);
3e5f5557
UD
321 nfilled = 0;
322 }
323
324 bbbody[nfilled++].iov_base = (char *) &grp->addresses[i];
325 bbbody[nfilled++].iov_base = &grp->counts[i];
b20e47cb 326 }
e7fd8a39 327 if (nfilled > 0)
fbb37d25 328 writev_not_cancel_no_status (fd, bbbody, nfilled);
b20e47cb 329 }
11c981a9
RM
330}
331
332
0413b54c
UD
333static void
334write_gmon (void)
b20e47cb 335{
14c44e2e
UD
336 int fd = -1;
337 char *env;
b20e47cb 338
14c44e2e
UD
339 env = getenv ("GMON_OUT_PREFIX");
340 if (env != NULL && !__libc_enable_secure)
b20e47cb 341 {
14c44e2e
UD
342 size_t len = strlen (env);
343 char buf[len + 20];
4c5b09ed 344 __snprintf (buf, sizeof (buf), "%s.%u", env, __getpid ());
c2284574 345 fd = __open_nocancel (buf, O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0666);
14c44e2e
UD
346 }
347
348 if (fd == -1)
349 {
c2284574 350 fd = __open_nocancel ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW,
fbb37d25 351 0666);
14c44e2e
UD
352 if (fd < 0)
353 {
354 char buf[300];
355 int errnum = errno;
df6f8969 356 __fxprintf (NULL, "_mcleanup: gmon.out: %s\n",
df6f8969 357 __strerror_r (errnum, buf, sizeof buf));
14c44e2e
UD
358 return;
359 }
b20e47cb
RM
360 }
361
362 /* write gmon.out header: */
f521be31
UD
363 struct real_gmon_hdr
364 {
365 char cookie[4];
366 int32_t version;
367 char spare[3 * 4];
368 } ghdr;
369 if (sizeof (ghdr) != sizeof (struct gmon_hdr)
370 || (offsetof (struct real_gmon_hdr, cookie)
371 != offsetof (struct gmon_hdr, cookie))
372 || (offsetof (struct real_gmon_hdr, version)
373 != offsetof (struct gmon_hdr, version)))
374 abort ();
5ae9d168 375 memcpy (&ghdr.cookie[0], GMON_MAGIC, sizeof (ghdr.cookie));
f521be31
UD
376 ghdr.version = GMON_VERSION;
377 memset (ghdr.spare, '\0', sizeof (ghdr.spare));
c647fb88 378 __write_nocancel (fd, &ghdr, sizeof (struct gmon_hdr));
b20e47cb
RM
379
380 /* write PC histogram: */
5ae9d168 381 write_hist (fd);
b20e47cb
RM
382
383 /* write call-graph: */
5ae9d168 384 write_call_graph (fd);
b20e47cb
RM
385
386 /* write basic-block execution counts: */
5ae9d168 387 write_bb_counts (fd);
b20e47cb 388
c181840c 389 __close_nocancel_nostatus (fd);
0413b54c
UD
390}
391
392
393void
394__write_profiling (void)
395{
396 int save = _gmonparam.state;
397 _gmonparam.state = GMON_PROF_OFF;
398 if (save == GMON_PROF_ON)
399 write_gmon ();
400 _gmonparam.state = save;
401}
f5bf21a7
UD
402#ifndef SHARED
403/* This symbol isn't used anywhere in the DSO and it is not exported.
404 This would normally mean it should be removed to get the same API
405 in static libraries. But since profiling is special in static libs
406 anyway we keep it. But not when building the DSO since some
407 quality assurance tests will otherwise trigger. */
0413b54c 408weak_alias (__write_profiling, write_profiling)
f5bf21a7 409#endif
0413b54c
UD
410
411
412void
413_mcleanup (void)
414{
14e9dd67 415 __moncontrol (0);
0413b54c 416
14e9dd67 417 if (_gmonparam.state != GMON_PROF_ERROR)
0413b54c
UD
418 write_gmon ();
419
14e9dd67 420 /* free the memory. */
72e6cdfa 421 free (_gmonparam.tos);
b20e47cb 422}