]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/arc/gmon/gmon.c
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / arc / gmon / gmon.c
CommitLineData
8eaaaea3 1/*-
2 * Copyright (c) 1983, 1992, 1993
3 * The Regents of the University of California. All rights reserved.
f1717362 4 * Copyright (C) 2007-2016 Free Software Foundation, Inc.
8eaaaea3 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. */
60struct __bb *__bb_head attribute_hidden;
61
62struct gmonparam _gmonparam attribute_hidden = { GMON_PROF_OFF };
63
64/*
65 * See profil(2) where this is described:
66 */
67static int s_scale;
68#define SCALE_1_TO_1 0x10000L
69
70#define ERR(s) write (STDERR_FILENO, s, sizeof (s) - 1)
71
72void moncontrol (int mode);
73void __moncontrol (int mode);
74static void write_hist (int fd) internal_function;
75static void write_call_graph (int fd) internal_function;
76static 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 */
83void
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}
105weak_alias (__moncontrol, moncontrol)
106
107
108void
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}
198weak_alias (__monstartup, monstartup)
199
200
201static void
202internal_function
203write_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
232static void
233internal_function
234write_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
333static void
334internal_function
335write_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
370static void
371write_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
420void
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. */
435weak_alias (__write_profiling, write_profiling)
436#endif
437
438
439void
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}