1/* Routines required for instrumenting a program. */ 2/* Compile this one with gcc. */ 3/* Copyright (C) 1989-2014 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 73#ifdef L_gcov_merge_dc 74 75/* Returns 1 if the function global id GID is not valid. */ 76 77static int 78__gcov_is_gid_insane (gcov_type gid) 79{ 80 if (EXTRACT_MODULE_ID_FROM_GLOBAL_ID (gid) == 0 81 || EXTRACT_FUNC_ID_FROM_GLOBAL_ID (gid) == 0) 82 return 1; 83 return 0; 84} 85 86/* The profile merging function used for merging direct call counts 87 This function is given array COUNTERS of N_COUNTERS old counters and it 88 reads the same number of counters from the gcov file. */ 89 90void 91__gcov_merge_dc (gcov_type *counters, unsigned n_counters) 92{ 93 unsigned i; 94 95 gcc_assert (!(n_counters % 2)); 96 for (i = 0; i < n_counters; i += 2) 97 { 98 gcov_type global_id = gcov_get_counter_target (); 99 gcov_type call_count = gcov_get_counter (); 100 101 /* Note that global id counter may never have been set if no calls were 102 made from this call-site. */ 103 if (counters[i] && global_id) 104 { 105 /* TODO race condition requires us do the following correction. */ 106 if (__gcov_is_gid_insane (counters[i])) 107 counters[i] = global_id; 108 else if (__gcov_is_gid_insane (global_id)) 109 global_id = counters[i]; 110 111#if !defined(__KERNEL__) 112 /* In the case of inconsistency, use the src's target. */ 113 if (counters[i] != global_id) 114 fprintf (stderr, "Warning: Inconsistent call targets in" 115 " direct-call profile.\n"); 116#endif 117 } 118 else if (global_id) 119 counters[i] = global_id; 120 121 counters[i + 1] += call_count; 122 123 /* Reset. */ 124 if (__gcov_is_gid_insane (counters[i])) 125 counters[i] = counters[i + 1] = 0; 126 127 /* Assert that the invariant (global_id == 0) <==> (call_count == 0) 128 holds true after merging. */ 129 if (counters[i] == 0) 130 counters[i+1] = 0; 131 if (counters[i + 1] == 0) 132 counters[i] = 0; 133 } 134} 135#endif 136 137 138#ifdef L_gcov_merge_icall_topn 139/* The profile merging function used for merging indirect call counts 140 This function is given array COUNTERS of N_COUNTERS old counters and it 141 reads the same number of counters from the gcov file. */ 142 143void 144__gcov_merge_icall_topn (gcov_type *counters, unsigned n_counters) 145{ 146 unsigned i, j, k, m; 147 148 gcc_assert (!(n_counters % GCOV_ICALL_TOPN_NCOUNTS)); 149 for (i = 0; i < n_counters; i += GCOV_ICALL_TOPN_NCOUNTS) 150 { 151 gcov_type *value_array = &counters[i + 1]; 152 unsigned tmp_size = 2 * (GCOV_ICALL_TOPN_NCOUNTS - 1); 153 gcov_type *tmp_array 154 = (gcov_type *) alloca (tmp_size * sizeof (gcov_type)); 155 156 for (j = 0; j < tmp_size; j++) 157 tmp_array[j] = 0; 158 159 for (j = 0; j < GCOV_ICALL_TOPN_NCOUNTS - 1; j += 2) 160 { 161 tmp_array[j] = value_array[j]; 162 tmp_array[j + 1] = value_array [j + 1]; 163 } 164 165 /* Skip the number_of_eviction entry. */ 166 gcov_get_counter (); 167 for (k = 0; k < GCOV_ICALL_TOPN_NCOUNTS - 1; k += 2) 168 { 169 int found = 0; 170 gcov_type global_id = gcov_get_counter_target (); 171 gcov_type call_count = gcov_get_counter (); 172 for (m = 0; m < j; m += 2) 173 { 174 if (tmp_array[m] == global_id) 175 { 176 found = 1; 177 tmp_array[m + 1] += call_count; 178 break; 179 } 180 } 181 if (!found) 182 { 183 tmp_array[j] = global_id; 184 tmp_array[j + 1] = call_count; 185 j += 2; 186 } 187 } 188 /* Now sort the temp array */ 189 gcov_sort_n_vals (tmp_array, j); 190 191 /* Now copy back the top half of the temp array */ 192 for (k = 0; k < GCOV_ICALL_TOPN_NCOUNTS - 1; k += 2) 193 { 194 value_array[k] = tmp_array[k]; 195 value_array[k + 1] = tmp_array[k + 1]; 196 } 197 } 198} 199#endif 200 201 202#ifdef L_gcov_merge_time_profile 203/* Time profiles are merged so that minimum from all valid (greater than zero) 204 is stored. There could be a fork that creates new counters. To have 205 the profile stable, we chosen to pick the smallest function visit time. */ 206void 207__gcov_merge_time_profile (gcov_type *counters, unsigned n_counters) 208{ 209 unsigned int i; 210 gcov_type value; 211 212 for (i = 0; i < n_counters; i++) 213 { 214 value = gcov_get_counter_target (); 215 216 if (value && (!counters[i] || value < counters[i])) 217 counters[i] = value; 218 } 219} 220#endif /* L_gcov_merge_time_profile */ 221 222#ifdef L_gcov_merge_single 223/* The profile merging function for choosing the most common value. 224 It is given an array COUNTERS of N_COUNTERS old counters and it 225 reads the same number of counters from the gcov file. The counters 226 are split into 3-tuples where the members of the tuple have 227 meanings: 228 229 -- the stored candidate on the most common value of the measured entity 230 -- counter 231 -- total number of evaluations of the value */ 232void 233__gcov_merge_single (gcov_type *counters, unsigned n_counters) 234{ 235 unsigned i, n_measures; 236 gcov_type value, counter, all; 237 238 gcc_assert (!(n_counters % 3)); 239 n_measures = n_counters / 3; 240 for (i = 0; i < n_measures; i++, counters += 3) 241 { 242 value = gcov_get_counter_target (); 243 counter = gcov_get_counter (); 244 all = gcov_get_counter (); 245 246 if (counters[0] == value) 247 counters[1] += counter; 248 else if (counter > counters[1]) 249 { 250 counters[0] = value; 251 counters[1] = counter - counters[1]; 252 } 253 else 254 counters[1] -= counter; 255 counters[2] += all; 256 } 257} 258#endif /* L_gcov_merge_single */ 259 260#ifdef L_gcov_merge_delta 261/* The profile merging function for choosing the most common 262 difference between two consecutive evaluations of the value. It is 263 given an array COUNTERS of N_COUNTERS old counters and it reads the 264 same number of counters from the gcov file. The counters are split 265 into 4-tuples where the members of the tuple have meanings: 266 267 -- the last value of the measured entity 268 -- the stored candidate on the most common difference 269 -- counter 270 -- total number of evaluations of the value */ 271void 272__gcov_merge_delta (gcov_type *counters, unsigned n_counters) 273{ 274 unsigned i, n_measures; 275 gcov_type value, counter, all; 276 277 gcc_assert (!(n_counters % 4)); 278 n_measures = n_counters / 4; 279 for (i = 0; i < n_measures; i++, counters += 4) 280 { 281 /* last = */ gcov_get_counter (); 282 value = gcov_get_counter_target (); 283 counter = gcov_get_counter (); 284 all = gcov_get_counter (); 285 286 if (counters[1] == value) 287 counters[2] += counter; 288 else if (counter > counters[2]) 289 { 290 counters[1] = value; 291 counters[2] = counter - counters[2]; 292 } 293 else 294 counters[2] -= counter; 295 counters[3] += all; 296 } 297} 298#endif /* L_gcov_merge_delta */ 299#endif /* inhibit_libc */ 300