1/* Routines required for instrumenting a program. */ 2/* Compile this one with gcc. */ 3/* Copyright (C) 1989-2015 Free Software Foundation, Inc. 4 5This file is part of GCC. 6 7GCC is free software; you can redistribute it and/or modify it under 8the terms of the GNU General Public License as published by the Free 9Software Foundation; either version 3, or (at your option) any later 10version. 11 12GCC is distributed in the hope that it will be useful, but WITHOUT ANY 13WARRANTY; without even the implied warranty of MERCHANTABILITY or 14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15for more details. 16 17Under Section 7 of GPL version 3, you are granted additional 18permissions described in the GCC Runtime Library Exception, version 193.1, as published by the Free Software Foundation. 20 21You should have received a copy of the GNU General Public License and 22a copy of the GCC Runtime Library Exception along with this program; 23see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 24<http://www.gnu.org/licenses/>. */ 25 26#include "libgcov.h" 27 28#if defined(inhibit_libc) 29/* If libc and its header files are not available, provide dummy functions. */ 30 31#ifdef L_gcov_merge_add 32void __gcov_merge_add (gcov_type *counters __attribute__ ((unused)), 33 unsigned n_counters __attribute__ ((unused))) {} 34#endif 35 36#ifdef L_gcov_merge_single 37void __gcov_merge_single (gcov_type *counters __attribute__ ((unused)), 38 unsigned n_counters __attribute__ ((unused))) {} 39#endif 40 41#ifdef L_gcov_merge_delta 42void __gcov_merge_delta (gcov_type *counters __attribute__ ((unused)), 43 unsigned n_counters __attribute__ ((unused))) {} 44#endif 45 46#else 47 48#ifdef L_gcov_merge_add 49/* The profile merging function that just adds the counters. It is given 50 an array COUNTERS of N_COUNTERS old counters and it reads the same number 51 of counters from the gcov file. */ 52void 53__gcov_merge_add (gcov_type *counters, unsigned n_counters) 54{ 55 for (; n_counters; counters++, n_counters--) 56 *counters += gcov_get_counter (); 57} 58#endif /* L_gcov_merge_add */ 59 60#ifdef L_gcov_merge_ior 61/* The profile merging function that just adds the counters. It is given 62 an array COUNTERS of N_COUNTERS old counters and it reads the same number 63 of counters from the gcov file. */ 64void 65__gcov_merge_ior (gcov_type *counters, unsigned n_counters) 66{ 67 for (; n_counters; counters++, n_counters--) 68 *counters |= gcov_get_counter_target (); 69} 70#endif 71 72#ifdef L_gcov_merge_time_profile 73/* Time profiles are merged so that minimum from all valid (greater than zero) 74 is stored. There could be a fork that creates new counters. To have 75 the profile stable, we chosen to pick the smallest function visit time. */ 76void 77__gcov_merge_time_profile (gcov_type *counters, unsigned n_counters) 78{ 79 unsigned int i; 80 gcov_type value; 81 82 for (i = 0; i < n_counters; i++) 83 { 84 value = gcov_get_counter_target (); 85 86 if (value && (!counters[i] || value < counters[i])) 87 counters[i] = value; 88 } 89} 90#endif /* L_gcov_merge_time_profile */ 91 92#ifdef L_gcov_merge_single 93/* The profile merging function for choosing the most common value. 94 It is given an array COUNTERS of N_COUNTERS old counters and it 95 reads the same number of counters from the gcov file. The counters 96 are split into 3-tuples where the members of the tuple have 97 meanings: 98 99 -- the stored candidate on the most common value of the measured entity 100 -- counter 101 -- total number of evaluations of the value */ 102void 103__gcov_merge_single (gcov_type *counters, unsigned n_counters) 104{ 105 unsigned i, n_measures; 106 gcov_type value, counter, all; 107 108 gcc_assert (!(n_counters % 3)); 109 n_measures = n_counters / 3; 110 for (i = 0; i < n_measures; i++, counters += 3) 111 { 112 value = gcov_get_counter_target (); 113 counter = gcov_get_counter (); 114 all = gcov_get_counter (); 115 116 if (counters[0] == value) 117 counters[1] += counter; 118 else if (counter > counters[1]) 119 { 120 counters[0] = value; 121 counters[1] = counter - counters[1]; 122 } 123 else 124 counters[1] -= counter; 125 counters[2] += all; 126 } 127} 128#endif /* L_gcov_merge_single */ 129 130#ifdef L_gcov_merge_delta 131/* The profile merging function for choosing the most common 132 difference between two consecutive evaluations of the value. It is 133 given an array COUNTERS of N_COUNTERS old counters and it reads the 134 same number of counters from the gcov file. The counters are split 135 into 4-tuples where the members of the tuple have meanings: 136 137 -- the last value of the measured entity 138 -- the stored candidate on the most common difference 139 -- counter 140 -- total number of evaluations of the value */ 141void 142__gcov_merge_delta (gcov_type *counters, unsigned n_counters) 143{ 144 unsigned i, n_measures; 145 gcov_type value, counter, all; 146 147 gcc_assert (!(n_counters % 4)); 148 n_measures = n_counters / 4; 149 for (i = 0; i < n_measures; i++, counters += 4) 150 { 151 /* last = */ gcov_get_counter (); 152 value = gcov_get_counter_target (); 153 counter = gcov_get_counter (); 154 all = gcov_get_counter (); 155 156 if (counters[1] == value) 157 counters[2] += counter; 158 else if (counter > counters[2]) 159 { 160 counters[1] = value; 161 counters[2] = counter - counters[2]; 162 } 163 else 164 counters[2] -= counter; 165 counters[3] += all; 166 } 167} 168#endif /* L_gcov_merge_delta */ 169 170#ifdef L_gcov_merge_icall_topn 171/* The profile merging function used for merging indirect call counts 172 This function is given array COUNTERS of N_COUNTERS old counters and it 173 reads the same number of counters from the gcov file. */ 174 175void 176__gcov_merge_icall_topn (gcov_type *counters, unsigned n_counters) 177{ 178 unsigned i, j, k, m; 179 180 gcc_assert (!(n_counters % GCOV_ICALL_TOPN_NCOUNTS)); 181 for (i = 0; i < n_counters; i += GCOV_ICALL_TOPN_NCOUNTS) 182 { 183 gcov_type *value_array = &counters[i + 1]; 184 unsigned tmp_size = 2 * (GCOV_ICALL_TOPN_NCOUNTS - 1); 185 gcov_type *tmp_array 186 = (gcov_type *) alloca (tmp_size * sizeof (gcov_type)); 187 188 for (j = 0; j < tmp_size; j++) 189 tmp_array[j] = 0; 190 191 for (j = 0; j < GCOV_ICALL_TOPN_NCOUNTS - 1; j += 2) 192 { 193 tmp_array[j] = value_array[j]; 194 tmp_array[j + 1] = value_array [j + 1]; 195 } 196 197 /* Skip the number_of_eviction entry. */ 198 gcov_get_counter (); 199 for (k = 0; k < GCOV_ICALL_TOPN_NCOUNTS - 1; k += 2) 200 { 201 int found = 0; 202 gcov_type global_id = gcov_get_counter_target (); 203 gcov_type call_count = gcov_get_counter (); 204 for (m = 0; m < j; m += 2) 205 { 206 if (tmp_array[m] == global_id) 207 { 208 found = 1; 209 tmp_array[m + 1] += call_count; 210 break; 211 } 212 } 213 if (!found) 214 { 215 tmp_array[j] = global_id; 216 tmp_array[j + 1] = call_count; 217 j += 2; 218 } 219 } 220 /* Now sort the temp array */ 221 gcov_sort_n_vals (tmp_array, j); 222 223 /* Now copy back the top half of the temp array */ 224 for (k = 0; k < GCOV_ICALL_TOPN_NCOUNTS - 1; k += 2) 225 { 226 value_array[k] = tmp_array[k]; 227 value_array[k + 1] = tmp_array[k + 1]; 228 } 229 } 230} 231#endif /* L_gcov_merge_icall_topn */ 232#endif /* inhibit_libc */ 233