Import pre-release gcc-5.0 to new vendor branch
[dragonfly.git] / contrib / gcc-5.0 / libgcc / config / arc / gmon / gmon.c
1 /*-
2  * Copyright (c) 1983, 1992, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  * Copyright (C) 2007-2015 Free Software Foundation, Inc.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 4. Neither the name of the University nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 #if 0
31 #include <sys/param.h>
32 #include <sys/time.h>
33 #endif
34 #include <sys/gmon.h>
35 #include <sys/gmon_out.h>
36
37 #include <stddef.h>
38 #include <errno.h>
39 #include <stdio.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 #if 0
48 #include <libc-internal.h>
49 #include <not-cancel.h>
50
51 #ifdef USE_IN_LIBIO
52 # include <wchar.h>
53 #endif
54 #endif
55 #define internal_function
56 #define weak_alias(fun,aliasid) extern __typeof(fun) aliasid __attribute__ ((weak, alias (#fun)));
57 #define __libc_enable_secure 0
58
59 /*  Head of basic-block list or NULL. */
60 struct __bb *__bb_head attribute_hidden;
61
62 struct gmonparam _gmonparam attribute_hidden = { GMON_PROF_OFF };
63
64 /*
65  * See profil(2) where this is described:
66  */
67 static int      s_scale;
68 #define         SCALE_1_TO_1    0x10000L
69
70 #define ERR(s) write (STDERR_FILENO, s, sizeof (s) - 1)
71
72 void moncontrol (int mode);
73 void __moncontrol (int mode);
74 static void write_hist (int fd) internal_function;
75 static void write_call_graph (int fd) internal_function;
76 static void write_bb_counts (int fd) internal_function;
77
78 /*
79  * Control profiling
80  *      profiling is what mcount checks to see if
81  *      all the data structures are ready.
82  */
83 void
84 __moncontrol (int mode)
85 {
86   struct gmonparam *p = &_gmonparam;
87
88   /* Don't change the state if we ran into an error.  */
89   if (p->state == GMON_PROF_ERROR)
90     return;
91
92   if (mode)
93     {
94       /* start */
95       __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale);
96       p->state = GMON_PROF_ON;
97     }
98   else
99     {
100       /* stop */
101       __profil(NULL, 0, 0, 0);
102       p->state = GMON_PROF_OFF;
103     }
104 }
105 weak_alias (__moncontrol, moncontrol)
106
107
108 void
109 __monstartup (u_long lowpc, u_long highpc)
110 {
111   register int o;
112   char *cp;
113   struct gmonparam *p = &_gmonparam;
114   int linesz;
115
116   /*
117    * round lowpc and highpc to multiples of the density we're using
118    * so the rest of the scaling (here and in gprof) stays in ints.
119    */
120   p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
121   if (sizeof *p->froms % sizeof(HISTCOUNTER) != 0)
122     {
123       p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
124       p->textsize = p->highpc - p->lowpc;
125       p->kcountsize = ROUNDUP((p->textsize + HISTFRACTION - 1) / HISTFRACTION,
126                               sizeof (*p->froms));
127     }
128   else
129     {
130       /* Avoid odd scales by rounding up highpc to get kcountsize rounded.  */
131       p->textsize = ROUNDUP (highpc - p->lowpc,
132                              HISTFRACTION * sizeof (*p->froms));
133       p->highpc = p->lowpc + p->textsize;
134       p->kcountsize = p->textsize / HISTFRACTION;
135     }
136   p->hashfraction = HASHFRACTION;
137   p->log_hashfraction = -1;
138   /* The following test must be kept in sync with the corresponding
139      test in mcount.c.  */
140   if ((HASHFRACTION & (HASHFRACTION - 1)) == 0) {
141       /* if HASHFRACTION is a power of two, mcount can use shifting
142          instead of integer division.  Precompute shift amount. */
143       p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1;
144   }
145   p->tolimit = p->textsize * ARCDENSITY / 100;
146   if (p->tolimit < MINARCS)
147     p->tolimit = MINARCS;
148   else if (p->tolimit > MAXARCS)
149     p->tolimit = MAXARCS;
150   p->tossize = p->tolimit * sizeof(struct tostruct);
151
152   /* p->kcount must not share cache lines with the adjacent data, because
153      we use uncached accesses while profiling.  */
154   linesz = __dcache_linesz ();
155   cp = calloc (ROUNDUP (p->kcountsize, linesz) + p->tossize
156                + (linesz - 1), 1);
157   if (! cp)
158     {
159       ERR("monstartup: out of memory\n");
160       p->tos = NULL;
161       p->state = GMON_PROF_ERROR;
162       /* In case we loose the error state due to a race,
163          prevent invalid writes also by clearing tolimit.  */
164       p->tolimit = 0;
165       return;
166     }
167   p->tos = (struct tostruct *)cp;
168   cp += p->tossize;
169   cp = (char *) ROUNDUP ((ptrdiff_t) cp, linesz);
170   p->kcount = (HISTCOUNTER *)cp;
171   cp += ROUNDUP (p->kcountsize, linesz);
172
173   p->tos[0].link = 0;
174
175   o = p->highpc - p->lowpc;
176   if (p->kcountsize < (u_long) o)
177     {
178 #ifndef hp300
179       s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
180 #else
181       /* avoid floating point operations */
182       int quot = o / p->kcountsize;
183
184       if (quot >= 0x10000)
185         s_scale = 1;
186       else if (quot >= 0x100)
187         s_scale = 0x10000 / quot;
188       else if (o >= 0x800000)
189         s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
190       else
191         s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
192 #endif
193     } else
194       s_scale = SCALE_1_TO_1;
195
196   __moncontrol(1);
197 }
198 weak_alias (__monstartup, monstartup)
199
200
201 static void
202 internal_function
203 write_hist (int fd)
204 {
205   u_char tag = GMON_TAG_TIME_HIST;
206   struct arc_gmon_hist_hdr thdr __attribute__ ((aligned (__alignof__ (char *))));
207   int r;
208
209   if (_gmonparam.kcountsize > 0)
210     {
211       *(char **) thdr.low_pc = (char *) _gmonparam.lowpc;
212       *(char **) thdr.high_pc = (char *) _gmonparam.highpc;
213       *(int32_t *) thdr.hist_size = (_gmonparam.kcountsize
214                                      / sizeof (HISTCOUNTER));
215       *(int32_t *) thdr.prof_rate = __profile_frequency ();
216       strncpy (thdr.dimen, "seconds", sizeof (thdr.dimen));
217       thdr.dimen_abbrev = 's';
218
219       r = write (fd, &tag, sizeof tag);
220       if (r != sizeof tag)
221         return;
222       r = write (fd, &thdr, sizeof thdr);
223       if (r != sizeof thdr)
224         return;
225       r = write (fd,_gmonparam.kcount, _gmonparam.kcountsize);
226       if ((unsigned) r != _gmonparam.kcountsize)
227         return;
228     }
229 }
230
231
232 static void
233 internal_function
234 write_call_graph (int fd)
235 {
236 #define NARCS_PER_WRITE 64
237 #define BYTES_PER_ARC (1 + sizeof (struct gmon_cg_arc_record))
238 #define BYTES_PER_WRITE (BYTES_PER_ARC * NARCS_PER_WRITE)
239   ARCINDEX to_index;
240   u_long frompc, selfpc, count;
241   char buffer[BYTES_PER_WRITE], *p;
242   u_long *prof_desc = __arc_profile_desc_secstart;
243   u_long *prof_count = __arc_profile_counters_secstart;
244   u_long *prof_desc_end = __arc_profile_desc_secend;
245   u_long *prof_forward = __arc_profile_forward_secstart;
246
247   for (p = buffer; p < buffer + BYTES_PER_WRITE; p += BYTES_PER_ARC)
248     *p = GMON_TAG_CG_ARC;
249   p = buffer;
250   frompc = *prof_desc++ & -2;
251   while (prof_desc < prof_desc_end)
252     {
253       selfpc = *prof_desc++;
254       if (selfpc & 1)
255         {
256           frompc = selfpc & -2;
257           selfpc = *prof_desc++;
258         }
259       count = *prof_count++;
260       if (selfpc)
261         {
262           struct arc
263             {
264               char *frompc;
265               char *selfpc;
266               int32_t count;
267             }
268           arc;
269
270           if (!count)
271             continue;
272           arc.frompc = (char *) frompc;
273           arc.selfpc = (char *) selfpc;
274           arc.count  = count;
275           memcpy (p + 1, &arc, sizeof arc);
276           p += 1 + sizeof arc;
277
278           if (p == buffer + BYTES_PER_WRITE)
279             {
280               write (fd, buffer, BYTES_PER_WRITE);
281               p = buffer;
282             }
283         }
284       else
285         {
286           for (to_index = count;
287                to_index != 0;
288                to_index = _gmonparam.tos[to_index].link)
289             {
290               struct arc
291                 {
292                   char *frompc;
293                   char *selfpc;
294                   int32_t count;
295                 }
296               arc;
297
298               arc.frompc = (char *) frompc;
299               arc.selfpc = (char *) _gmonparam.tos[to_index].selfpc;
300               arc.count  = _gmonparam.tos[to_index].count;
301               memcpy (p + 1, &arc, sizeof arc);
302               p += 1 + sizeof arc;
303
304               if (p == buffer + BYTES_PER_WRITE)
305                 {
306                   write (fd, buffer, BYTES_PER_WRITE);
307                   p = buffer;
308                 }
309             }
310         }
311     }
312   while (prof_forward < __arc_profile_forward_secend)
313     {
314       /* ??? The 'call count' is actually supposed to be a fixed point
315          factor, with 16 bits each before and after the point.
316          It would be much nicer if we figured out the actual number
317          of calls to the caller, and multiplied that with the fixed point
318          factor to arrive at the estimated calls for the callee.  */
319       memcpy (p + 1, prof_forward, 3 * sizeof *prof_forward);
320       prof_forward += 3;
321       p += 1 + 3 * sizeof *prof_forward;
322       if (p == buffer + BYTES_PER_WRITE)
323         {
324           write (fd, buffer, BYTES_PER_WRITE);
325           p = buffer;
326         }
327     }
328   if (p != buffer)
329     write (fd, buffer, p - buffer);
330 }
331
332
333 static void
334 internal_function
335 write_bb_counts (int fd)
336 {
337   struct __bb *grp;
338   u_char tag = GMON_TAG_BB_COUNT;
339   size_t ncounts;
340   size_t i;
341
342   struct { unsigned long address; long count; } bbbody[8];
343   size_t nfilled;
344
345   /* Write each group of basic-block info (all basic-blocks in a
346      compilation unit form a single group). */
347
348   for (grp = __bb_head; grp; grp = grp->next)
349     {
350       ncounts = grp->ncounts;
351       write (fd, &tag, 1);
352       write (fd, &ncounts, sizeof ncounts);
353       for (nfilled = i = 0; i < ncounts; ++i)
354         {
355           if (nfilled == sizeof (bbbody) / sizeof (bbbody[0]))
356             {
357               write (fd, bbbody, sizeof bbbody);
358               nfilled = 0;
359             }
360
361           bbbody[nfilled].address = grp->addresses[i];
362           bbbody[nfilled++].count = grp->counts[i];
363         }
364       if (nfilled > 0)
365         write (fd, bbbody, nfilled * sizeof bbbody[0]);
366     }
367 }
368
369
370 static void
371 write_gmon (void)
372 {
373     struct gmon_hdr ghdr __attribute__ ((aligned (__alignof__ (int))));
374     int fd = -1;
375     char *env;
376
377 #ifndef O_NOFOLLOW
378 # define O_NOFOLLOW     0
379 #endif
380
381     env = getenv ("GMON_OUT_PREFIX");
382     if (env != NULL && !__libc_enable_secure)
383       {
384         size_t len = strlen (env);
385         char buf[len + 20];
386         snprintf (buf, sizeof (buf), "%s.%u", env, getpid ());
387         fd = open (buf, O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW, 0666);
388       }
389
390     if (fd == -1)
391       {
392         fd = open ("gmon.out", O_CREAT|O_TRUNC|O_WRONLY|O_NOFOLLOW,
393                               0666);
394         if (fd < 0)
395           {
396             perror ("_mcleanup: gmon.out");
397             return;
398           }
399       }
400
401     /* write gmon.out header: */
402     memset (&ghdr, '\0', sizeof (struct gmon_hdr));
403     memcpy (&ghdr.cookie[0], GMON_MAGIC, sizeof (ghdr.cookie));
404     *(int32_t *) ghdr.version = GMON_VERSION;
405     write (fd, &ghdr, sizeof (struct gmon_hdr));
406
407     /* write PC histogram: */
408     write_hist (fd);
409
410     /* write call-graph: */
411     write_call_graph (fd);
412
413     /* write basic-block execution counts: */
414     write_bb_counts (fd);
415
416     close (fd);
417 }
418
419
420 void
421 __write_profiling (void)
422 {
423   int save = _gmonparam.state;
424   _gmonparam.state = GMON_PROF_OFF;
425   if (save == GMON_PROF_ON)
426     write_gmon ();
427   _gmonparam.state = save;
428 }
429 #ifndef SHARED
430 /* This symbol isn't used anywhere in the DSO and it is not exported.
431    This would normally mean it should be removed to get the same API
432    in static libraries.  But since profiling is special in static libs
433    anyway we keep it.  But not when building the DSO since some
434    quality assurance tests will otherwise trigger.  */
435 weak_alias (__write_profiling, write_profiling)
436 #endif
437
438
439 void
440 _mcleanup (void)
441 {
442   __moncontrol (0);
443
444   if (_gmonparam.state != GMON_PROF_ERROR)
445     write_gmon ();
446
447   /* free the memory. */
448   if (_gmonparam.tos != NULL)
449     free (_gmonparam.tos);
450 }