gcov: make profile merging smarter
[official-gcc.git] / libgcc / libgcov.h
blob2a365c95759981b3f17abd36c870098fbb70bb92
1 /* Header file for libgcov-*.c.
2 Copyright (C) 1996-2021 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
25 #ifndef GCC_LIBGCOV_H
26 #define GCC_LIBGCOV_H
28 /* work around the poisoned malloc/calloc in system.h. */
29 #ifndef xmalloc
30 #define xmalloc malloc
31 #endif
32 #ifndef xcalloc
33 #define xcalloc calloc
34 #endif
36 #ifndef IN_GCOV_TOOL
37 /* About the target. */
38 /* This path will be used by libgcov runtime. */
40 #include "tconfig.h"
41 #include "auto-target.h"
42 #include "tsystem.h"
43 #include "coretypes.h"
44 #include "tm.h"
45 #include "libgcc_tm.h"
46 #include "gcov.h"
48 #if HAVE_SYS_MMAN_H
49 #include <sys/mman.h>
50 #endif
52 #if __CHAR_BIT__ == 8
53 typedef unsigned gcov_unsigned_t __attribute__ ((mode (SI)));
54 typedef unsigned gcov_position_t __attribute__ ((mode (SI)));
55 #if __LIBGCC_GCOV_TYPE_SIZE > 32
56 typedef signed gcov_type __attribute__ ((mode (DI)));
57 typedef unsigned gcov_type_unsigned __attribute__ ((mode (DI)));
58 #else
59 typedef signed gcov_type __attribute__ ((mode (SI)));
60 typedef unsigned gcov_type_unsigned __attribute__ ((mode (SI)));
61 #endif
62 #else
63 #if __CHAR_BIT__ == 16
64 typedef unsigned gcov_unsigned_t __attribute__ ((mode (HI)));
65 typedef unsigned gcov_position_t __attribute__ ((mode (HI)));
66 #if __LIBGCC_GCOV_TYPE_SIZE > 32
67 typedef signed gcov_type __attribute__ ((mode (SI)));
68 typedef unsigned gcov_type_unsigned __attribute__ ((mode (SI)));
69 #else
70 typedef signed gcov_type __attribute__ ((mode (HI)));
71 typedef unsigned gcov_type_unsigned __attribute__ ((mode (HI)));
72 #endif
73 #else
74 typedef unsigned gcov_unsigned_t __attribute__ ((mode (QI)));
75 typedef unsigned gcov_position_t __attribute__ ((mode (QI)));
76 #if __LIBGCC_GCOV_TYPE_SIZE > 32
77 typedef signed gcov_type __attribute__ ((mode (HI)));
78 typedef unsigned gcov_type_unsigned __attribute__ ((mode (HI)));
79 #else
80 typedef signed gcov_type __attribute__ ((mode (QI)));
81 typedef unsigned gcov_type_unsigned __attribute__ ((mode (QI)));
82 #endif
83 #endif
84 #endif
86 #if defined (TARGET_POSIX_IO)
87 #define GCOV_LOCKED 1
88 #else
89 #define GCOV_LOCKED 0
90 #endif
92 #if defined (__MSVCRT__)
93 #define GCOV_LOCKED_WITH_LOCKING 1
94 #else
95 #define GCOV_LOCKED_WITH_LOCKING 0
96 #endif
98 #ifndef GCOV_SUPPORTS_ATOMIC
99 /* Detect whether target can support atomic update of profilers. */
100 #if __SIZEOF_LONG_LONG__ == 4 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
101 #define GCOV_SUPPORTS_ATOMIC 1
102 #else
103 #if __SIZEOF_LONG_LONG__ == 8 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
104 #define GCOV_SUPPORTS_ATOMIC 1
105 #else
106 #define GCOV_SUPPORTS_ATOMIC 0
107 #endif
108 #endif
109 #endif
111 /* In libgcov we need these functions to be extern, so prefix them with
112 __gcov. In libgcov they must also be hidden so that the instance in
113 the executable is not also used in a DSO. */
114 #define gcov_var __gcov_var
115 #define gcov_open __gcov_open
116 #define gcov_close __gcov_close
117 #define gcov_position __gcov_position
118 #define gcov_seek __gcov_seek
119 #define gcov_rewrite __gcov_rewrite
120 #define gcov_is_error __gcov_is_error
121 #define gcov_write_unsigned __gcov_write_unsigned
122 #define gcov_write_summary __gcov_write_summary
123 #define gcov_read_unsigned __gcov_read_unsigned
124 #define gcov_read_counter __gcov_read_counter
125 #define gcov_read_summary __gcov_read_summary
127 #else /* IN_GCOV_TOOL */
128 /* About the host. */
129 /* This path will be compiled for the host and linked into
130 gcov-tool binary. */
132 #include "config.h"
133 #include "system.h"
134 #include "coretypes.h"
135 #include "tm.h"
137 typedef unsigned gcov_unsigned_t;
138 typedef unsigned gcov_position_t;
139 /* gcov_type is typedef'd elsewhere for the compiler */
141 #if defined (HOST_HAS_F_SETLKW)
142 #define GCOV_LOCKED 1
143 #else
144 #define GCOV_LOCKED 0
145 #endif
147 #if defined (HOST_HAS_LK_LOCK)
148 #define GCOV_LOCKED_WITH_LOCKING 1
149 #else
150 #define GCOV_LOCKED_WITH_LOCKING 0
151 #endif
153 /* Some Macros specific to gcov-tool. */
155 #define L_gcov 1
156 #define L_gcov_merge_add 1
157 #define L_gcov_merge_topn 1
158 #define L_gcov_merge_ior 1
159 #define L_gcov_merge_time_profile 1
161 extern gcov_type gcov_read_counter_mem ();
162 extern unsigned gcov_get_merge_weight ();
163 extern struct gcov_info *gcov_list;
165 #endif /* !IN_GCOV_TOOL */
167 #if defined(inhibit_libc)
168 #define IN_LIBGCOV (-1)
169 #else
170 #define IN_LIBGCOV 1
171 #if defined(L_gcov)
172 #define GCOV_LINKAGE /* nothing */
173 #endif
174 #endif
176 /* Poison these, so they don't accidentally slip in. */
177 #pragma GCC poison gcov_write_string gcov_write_tag gcov_write_length
178 #pragma GCC poison gcov_time
180 #ifdef HAVE_GAS_HIDDEN
181 #define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden")))
182 #else
183 #define ATTRIBUTE_HIDDEN
184 #endif
186 #if HAVE_SYS_MMAN_H
187 #ifndef MAP_FAILED
188 #define MAP_FAILED ((void *)-1)
189 #endif
191 #if !defined (MAP_ANONYMOUS) && defined (MAP_ANON)
192 #define MAP_ANONYMOUS MAP_ANON
193 #endif
194 #endif
196 #include "gcov-io.h"
198 /* Structures embedded in coveraged program. The structures generated
199 by write_profile must match these. */
201 /* Information about counters for a single function. */
202 struct gcov_ctr_info
204 gcov_unsigned_t num; /* number of counters. */
205 gcov_type *values; /* their values. */
208 /* Information about a single function. This uses the trailing array
209 idiom. The number of counters is determined from the merge pointer
210 array in gcov_info. The key is used to detect which of a set of
211 comdat functions was selected -- it points to the gcov_info object
212 of the object file containing the selected comdat function. */
214 struct gcov_fn_info
216 const struct gcov_info *key; /* comdat key */
217 gcov_unsigned_t ident; /* unique ident of function */
218 gcov_unsigned_t lineno_checksum; /* function lineo_checksum */
219 gcov_unsigned_t cfg_checksum; /* function cfg checksum */
220 struct gcov_ctr_info ctrs[1]; /* instrumented counters */
223 /* Type of function used to merge counters. */
224 typedef void (*gcov_merge_fn) (gcov_type *, gcov_unsigned_t);
226 /* Information about a single object file. */
227 struct gcov_info
229 gcov_unsigned_t version; /* expected version number */
230 struct gcov_info *next; /* link to next, used by libgcov */
232 gcov_unsigned_t stamp; /* uniquifying time stamp */
233 gcov_unsigned_t checksum; /* unique object checksum */
234 const char *filename; /* output file name */
236 gcov_merge_fn merge[GCOV_COUNTERS]; /* merge functions (null for
237 unused) */
239 unsigned n_functions; /* number of functions */
241 #ifndef IN_GCOV_TOOL
242 const struct gcov_fn_info *const *functions; /* pointer to pointers
243 to function information */
244 #else
245 struct gcov_fn_info **functions;
246 struct gcov_summary summary;
247 #endif /* !IN_GCOV_TOOL */
250 /* Root of a program/shared-object state */
251 struct gcov_root
253 struct gcov_info *list;
254 unsigned dumped : 1; /* counts have been dumped. */
255 unsigned run_counted : 1; /* run has been accounted for. */
256 struct gcov_root *next;
257 struct gcov_root *prev;
260 extern struct gcov_root __gcov_root ATTRIBUTE_HIDDEN;
262 struct gcov_master
264 gcov_unsigned_t version;
265 struct gcov_root *root;
268 struct indirect_call_tuple
270 /* Callee function. */
271 void *callee;
273 /* Pointer to counters. */
274 gcov_type *counters;
277 /* Exactly one of these will be active in the process. */
278 extern struct gcov_master __gcov_master;
279 extern struct gcov_kvp *__gcov_kvp_dynamic_pool;
280 extern unsigned __gcov_kvp_dynamic_pool_index;
281 extern unsigned __gcov_kvp_dynamic_pool_size;
283 /* Dump a set of gcov objects. */
284 extern void __gcov_dump_one (struct gcov_root *) ATTRIBUTE_HIDDEN;
286 /* Register a new object file module. */
287 extern void __gcov_init (struct gcov_info *) ATTRIBUTE_HIDDEN;
289 /* GCOV exit function registered via a static destructor. */
290 extern void __gcov_exit (void) ATTRIBUTE_HIDDEN;
292 /* Function to reset all counters to 0. Both externally visible (and
293 overridable) and internal version. */
294 extern void __gcov_reset_int (void) ATTRIBUTE_HIDDEN;
296 /* User function to enable early write of profile information so far. */
297 extern void __gcov_dump_int (void) ATTRIBUTE_HIDDEN;
299 /* Lock critical section for __gcov_dump and __gcov_reset functions. */
300 extern void __gcov_lock (void) ATTRIBUTE_HIDDEN;
302 /* Unlock critical section for __gcov_dump and __gcov_reset functions. */
303 extern void __gcov_unlock (void) ATTRIBUTE_HIDDEN;
305 /* The merge function that just sums the counters. */
306 extern void __gcov_merge_add (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
308 /* The merge function to select the minimum valid counter value. */
309 extern void __gcov_merge_time_profile (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
311 /* The merge function to choose the most common N values. */
312 extern void __gcov_merge_topn (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
314 /* The merge function that just ors the counters together. */
315 extern void __gcov_merge_ior (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
317 /* The profiler functions. */
318 extern void __gcov_interval_profiler (gcov_type *, gcov_type, int, unsigned);
319 extern void __gcov_interval_profiler_atomic (gcov_type *, gcov_type, int,
320 unsigned);
321 extern void __gcov_pow2_profiler (gcov_type *, gcov_type);
322 extern void __gcov_pow2_profiler_atomic (gcov_type *, gcov_type);
323 extern void __gcov_topn_values_profiler (gcov_type *, gcov_type);
324 extern void __gcov_topn_values_profiler_atomic (gcov_type *, gcov_type);
325 extern void __gcov_indirect_call_profiler_v4 (gcov_type, void *);
326 extern void __gcov_indirect_call_profiler_v4_atomic (gcov_type, void *);
327 extern void __gcov_time_profiler (gcov_type *);
328 extern void __gcov_time_profiler_atomic (gcov_type *);
329 extern void __gcov_average_profiler (gcov_type *, gcov_type);
330 extern void __gcov_average_profiler_atomic (gcov_type *, gcov_type);
331 extern void __gcov_ior_profiler (gcov_type *, gcov_type);
332 extern void __gcov_ior_profiler_atomic (gcov_type *, gcov_type);
334 #ifndef inhibit_libc
335 /* The wrappers around some library functions.. */
336 extern pid_t __gcov_fork (void) ATTRIBUTE_HIDDEN;
337 extern int __gcov_execl (const char *, char *, ...) ATTRIBUTE_HIDDEN;
338 extern int __gcov_execlp (const char *, char *, ...) ATTRIBUTE_HIDDEN;
339 extern int __gcov_execle (const char *, char *, ...) ATTRIBUTE_HIDDEN;
340 extern int __gcov_execv (const char *, char *const []) ATTRIBUTE_HIDDEN;
341 extern int __gcov_execvp (const char *, char *const []) ATTRIBUTE_HIDDEN;
342 extern int __gcov_execve (const char *, char *const [], char *const [])
343 ATTRIBUTE_HIDDEN;
345 /* Functions that only available in libgcov. */
346 GCOV_LINKAGE int gcov_open (const char */*name*/) ATTRIBUTE_HIDDEN;
347 GCOV_LINKAGE void gcov_write_summary (gcov_unsigned_t /*tag*/,
348 const struct gcov_summary *)
349 ATTRIBUTE_HIDDEN;
350 GCOV_LINKAGE void gcov_seek (gcov_position_t /*position*/) ATTRIBUTE_HIDDEN;
351 GCOV_LINKAGE void gcov_rewrite (void) ATTRIBUTE_HIDDEN;
353 /* "Counts" stored in gcda files can be a real counter value, or
354 an target address. When differentiate these two types because
355 when manipulating counts, we should only change real counter values,
356 rather target addresses. */
358 static inline gcov_type
359 gcov_get_counter (void)
361 #ifndef IN_GCOV_TOOL
362 /* This version is for reading count values in libgcov runtime:
363 we read from gcda files. */
365 return gcov_read_counter ();
366 #else
367 /* This version is for gcov-tool. We read the value from memory and
368 multiply it by the merge weight. */
370 return gcov_read_counter_mem () * gcov_get_merge_weight ();
371 #endif
374 /* Similar function as gcov_get_counter(), but do not scale
375 when read value is equal to IGNORE_SCALING. */
377 static inline gcov_type
378 gcov_get_counter_ignore_scaling (gcov_type ignore_scaling ATTRIBUTE_UNUSED)
380 #ifndef IN_GCOV_TOOL
381 /* This version is for reading count values in libgcov runtime:
382 we read from gcda files. */
384 return gcov_read_counter ();
385 #else
386 /* This version is for gcov-tool. We read the value from memory and
387 multiply it by the merge weight. */
389 gcov_type v = gcov_read_counter_mem ();
390 if (v != ignore_scaling)
391 v *= gcov_get_merge_weight ();
393 return v;
394 #endif
397 /* Similar function as gcov_get_counter(), but handles target address
398 counters. */
400 static inline gcov_type
401 gcov_get_counter_target (void)
403 #ifndef IN_GCOV_TOOL
404 /* This version is for reading count target values in libgcov runtime:
405 we read from gcda files. */
407 return gcov_read_counter ();
408 #else
409 /* This version is for gcov-tool. We read the value from memory and we do NOT
410 multiply it by the merge weight. */
412 return gcov_read_counter_mem ();
413 #endif
416 /* Add VALUE to *COUNTER and make it with atomic operation
417 if USE_ATOMIC is true. */
419 static inline void
420 gcov_counter_add (gcov_type *counter, gcov_type value,
421 int use_atomic ATTRIBUTE_UNUSED)
423 #if GCOV_SUPPORTS_ATOMIC
424 if (use_atomic)
425 __atomic_fetch_add (counter, value, __ATOMIC_RELAXED);
426 else
427 #endif
428 *counter += value;
431 #if HAVE_SYS_MMAN_H
433 /* Allocate LENGTH with mmap function. */
435 static inline void *
436 malloc_mmap (size_t length)
438 return mmap (NULL, length, PROT_READ | PROT_WRITE,
439 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
442 #endif
444 /* Allocate gcov_kvp from statically pre-allocated pool,
445 or use heap otherwise. */
447 static inline struct gcov_kvp *
448 allocate_gcov_kvp (void)
450 #define MMAP_CHUNK_SIZE (128 * 1024)
451 struct gcov_kvp *new_node = NULL;
452 unsigned kvp_sizeof = sizeof(struct gcov_kvp);
454 /* Try mmaped pool if available. */
455 #if !defined(IN_GCOV_TOOL) && !defined(L_gcov_merge_topn) && HAVE_SYS_MMAN_H
456 if (__gcov_kvp_dynamic_pool == NULL
457 || __gcov_kvp_dynamic_pool_index >= __gcov_kvp_dynamic_pool_size)
459 void *ptr = malloc_mmap (MMAP_CHUNK_SIZE);
460 if (ptr != MAP_FAILED)
462 __gcov_kvp_dynamic_pool = ptr;
463 __gcov_kvp_dynamic_pool_size = MMAP_CHUNK_SIZE / kvp_sizeof;
464 __gcov_kvp_dynamic_pool_index = 0;
468 if (__gcov_kvp_dynamic_pool != NULL)
470 unsigned index;
471 #if GCOV_SUPPORTS_ATOMIC
472 index
473 = __atomic_fetch_add (&__gcov_kvp_dynamic_pool_index, 1,
474 __ATOMIC_RELAXED);
475 #else
476 index = __gcov_kvp_dynamic_pool_index++;
477 #endif
478 if (index < __gcov_kvp_dynamic_pool_size)
479 new_node = __gcov_kvp_dynamic_pool + index;
481 #endif
483 /* Fallback to malloc. */
484 if (new_node == NULL)
485 new_node = (struct gcov_kvp *)xcalloc (1, kvp_sizeof);
487 return new_node;
490 /* Add key value pair VALUE:COUNT to a top N COUNTERS. When INCREMENT_TOTAL
491 is true, add COUNT to total of the TOP counter. If USE_ATOMIC is true,
492 do it in atomic way. Return true when the counter is full, otherwise
493 return false. */
495 static inline unsigned
496 gcov_topn_add_value (gcov_type *counters, gcov_type value, gcov_type count,
497 int use_atomic, int increment_total)
499 if (increment_total)
501 /* In the multi-threaded mode, we can have an already merged profile
502 with a negative total value. In that case, we should bail out. */
503 if (counters[0] < 0)
504 return 0;
505 gcov_counter_add (&counters[0], 1, use_atomic);
508 struct gcov_kvp *prev_node = NULL;
509 struct gcov_kvp *minimal_node = NULL;
510 struct gcov_kvp *current_node = (struct gcov_kvp *)(intptr_t)counters[2];
512 while (current_node)
514 if (current_node->value == value)
516 gcov_counter_add (&current_node->count, count, use_atomic);
517 return 0;
520 if (minimal_node == NULL
521 || current_node->count < minimal_node->count)
522 minimal_node = current_node;
524 prev_node = current_node;
525 current_node = current_node->next;
528 if (counters[1] == GCOV_TOPN_MAXIMUM_TRACKED_VALUES)
530 if (--minimal_node->count < count)
532 minimal_node->value = value;
533 minimal_node->count = count;
536 return 1;
538 else
540 struct gcov_kvp *new_node = allocate_gcov_kvp ();
541 if (new_node == NULL)
542 return 0;
544 new_node->value = value;
545 new_node->count = count;
547 int success = 0;
548 if (!counters[2])
550 #if GCOV_SUPPORTS_ATOMIC
551 if (use_atomic)
553 struct gcov_kvp **ptr = (struct gcov_kvp **)(intptr_t)&counters[2];
554 success = !__sync_val_compare_and_swap (ptr, 0, new_node);
556 else
557 #endif
559 counters[2] = (intptr_t)new_node;
560 success = 1;
563 else if (prev_node && !prev_node->next)
565 #if GCOV_SUPPORTS_ATOMIC
566 if (use_atomic)
567 success = !__sync_val_compare_and_swap (&prev_node->next, 0,
568 new_node);
569 else
570 #endif
572 prev_node->next = new_node;
573 success = 1;
577 /* Increment number of nodes. */
578 if (success)
579 gcov_counter_add (&counters[1], 1, use_atomic);
582 return 0;
585 #endif /* !inhibit_libc */
587 #endif /* GCC_LIBGCOV_H */