libgcov-profiler.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /* Routines required for instrumenting a program. */
  2. /* Compile this one with gcc. */
  3. /* Copyright (C) 1989-2022 Free Software Foundation, Inc.
  4. This file is part of GCC.
  5. GCC is free software; you can redistribute it and/or modify it under
  6. the terms of the GNU General Public License as published by the Free
  7. Software Foundation; either version 3, or (at your option) any later
  8. version.
  9. GCC is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  12. for more details.
  13. Under Section 7 of GPL version 3, you are granted additional
  14. permissions described in the GCC Runtime Library Exception, version
  15. 3.1, as published by the Free Software Foundation.
  16. You should have received a copy of the GNU General Public License and
  17. a copy of the GCC Runtime Library Exception along with this program;
  18. see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. <http://www.gnu.org/licenses/>. */
  20. #include "libgcov.h"
  21. #if !defined(inhibit_libc)
  22. #ifdef L_gcov_interval_profiler
  23. /* If VALUE is in interval <START, START + STEPS - 1>, then increases the
  24. corresponding counter in COUNTERS. If the VALUE is above or below
  25. the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
  26. instead. */
  27. void
  28. __gcov_interval_profiler (gcov_type *counters, gcov_type value,
  29. int start, unsigned steps)
  30. {
  31. gcov_type delta = value - start;
  32. if (delta < 0)
  33. counters[steps + 1]++;
  34. else if (delta >= steps)
  35. counters[steps]++;
  36. else
  37. counters[delta]++;
  38. }
  39. #endif
  40. #if defined(L_gcov_interval_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
  41. /* If VALUE is in interval <START, START + STEPS - 1>, then increases the
  42. corresponding counter in COUNTERS. If the VALUE is above or below
  43. the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
  44. instead. Function is thread-safe. */
  45. void
  46. __gcov_interval_profiler_atomic (gcov_type *counters, gcov_type value,
  47. int start, unsigned steps)
  48. {
  49. gcov_type delta = value - start;
  50. if (delta < 0)
  51. __atomic_fetch_add (&counters[steps + 1], 1, __ATOMIC_RELAXED);
  52. else if (delta >= steps)
  53. __atomic_fetch_add (&counters[steps], 1, __ATOMIC_RELAXED);
  54. else
  55. __atomic_fetch_add (&counters[delta], 1, __ATOMIC_RELAXED);
  56. }
  57. #endif
  58. #ifdef L_gcov_pow2_profiler
  59. /* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
  60. COUNTERS[0] is incremented. */
  61. void
  62. __gcov_pow2_profiler (gcov_type *counters, gcov_type value)
  63. {
  64. if (value == 0 || (value & (value - 1)))
  65. counters[0]++;
  66. else
  67. counters[1]++;
  68. }
  69. #endif
  70. #if defined(L_gcov_pow2_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
  71. /* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
  72. COUNTERS[0] is incremented. Function is thread-safe. */
  73. void
  74. __gcov_pow2_profiler_atomic (gcov_type *counters, gcov_type value)
  75. {
  76. if (value == 0 || (value & (value - 1)))
  77. __atomic_fetch_add (&counters[0], 1, __ATOMIC_RELAXED);
  78. else
  79. __atomic_fetch_add (&counters[1], 1, __ATOMIC_RELAXED);
  80. }
  81. #endif
  82. /* Tries to determine N most commons value among its inputs. */
  83. static inline void
  84. __gcov_topn_values_profiler_body (gcov_type *counters, gcov_type value,
  85. int use_atomic)
  86. {
  87. gcov_topn_add_value (counters, value, 1, use_atomic, 1);
  88. }
  89. #ifdef L_gcov_topn_values_profiler
  90. void
  91. __gcov_topn_values_profiler (gcov_type *counters, gcov_type value)
  92. {
  93. __gcov_topn_values_profiler_body (counters, value, 0);
  94. }
  95. #endif
  96. #if defined(L_gcov_topn_values_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
  97. /* Update one value profilers (COUNTERS) for a given VALUE.
  98. CAVEAT: Following function is not thread-safe, only total number
  99. of executions (COUNTERS[2]) is update with an atomic instruction.
  100. Problem is that one cannot atomically update two counters
  101. (COUNTERS[0] and COUNTERS[1]), for more information please read
  102. following email thread:
  103. https://gcc.gnu.org/ml/gcc-patches/2016-08/msg00024.html. */
  104. void
  105. __gcov_topn_values_profiler_atomic (gcov_type *counters, gcov_type value)
  106. {
  107. __gcov_topn_values_profiler_body (counters, value, 1);
  108. }
  109. #endif
  110. #ifdef L_gcov_indirect_call_profiler_v4
  111. /* These two variables are used to actually track caller and callee. Keep
  112. them in TLS memory so races are not common (they are written to often).
  113. The variables are set directly by GCC instrumented code, so declaration
  114. here must match one in tree-profile.c */
  115. #if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS)
  116. __thread
  117. #endif
  118. struct indirect_call_tuple __gcov_indirect_call;
  119. /* By default, the C++ compiler will use function addresses in the
  120. vtable entries. Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero
  121. tells the compiler to use function descriptors instead. The value
  122. of this macro says how many words wide the descriptor is (normally 2).
  123. It is assumed that the address of a function descriptor may be treated
  124. as a pointer to a function. */
  125. /* Tries to determine the most common value among its inputs. */
  126. static inline void
  127. __gcov_indirect_call_profiler_body (gcov_type value, void *cur_func,
  128. int use_atomic)
  129. {
  130. /* If the C++ virtual tables contain function descriptors then one
  131. function may have multiple descriptors and we need to dereference
  132. the descriptors to see if they point to the same function. */
  133. if (cur_func == __gcov_indirect_call.callee
  134. || (__LIBGCC_VTABLE_USES_DESCRIPTORS__
  135. && *(void **) cur_func == *(void **) __gcov_indirect_call.callee))
  136. __gcov_topn_values_profiler_body (__gcov_indirect_call.counters, value,
  137. use_atomic);
  138. __gcov_indirect_call.callee = NULL;
  139. }
  140. void
  141. __gcov_indirect_call_profiler_v4 (gcov_type value, void *cur_func)
  142. {
  143. __gcov_indirect_call_profiler_body (value, cur_func, 0);
  144. }
  145. #if GCOV_SUPPORTS_ATOMIC
  146. void
  147. __gcov_indirect_call_profiler_v4_atomic (gcov_type value, void *cur_func)
  148. {
  149. __gcov_indirect_call_profiler_body (value, cur_func, 1);
  150. }
  151. #endif
  152. #endif
  153. #ifdef L_gcov_time_profiler
  154. /* Counter for first visit of each function. */
  155. gcov_type __gcov_time_profiler_counter ATTRIBUTE_HIDDEN;
  156. #endif
  157. #ifdef L_gcov_average_profiler
  158. /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
  159. to saturate up. */
  160. void
  161. __gcov_average_profiler (gcov_type *counters, gcov_type value)
  162. {
  163. counters[0] += value;
  164. counters[1] ++;
  165. }
  166. #endif
  167. #if defined(L_gcov_average_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
  168. /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
  169. to saturate up. Function is thread-safe. */
  170. void
  171. __gcov_average_profiler_atomic (gcov_type *counters, gcov_type value)
  172. {
  173. __atomic_fetch_add (&counters[0], value, __ATOMIC_RELAXED);
  174. __atomic_fetch_add (&counters[1], 1, __ATOMIC_RELAXED);
  175. }
  176. #endif
  177. #ifdef L_gcov_ior_profiler
  178. /* Bitwise-OR VALUE into COUNTER. */
  179. void
  180. __gcov_ior_profiler (gcov_type *counters, gcov_type value)
  181. {
  182. *counters |= value;
  183. }
  184. #endif
  185. #if defined(L_gcov_ior_profiler_atomic) && GCOV_SUPPORTS_ATOMIC
  186. /* Bitwise-OR VALUE into COUNTER. Function is thread-safe. */
  187. void
  188. __gcov_ior_profiler_atomic (gcov_type *counters, gcov_type value)
  189. {
  190. __atomic_fetch_or (&counters[0], value, __ATOMIC_RELAXED);
  191. }
  192. #endif
  193. #endif /* inhibit_libc */