comparison libgcc/libgcov-driver.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
comparison
equal deleted inserted replaced
131:84e7813d76e9 145:1830386684a0
1 /* Routines required for instrumenting a program. */ 1 /* Routines required for instrumenting a program. */
2 /* Compile this one with gcc. */ 2 /* Compile this one with gcc. */
3 /* Copyright (C) 1989-2018 Free Software Foundation, Inc. 3 /* Copyright (C) 1989-2020 Free Software Foundation, Inc.
4 4
5 This file is part of GCC. 5 This file is part of GCC.
6 6
7 GCC is free software; you can redistribute it and/or modify it under 7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free 8 the terms of the GNU General Public License as published by the Free
51 static void gcov_error_exit (void); 51 static void gcov_error_exit (void);
52 #endif 52 #endif
53 53
54 #include "gcov-io.c" 54 #include "gcov-io.c"
55 55
56 #define GCOV_PROF_PREFIX "libgcov profiling error:%s:"
57
56 struct gcov_fn_buffer 58 struct gcov_fn_buffer
57 { 59 {
58 struct gcov_fn_buffer *next; 60 struct gcov_fn_buffer *next;
59 unsigned fn_ix; 61 unsigned fn_ix;
60 struct gcov_fn_info info; 62 struct gcov_fn_info info;
149 151
150 *end_ptr = fn_buffer; 152 *end_ptr = fn_buffer;
151 return &fn_buffer->next; 153 return &fn_buffer->next;
152 154
153 fail: 155 fail:
154 gcov_error ("profiling:%s:Function %u %s %u \n", filename, fn_ix, 156 gcov_error (GCOV_PROF_PREFIX "Function %u %s %u \n", filename, fn_ix,
155 len ? "cannot allocate" : "counter mismatch", len ? len : ix); 157 len ? "cannot allocate" : "counter mismatch", len ? len : ix);
156 158
157 return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix); 159 return (struct gcov_fn_buffer **)free_fn_data (gi_ptr, fn_buffer, ix);
160 }
161
162 /* Convert VERSION into a string description and return the it.
163 BUFFER is used for storage of the string. The code should be
164 aligned wit gcov-iov.c. */
165
166 static char *
167 gcov_version_string (char *buffer, char version[4])
168 {
169 if (version[0] < 'A' || version[0] > 'Z'
170 || version[1] < '0' || version[1] > '9'
171 || version[2] < '0' || version[2] > '9')
172 sprintf (buffer, "(unknown)");
173 else
174 {
175 unsigned major = 10 * (version[0] - 'A') + (version[1] - '0');
176 unsigned minor = version[2] - '0';
177 sprintf (buffer, "%u.%u (%s)", major, minor,
178 version[3] == '*' ? "release" : "experimental");
179 }
180 return buffer;
158 } 181 }
159 182
160 /* Check if VERSION of the info block PTR matches libgcov one. 183 /* Check if VERSION of the info block PTR matches libgcov one.
161 Return 1 on success, or zero in case of versions mismatch. 184 Return 1 on success, or zero in case of versions mismatch.
162 If FILENAME is not NULL, its value used for reporting purposes 185 If FILENAME is not NULL, its value used for reporting purposes
167 const char *filename) 190 const char *filename)
168 { 191 {
169 if (version != GCOV_VERSION) 192 if (version != GCOV_VERSION)
170 { 193 {
171 char v[4], e[4]; 194 char v[4], e[4];
195 char version_string[128], expected_string[128];
172 196
173 GCOV_UNSIGNED2STRING (v, version); 197 GCOV_UNSIGNED2STRING (v, version);
174 GCOV_UNSIGNED2STRING (e, GCOV_VERSION); 198 GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
175 199
176 gcov_error ("profiling:%s:Version mismatch - expected %.4s got %.4s\n", 200 gcov_error (GCOV_PROF_PREFIX "Version mismatch - expected %s (%.4s) "
177 filename? filename : ptr->filename, e, v); 201 "got %s (%.4s)\n",
202 filename? filename : ptr->filename,
203 gcov_version_string (expected_string, e), e,
204 gcov_version_string (version_string, v), v);
178 return 0; 205 return 0;
179 } 206 }
180 return 1; 207 return 1;
181 } 208 }
182 209
183 /* buffer for the fn_data from another program. */ 210 /* buffer for the fn_data from another program. */
184 static struct gcov_fn_buffer *fn_buffer; 211 static struct gcov_fn_buffer *fn_buffer;
185 212
186 /* Including system dependent components. */ 213 /* Including system dependent components. */
187 #include "libgcov-driver-system.c" 214 #include "libgcov-driver-system.c"
215
216 /* Prune TOP N value COUNTERS. It's needed in order to preserve
217 reproducibility of builds. */
218
219 static void
220 prune_topn_counter (gcov_type *counters, gcov_type all)
221 {
222 for (unsigned i = 0; i < GCOV_TOPN_VALUES; i++)
223 if (counters[2 * i + 1] < all)
224 {
225 counters[2 * i] = 0;
226 counters[2 * i + 1] = 0;
227 }
228 }
229
230 /* Prune counters so that they are ready to store or merge. */
231
232 static void
233 prune_counters (struct gcov_info *gi)
234 {
235 for (unsigned i = 0; i < gi->n_functions; i++)
236 {
237 const struct gcov_fn_info *gfi = gi->functions[i];
238 const struct gcov_ctr_info *ci = gfi->ctrs;
239
240 for (unsigned j = 0; j < GCOV_COUNTERS; j++)
241 {
242 if (gi->merge[j] == NULL)
243 continue;
244
245 if (gi->merge[j] == __gcov_merge_topn)
246 {
247 gcc_assert (!(ci->num % GCOV_TOPN_VALUES_COUNTERS));
248 for (unsigned k = 0; k < (ci->num / GCOV_TOPN_VALUES_COUNTERS);
249 k++)
250 {
251 gcov_type *counters
252 = ci->values + (k * GCOV_TOPN_VALUES_COUNTERS);
253 prune_topn_counter (counters + 1, *counters);
254 }
255 }
256 ci++;
257 }
258 }
259 }
188 260
189 /* This function merges counters in GI_PTR to an existing gcda file. 261 /* This function merges counters in GI_PTR to an existing gcda file.
190 Return 0 on success. 262 Return 0 on success.
191 Return -1 on error. In this case, caller will goto read_fatal. */ 263 Return -1 on error. In this case, caller will goto read_fatal. */
192 264
207 279
208 length = gcov_read_unsigned (); 280 length = gcov_read_unsigned ();
209 if (length != gi_ptr->stamp) 281 if (length != gi_ptr->stamp)
210 { 282 {
211 /* Read from a different compilation. Overwrite the file. */ 283 /* Read from a different compilation. Overwrite the file. */
212 gcov_error ("profiling:%s:overwriting an existing profile data " 284 gcov_error (GCOV_PROF_PREFIX "overwriting an existing profile data "
213 "with a different timestamp\n", filename); 285 "with a different timestamp\n", filename);
214 return 0; 286 return 0;
215 } 287 }
216 288
217 tag = gcov_read_unsigned (); 289 tag = gcov_read_unsigned ();
287 } 359 }
288 360
289 if (tag) 361 if (tag)
290 { 362 {
291 read_mismatch:; 363 read_mismatch:;
292 gcov_error ("profiling:%s:Merge mismatch for %s %u\n", 364 gcov_error (GCOV_PROF_PREFIX "Merge mismatch for %s %u\n",
293 filename, f_ix >= 0 ? "function" : "summary", 365 filename, f_ix >= 0 ? "function" : "summary",
294 f_ix < 0 ? -1 - f_ix : f_ix); 366 f_ix < 0 ? -1 - f_ix : f_ix);
295 return -1; 367 return -1;
296 } 368 }
297 return 0; 369 return 0;
298 370
299 read_error: 371 read_error:
300 gcov_error ("profiling:%s:%s merging\n", filename, 372 gcov_error (GCOV_PROF_PREFIX "%s merging\n", filename,
301 error < 0 ? "Overflow": "Error"); 373 error < 0 ? "Overflow": "Error");
302 return -1; 374 return -1;
303 } 375 }
304 376
305 /* Write counters in GI_PTR and the summary in PRG to a gcda file. In 377 /* Write counters in GI_PTR and the summary in PRG to a gcda file. In
386 summary->runs++; 458 summary->runs++;
387 summary->sum_max += run_max; 459 summary->sum_max += run_max;
388 } 460 }
389 } 461 }
390 462
391 /* Sort N entries in VALUE_ARRAY in descending order.
392 Each entry in VALUE_ARRAY has two values. The sorting
393 is based on the second value. */
394
395 GCOV_LINKAGE void
396 gcov_sort_n_vals (gcov_type *value_array, int n)
397 {
398 int j, k;
399
400 for (j = 2; j < n; j += 2)
401 {
402 gcov_type cur_ent[2];
403
404 cur_ent[0] = value_array[j];
405 cur_ent[1] = value_array[j + 1];
406 k = j - 2;
407 while (k >= 0 && value_array[k + 1] < cur_ent[1])
408 {
409 value_array[k + 2] = value_array[k];
410 value_array[k + 3] = value_array[k+1];
411 k -= 2;
412 }
413 value_array[k + 2] = cur_ent[0];
414 value_array[k + 3] = cur_ent[1];
415 }
416 }
417
418 /* Sort the profile counters for all indirect call sites. Counters
419 for each call site are allocated in array COUNTERS. */
420
421 static void
422 gcov_sort_icall_topn_counter (const struct gcov_ctr_info *counters)
423 {
424 int i;
425 gcov_type *values;
426 int n = counters->num;
427
428 gcc_assert (!(n % GCOV_ICALL_TOPN_NCOUNTS));
429 values = counters->values;
430
431 for (i = 0; i < n; i += GCOV_ICALL_TOPN_NCOUNTS)
432 {
433 gcov_type *value_array = &values[i + 1];
434 gcov_sort_n_vals (value_array, GCOV_ICALL_TOPN_NCOUNTS - 1);
435 }
436 }
437
438 /* Sort topn indirect_call profile counters in GI_PTR. */
439
440 static void
441 gcov_sort_topn_counter_arrays (const struct gcov_info *gi_ptr)
442 {
443 unsigned int i;
444 int f_ix;
445 const struct gcov_fn_info *gfi_ptr;
446 const struct gcov_ctr_info *ci_ptr;
447
448 if (!gi_ptr->merge[GCOV_COUNTER_ICALL_TOPNV])
449 return;
450
451 for (f_ix = 0; (unsigned)f_ix != gi_ptr->n_functions; f_ix++)
452 {
453 gfi_ptr = gi_ptr->functions[f_ix];
454 ci_ptr = gfi_ptr->ctrs;
455 for (i = 0; i < GCOV_COUNTERS; i++)
456 {
457 if (!gi_ptr->merge[i])
458 continue;
459 if (i == GCOV_COUNTER_ICALL_TOPNV)
460 {
461 gcov_sort_icall_topn_counter (ci_ptr);
462 break;
463 }
464 ci_ptr++;
465 }
466 }
467 }
468
469 /* Dump the coverage counts for one gcov_info object. We merge with existing 463 /* Dump the coverage counts for one gcov_info object. We merge with existing
470 counts when possible, to avoid growing the .da files ad infinitum. We use 464 counts when possible, to avoid growing the .da files ad infinitum. We use
471 this program's checksum to make sure we only accumulate whole program 465 this program's checksum to make sure we only accumulate whole program
472 statistics to the correct summary. An object file might be embedded 466 statistics to the correct summary. An object file might be embedded
473 in two separate programs, and we must keep the two program 467 in two separate programs, and we must keep the two program
478 unsigned run_counted, gcov_type run_max) 472 unsigned run_counted, gcov_type run_max)
479 { 473 {
480 struct gcov_summary summary = {}; 474 struct gcov_summary summary = {};
481 int error; 475 int error;
482 gcov_unsigned_t tag; 476 gcov_unsigned_t tag;
483
484 fn_buffer = 0; 477 fn_buffer = 0;
485 478
486 gcov_sort_topn_counter_arrays (gi_ptr); 479 /* Prune current counters before we merge them. */
480 prune_counters (gi_ptr);
487 481
488 error = gcov_exit_open_gcda_file (gi_ptr, gf); 482 error = gcov_exit_open_gcda_file (gi_ptr, gf);
489 if (error == -1) 483 if (error == -1)
490 return; 484 return;
491 485
493 if (tag) 487 if (tag)
494 { 488 {
495 /* Merge data from file. */ 489 /* Merge data from file. */
496 if (tag != GCOV_DATA_MAGIC) 490 if (tag != GCOV_DATA_MAGIC)
497 { 491 {
498 gcov_error ("profiling:%s:Not a gcov data file\n", gf->filename); 492 gcov_error (GCOV_PROF_PREFIX "Not a gcov data file\n",
493 gf->filename);
499 goto read_fatal; 494 goto read_fatal;
500 } 495 }
501 error = merge_one_data (gf->filename, gi_ptr, &summary); 496 error = merge_one_data (gf->filename, gi_ptr, &summary);
502 if (error == -1) 497 if (error == -1)
503 goto read_fatal; 498 goto read_fatal;
514 while (fn_buffer) 509 while (fn_buffer)
515 fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS); 510 fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
516 511
517 if ((error = gcov_close ())) 512 if ((error = gcov_close ()))
518 gcov_error (error < 0 ? 513 gcov_error (error < 0 ?
519 "profiling:%s:Overflow writing\n" : 514 GCOV_PROF_PREFIX "Overflow writing\n" :
520 "profiling:%s:Error writing\n", 515 GCOV_PROF_PREFIX "Error writing\n",
521 gf->filename); 516 gf->filename);
522 } 517 }
523 518
524 519
525 /* Dump all the coverage counts for the program. It first computes program 520 /* Dump all the coverage counts for the program. It first computes program