.
[glibc/history.git] / gmon / gmon.c
blob9f8dda1cec0885b2d6aa037a173e039cb4b83da7
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>
46 #ifdef USE_IN_LIBIO
47 # include <wchar.h>
48 #endif
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 (STDERR_FILENO, s, sizeof (s) - 1)
63 void moncontrol __P ((int mode));
64 void __moncontrol __P ((int mode));
65 static void write_hist __P ((int fd)) internal_function;
66 static void write_call_graph __P ((int fd)) internal_function;
67 static void write_bb_counts __P ((int fd)) internal_function;
70 * Control profiling
71 * profiling is what mcount checks to see if
72 * all the data structures are ready.
74 void
75 __moncontrol (mode)
76 int mode;
78 struct gmonparam *p = &_gmonparam;
80 /* Don't change the state if we ran into an error. */
81 if (p->state == GMON_PROF_ERROR)
82 return;
84 if (mode)
86 /* start */
87 __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale);
88 p->state = GMON_PROF_ON;
90 else
92 /* stop */
93 __profil(NULL, 0, 0, 0);
94 p->state = GMON_PROF_OFF;
97 weak_alias (__moncontrol, moncontrol)
100 void
101 __monstartup (lowpc, highpc)
102 u_long lowpc;
103 u_long highpc;
105 register int o;
106 char *cp;
107 struct gmonparam *p = &_gmonparam;
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.
113 p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
114 p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
115 p->textsize = p->highpc - p->lowpc;
116 p->kcountsize = p->textsize / HISTFRACTION;
117 p->hashfraction = HASHFRACTION;
118 p->log_hashfraction = -1;
119 /* The following test must be kept in sync with the corresponding
120 test in mcount.c. */
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;
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);
134 cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1);
135 if (! cp)
137 ERR("monstartup: out of memory\n");
138 p->tos = NULL;
139 p->state = GMON_PROF_ERROR;
140 return;
142 p->tos = (struct tostruct *)cp;
143 cp += p->tossize;
144 p->kcount = (HISTCOUNTER *)cp;
145 cp += p->kcountsize;
146 p->froms = (ARCINDEX *)cp;
148 p->tos[0].link = 0;
150 o = p->highpc - p->lowpc;
151 if (p->kcountsize < (u_long) o)
153 #ifndef hp300
154 s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
155 #else
156 /* avoid floating point operations */
157 int quot = o / p->kcountsize;
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);
167 #endif
168 } else
169 s_scale = SCALE_1_TO_1;
171 __moncontrol(1);
173 weak_alias(__monstartup, monstartup)
176 static void
177 internal_function
178 write_hist (fd)
179 int fd;
181 u_char tag = GMON_TAG_TIME_HIST;
182 struct gmon_hist_hdr thdr __attribute__ ((aligned (__alignof__ (char *))));
184 if (_gmonparam.kcountsize > 0)
186 struct iovec iov[3] =
188 { &tag, sizeof (tag) },
189 { &thdr, sizeof (struct gmon_hist_hdr) },
190 { _gmonparam.kcount, _gmonparam.kcountsize }
193 *(char **) thdr.low_pc = (char *) _gmonparam.lowpc;
194 *(char **) thdr.high_pc = (char *) _gmonparam.highpc;
195 *(int32_t *) thdr.hist_size = (_gmonparam.kcountsize
196 / sizeof (HISTCOUNTER));
197 *(int32_t *) thdr.prof_rate = __profile_frequency ();
198 strncpy (thdr.dimen, "seconds", sizeof (thdr.dimen));
199 thdr.dimen_abbrev = 's';
201 __writev (fd, iov, 3);
206 static void
207 internal_function
208 write_call_graph (fd)
209 int fd;
211 #define NARCS_PER_WRITEV 32
212 u_char tag = GMON_TAG_CG_ARC;
213 struct gmon_cg_arc_record raw_arc[NARCS_PER_WRITEV]
214 __attribute__ ((aligned (__alignof__ (char*))));
215 ARCINDEX from_index, to_index;
216 u_long from_len;
217 u_long frompc;
218 struct iovec iov[2 * NARCS_PER_WRITEV];
219 int nfilled;
221 for (nfilled = 0; nfilled < NARCS_PER_WRITEV; ++nfilled)
223 iov[2 * nfilled].iov_base = &tag;
224 iov[2 * nfilled].iov_len = sizeof (tag);
226 iov[2 * nfilled + 1].iov_base = &raw_arc[nfilled];
227 iov[2 * nfilled + 1].iov_len = sizeof (struct gmon_cg_arc_record);
230 nfilled = 0;
231 from_len = _gmonparam.fromssize / sizeof (*_gmonparam.froms);
232 for (from_index = 0; from_index < from_len; ++from_index)
234 if (_gmonparam.froms[from_index] == 0)
235 continue;
237 frompc = _gmonparam.lowpc;
238 frompc += (from_index * _gmonparam.hashfraction
239 * sizeof (*_gmonparam.froms));
240 for (to_index = _gmonparam.froms[from_index];
241 to_index != 0;
242 to_index = _gmonparam.tos[to_index].link)
244 struct arc
246 char *frompc;
247 char *selfpc;
248 int32_t count;
250 arc;
252 arc.frompc = (char *) frompc;
253 arc.selfpc = (char *) _gmonparam.tos[to_index].selfpc;
254 arc.count = _gmonparam.tos[to_index].count;
255 memcpy (raw_arc + nfilled, &arc, sizeof (raw_arc [0]));
257 if (++nfilled == NARCS_PER_WRITEV)
259 __writev (fd, iov, 2 * nfilled);
260 nfilled = 0;
264 if (nfilled > 0)
265 __writev (fd, iov, 2 * nfilled);
269 static void
270 internal_function
271 write_bb_counts (fd)
272 int fd;
274 struct __bb *grp;
275 u_char tag = GMON_TAG_BB_COUNT;
276 size_t ncounts;
277 size_t i;
279 struct iovec bbhead[2] =
281 { &tag, sizeof (tag) },
282 { &ncounts, sizeof (ncounts) }
284 struct iovec bbbody[8];
285 size_t nfilled;
287 for (i = 0; i < (sizeof (bbbody) / sizeof (bbbody[0])); i += 2)
289 bbbody[i].iov_len = sizeof (grp->addresses[0]);
290 bbbody[i + 1].iov_len = sizeof (grp->counts[0]);
293 /* Write each group of basic-block info (all basic-blocks in a
294 compilation unit form a single group). */
296 for (grp = __bb_head; grp; grp = grp->next)
298 ncounts = grp->ncounts;
299 __writev (fd, bbhead, 2);
300 for (nfilled = i = 0; i < ncounts; ++i)
302 if (nfilled > (sizeof (bbbody) / sizeof (bbbody[0])) - 2)
304 __writev (fd, bbbody, nfilled);
305 nfilled = 0;
308 bbbody[nfilled++].iov_base = (char *) &grp->addresses[i];
309 bbbody[nfilled++].iov_base = &grp->counts[i];
311 if (nfilled > 0)
312 __writev (fd, bbbody, nfilled);
317 static void
318 write_gmon (void)
320 struct gmon_hdr ghdr __attribute__ ((aligned (__alignof__ (int))));
321 int fd = -1;
322 char *env;
324 #ifndef O_NOFOLLOW
325 # define O_NOFOLLOW 0
326 #endif
328 env = getenv ("GMON_OUT_PREFIX");
329 if (env != NULL && !__libc_enable_secure)
331 size_t len = strlen (env);
332 char buf[len + 20];
333 sprintf (buf, "%s.%u", env, __getpid ());
334 fd = __open (buf, O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0666);
337 if (fd == -1)
339 fd = __open ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0666);
340 if (fd < 0)
342 char buf[300];
343 int errnum = errno;
344 #ifdef USE_IN_LIBIO
345 if (_IO_fwide (stderr, 0) > 0)
346 __fwprintf (stderr, L"_mcleanup: gmon.out: %s\n",
347 __strerror_r (errnum, buf, sizeof buf));
348 else
349 #endif
350 fprintf (stderr, "_mcleanup: gmon.out: %s\n",
351 __strerror_r (errnum, buf, sizeof buf));
352 return;
356 /* write gmon.out header: */
357 memset (&ghdr, '\0', sizeof (struct gmon_hdr));
358 memcpy (&ghdr.cookie[0], GMON_MAGIC, sizeof (ghdr.cookie));
359 *(int32_t *) ghdr.version = GMON_VERSION;
360 __write (fd, &ghdr, sizeof (struct gmon_hdr));
362 /* write PC histogram: */
363 write_hist (fd);
365 /* write call-graph: */
366 write_call_graph (fd);
368 /* write basic-block execution counts: */
369 write_bb_counts (fd);
371 __close (fd);
375 void
376 __write_profiling (void)
378 int save = _gmonparam.state;
379 _gmonparam.state = GMON_PROF_OFF;
380 if (save == GMON_PROF_ON)
381 write_gmon ();
382 _gmonparam.state = save;
384 #ifndef SHARED
385 /* This symbol isn't used anywhere in the DSO and it is not exported.
386 This would normally mean it should be removed to get the same API
387 in static libraries. But since profiling is special in static libs
388 anyway we keep it. But not when building the DSO since some
389 quality assurance tests will otherwise trigger. */
390 weak_alias (__write_profiling, write_profiling)
391 #endif
394 void
395 _mcleanup (void)
397 __moncontrol (0);
399 if (_gmonparam.state != GMON_PROF_ERROR)
400 write_gmon ();
402 /* free the memory. */
403 if (_gmonparam.tos != NULL)
404 free (_gmonparam.tos);