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