tile: update libm-test-ulps for new tests
[platform/upstream/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 }