2.9
[glibc/nacl-glibc.git] / gmon / gmon.c
blob8e2eddd0bcbe851a6be7b56221e2c16e6b6ca68c
1 /*-
2 * Copyright (c) 1983, 1992, 1993
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>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <libc-internal.h>
45 #include <not-cancel.h>
47 #ifdef USE_IN_LIBIO
48 # include <wchar.h>
49 #endif
51 /* Head of basic-block list or NULL. */
52 struct __bb *__bb_head attribute_hidden;
54 struct gmonparam _gmonparam attribute_hidden = { GMON_PROF_OFF };
57 * See profil(2) where this is described:
59 static int s_scale;
60 #define SCALE_1_TO_1 0x10000L
62 #define ERR(s) write_not_cancel (STDERR_FILENO, s, sizeof (s) - 1)
64 void moncontrol (int mode);
65 void __moncontrol (int mode);
66 static void write_hist (int fd) internal_function;
67 static void write_call_graph (int fd) internal_function;
68 static void write_bb_counts (int fd) internal_function;
71 * Control profiling
72 * profiling is what mcount checks to see if
73 * all the data structures are ready.
75 void
76 __moncontrol (mode)
77 int mode;
79 struct gmonparam *p = &_gmonparam;
81 /* Don't change the state if we ran into an error. */
82 if (p->state == GMON_PROF_ERROR)
83 return;
85 if (mode)
87 /* start */
88 __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale);
89 p->state = GMON_PROF_ON;
91 else
93 /* stop */
94 __profil(NULL, 0, 0, 0);
95 p->state = GMON_PROF_OFF;
98 weak_alias (__moncontrol, moncontrol)
101 void
102 __monstartup (lowpc, highpc)
103 u_long lowpc;
104 u_long highpc;
106 register int o;
107 char *cp;
108 struct gmonparam *p = &_gmonparam;
111 * round lowpc and highpc to multiples of the density we're using
112 * so the rest of the scaling (here and in gprof) stays in ints.
114 p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
115 p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
116 p->textsize = p->highpc - p->lowpc;
117 p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms));
118 p->hashfraction = HASHFRACTION;
119 p->log_hashfraction = -1;
120 /* The following test must be kept in sync with the corresponding
121 test in mcount.c. */
122 if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) {
123 /* if HASHFRACTION is a power of two, mcount can use shifting
124 instead of integer division. Precompute shift amount. */
125 p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1;
127 p->fromssize = p->textsize / HASHFRACTION;
128 p->tolimit = p->textsize * ARCDENSITY / 100;
129 if (p->tolimit < MINARCS)
130 p->tolimit = MINARCS;
131 else if (p->tolimit > MAXARCS)
132 p->tolimit = MAXARCS;
133 p->tossize = p->tolimit * sizeof(struct tostruct);
135 cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1);
136 if (! cp)
138 ERR("monstartup: out of memory\n");
139 p->tos = NULL;
140 p->state = GMON_PROF_ERROR;
141 return;
143 p->tos = (struct tostruct *)cp;
144 cp += p->tossize;
145 p->kcount = (HISTCOUNTER *)cp;
146 cp += p->kcountsize;
147 p->froms = (ARCINDEX *)cp;
149 p->tos[0].link = 0;
151 o = p->highpc - p->lowpc;
152 if (p->kcountsize < (u_long) o)
154 #ifndef hp300
155 s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
156 #else
157 /* avoid floating point operations */
158 int quot = o / p->kcountsize;
160 if (quot >= 0x10000)
161 s_scale = 1;
162 else if (quot >= 0x100)
163 s_scale = 0x10000 / quot;
164 else if (o >= 0x800000)
165 s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
166 else
167 s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
168 #endif
169 } else
170 s_scale = SCALE_1_TO_1;
172 __moncontrol(1);
174 weak_alias (__monstartup, monstartup)
177 static void
178 internal_function
179 write_hist (fd)
180 int fd;
182 u_char tag = GMON_TAG_TIME_HIST;
183 struct gmon_hist_hdr thdr __attribute__ ((aligned (__alignof__ (char *))));
185 if (_gmonparam.kcountsize > 0)
187 struct iovec iov[3] =
189 { &tag, sizeof (tag) },
190 { &thdr, sizeof (struct gmon_hist_hdr) },
191 { _gmonparam.kcount, _gmonparam.kcountsize }
194 *(char **) thdr.low_pc = (char *) _gmonparam.lowpc;
195 *(char **) thdr.high_pc = (char *) _gmonparam.highpc;
196 *(int32_t *) thdr.hist_size = (_gmonparam.kcountsize
197 / sizeof (HISTCOUNTER));
198 *(int32_t *) thdr.prof_rate = __profile_frequency ();
199 strncpy (thdr.dimen, "seconds", sizeof (thdr.dimen));
200 thdr.dimen_abbrev = 's';
202 writev_not_cancel_no_status (fd, iov, 3);
207 static void
208 internal_function
209 write_call_graph (fd)
210 int fd;
212 #define NARCS_PER_WRITEV 32
213 u_char tag = GMON_TAG_CG_ARC;
214 struct gmon_cg_arc_record raw_arc[NARCS_PER_WRITEV]
215 __attribute__ ((aligned (__alignof__ (char*))));
216 ARCINDEX from_index, to_index;
217 u_long from_len;
218 u_long frompc;
219 struct iovec iov[2 * NARCS_PER_WRITEV];
220 int nfilled;
222 for (nfilled = 0; nfilled < NARCS_PER_WRITEV; ++nfilled)
224 iov[2 * nfilled].iov_base = &tag;
225 iov[2 * nfilled].iov_len = sizeof (tag);
227 iov[2 * nfilled + 1].iov_base = &raw_arc[nfilled];
228 iov[2 * nfilled + 1].iov_len = sizeof (struct gmon_cg_arc_record);
231 nfilled = 0;
232 from_len = _gmonparam.fromssize / sizeof (*_gmonparam.froms);
233 for (from_index = 0; from_index < from_len; ++from_index)
235 if (_gmonparam.froms[from_index] == 0)
236 continue;
238 frompc = _gmonparam.lowpc;
239 frompc += (from_index * _gmonparam.hashfraction
240 * sizeof (*_gmonparam.froms));
241 for (to_index = _gmonparam.froms[from_index];
242 to_index != 0;
243 to_index = _gmonparam.tos[to_index].link)
245 struct arc
247 char *frompc;
248 char *selfpc;
249 int32_t count;
251 arc;
253 arc.frompc = (char *) frompc;
254 arc.selfpc = (char *) _gmonparam.tos[to_index].selfpc;
255 arc.count = _gmonparam.tos[to_index].count;
256 memcpy (raw_arc + nfilled, &arc, sizeof (raw_arc [0]));
258 if (++nfilled == NARCS_PER_WRITEV)
260 writev_not_cancel_no_status (fd, iov, 2 * nfilled);
261 nfilled = 0;
265 if (nfilled > 0)
266 writev_not_cancel_no_status (fd, iov, 2 * nfilled);
270 static void
271 internal_function
272 write_bb_counts (fd)
273 int fd;
275 struct __bb *grp;
276 u_char tag = GMON_TAG_BB_COUNT;
277 size_t ncounts;
278 size_t i;
280 struct iovec bbhead[2] =
282 { &tag, sizeof (tag) },
283 { &ncounts, sizeof (ncounts) }
285 struct iovec bbbody[8];
286 size_t nfilled;
288 for (i = 0; i < (sizeof (bbbody) / sizeof (bbbody[0])); i += 2)
290 bbbody[i].iov_len = sizeof (grp->addresses[0]);
291 bbbody[i + 1].iov_len = sizeof (grp->counts[0]);
294 /* Write each group of basic-block info (all basic-blocks in a
295 compilation unit form a single group). */
297 for (grp = __bb_head; grp; grp = grp->next)
299 ncounts = grp->ncounts;
300 writev_not_cancel_no_status (fd, bbhead, 2);
301 for (nfilled = i = 0; i < ncounts; ++i)
303 if (nfilled > (sizeof (bbbody) / sizeof (bbbody[0])) - 2)
305 writev_not_cancel_no_status (fd, bbbody, nfilled);
306 nfilled = 0;
309 bbbody[nfilled++].iov_base = (char *) &grp->addresses[i];
310 bbbody[nfilled++].iov_base = &grp->counts[i];
312 if (nfilled > 0)
313 writev_not_cancel_no_status (fd, bbbody, nfilled);
318 static void
319 write_gmon (void)
321 struct gmon_hdr ghdr __attribute__ ((aligned (__alignof__ (int))));
322 int fd = -1;
323 char *env;
325 #ifndef O_NOFOLLOW
326 # define O_NOFOLLOW 0
327 #endif
329 env = getenv ("GMON_OUT_PREFIX");
330 if (env != NULL && !__libc_enable_secure)
332 size_t len = strlen (env);
333 char buf[len + 20];
334 __snprintf (buf, sizeof (buf), "%s.%u", env, __getpid ());
335 fd = open_not_cancel (buf, O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0666);
338 if (fd == -1)
340 fd = open_not_cancel ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW,
341 0666);
342 if (fd < 0)
344 char buf[300];
345 int errnum = errno;
346 __fxprintf (NULL, "_mcleanup: gmon.out: %s\n",
347 __strerror_r (errnum, buf, sizeof buf));
348 return;
352 /* write gmon.out header: */
353 memset (&ghdr, '\0', sizeof (struct gmon_hdr));
354 memcpy (&ghdr.cookie[0], GMON_MAGIC, sizeof (ghdr.cookie));
355 *(int32_t *) ghdr.version = GMON_VERSION;
356 write_not_cancel (fd, &ghdr, sizeof (struct gmon_hdr));
358 /* write PC histogram: */
359 write_hist (fd);
361 /* write call-graph: */
362 write_call_graph (fd);
364 /* write basic-block execution counts: */
365 write_bb_counts (fd);
367 close_not_cancel_no_status (fd);
371 void
372 __write_profiling (void)
374 int save = _gmonparam.state;
375 _gmonparam.state = GMON_PROF_OFF;
376 if (save == GMON_PROF_ON)
377 write_gmon ();
378 _gmonparam.state = save;
380 #ifndef SHARED
381 /* This symbol isn't used anywhere in the DSO and it is not exported.
382 This would normally mean it should be removed to get the same API
383 in static libraries. But since profiling is special in static libs
384 anyway we keep it. But not when building the DSO since some
385 quality assurance tests will otherwise trigger. */
386 weak_alias (__write_profiling, write_profiling)
387 #endif
390 void
391 _mcleanup (void)
393 __moncontrol (0);
395 if (_gmonparam.state != GMON_PROF_ERROR)
396 write_gmon ();
398 /* free the memory. */
399 free (_gmonparam.tos);