ldbl-128ibm: Automatic replacing of _Float128 and L()
[glibc.git] / gmon / gmon.c
blob4e48eba1bfdf473f88c386cb72f9f2336ffae5d5
1 /*-
2 * Copyright (c) 1983, 1992, 1993, 2011
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
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 * 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
27 * SUCH DAMAGE.
29 #include <sys/param.h>
30 #include <sys/time.h>
31 #include <sys/gmon.h>
32 #include <sys/gmon_out.h>
33 #include <sys/uio.h>
35 #include <errno.h>
36 #include <stdio.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <wchar.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <stddef.h>
45 #include <unistd.h>
46 #include <libc-internal.h>
47 #include <not-cancel.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:
58 static int s_scale;
59 #define SCALE_1_TO_1 0x10000L
61 #define ERR(s) __write_nocancel (STDERR_FILENO, s, sizeof (s) - 1)
63 void moncontrol (int mode);
64 void __moncontrol (int mode);
65 static void write_hist (int fd);
66 static void write_call_graph (int fd);
67 static void write_bb_counts (int fd);
70 * Control profiling
71 * profiling is what mcount checks to see if
72 * all the data structures are ready.
74 void
75 __moncontrol (int mode)
77 struct gmonparam *p = &_gmonparam;
79 /* Don't change the state if we ran into an error. */
80 if (p->state == GMON_PROF_ERROR)
81 return;
83 if (mode)
85 /* start */
86 __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale);
87 p->state = GMON_PROF_ON;
89 else
91 /* stop */
92 __profil(NULL, 0, 0, 0);
93 p->state = GMON_PROF_OFF;
96 weak_alias (__moncontrol, moncontrol)
99 void
100 __monstartup (u_long lowpc, u_long highpc)
102 int o;
103 char *cp;
104 struct gmonparam *p = &_gmonparam;
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.
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 = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms));
114 p->hashfraction = HASHFRACTION;
115 p->log_hashfraction = -1;
116 /* The following test must be kept in sync with the corresponding
117 test in mcount.c. */
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;
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);
131 cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1);
132 if (! cp)
134 ERR("monstartup: out of memory\n");
135 p->tos = NULL;
136 p->state = GMON_PROF_ERROR;
137 return;
139 p->tos = (struct tostruct *)cp;
140 cp += p->tossize;
141 p->kcount = (HISTCOUNTER *)cp;
142 cp += p->kcountsize;
143 p->froms = (ARCINDEX *)cp;
145 p->tos[0].link = 0;
147 o = p->highpc - p->lowpc;
148 if (p->kcountsize < (u_long) o)
150 #ifndef hp300
151 s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
152 #else
153 /* avoid floating point operations */
154 int quot = o / p->kcountsize;
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);
164 #endif
165 } else
166 s_scale = SCALE_1_TO_1;
168 __moncontrol(1);
170 weak_alias (__monstartup, monstartup)
173 static void
174 write_hist (int fd)
176 u_char tag = GMON_TAG_TIME_HIST;
178 if (_gmonparam.kcountsize > 0)
180 struct real_gmon_hist_hdr
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;
189 struct iovec iov[3] =
191 { &tag, sizeof (tag) },
192 { &thdr, sizeof (struct gmon_hist_hdr) },
193 { _gmonparam.kcount, _gmonparam.kcountsize }
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 ();
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 ();
215 strncpy (thdr.dimen, "seconds", sizeof (thdr.dimen));
216 thdr.dimen_abbrev = 's';
218 __writev_nocancel_nostatus (fd, iov, 3);
223 static void
224 write_call_graph (int fd)
226 #define NARCS_PER_WRITEV 32
227 u_char tag = GMON_TAG_CG_ARC;
228 struct gmon_cg_arc_record raw_arc[NARCS_PER_WRITEV]
229 __attribute__ ((aligned (__alignof__ (char*))));
230 ARCINDEX from_index, to_index;
231 u_long from_len;
232 u_long frompc;
233 struct iovec iov[2 * NARCS_PER_WRITEV];
234 int nfilled;
236 for (nfilled = 0; nfilled < NARCS_PER_WRITEV; ++nfilled)
238 iov[2 * nfilled].iov_base = &tag;
239 iov[2 * nfilled].iov_len = sizeof (tag);
241 iov[2 * nfilled + 1].iov_base = &raw_arc[nfilled];
242 iov[2 * nfilled + 1].iov_len = sizeof (struct gmon_cg_arc_record);
245 nfilled = 0;
246 from_len = _gmonparam.fromssize / sizeof (*_gmonparam.froms);
247 for (from_index = 0; from_index < from_len; ++from_index)
249 if (_gmonparam.froms[from_index] == 0)
250 continue;
252 frompc = _gmonparam.lowpc;
253 frompc += (from_index * _gmonparam.hashfraction
254 * sizeof (*_gmonparam.froms));
255 for (to_index = _gmonparam.froms[from_index];
256 to_index != 0;
257 to_index = _gmonparam.tos[to_index].link)
259 struct arc
261 char *frompc;
262 char *selfpc;
263 int32_t count;
265 arc;
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]));
272 if (++nfilled == NARCS_PER_WRITEV)
274 __writev_nocancel_nostatus (fd, iov, 2 * nfilled);
275 nfilled = 0;
279 if (nfilled > 0)
280 __writev_nocancel_nostatus (fd, iov, 2 * nfilled);
284 static void
285 write_bb_counts (int fd)
287 struct __bb *grp;
288 u_char tag = GMON_TAG_BB_COUNT;
289 size_t ncounts;
290 size_t i;
292 struct iovec bbhead[2] =
294 { &tag, sizeof (tag) },
295 { &ncounts, sizeof (ncounts) }
297 struct iovec bbbody[8];
298 size_t nfilled;
300 for (i = 0; i < (sizeof (bbbody) / sizeof (bbbody[0])); i += 2)
302 bbbody[i].iov_len = sizeof (grp->addresses[0]);
303 bbbody[i + 1].iov_len = sizeof (grp->counts[0]);
306 /* Write each group of basic-block info (all basic-blocks in a
307 compilation unit form a single group). */
309 for (grp = __bb_head; grp; grp = grp->next)
311 ncounts = grp->ncounts;
312 __writev_nocancel_nostatus (fd, bbhead, 2);
313 for (nfilled = i = 0; i < ncounts; ++i)
315 if (nfilled > (sizeof (bbbody) / sizeof (bbbody[0])) - 2)
317 __writev_nocancel_nostatus (fd, bbbody, nfilled);
318 nfilled = 0;
321 bbbody[nfilled++].iov_base = (char *) &grp->addresses[i];
322 bbbody[nfilled++].iov_base = &grp->counts[i];
324 if (nfilled > 0)
325 __writev_nocancel_nostatus (fd, bbbody, nfilled);
330 static void
331 write_gmon (void)
333 int fd = -1;
334 char *env;
336 env = getenv ("GMON_OUT_PREFIX");
337 if (env != NULL && !__libc_enable_secure)
339 size_t len = strlen (env);
340 char buf[len + 20];
341 __snprintf (buf, sizeof (buf), "%s.%u", env, __getpid ());
342 fd = __open_nocancel (buf, O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0666);
345 if (fd == -1)
347 fd = __open_nocancel ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW,
348 0666);
349 if (fd < 0)
351 char buf[300];
352 int errnum = errno;
353 __fxprintf (NULL, "_mcleanup: gmon.out: %s\n",
354 __strerror_r (errnum, buf, sizeof buf));
355 return;
359 /* write gmon.out header: */
360 struct real_gmon_hdr
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 ();
372 memcpy (&ghdr.cookie[0], GMON_MAGIC, sizeof (ghdr.cookie));
373 ghdr.version = GMON_VERSION;
374 memset (ghdr.spare, '\0', sizeof (ghdr.spare));
375 __write_nocancel (fd, &ghdr, sizeof (struct gmon_hdr));
377 /* write PC histogram: */
378 write_hist (fd);
380 /* write call-graph: */
381 write_call_graph (fd);
383 /* write basic-block execution counts: */
384 write_bb_counts (fd);
386 __close_nocancel_nostatus (fd);
390 void
391 __write_profiling (void)
393 int save = _gmonparam.state;
394 _gmonparam.state = GMON_PROF_OFF;
395 if (save == GMON_PROF_ON)
396 write_gmon ();
397 _gmonparam.state = save;
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. */
405 weak_alias (__write_profiling, write_profiling)
406 #endif
409 void
410 _mcleanup (void)
412 __moncontrol (0);
414 if (_gmonparam.state != GMON_PROF_ERROR)
415 write_gmon ();
417 /* free the memory. */
418 free (_gmonparam.tos);