]> git.ipfire.org Git - thirdparty/glibc.git/blob - gmon/gmon.c
Cleanup of configuration options
[thirdparty/glibc.git] / gmon / gmon.c
1 /*-
2 * Copyright (c) 1983, 1992, 1993, 2011
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.
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 */
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>
34
35 #include <errno.h>
36 #include <stdio.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <wchar.h>
40
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>
48
49
50 /* Head of basic-block list or NULL. */
51 struct __bb *__bb_head attribute_hidden;
52
53 struct gmonparam _gmonparam attribute_hidden = { GMON_PROF_OFF };
54
55 /*
56 * See profil(2) where this is described:
57 */
58 static int s_scale;
59 #define SCALE_1_TO_1 0x10000L
60
61 #define ERR(s) write_not_cancel (STDERR_FILENO, s, sizeof (s) - 1)
62
63 void moncontrol (int mode);
64 void __moncontrol (int mode);
65 static void write_hist (int fd) internal_function;
66 static void write_call_graph (int fd) internal_function;
67 static void write_bb_counts (int fd) internal_function;
68
69 /*
70 * Control profiling
71 * profiling is what mcount checks to see if
72 * all the data structures are ready.
73 */
74 void
75 __moncontrol (mode)
76 int mode;
77 {
78 struct gmonparam *p = &_gmonparam;
79
80 /* Don't change the state if we ran into an error. */
81 if (p->state == GMON_PROF_ERROR)
82 return;
83
84 if (mode)
85 {
86 /* start */
87 __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale);
88 p->state = GMON_PROF_ON;
89 }
90 else
91 {
92 /* stop */
93 __profil(NULL, 0, 0, 0);
94 p->state = GMON_PROF_OFF;
95 }
96 }
97 weak_alias (__moncontrol, moncontrol)
98
99
100 void
101 __monstartup (lowpc, highpc)
102 u_long lowpc;
103 u_long highpc;
104 {
105 register int o;
106 char *cp;
107 struct gmonparam *p = &_gmonparam;
108
109 /*
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.
112 */
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 = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms));
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;
125 }
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);
133
134 cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1);
135 if (! cp)
136 {
137 ERR("monstartup: out of memory\n");
138 p->tos = NULL;
139 p->state = GMON_PROF_ERROR;
140 return;
141 }
142 p->tos = (struct tostruct *)cp;
143 cp += p->tossize;
144 p->kcount = (HISTCOUNTER *)cp;
145 cp += p->kcountsize;
146 p->froms = (ARCINDEX *)cp;
147
148 p->tos[0].link = 0;
149
150 o = p->highpc - p->lowpc;
151 if (p->kcountsize < (u_long) o)
152 {
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;
158
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;
170
171 __moncontrol(1);
172 }
173 weak_alias (__monstartup, monstartup)
174
175
176 static void
177 internal_function
178 write_hist (fd)
179 int fd;
180 {
181 u_char tag = GMON_TAG_TIME_HIST;
182
183 if (_gmonparam.kcountsize > 0)
184 {
185 struct real_gmon_hist_hdr
186 {
187 char *low_pc;
188 char *high_pc;
189 int32_t hist_size;
190 int32_t prof_rate;
191 char dimen[15];
192 char dimen_abbrev;
193 } thdr;
194 struct iovec iov[3] =
195 {
196 { &tag, sizeof (tag) },
197 { &thdr, sizeof (struct gmon_hist_hdr) },
198 { _gmonparam.kcount, _gmonparam.kcountsize }
199 };
200
201 if (sizeof (thdr) != sizeof (struct gmon_hist_hdr)
202 || (offsetof (struct real_gmon_hist_hdr, low_pc)
203 != offsetof (struct gmon_hist_hdr, low_pc))
204 || (offsetof (struct real_gmon_hist_hdr, high_pc)
205 != offsetof (struct gmon_hist_hdr, high_pc))
206 || (offsetof (struct real_gmon_hist_hdr, hist_size)
207 != offsetof (struct gmon_hist_hdr, hist_size))
208 || (offsetof (struct real_gmon_hist_hdr, prof_rate)
209 != offsetof (struct gmon_hist_hdr, prof_rate))
210 || (offsetof (struct real_gmon_hist_hdr, dimen)
211 != offsetof (struct gmon_hist_hdr, dimen))
212 || (offsetof (struct real_gmon_hist_hdr, dimen_abbrev)
213 != offsetof (struct gmon_hist_hdr, dimen_abbrev)))
214 abort ();
215
216 thdr.low_pc = (char *) _gmonparam.lowpc;
217 thdr.high_pc = (char *) _gmonparam.highpc;
218 thdr.hist_size = _gmonparam.kcountsize / sizeof (HISTCOUNTER);
219 thdr.prof_rate = __profile_frequency ();
220 strncpy (thdr.dimen, "seconds", sizeof (thdr.dimen));
221 thdr.dimen_abbrev = 's';
222
223 writev_not_cancel_no_status (fd, iov, 3);
224 }
225 }
226
227
228 static void
229 internal_function
230 write_call_graph (fd)
231 int fd;
232 {
233 #define NARCS_PER_WRITEV 32
234 u_char tag = GMON_TAG_CG_ARC;
235 struct gmon_cg_arc_record raw_arc[NARCS_PER_WRITEV]
236 __attribute__ ((aligned (__alignof__ (char*))));
237 ARCINDEX from_index, to_index;
238 u_long from_len;
239 u_long frompc;
240 struct iovec iov[2 * NARCS_PER_WRITEV];
241 int nfilled;
242
243 for (nfilled = 0; nfilled < NARCS_PER_WRITEV; ++nfilled)
244 {
245 iov[2 * nfilled].iov_base = &tag;
246 iov[2 * nfilled].iov_len = sizeof (tag);
247
248 iov[2 * nfilled + 1].iov_base = &raw_arc[nfilled];
249 iov[2 * nfilled + 1].iov_len = sizeof (struct gmon_cg_arc_record);
250 }
251
252 nfilled = 0;
253 from_len = _gmonparam.fromssize / sizeof (*_gmonparam.froms);
254 for (from_index = 0; from_index < from_len; ++from_index)
255 {
256 if (_gmonparam.froms[from_index] == 0)
257 continue;
258
259 frompc = _gmonparam.lowpc;
260 frompc += (from_index * _gmonparam.hashfraction
261 * sizeof (*_gmonparam.froms));
262 for (to_index = _gmonparam.froms[from_index];
263 to_index != 0;
264 to_index = _gmonparam.tos[to_index].link)
265 {
266 struct arc
267 {
268 char *frompc;
269 char *selfpc;
270 int32_t count;
271 }
272 arc;
273
274 arc.frompc = (char *) frompc;
275 arc.selfpc = (char *) _gmonparam.tos[to_index].selfpc;
276 arc.count = _gmonparam.tos[to_index].count;
277 memcpy (raw_arc + nfilled, &arc, sizeof (raw_arc [0]));
278
279 if (++nfilled == NARCS_PER_WRITEV)
280 {
281 writev_not_cancel_no_status (fd, iov, 2 * nfilled);
282 nfilled = 0;
283 }
284 }
285 }
286 if (nfilled > 0)
287 writev_not_cancel_no_status (fd, iov, 2 * nfilled);
288 }
289
290
291 static void
292 internal_function
293 write_bb_counts (fd)
294 int fd;
295 {
296 struct __bb *grp;
297 u_char tag = GMON_TAG_BB_COUNT;
298 size_t ncounts;
299 size_t i;
300
301 struct iovec bbhead[2] =
302 {
303 { &tag, sizeof (tag) },
304 { &ncounts, sizeof (ncounts) }
305 };
306 struct iovec bbbody[8];
307 size_t nfilled;
308
309 for (i = 0; i < (sizeof (bbbody) / sizeof (bbbody[0])); i += 2)
310 {
311 bbbody[i].iov_len = sizeof (grp->addresses[0]);
312 bbbody[i + 1].iov_len = sizeof (grp->counts[0]);
313 }
314
315 /* Write each group of basic-block info (all basic-blocks in a
316 compilation unit form a single group). */
317
318 for (grp = __bb_head; grp; grp = grp->next)
319 {
320 ncounts = grp->ncounts;
321 writev_not_cancel_no_status (fd, bbhead, 2);
322 for (nfilled = i = 0; i < ncounts; ++i)
323 {
324 if (nfilled > (sizeof (bbbody) / sizeof (bbbody[0])) - 2)
325 {
326 writev_not_cancel_no_status (fd, bbbody, nfilled);
327 nfilled = 0;
328 }
329
330 bbbody[nfilled++].iov_base = (char *) &grp->addresses[i];
331 bbbody[nfilled++].iov_base = &grp->counts[i];
332 }
333 if (nfilled > 0)
334 writev_not_cancel_no_status (fd, bbbody, nfilled);
335 }
336 }
337
338
339 static void
340 write_gmon (void)
341 {
342 int fd = -1;
343 char *env;
344
345 #ifndef O_NOFOLLOW
346 # define O_NOFOLLOW 0
347 #endif
348
349 env = getenv ("GMON_OUT_PREFIX");
350 if (env != NULL && !__libc_enable_secure)
351 {
352 size_t len = strlen (env);
353 char buf[len + 20];
354 __snprintf (buf, sizeof (buf), "%s.%u", env, __getpid ());
355 fd = open_not_cancel (buf, O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0666);
356 }
357
358 if (fd == -1)
359 {
360 fd = open_not_cancel ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW,
361 0666);
362 if (fd < 0)
363 {
364 char buf[300];
365 int errnum = errno;
366 __fxprintf (NULL, "_mcleanup: gmon.out: %s\n",
367 __strerror_r (errnum, buf, sizeof buf));
368 return;
369 }
370 }
371
372 /* write gmon.out header: */
373 struct real_gmon_hdr
374 {
375 char cookie[4];
376 int32_t version;
377 char spare[3 * 4];
378 } ghdr;
379 if (sizeof (ghdr) != sizeof (struct gmon_hdr)
380 || (offsetof (struct real_gmon_hdr, cookie)
381 != offsetof (struct gmon_hdr, cookie))
382 || (offsetof (struct real_gmon_hdr, version)
383 != offsetof (struct gmon_hdr, version)))
384 abort ();
385 memcpy (&ghdr.cookie[0], GMON_MAGIC, sizeof (ghdr.cookie));
386 ghdr.version = GMON_VERSION;
387 memset (ghdr.spare, '\0', sizeof (ghdr.spare));
388 write_not_cancel (fd, &ghdr, sizeof (struct gmon_hdr));
389
390 /* write PC histogram: */
391 write_hist (fd);
392
393 /* write call-graph: */
394 write_call_graph (fd);
395
396 /* write basic-block execution counts: */
397 write_bb_counts (fd);
398
399 close_not_cancel_no_status (fd);
400 }
401
402
403 void
404 __write_profiling (void)
405 {
406 int save = _gmonparam.state;
407 _gmonparam.state = GMON_PROF_OFF;
408 if (save == GMON_PROF_ON)
409 write_gmon ();
410 _gmonparam.state = save;
411 }
412 #ifndef SHARED
413 /* This symbol isn't used anywhere in the DSO and it is not exported.
414 This would normally mean it should be removed to get the same API
415 in static libraries. But since profiling is special in static libs
416 anyway we keep it. But not when building the DSO since some
417 quality assurance tests will otherwise trigger. */
418 weak_alias (__write_profiling, write_profiling)
419 #endif
420
421
422 void
423 _mcleanup (void)
424 {
425 __moncontrol (0);
426
427 if (_gmonparam.state != GMON_PROF_ERROR)
428 write_gmon ();
429
430 /* free the memory. */
431 free (_gmonparam.tos);
432 }