2 * Copyright (c) 1983, 1992, 1993, 2011
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/param.h>
32 #include <sys/gmon_out.h>
46 #include <libc-internal.h>
47 #include <not-cancel.h>
50 /* Head of basic-block list or NULL. */
51 struct __bb
*__bb_head attribute_hidden
;
53 struct gmonparam _gmonparam attribute_hidden
= { GMON_PROF_OFF
};
56 * See profil(2) where this is described:
59 #define SCALE_1_TO_1 0x10000L
61 #define ERR(s) write_not_cancel (STDERR_FILENO, s, sizeof (s) - 1)
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
;
71 * profiling is what mcount checks to see if
72 * all the data structures are ready.
75 __moncontrol (int mode
)
77 struct gmonparam
*p
= &_gmonparam
;
79 /* Don't change the state if we ran into an error. */
80 if (p
->state
== GMON_PROF_ERROR
)
86 __profil((void *) p
->kcount
, p
->kcountsize
, p
->lowpc
, s_scale
);
87 p
->state
= GMON_PROF_ON
;
92 __profil(NULL
, 0, 0, 0);
93 p
->state
= GMON_PROF_OFF
;
96 weak_alias (__moncontrol
, moncontrol
)
100 __monstartup (u_long lowpc
, u_long highpc
)
104 struct gmonparam
*p
= &_gmonparam
;
107 * round lowpc and highpc to multiples of the density we're using
108 * so the rest of the scaling (here and in gprof) stays in ints.
110 p
->lowpc
= ROUNDDOWN(lowpc
, HISTFRACTION
* sizeof(HISTCOUNTER
));
111 p
->highpc
= ROUNDUP(highpc
, HISTFRACTION
* sizeof(HISTCOUNTER
));
112 p
->textsize
= p
->highpc
- p
->lowpc
;
113 p
->kcountsize
= ROUNDUP(p
->textsize
/ HISTFRACTION
, sizeof(*p
->froms
));
114 p
->hashfraction
= HASHFRACTION
;
115 p
->log_hashfraction
= -1;
116 /* The following test must be kept in sync with the corresponding
118 if ((HASHFRACTION
& (HASHFRACTION
- 1)) == 0) {
119 /* if HASHFRACTION is a power of two, mcount can use shifting
120 instead of integer division. Precompute shift amount. */
121 p
->log_hashfraction
= ffs(p
->hashfraction
* sizeof(*p
->froms
)) - 1;
123 p
->fromssize
= p
->textsize
/ HASHFRACTION
;
124 p
->tolimit
= p
->textsize
* ARCDENSITY
/ 100;
125 if (p
->tolimit
< MINARCS
)
126 p
->tolimit
= MINARCS
;
127 else if (p
->tolimit
> MAXARCS
)
128 p
->tolimit
= MAXARCS
;
129 p
->tossize
= p
->tolimit
* sizeof(struct tostruct
);
131 cp
= calloc (p
->kcountsize
+ p
->fromssize
+ p
->tossize
, 1);
134 ERR("monstartup: out of memory\n");
136 p
->state
= GMON_PROF_ERROR
;
139 p
->tos
= (struct tostruct
*)cp
;
141 p
->kcount
= (HISTCOUNTER
*)cp
;
143 p
->froms
= (ARCINDEX
*)cp
;
147 o
= p
->highpc
- p
->lowpc
;
148 if (p
->kcountsize
< (u_long
) o
)
151 s_scale
= ((float)p
->kcountsize
/ o
) * SCALE_1_TO_1
;
153 /* avoid floating point operations */
154 int quot
= o
/ p
->kcountsize
;
158 else if (quot
>= 0x100)
159 s_scale
= 0x10000 / quot
;
160 else if (o
>= 0x800000)
161 s_scale
= 0x1000000 / (o
/ (p
->kcountsize
>> 8));
163 s_scale
= 0x1000000 / ((o
<< 8) / p
->kcountsize
);
166 s_scale
= SCALE_1_TO_1
;
170 weak_alias (__monstartup
, monstartup
)
177 u_char tag
= GMON_TAG_TIME_HIST
;
179 if (_gmonparam
.kcountsize
> 0)
181 struct real_gmon_hist_hdr
190 struct iovec iov
[3] =
192 { &tag
, sizeof (tag
) },
193 { &thdr
, sizeof (struct gmon_hist_hdr
) },
194 { _gmonparam
.kcount
, _gmonparam
.kcountsize
}
197 if (sizeof (thdr
) != sizeof (struct gmon_hist_hdr
)
198 || (offsetof (struct real_gmon_hist_hdr
, low_pc
)
199 != offsetof (struct gmon_hist_hdr
, low_pc
))
200 || (offsetof (struct real_gmon_hist_hdr
, high_pc
)
201 != offsetof (struct gmon_hist_hdr
, high_pc
))
202 || (offsetof (struct real_gmon_hist_hdr
, hist_size
)
203 != offsetof (struct gmon_hist_hdr
, hist_size
))
204 || (offsetof (struct real_gmon_hist_hdr
, prof_rate
)
205 != offsetof (struct gmon_hist_hdr
, prof_rate
))
206 || (offsetof (struct real_gmon_hist_hdr
, dimen
)
207 != offsetof (struct gmon_hist_hdr
, dimen
))
208 || (offsetof (struct real_gmon_hist_hdr
, dimen_abbrev
)
209 != offsetof (struct gmon_hist_hdr
, dimen_abbrev
)))
212 thdr
.low_pc
= (char *) _gmonparam
.lowpc
;
213 thdr
.high_pc
= (char *) _gmonparam
.highpc
;
214 thdr
.hist_size
= _gmonparam
.kcountsize
/ sizeof (HISTCOUNTER
);
215 thdr
.prof_rate
= __profile_frequency ();
216 strncpy (thdr
.dimen
, "seconds", sizeof (thdr
.dimen
));
217 thdr
.dimen_abbrev
= 's';
219 writev_not_cancel_no_status (fd
, iov
, 3);
226 write_call_graph (int fd
)
228 #define NARCS_PER_WRITEV 32
229 u_char tag
= GMON_TAG_CG_ARC
;
230 struct gmon_cg_arc_record raw_arc
[NARCS_PER_WRITEV
]
231 __attribute__ ((aligned (__alignof__ (char*))));
232 ARCINDEX from_index
, to_index
;
235 struct iovec iov
[2 * NARCS_PER_WRITEV
];
238 for (nfilled
= 0; nfilled
< NARCS_PER_WRITEV
; ++nfilled
)
240 iov
[2 * nfilled
].iov_base
= &tag
;
241 iov
[2 * nfilled
].iov_len
= sizeof (tag
);
243 iov
[2 * nfilled
+ 1].iov_base
= &raw_arc
[nfilled
];
244 iov
[2 * nfilled
+ 1].iov_len
= sizeof (struct gmon_cg_arc_record
);
248 from_len
= _gmonparam
.fromssize
/ sizeof (*_gmonparam
.froms
);
249 for (from_index
= 0; from_index
< from_len
; ++from_index
)
251 if (_gmonparam
.froms
[from_index
] == 0)
254 frompc
= _gmonparam
.lowpc
;
255 frompc
+= (from_index
* _gmonparam
.hashfraction
256 * sizeof (*_gmonparam
.froms
));
257 for (to_index
= _gmonparam
.froms
[from_index
];
259 to_index
= _gmonparam
.tos
[to_index
].link
)
269 arc
.frompc
= (char *) frompc
;
270 arc
.selfpc
= (char *) _gmonparam
.tos
[to_index
].selfpc
;
271 arc
.count
= _gmonparam
.tos
[to_index
].count
;
272 memcpy (raw_arc
+ nfilled
, &arc
, sizeof (raw_arc
[0]));
274 if (++nfilled
== NARCS_PER_WRITEV
)
276 writev_not_cancel_no_status (fd
, iov
, 2 * nfilled
);
282 writev_not_cancel_no_status (fd
, iov
, 2 * nfilled
);
288 write_bb_counts (int fd
)
291 u_char tag
= GMON_TAG_BB_COUNT
;
295 struct iovec bbhead
[2] =
297 { &tag
, sizeof (tag
) },
298 { &ncounts
, sizeof (ncounts
) }
300 struct iovec bbbody
[8];
303 for (i
= 0; i
< (sizeof (bbbody
) / sizeof (bbbody
[0])); i
+= 2)
305 bbbody
[i
].iov_len
= sizeof (grp
->addresses
[0]);
306 bbbody
[i
+ 1].iov_len
= sizeof (grp
->counts
[0]);
309 /* Write each group of basic-block info (all basic-blocks in a
310 compilation unit form a single group). */
312 for (grp
= __bb_head
; grp
; grp
= grp
->next
)
314 ncounts
= grp
->ncounts
;
315 writev_not_cancel_no_status (fd
, bbhead
, 2);
316 for (nfilled
= i
= 0; i
< ncounts
; ++i
)
318 if (nfilled
> (sizeof (bbbody
) / sizeof (bbbody
[0])) - 2)
320 writev_not_cancel_no_status (fd
, bbbody
, nfilled
);
324 bbbody
[nfilled
++].iov_base
= (char *) &grp
->addresses
[i
];
325 bbbody
[nfilled
++].iov_base
= &grp
->counts
[i
];
328 writev_not_cancel_no_status (fd
, bbbody
, nfilled
);
340 # define O_NOFOLLOW 0
343 env
= getenv ("GMON_OUT_PREFIX");
344 if (env
!= NULL
&& !__libc_enable_secure
)
346 size_t len
= strlen (env
);
348 __snprintf (buf
, sizeof (buf
), "%s.%u", env
, __getpid ());
349 fd
= open_not_cancel (buf
, O_CREAT
|O_TRUNC
|O_WRONLY
|O_NOFOLLOW
, 0666);
354 fd
= open_not_cancel ("gmon.out", O_CREAT
|O_TRUNC
|O_WRONLY
|O_NOFOLLOW
,
360 __fxprintf (NULL
, "_mcleanup: gmon.out: %s\n",
361 __strerror_r (errnum
, buf
, sizeof buf
));
366 /* write gmon.out header: */
373 if (sizeof (ghdr
) != sizeof (struct gmon_hdr
)
374 || (offsetof (struct real_gmon_hdr
, cookie
)
375 != offsetof (struct gmon_hdr
, cookie
))
376 || (offsetof (struct real_gmon_hdr
, version
)
377 != offsetof (struct gmon_hdr
, version
)))
379 memcpy (&ghdr
.cookie
[0], GMON_MAGIC
, sizeof (ghdr
.cookie
));
380 ghdr
.version
= GMON_VERSION
;
381 memset (ghdr
.spare
, '\0', sizeof (ghdr
.spare
));
382 write_not_cancel (fd
, &ghdr
, sizeof (struct gmon_hdr
));
384 /* write PC histogram: */
387 /* write call-graph: */
388 write_call_graph (fd
);
390 /* write basic-block execution counts: */
391 write_bb_counts (fd
);
393 close_not_cancel_no_status (fd
);
398 __write_profiling (void)
400 int save
= _gmonparam
.state
;
401 _gmonparam
.state
= GMON_PROF_OFF
;
402 if (save
== GMON_PROF_ON
)
404 _gmonparam
.state
= save
;
407 /* This symbol isn't used anywhere in the DSO and it is not exported.
408 This would normally mean it should be removed to get the same API
409 in static libraries. But since profiling is special in static libs
410 anyway we keep it. But not when building the DSO since some
411 quality assurance tests will otherwise trigger. */
412 weak_alias (__write_profiling
, write_profiling
)
421 if (_gmonparam
.state
!= GMON_PROF_ERROR
)
424 /* free the memory. */
425 free (_gmonparam
.tos
);