Updated to fedora-glibc-20090427T1419
[glibc/history.git] / gmon / gmon.c
blobaf2ac1c0f6698e81354869539c196f6104c81fce
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 <stddef.h>
44 #include <unistd.h>
45 #include <libc-internal.h>
46 #include <not-cancel.h>
48 #ifdef USE_IN_LIBIO
49 # include <wchar.h>
50 #endif
52 /* Head of basic-block list or NULL. */
53 struct __bb *__bb_head attribute_hidden;
55 struct gmonparam _gmonparam attribute_hidden = { GMON_PROF_OFF };
58 * See profil(2) where this is described:
60 static int s_scale;
61 #define SCALE_1_TO_1 0x10000L
63 #define ERR(s) write_not_cancel (STDERR_FILENO, s, sizeof (s) - 1)
65 void moncontrol (int mode);
66 void __moncontrol (int mode);
67 static void write_hist (int fd) internal_function;
68 static void write_call_graph (int fd) internal_function;
69 static void write_bb_counts (int fd) internal_function;
72 * Control profiling
73 * profiling is what mcount checks to see if
74 * all the data structures are ready.
76 void
77 __moncontrol (mode)
78 int mode;
80 struct gmonparam *p = &_gmonparam;
82 /* Don't change the state if we ran into an error. */
83 if (p->state == GMON_PROF_ERROR)
84 return;
86 if (mode)
88 /* start */
89 __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale);
90 p->state = GMON_PROF_ON;
92 else
94 /* stop */
95 __profil(NULL, 0, 0, 0);
96 p->state = GMON_PROF_OFF;
99 weak_alias (__moncontrol, moncontrol)
102 void
103 __monstartup (lowpc, highpc)
104 u_long lowpc;
105 u_long highpc;
107 register int o;
108 char *cp;
109 struct gmonparam *p = &_gmonparam;
112 * round lowpc and highpc to multiples of the density we're using
113 * so the rest of the scaling (here and in gprof) stays in ints.
115 p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
116 p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
117 p->textsize = p->highpc - p->lowpc;
118 p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms));
119 p->hashfraction = HASHFRACTION;
120 p->log_hashfraction = -1;
121 /* The following test must be kept in sync with the corresponding
122 test in mcount.c. */
123 if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) {
124 /* if HASHFRACTION is a power of two, mcount can use shifting
125 instead of integer division. Precompute shift amount. */
126 p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1;
128 p->fromssize = p->textsize / HASHFRACTION;
129 p->tolimit = p->textsize * ARCDENSITY / 100;
130 if (p->tolimit < MINARCS)
131 p->tolimit = MINARCS;
132 else if (p->tolimit > MAXARCS)
133 p->tolimit = MAXARCS;
134 p->tossize = p->tolimit * sizeof(struct tostruct);
136 cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1);
137 if (! cp)
139 ERR("monstartup: out of memory\n");
140 p->tos = NULL;
141 p->state = GMON_PROF_ERROR;
142 return;
144 p->tos = (struct tostruct *)cp;
145 cp += p->tossize;
146 p->kcount = (HISTCOUNTER *)cp;
147 cp += p->kcountsize;
148 p->froms = (ARCINDEX *)cp;
150 p->tos[0].link = 0;
152 o = p->highpc - p->lowpc;
153 if (p->kcountsize < (u_long) o)
155 #ifndef hp300
156 s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
157 #else
158 /* avoid floating point operations */
159 int quot = o / p->kcountsize;
161 if (quot >= 0x10000)
162 s_scale = 1;
163 else if (quot >= 0x100)
164 s_scale = 0x10000 / quot;
165 else if (o >= 0x800000)
166 s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
167 else
168 s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
169 #endif
170 } else
171 s_scale = SCALE_1_TO_1;
173 __moncontrol(1);
175 weak_alias (__monstartup, monstartup)
178 static void
179 internal_function
180 write_hist (fd)
181 int fd;
183 u_char tag = GMON_TAG_TIME_HIST;
185 if (_gmonparam.kcountsize > 0)
187 struct real_gmon_hist_hdr
189 char *low_pc;
190 char *high_pc;
191 int32_t hist_size;
192 int32_t prof_rate;
193 char dimen[15];
194 char dimen_abbrev;
195 } thdr;
196 struct iovec iov[3] =
198 { &tag, sizeof (tag) },
199 { &thdr, sizeof (struct gmon_hist_hdr) },
200 { _gmonparam.kcount, _gmonparam.kcountsize }
203 if (sizeof (thdr) != sizeof (struct gmon_hist_hdr)
204 || (offsetof (struct real_gmon_hist_hdr, low_pc)
205 != offsetof (struct gmon_hist_hdr, low_pc))
206 || (offsetof (struct real_gmon_hist_hdr, high_pc)
207 != offsetof (struct gmon_hist_hdr, high_pc))
208 || (offsetof (struct real_gmon_hist_hdr, hist_size)
209 != offsetof (struct gmon_hist_hdr, hist_size))
210 || (offsetof (struct real_gmon_hist_hdr, prof_rate)
211 != offsetof (struct gmon_hist_hdr, prof_rate))
212 || (offsetof (struct real_gmon_hist_hdr, dimen)
213 != offsetof (struct gmon_hist_hdr, dimen))
214 || (offsetof (struct real_gmon_hist_hdr, dimen_abbrev)
215 != offsetof (struct gmon_hist_hdr, dimen_abbrev)))
216 abort ();
218 thdr.low_pc = (char *) _gmonparam.lowpc;
219 thdr.high_pc = (char *) _gmonparam.highpc;
220 thdr.hist_size = _gmonparam.kcountsize / sizeof (HISTCOUNTER);
221 thdr.prof_rate = __profile_frequency ();
222 strncpy (thdr.dimen, "seconds", sizeof (thdr.dimen));
223 thdr.dimen_abbrev = 's';
225 writev_not_cancel_no_status (fd, iov, 3);
230 static void
231 internal_function
232 write_call_graph (fd)
233 int fd;
235 #define NARCS_PER_WRITEV 32
236 u_char tag = GMON_TAG_CG_ARC;
237 struct gmon_cg_arc_record raw_arc[NARCS_PER_WRITEV]
238 __attribute__ ((aligned (__alignof__ (char*))));
239 ARCINDEX from_index, to_index;
240 u_long from_len;
241 u_long frompc;
242 struct iovec iov[2 * NARCS_PER_WRITEV];
243 int nfilled;
245 for (nfilled = 0; nfilled < NARCS_PER_WRITEV; ++nfilled)
247 iov[2 * nfilled].iov_base = &tag;
248 iov[2 * nfilled].iov_len = sizeof (tag);
250 iov[2 * nfilled + 1].iov_base = &raw_arc[nfilled];
251 iov[2 * nfilled + 1].iov_len = sizeof (struct gmon_cg_arc_record);
254 nfilled = 0;
255 from_len = _gmonparam.fromssize / sizeof (*_gmonparam.froms);
256 for (from_index = 0; from_index < from_len; ++from_index)
258 if (_gmonparam.froms[from_index] == 0)
259 continue;
261 frompc = _gmonparam.lowpc;
262 frompc += (from_index * _gmonparam.hashfraction
263 * sizeof (*_gmonparam.froms));
264 for (to_index = _gmonparam.froms[from_index];
265 to_index != 0;
266 to_index = _gmonparam.tos[to_index].link)
268 struct arc
270 char *frompc;
271 char *selfpc;
272 int32_t count;
274 arc;
276 arc.frompc = (char *) frompc;
277 arc.selfpc = (char *) _gmonparam.tos[to_index].selfpc;
278 arc.count = _gmonparam.tos[to_index].count;
279 memcpy (raw_arc + nfilled, &arc, sizeof (raw_arc [0]));
281 if (++nfilled == NARCS_PER_WRITEV)
283 writev_not_cancel_no_status (fd, iov, 2 * nfilled);
284 nfilled = 0;
288 if (nfilled > 0)
289 writev_not_cancel_no_status (fd, iov, 2 * nfilled);
293 static void
294 internal_function
295 write_bb_counts (fd)
296 int fd;
298 struct __bb *grp;
299 u_char tag = GMON_TAG_BB_COUNT;
300 size_t ncounts;
301 size_t i;
303 struct iovec bbhead[2] =
305 { &tag, sizeof (tag) },
306 { &ncounts, sizeof (ncounts) }
308 struct iovec bbbody[8];
309 size_t nfilled;
311 for (i = 0; i < (sizeof (bbbody) / sizeof (bbbody[0])); i += 2)
313 bbbody[i].iov_len = sizeof (grp->addresses[0]);
314 bbbody[i + 1].iov_len = sizeof (grp->counts[0]);
317 /* Write each group of basic-block info (all basic-blocks in a
318 compilation unit form a single group). */
320 for (grp = __bb_head; grp; grp = grp->next)
322 ncounts = grp->ncounts;
323 writev_not_cancel_no_status (fd, bbhead, 2);
324 for (nfilled = i = 0; i < ncounts; ++i)
326 if (nfilled > (sizeof (bbbody) / sizeof (bbbody[0])) - 2)
328 writev_not_cancel_no_status (fd, bbbody, nfilled);
329 nfilled = 0;
332 bbbody[nfilled++].iov_base = (char *) &grp->addresses[i];
333 bbbody[nfilled++].iov_base = &grp->counts[i];
335 if (nfilled > 0)
336 writev_not_cancel_no_status (fd, bbbody, nfilled);
341 static void
342 write_gmon (void)
344 int fd = -1;
345 char *env;
347 #ifndef O_NOFOLLOW
348 # define O_NOFOLLOW 0
349 #endif
351 env = getenv ("GMON_OUT_PREFIX");
352 if (env != NULL && !__libc_enable_secure)
354 size_t len = strlen (env);
355 char buf[len + 20];
356 __snprintf (buf, sizeof (buf), "%s.%u", env, __getpid ());
357 fd = open_not_cancel (buf, O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0666);
360 if (fd == -1)
362 fd = open_not_cancel ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW,
363 0666);
364 if (fd < 0)
366 char buf[300];
367 int errnum = errno;
368 __fxprintf (NULL, "_mcleanup: gmon.out: %s\n",
369 __strerror_r (errnum, buf, sizeof buf));
370 return;
374 /* write gmon.out header: */
375 struct real_gmon_hdr
377 char cookie[4];
378 int32_t version;
379 char spare[3 * 4];
380 } ghdr;
381 if (sizeof (ghdr) != sizeof (struct gmon_hdr)
382 || (offsetof (struct real_gmon_hdr, cookie)
383 != offsetof (struct gmon_hdr, cookie))
384 || (offsetof (struct real_gmon_hdr, version)
385 != offsetof (struct gmon_hdr, version)))
386 abort ();
387 memcpy (&ghdr.cookie[0], GMON_MAGIC, sizeof (ghdr.cookie));
388 ghdr.version = GMON_VERSION;
389 memset (ghdr.spare, '\0', sizeof (ghdr.spare));
390 write_not_cancel (fd, &ghdr, sizeof (struct gmon_hdr));
392 /* write PC histogram: */
393 write_hist (fd);
395 /* write call-graph: */
396 write_call_graph (fd);
398 /* write basic-block execution counts: */
399 write_bb_counts (fd);
401 close_not_cancel_no_status (fd);
405 void
406 __write_profiling (void)
408 int save = _gmonparam.state;
409 _gmonparam.state = GMON_PROF_OFF;
410 if (save == GMON_PROF_ON)
411 write_gmon ();
412 _gmonparam.state = save;
414 #ifndef SHARED
415 /* This symbol isn't used anywhere in the DSO and it is not exported.
416 This would normally mean it should be removed to get the same API
417 in static libraries. But since profiling is special in static libs
418 anyway we keep it. But not when building the DSO since some
419 quality assurance tests will otherwise trigger. */
420 weak_alias (__write_profiling, write_profiling)
421 #endif
424 void
425 _mcleanup (void)
427 __moncontrol (0);
429 if (_gmonparam.state != GMON_PROF_ERROR)
430 write_gmon ();
432 /* free the memory. */
433 free (_gmonparam.tos);