Mercurial > hg > CbC > CbC_gcc
comparison gcc/gcov-io.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | 77e2b8dfacca |
children | 84e7813d76e9 |
comparison
equal
deleted
inserted
replaced
68:561a7518be6b | 111:04ced10e8804 |
---|---|
1 /* File format for coverage information | 1 /* File format for coverage information |
2 Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004, 2005, 2007, | 2 Copyright (C) 1996-2017 Free Software Foundation, Inc. |
3 2008 Free Software Foundation, Inc. | |
4 Contributed by Bob Manson <manson@cygnus.com>. | 3 Contributed by Bob Manson <manson@cygnus.com>. |
5 Completely remangled by Nathan Sidwell <nathan@codesourcery.com>. | 4 Completely remangled by Nathan Sidwell <nathan@codesourcery.com>. |
6 | 5 |
7 This file is part of GCC. | 6 This file is part of GCC. |
8 | 7 |
14 GCC is distributed in the hope that it will be useful, but WITHOUT ANY | 13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or | 14 WARRANTY; without even the implied warranty of MERCHANTABILITY or |
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | 15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
17 for more details. | 16 for more details. |
18 | 17 |
19 You should have received a copy of the GNU General Public License | 18 Under Section 7 of GPL version 3, you are granted additional |
20 along with GCC; see the file COPYING3. If not see | 19 permissions described in the GCC Runtime Library Exception, version |
20 3.1, as published by the Free Software Foundation. | |
21 | |
22 You should have received a copy of the GNU General Public License and | |
23 a copy of the GCC Runtime Library Exception along with this program; | |
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
21 <http://www.gnu.org/licenses/>. */ | 25 <http://www.gnu.org/licenses/>. */ |
22 | 26 |
23 /* Routines declared in gcov-io.h. This file should be #included by | 27 /* Routines declared in gcov-io.h. This file should be #included by |
24 another source file, after having #included gcov-io.h. */ | 28 another source file, after having #included gcov-io.h. */ |
25 | 29 |
28 static gcov_unsigned_t *gcov_write_words (unsigned); | 32 static gcov_unsigned_t *gcov_write_words (unsigned); |
29 #endif | 33 #endif |
30 static const gcov_unsigned_t *gcov_read_words (unsigned); | 34 static const gcov_unsigned_t *gcov_read_words (unsigned); |
31 #if !IN_LIBGCOV | 35 #if !IN_LIBGCOV |
32 static void gcov_allocate (unsigned); | 36 static void gcov_allocate (unsigned); |
37 #endif | |
38 | |
39 /* Optimum number of gcov_unsigned_t's read from or written to disk. */ | |
40 #define GCOV_BLOCK_SIZE (1 << 10) | |
41 | |
42 struct gcov_var | |
43 { | |
44 FILE *file; | |
45 gcov_position_t start; /* Position of first byte of block */ | |
46 unsigned offset; /* Read/write position within the block. */ | |
47 unsigned length; /* Read limit in the block. */ | |
48 unsigned overread; /* Number of words overread. */ | |
49 int error; /* < 0 overflow, > 0 disk error. */ | |
50 int mode; /* < 0 writing, > 0 reading */ | |
51 #if IN_LIBGCOV | |
52 /* Holds one block plus 4 bytes, thus all coverage reads & writes | |
53 fit within this buffer and we always can transfer GCOV_BLOCK_SIZE | |
54 to and from the disk. libgcov never backtracks and only writes 4 | |
55 or 8 byte objects. */ | |
56 gcov_unsigned_t buffer[GCOV_BLOCK_SIZE + 1]; | |
57 #else | |
58 int endian; /* Swap endianness. */ | |
59 /* Holds a variable length block, as the compiler can write | |
60 strings and needs to backtrack. */ | |
61 size_t alloc; | |
62 gcov_unsigned_t *buffer; | |
63 #endif | |
64 } gcov_var; | |
65 | |
66 /* Save the current position in the gcov file. */ | |
67 /* We need to expose this function when compiling for gcov-tool. */ | |
68 #ifndef IN_GCOV_TOOL | |
69 static inline | |
70 #endif | |
71 gcov_position_t | |
72 gcov_position (void) | |
73 { | |
74 gcov_nonruntime_assert (gcov_var.mode > 0); | |
75 return gcov_var.start + gcov_var.offset; | |
76 } | |
77 | |
78 /* Return nonzero if the error flag is set. */ | |
79 /* We need to expose this function when compiling for gcov-tool. */ | |
80 #ifndef IN_GCOV_TOOL | |
81 static inline | |
82 #endif | |
83 int | |
84 gcov_is_error (void) | |
85 { | |
86 return gcov_var.file ? gcov_var.error : 1; | |
87 } | |
88 | |
89 #if IN_LIBGCOV | |
90 /* Move to beginning of file and initialize for writing. */ | |
91 GCOV_LINKAGE inline void | |
92 gcov_rewrite (void) | |
93 { | |
94 gcov_var.mode = -1; | |
95 gcov_var.start = 0; | |
96 gcov_var.offset = 0; | |
97 fseek (gcov_var.file, 0L, SEEK_SET); | |
98 } | |
33 #endif | 99 #endif |
34 | 100 |
35 static inline gcov_unsigned_t from_file (gcov_unsigned_t value) | 101 static inline gcov_unsigned_t from_file (gcov_unsigned_t value) |
36 { | 102 { |
37 #if !IN_LIBGCOV | 103 #if !IN_LIBGCOV |
47 /* Open a gcov file. NAME is the name of the file to open and MODE | 113 /* Open a gcov file. NAME is the name of the file to open and MODE |
48 indicates whether a new file should be created, or an existing file | 114 indicates whether a new file should be created, or an existing file |
49 opened. If MODE is >= 0 an existing file will be opened, if | 115 opened. If MODE is >= 0 an existing file will be opened, if |
50 possible, and if MODE is <= 0, a new file will be created. Use | 116 possible, and if MODE is <= 0, a new file will be created. Use |
51 MODE=0 to attempt to reopen an existing file and then fall back on | 117 MODE=0 to attempt to reopen an existing file and then fall back on |
52 creating a new one. If MODE < 0, the file will be opened in | 118 creating a new one. If MODE > 0, the file will be opened in |
53 read-only mode. Otherwise it will be opened for modification. | 119 read-only mode. Otherwise it will be opened for modification. |
54 Return zero on failure, >0 on opening an existing file and <0 on | 120 Return zero on failure, non-zero on success. */ |
55 creating a new one. */ | |
56 | 121 |
57 GCOV_LINKAGE int | 122 GCOV_LINKAGE int |
58 #if IN_LIBGCOV | 123 #if IN_LIBGCOV |
59 gcov_open (const char *name) | 124 gcov_open (const char *name) |
60 #else | 125 #else |
61 gcov_open (const char *name, int mode) | 126 gcov_open (const char *name, int mode) |
62 #endif | 127 #endif |
63 { | 128 { |
64 #if IN_LIBGCOV | 129 #if IN_LIBGCOV |
65 const int mode = 0; | 130 int mode = 0; |
66 #endif | 131 #endif |
67 #if GCOV_LOCKED | 132 #if GCOV_LOCKED |
68 struct flock s_flock; | 133 struct flock s_flock; |
69 int fd; | 134 int fd; |
70 | 135 |
72 s_flock.l_start = 0; | 137 s_flock.l_start = 0; |
73 s_flock.l_len = 0; /* Until EOF. */ | 138 s_flock.l_len = 0; /* Until EOF. */ |
74 s_flock.l_pid = getpid (); | 139 s_flock.l_pid = getpid (); |
75 #endif | 140 #endif |
76 | 141 |
77 gcc_assert (!gcov_var.file); | 142 gcov_nonruntime_assert (!gcov_var.file); |
78 gcov_var.start = 0; | 143 gcov_var.start = 0; |
79 gcov_var.offset = gcov_var.length = 0; | 144 gcov_var.offset = gcov_var.length = 0; |
80 gcov_var.overread = -1u; | 145 gcov_var.overread = -1u; |
81 gcov_var.error = 0; | 146 gcov_var.error = 0; |
82 #if !IN_LIBGCOV | 147 #if !IN_LIBGCOV |
85 #if GCOV_LOCKED | 150 #if GCOV_LOCKED |
86 if (mode > 0) | 151 if (mode > 0) |
87 { | 152 { |
88 /* Read-only mode - acquire a read-lock. */ | 153 /* Read-only mode - acquire a read-lock. */ |
89 s_flock.l_type = F_RDLCK; | 154 s_flock.l_type = F_RDLCK; |
90 fd = open (name, O_RDONLY); | 155 /* pass mode (ignored) for compatibility */ |
156 fd = open (name, O_RDONLY, S_IRUSR | S_IWUSR); | |
91 } | 157 } |
92 else | 158 else |
93 { | 159 { |
94 /* Write mode - acquire a write-lock. */ | 160 /* Write mode - acquire a write-lock. */ |
95 s_flock.l_type = F_WRLCK; | 161 s_flock.l_type = F_WRLCK; |
96 fd = open (name, O_RDWR | O_CREAT, 0666); | 162 /* Truncate if force new mode. */ |
163 fd = open (name, O_RDWR | O_CREAT | (mode < 0 ? O_TRUNC : 0), 0666); | |
97 } | 164 } |
98 if (fd < 0) | 165 if (fd < 0) |
99 return 0; | 166 return 0; |
100 | 167 |
101 while (fcntl (fd, F_SETLKW, &s_flock) && errno == EINTR) | 168 while (fcntl (fd, F_SETLKW, &s_flock) && errno == EINTR) |
106 if (!gcov_var.file) | 173 if (!gcov_var.file) |
107 { | 174 { |
108 close (fd); | 175 close (fd); |
109 return 0; | 176 return 0; |
110 } | 177 } |
111 | |
112 if (mode > 0) | |
113 gcov_var.mode = 1; | |
114 else if (mode == 0) | |
115 { | |
116 struct stat st; | |
117 | |
118 if (fstat (fd, &st) < 0) | |
119 { | |
120 fclose (gcov_var.file); | |
121 gcov_var.file = 0; | |
122 return 0; | |
123 } | |
124 if (st.st_size != 0) | |
125 gcov_var.mode = 1; | |
126 else | |
127 gcov_var.mode = mode * 2 + 1; | |
128 } | |
129 else | |
130 gcov_var.mode = mode * 2 + 1; | |
131 #else | 178 #else |
132 if (mode >= 0) | 179 if (mode >= 0) |
180 /* Open an existing file. */ | |
133 gcov_var.file = fopen (name, (mode > 0) ? "rb" : "r+b"); | 181 gcov_var.file = fopen (name, (mode > 0) ? "rb" : "r+b"); |
134 | 182 |
135 if (gcov_var.file) | 183 if (gcov_var.file) |
136 gcov_var.mode = 1; | 184 mode = 1; |
137 else if (mode <= 0) | 185 else if (mode <= 0) |
138 { | 186 /* Create a new file. */ |
139 gcov_var.file = fopen (name, "w+b"); | 187 gcov_var.file = fopen (name, "w+b"); |
140 if (gcov_var.file) | 188 |
141 gcov_var.mode = mode * 2 + 1; | |
142 } | |
143 if (!gcov_var.file) | 189 if (!gcov_var.file) |
144 return 0; | 190 return 0; |
145 #endif | 191 #endif |
192 | |
193 gcov_var.mode = mode ? mode : 1; | |
146 | 194 |
147 setbuf (gcov_var.file, (char *)0); | 195 setbuf (gcov_var.file, (char *)0); |
148 | 196 |
149 return 1; | 197 return 1; |
150 } | 198 } |
229 static gcov_unsigned_t * | 277 static gcov_unsigned_t * |
230 gcov_write_words (unsigned words) | 278 gcov_write_words (unsigned words) |
231 { | 279 { |
232 gcov_unsigned_t *result; | 280 gcov_unsigned_t *result; |
233 | 281 |
234 gcc_assert (gcov_var.mode < 0); | 282 gcov_nonruntime_assert (gcov_var.mode < 0); |
235 #if IN_LIBGCOV | 283 #if IN_LIBGCOV |
236 if (gcov_var.offset >= GCOV_BLOCK_SIZE) | 284 if (gcov_var.offset >= GCOV_BLOCK_SIZE) |
237 { | 285 { |
238 gcov_write_block (GCOV_BLOCK_SIZE); | 286 gcov_write_block (GCOV_BLOCK_SIZE); |
239 if (gcov_var.offset) | 287 if (gcov_var.offset) |
240 { | 288 { |
241 gcc_assert (gcov_var.offset == 1); | |
242 memcpy (gcov_var.buffer, gcov_var.buffer + GCOV_BLOCK_SIZE, 4); | 289 memcpy (gcov_var.buffer, gcov_var.buffer + GCOV_BLOCK_SIZE, 4); |
243 } | 290 } |
244 } | 291 } |
245 #else | 292 #else |
246 if (gcov_var.offset + words > gcov_var.alloc) | 293 if (gcov_var.offset + words > gcov_var.alloc) |
298 } | 345 } |
299 | 346 |
300 buffer = gcov_write_words (1 + alloc); | 347 buffer = gcov_write_words (1 + alloc); |
301 | 348 |
302 buffer[0] = alloc; | 349 buffer[0] = alloc; |
303 buffer[alloc] = 0; | 350 |
304 memcpy (&buffer[1], string, length); | 351 if (alloc > 0) |
352 { | |
353 buffer[alloc] = 0; /* place nul terminators. */ | |
354 memcpy (&buffer[1], string, length); | |
355 } | |
356 } | |
357 #endif | |
358 | |
359 #if !IN_LIBGCOV | |
360 /* Write FILENAME to coverage file. Sets error flag on file | |
361 error, overflow flag on overflow */ | |
362 | |
363 GCOV_LINKAGE void | |
364 gcov_write_filename (const char *filename) | |
365 { | |
366 if (profile_abs_path_flag && filename && filename[0] | |
367 && !(IS_DIR_SEPARATOR (filename[0]) | |
368 #if HAVE_DOS_BASED_FILE_SYSTEM | |
369 || filename[1] == ':' | |
370 #endif | |
371 )) | |
372 { | |
373 char *buf = getcwd (NULL, 0); | |
374 if (buf != NULL && buf[0]) | |
375 { | |
376 size_t len = strlen (buf); | |
377 buf = (char*)xrealloc (buf, len + strlen (filename) + 2); | |
378 if (!IS_DIR_SEPARATOR (buf[len - 1])) | |
379 strcat (buf, "/"); | |
380 strcat (buf, filename); | |
381 gcov_write_string (buf); | |
382 free (buf); | |
383 return; | |
384 } | |
385 } | |
386 | |
387 gcov_write_string (filename); | |
305 } | 388 } |
306 #endif | 389 #endif |
307 | 390 |
308 #if !IN_LIBGCOV | 391 #if !IN_LIBGCOV |
309 /* Write a tag TAG and reserve space for the record length. Return a | 392 /* Write a tag TAG and reserve space for the record length. Return a |
331 { | 414 { |
332 unsigned offset; | 415 unsigned offset; |
333 gcov_unsigned_t length; | 416 gcov_unsigned_t length; |
334 gcov_unsigned_t *buffer; | 417 gcov_unsigned_t *buffer; |
335 | 418 |
336 gcc_assert (gcov_var.mode < 0); | 419 gcov_nonruntime_assert (gcov_var.mode < 0); |
337 gcc_assert (position + 2 <= gcov_var.start + gcov_var.offset); | 420 gcov_nonruntime_assert (position + 2 <= gcov_var.start + gcov_var.offset); |
338 gcc_assert (position >= gcov_var.start); | 421 gcov_nonruntime_assert (position >= gcov_var.start); |
339 offset = position - gcov_var.start; | 422 offset = position - gcov_var.start; |
340 length = gcov_var.offset - offset - 2; | 423 length = gcov_var.offset - offset - 2; |
341 buffer = (gcov_unsigned_t *) &gcov_var.buffer[offset]; | 424 buffer = (gcov_unsigned_t *) &gcov_var.buffer[offset]; |
342 buffer[1] = length; | 425 buffer[1] = length; |
343 if (gcov_var.offset >= GCOV_BLOCK_SIZE) | 426 if (gcov_var.offset >= GCOV_BLOCK_SIZE) |
361 overflow. */ | 444 overflow. */ |
362 | 445 |
363 GCOV_LINKAGE void | 446 GCOV_LINKAGE void |
364 gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary) | 447 gcov_write_summary (gcov_unsigned_t tag, const struct gcov_summary *summary) |
365 { | 448 { |
366 unsigned ix; | 449 unsigned ix, h_ix, bv_ix, h_cnt = 0; |
367 const struct gcov_ctr_summary *csum; | 450 const struct gcov_ctr_summary *csum; |
368 | 451 unsigned histo_bitvector[GCOV_HISTOGRAM_BITVECTOR_SIZE]; |
369 gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH); | 452 |
453 /* Count number of non-zero histogram entries, and fill in a bit vector | |
454 of non-zero indices. The histogram is only currently computed for arc | |
455 counters. */ | |
456 for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++) | |
457 histo_bitvector[bv_ix] = 0; | |
458 csum = &summary->ctrs[GCOV_COUNTER_ARCS]; | |
459 for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++) | |
460 if (csum->histogram[h_ix].num_counters) | |
461 { | |
462 histo_bitvector[h_ix / 32] |= 1 << (h_ix % 32); | |
463 h_cnt++; | |
464 } | |
465 gcov_write_tag_length (tag, GCOV_TAG_SUMMARY_LENGTH (h_cnt)); | |
370 gcov_write_unsigned (summary->checksum); | 466 gcov_write_unsigned (summary->checksum); |
371 for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++) | 467 for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++) |
372 { | 468 { |
373 gcov_write_unsigned (csum->num); | 469 gcov_write_unsigned (csum->num); |
374 gcov_write_unsigned (csum->runs); | 470 gcov_write_unsigned (csum->runs); |
375 gcov_write_counter (csum->sum_all); | 471 gcov_write_counter (csum->sum_all); |
376 gcov_write_counter (csum->run_max); | 472 gcov_write_counter (csum->run_max); |
377 gcov_write_counter (csum->sum_max); | 473 gcov_write_counter (csum->sum_max); |
474 if (ix != GCOV_COUNTER_ARCS) | |
475 { | |
476 for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++) | |
477 gcov_write_unsigned (0); | |
478 continue; | |
479 } | |
480 for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++) | |
481 gcov_write_unsigned (histo_bitvector[bv_ix]); | |
482 for (h_ix = 0; h_ix < GCOV_HISTOGRAM_SIZE; h_ix++) | |
483 { | |
484 if (!csum->histogram[h_ix].num_counters) | |
485 continue; | |
486 gcov_write_unsigned (csum->histogram[h_ix].num_counters); | |
487 gcov_write_counter (csum->histogram[h_ix].min_value); | |
488 gcov_write_counter (csum->histogram[h_ix].cum_value); | |
489 } | |
378 } | 490 } |
379 } | 491 } |
380 #endif /* IN_LIBGCOV */ | 492 #endif /* IN_LIBGCOV */ |
381 | 493 |
382 #endif /*!IN_GCOV */ | 494 #endif /*!IN_GCOV */ |
388 gcov_read_words (unsigned words) | 500 gcov_read_words (unsigned words) |
389 { | 501 { |
390 const gcov_unsigned_t *result; | 502 const gcov_unsigned_t *result; |
391 unsigned excess = gcov_var.length - gcov_var.offset; | 503 unsigned excess = gcov_var.length - gcov_var.offset; |
392 | 504 |
393 gcc_assert (gcov_var.mode > 0); | 505 if (gcov_var.mode <= 0) |
506 return NULL; | |
507 | |
394 if (excess < words) | 508 if (excess < words) |
395 { | 509 { |
396 gcov_var.start += gcov_var.offset; | 510 gcov_var.start += gcov_var.offset; |
397 #if IN_LIBGCOV | |
398 if (excess) | 511 if (excess) |
399 { | 512 { |
400 gcc_assert (excess == 1); | 513 #if IN_LIBGCOV |
401 memcpy (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, 4); | 514 memcpy (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, 4); |
515 #else | |
516 memmove (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, | |
517 excess * 4); | |
518 #endif | |
402 } | 519 } |
403 #else | |
404 memmove (gcov_var.buffer, gcov_var.buffer + gcov_var.offset, excess * 4); | |
405 #endif | |
406 gcov_var.offset = 0; | 520 gcov_var.offset = 0; |
407 gcov_var.length = excess; | 521 gcov_var.length = excess; |
408 #if IN_LIBGCOV | 522 #if IN_LIBGCOV |
409 gcc_assert (!gcov_var.length || gcov_var.length == 1); | |
410 excess = GCOV_BLOCK_SIZE; | 523 excess = GCOV_BLOCK_SIZE; |
411 #else | 524 #else |
412 if (gcov_var.length + words > gcov_var.alloc) | 525 if (gcov_var.length + words > gcov_var.alloc) |
413 gcov_allocate (gcov_var.length + words); | 526 gcov_allocate (gcov_var.length + words); |
414 excess = gcov_var.alloc - gcov_var.length; | 527 excess = gcov_var.alloc - gcov_var.length; |
461 gcov_var.error = -1; | 574 gcov_var.error = -1; |
462 | 575 |
463 return value; | 576 return value; |
464 } | 577 } |
465 | 578 |
579 /* We need to expose the below function when compiling for gcov-tool. */ | |
580 | |
581 #if !IN_LIBGCOV || defined (IN_GCOV_TOOL) | |
466 /* Read string from coverage file. Returns a pointer to a static | 582 /* Read string from coverage file. Returns a pointer to a static |
467 buffer, or NULL on empty string. You must copy the string before | 583 buffer, or NULL on empty string. You must copy the string before |
468 calling another gcov function. */ | 584 calling another gcov function. */ |
469 | 585 |
470 #if !IN_LIBGCOV | |
471 GCOV_LINKAGE const char * | 586 GCOV_LINKAGE const char * |
472 gcov_read_string (void) | 587 gcov_read_string (void) |
473 { | 588 { |
474 unsigned length = gcov_read_unsigned (); | 589 unsigned length = gcov_read_unsigned (); |
475 | 590 |
481 #endif | 596 #endif |
482 | 597 |
483 GCOV_LINKAGE void | 598 GCOV_LINKAGE void |
484 gcov_read_summary (struct gcov_summary *summary) | 599 gcov_read_summary (struct gcov_summary *summary) |
485 { | 600 { |
486 unsigned ix; | 601 unsigned ix, h_ix, bv_ix, h_cnt = 0; |
487 struct gcov_ctr_summary *csum; | 602 struct gcov_ctr_summary *csum; |
603 unsigned histo_bitvector[GCOV_HISTOGRAM_BITVECTOR_SIZE]; | |
604 unsigned cur_bitvector; | |
488 | 605 |
489 summary->checksum = gcov_read_unsigned (); | 606 summary->checksum = gcov_read_unsigned (); |
490 for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++) | 607 for (csum = summary->ctrs, ix = GCOV_COUNTERS_SUMMABLE; ix--; csum++) |
491 { | 608 { |
492 csum->num = gcov_read_unsigned (); | 609 csum->num = gcov_read_unsigned (); |
493 csum->runs = gcov_read_unsigned (); | 610 csum->runs = gcov_read_unsigned (); |
494 csum->sum_all = gcov_read_counter (); | 611 csum->sum_all = gcov_read_counter (); |
495 csum->run_max = gcov_read_counter (); | 612 csum->run_max = gcov_read_counter (); |
496 csum->sum_max = gcov_read_counter (); | 613 csum->sum_max = gcov_read_counter (); |
497 } | 614 memset (csum->histogram, 0, |
498 } | 615 sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE); |
499 | 616 for (bv_ix = 0; bv_ix < GCOV_HISTOGRAM_BITVECTOR_SIZE; bv_ix++) |
500 #if !IN_LIBGCOV | 617 { |
618 histo_bitvector[bv_ix] = gcov_read_unsigned (); | |
619 #if IN_LIBGCOV | |
620 /* When building libgcov we don't include system.h, which includes | |
621 hwint.h (where popcount_hwi is declared). However, libgcov.a | |
622 is built by the bootstrapped compiler and therefore the builtins | |
623 are always available. */ | |
624 h_cnt += __builtin_popcount (histo_bitvector[bv_ix]); | |
625 #else | |
626 h_cnt += popcount_hwi (histo_bitvector[bv_ix]); | |
627 #endif | |
628 } | |
629 bv_ix = 0; | |
630 h_ix = 0; | |
631 cur_bitvector = 0; | |
632 while (h_cnt--) | |
633 { | |
634 /* Find the index corresponding to the next entry we will read in. | |
635 First find the next non-zero bitvector and re-initialize | |
636 the histogram index accordingly, then right shift and increment | |
637 the index until we find a set bit. */ | |
638 while (!cur_bitvector) | |
639 { | |
640 h_ix = bv_ix * 32; | |
641 if (bv_ix >= GCOV_HISTOGRAM_BITVECTOR_SIZE) | |
642 gcov_error ("corrupted profile info: summary histogram " | |
643 "bitvector is corrupt"); | |
644 cur_bitvector = histo_bitvector[bv_ix++]; | |
645 } | |
646 while (!(cur_bitvector & 0x1)) | |
647 { | |
648 h_ix++; | |
649 cur_bitvector >>= 1; | |
650 } | |
651 if (h_ix >= GCOV_HISTOGRAM_SIZE) | |
652 gcov_error ("corrupted profile info: summary histogram " | |
653 "index is corrupt"); | |
654 | |
655 csum->histogram[h_ix].num_counters = gcov_read_unsigned (); | |
656 csum->histogram[h_ix].min_value = gcov_read_counter (); | |
657 csum->histogram[h_ix].cum_value = gcov_read_counter (); | |
658 /* Shift off the index we are done with and increment to the | |
659 corresponding next histogram entry. */ | |
660 cur_bitvector >>= 1; | |
661 h_ix++; | |
662 } | |
663 } | |
664 } | |
665 | |
666 /* We need to expose the below function when compiling for gcov-tool. */ | |
667 | |
668 #if !IN_LIBGCOV || defined (IN_GCOV_TOOL) | |
501 /* Reset to a known position. BASE should have been obtained from | 669 /* Reset to a known position. BASE should have been obtained from |
502 gcov_position, LENGTH should be a record length. */ | 670 gcov_position, LENGTH should be a record length. */ |
503 | 671 |
504 GCOV_LINKAGE void | 672 GCOV_LINKAGE void |
505 gcov_sync (gcov_position_t base, gcov_unsigned_t length) | 673 gcov_sync (gcov_position_t base, gcov_unsigned_t length) |
506 { | 674 { |
507 gcc_assert (gcov_var.mode > 0); | 675 gcov_nonruntime_assert (gcov_var.mode > 0); |
508 base += length; | 676 base += length; |
509 if (base - gcov_var.start <= gcov_var.length) | 677 if (base - gcov_var.start <= gcov_var.length) |
510 gcov_var.offset = base - gcov_var.start; | 678 gcov_var.offset = base - gcov_var.start; |
511 else | 679 else |
512 { | 680 { |
521 /* Move to a given position in a gcov file. */ | 689 /* Move to a given position in a gcov file. */ |
522 | 690 |
523 GCOV_LINKAGE void | 691 GCOV_LINKAGE void |
524 gcov_seek (gcov_position_t base) | 692 gcov_seek (gcov_position_t base) |
525 { | 693 { |
526 gcc_assert (gcov_var.mode < 0); | |
527 if (gcov_var.offset) | 694 if (gcov_var.offset) |
528 gcov_write_block (gcov_var.offset); | 695 gcov_write_block (gcov_var.offset); |
529 fseek (gcov_var.file, base << 2, SEEK_SET); | 696 fseek (gcov_var.file, base << 2, SEEK_SET); |
530 gcov_var.start = ftell (gcov_var.file) >> 2; | 697 gcov_var.start = ftell (gcov_var.file) >> 2; |
531 } | 698 } |
543 return 0; | 710 return 0; |
544 else | 711 else |
545 return status.st_mtime; | 712 return status.st_mtime; |
546 } | 713 } |
547 #endif /* IN_GCOV */ | 714 #endif /* IN_GCOV */ |
715 | |
716 #if !IN_GCOV | |
717 /* Determine the index into histogram for VALUE. */ | |
718 | |
719 #if IN_LIBGCOV | |
720 static unsigned | |
721 #else | |
722 GCOV_LINKAGE unsigned | |
723 #endif | |
724 gcov_histo_index (gcov_type value) | |
725 { | |
726 gcov_type_unsigned v = (gcov_type_unsigned)value; | |
727 unsigned r = 0; | |
728 unsigned prev2bits = 0; | |
729 | |
730 /* Find index into log2 scale histogram, where each of the log2 | |
731 sized buckets is divided into 4 linear sub-buckets for better | |
732 focus in the higher buckets. */ | |
733 | |
734 /* Find the place of the most-significant bit set. */ | |
735 if (v > 0) | |
736 { | |
737 #if IN_LIBGCOV | |
738 /* When building libgcov we don't include system.h, which includes | |
739 hwint.h (where floor_log2 is declared). However, libgcov.a | |
740 is built by the bootstrapped compiler and therefore the builtins | |
741 are always available. */ | |
742 r = sizeof (long long) * __CHAR_BIT__ - 1 - __builtin_clzll (v); | |
743 #else | |
744 /* We use floor_log2 from hwint.c, which takes a HOST_WIDE_INT | |
745 that is 64 bits and gcov_type_unsigned is 64 bits. */ | |
746 r = floor_log2 (v); | |
747 #endif | |
748 } | |
749 | |
750 /* If at most the 2 least significant bits are set (value is | |
751 0 - 3) then that value is our index into the lowest set of | |
752 four buckets. */ | |
753 if (r < 2) | |
754 return (unsigned)value; | |
755 | |
756 gcov_nonruntime_assert (r < 64); | |
757 | |
758 /* Find the two next most significant bits to determine which | |
759 of the four linear sub-buckets to select. */ | |
760 prev2bits = (v >> (r - 2)) & 0x3; | |
761 /* Finally, compose the final bucket index from the log2 index and | |
762 the next 2 bits. The minimum r value at this point is 2 since we | |
763 returned above if r was 2 or more, so the minimum bucket at this | |
764 point is 4. */ | |
765 return (r - 1) * 4 + prev2bits; | |
766 } | |
767 | |
768 /* Merge SRC_HISTO into TGT_HISTO. The counters are assumed to be in | |
769 the same relative order in both histograms, and are matched up | |
770 and merged in reverse order. Each counter is assigned an equal portion of | |
771 its entry's original cumulative counter value when computing the | |
772 new merged cum_value. */ | |
773 | |
774 static void gcov_histogram_merge (gcov_bucket_type *tgt_histo, | |
775 gcov_bucket_type *src_histo) | |
776 { | |
777 int src_i, tgt_i, tmp_i = 0; | |
778 unsigned src_num, tgt_num, merge_num; | |
779 gcov_type src_cum, tgt_cum, merge_src_cum, merge_tgt_cum, merge_cum; | |
780 gcov_type merge_min; | |
781 gcov_bucket_type tmp_histo[GCOV_HISTOGRAM_SIZE]; | |
782 int src_done = 0; | |
783 | |
784 memset (tmp_histo, 0, sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE); | |
785 | |
786 /* Assume that the counters are in the same relative order in both | |
787 histograms. Walk the histograms from largest to smallest entry, | |
788 matching up and combining counters in order. */ | |
789 src_num = 0; | |
790 src_cum = 0; | |
791 src_i = GCOV_HISTOGRAM_SIZE - 1; | |
792 for (tgt_i = GCOV_HISTOGRAM_SIZE - 1; tgt_i >= 0 && !src_done; tgt_i--) | |
793 { | |
794 tgt_num = tgt_histo[tgt_i].num_counters; | |
795 tgt_cum = tgt_histo[tgt_i].cum_value; | |
796 /* Keep going until all of the target histogram's counters at this | |
797 position have been matched and merged with counters from the | |
798 source histogram. */ | |
799 while (tgt_num > 0 && !src_done) | |
800 { | |
801 /* If this is either the first time through this loop or we just | |
802 exhausted the previous non-zero source histogram entry, look | |
803 for the next non-zero source histogram entry. */ | |
804 if (!src_num) | |
805 { | |
806 /* Locate the next non-zero entry. */ | |
807 while (src_i >= 0 && !src_histo[src_i].num_counters) | |
808 src_i--; | |
809 /* If source histogram has fewer counters, then just copy over the | |
810 remaining target counters and quit. */ | |
811 if (src_i < 0) | |
812 { | |
813 tmp_histo[tgt_i].num_counters += tgt_num; | |
814 tmp_histo[tgt_i].cum_value += tgt_cum; | |
815 if (!tmp_histo[tgt_i].min_value || | |
816 tgt_histo[tgt_i].min_value < tmp_histo[tgt_i].min_value) | |
817 tmp_histo[tgt_i].min_value = tgt_histo[tgt_i].min_value; | |
818 while (--tgt_i >= 0) | |
819 { | |
820 tmp_histo[tgt_i].num_counters | |
821 += tgt_histo[tgt_i].num_counters; | |
822 tmp_histo[tgt_i].cum_value += tgt_histo[tgt_i].cum_value; | |
823 if (!tmp_histo[tgt_i].min_value || | |
824 tgt_histo[tgt_i].min_value | |
825 < tmp_histo[tgt_i].min_value) | |
826 tmp_histo[tgt_i].min_value = tgt_histo[tgt_i].min_value; | |
827 } | |
828 | |
829 src_done = 1; | |
830 break; | |
831 } | |
832 | |
833 src_num = src_histo[src_i].num_counters; | |
834 src_cum = src_histo[src_i].cum_value; | |
835 } | |
836 | |
837 /* The number of counters to merge on this pass is the minimum | |
838 of the remaining counters from the current target and source | |
839 histogram entries. */ | |
840 merge_num = tgt_num; | |
841 if (src_num < merge_num) | |
842 merge_num = src_num; | |
843 | |
844 /* The merged min_value is the sum of the min_values from target | |
845 and source. */ | |
846 merge_min = tgt_histo[tgt_i].min_value + src_histo[src_i].min_value; | |
847 | |
848 /* Compute the portion of source and target entries' cum_value | |
849 that will be apportioned to the counters being merged. | |
850 The total remaining cum_value from each entry is divided | |
851 equally among the counters from that histogram entry if we | |
852 are not merging all of them. */ | |
853 merge_src_cum = src_cum; | |
854 if (merge_num < src_num) | |
855 merge_src_cum = merge_num * src_cum / src_num; | |
856 merge_tgt_cum = tgt_cum; | |
857 if (merge_num < tgt_num) | |
858 merge_tgt_cum = merge_num * tgt_cum / tgt_num; | |
859 /* The merged cum_value is the sum of the source and target | |
860 components. */ | |
861 merge_cum = merge_src_cum + merge_tgt_cum; | |
862 | |
863 /* Update the remaining number of counters and cum_value left | |
864 to be merged from this source and target entry. */ | |
865 src_cum -= merge_src_cum; | |
866 tgt_cum -= merge_tgt_cum; | |
867 src_num -= merge_num; | |
868 tgt_num -= merge_num; | |
869 | |
870 /* The merged counters get placed in the new merged histogram | |
871 at the entry for the merged min_value. */ | |
872 tmp_i = gcov_histo_index (merge_min); | |
873 gcov_nonruntime_assert (tmp_i < GCOV_HISTOGRAM_SIZE); | |
874 tmp_histo[tmp_i].num_counters += merge_num; | |
875 tmp_histo[tmp_i].cum_value += merge_cum; | |
876 if (!tmp_histo[tmp_i].min_value || | |
877 merge_min < tmp_histo[tmp_i].min_value) | |
878 tmp_histo[tmp_i].min_value = merge_min; | |
879 | |
880 /* Ensure the search for the next non-zero src_histo entry starts | |
881 at the next smallest histogram bucket. */ | |
882 if (!src_num) | |
883 src_i--; | |
884 } | |
885 } | |
886 | |
887 gcov_nonruntime_assert (tgt_i < 0); | |
888 | |
889 /* In the case where there were more counters in the source histogram, | |
890 accumulate the remaining unmerged cumulative counter values. Add | |
891 those to the smallest non-zero target histogram entry. Otherwise, | |
892 the total cumulative counter values in the histogram will be smaller | |
893 than the sum_all stored in the summary, which will complicate | |
894 computing the working set information from the histogram later on. */ | |
895 if (src_num) | |
896 src_i--; | |
897 while (src_i >= 0) | |
898 { | |
899 src_cum += src_histo[src_i].cum_value; | |
900 src_i--; | |
901 } | |
902 /* At this point, tmp_i should be the smallest non-zero entry in the | |
903 tmp_histo. */ | |
904 gcov_nonruntime_assert (tmp_i >= 0 && tmp_i < GCOV_HISTOGRAM_SIZE | |
905 && tmp_histo[tmp_i].num_counters > 0); | |
906 tmp_histo[tmp_i].cum_value += src_cum; | |
907 | |
908 /* Finally, copy the merged histogram into tgt_histo. */ | |
909 memcpy (tgt_histo, tmp_histo, | |
910 sizeof (gcov_bucket_type) * GCOV_HISTOGRAM_SIZE); | |
911 } | |
912 #endif /* !IN_GCOV */ | |
913 | |
914 /* This is used by gcov-dump (IN_GCOV == -1) and in the compiler | |
915 (!IN_GCOV && !IN_LIBGCOV). */ | |
916 #if IN_GCOV <= 0 && !IN_LIBGCOV | |
917 /* Compute the working set information from the counter histogram in | |
918 the profile summary. This is an array of information corresponding to a | |
919 range of percentages of the total execution count (sum_all), and includes | |
920 the number of counters required to cover that working set percentage and | |
921 the minimum counter value in that working set. */ | |
922 | |
923 GCOV_LINKAGE void | |
924 compute_working_sets (const struct gcov_ctr_summary *summary, | |
925 gcov_working_set_t *gcov_working_sets) | |
926 { | |
927 gcov_type working_set_cum_values[NUM_GCOV_WORKING_SETS]; | |
928 gcov_type ws_cum_hotness_incr; | |
929 gcov_type cum, tmp_cum; | |
930 const gcov_bucket_type *histo_bucket; | |
931 unsigned ws_ix, c_num, count; | |
932 int h_ix; | |
933 | |
934 /* Compute the amount of sum_all that the cumulative hotness grows | |
935 by in each successive working set entry, which depends on the | |
936 number of working set entries. */ | |
937 ws_cum_hotness_incr = summary->sum_all / NUM_GCOV_WORKING_SETS; | |
938 | |
939 /* Next fill in an array of the cumulative hotness values corresponding | |
940 to each working set summary entry we are going to compute below. | |
941 Skip 0% statistics, which can be extrapolated from the | |
942 rest of the summary data. */ | |
943 cum = ws_cum_hotness_incr; | |
944 for (ws_ix = 0; ws_ix < NUM_GCOV_WORKING_SETS; | |
945 ws_ix++, cum += ws_cum_hotness_incr) | |
946 working_set_cum_values[ws_ix] = cum; | |
947 /* The last summary entry is reserved for (roughly) 99.9% of the | |
948 working set. Divide by 1024 so it becomes a shift, which gives | |
949 almost exactly 99.9%. */ | |
950 working_set_cum_values[NUM_GCOV_WORKING_SETS-1] | |
951 = summary->sum_all - summary->sum_all/1024; | |
952 | |
953 /* Next, walk through the histogram in decending order of hotness | |
954 and compute the statistics for the working set summary array. | |
955 As histogram entries are accumulated, we check to see which | |
956 working set entries have had their expected cum_value reached | |
957 and fill them in, walking the working set entries in increasing | |
958 size of cum_value. */ | |
959 ws_ix = 0; /* The current entry into the working set array. */ | |
960 cum = 0; /* The current accumulated counter sum. */ | |
961 count = 0; /* The current accumulated count of block counters. */ | |
962 for (h_ix = GCOV_HISTOGRAM_SIZE - 1; | |
963 h_ix >= 0 && ws_ix < NUM_GCOV_WORKING_SETS; h_ix--) | |
964 { | |
965 histo_bucket = &summary->histogram[h_ix]; | |
966 | |
967 /* If we haven't reached the required cumulative counter value for | |
968 the current working set percentage, simply accumulate this histogram | |
969 entry into the running sums and continue to the next histogram | |
970 entry. */ | |
971 if (cum + histo_bucket->cum_value < working_set_cum_values[ws_ix]) | |
972 { | |
973 cum += histo_bucket->cum_value; | |
974 count += histo_bucket->num_counters; | |
975 continue; | |
976 } | |
977 | |
978 /* If adding the current histogram entry's cumulative counter value | |
979 causes us to exceed the current working set size, then estimate | |
980 how many of this histogram entry's counter values are required to | |
981 reach the working set size, and fill in working set entries | |
982 as we reach their expected cumulative value. */ | |
983 for (c_num = 0, tmp_cum = cum; | |
984 c_num < histo_bucket->num_counters && ws_ix < NUM_GCOV_WORKING_SETS; | |
985 c_num++) | |
986 { | |
987 count++; | |
988 /* If we haven't reached the last histogram entry counter, add | |
989 in the minimum value again. This will underestimate the | |
990 cumulative sum so far, because many of the counter values in this | |
991 entry may have been larger than the minimum. We could add in the | |
992 average value every time, but that would require an expensive | |
993 divide operation. */ | |
994 if (c_num + 1 < histo_bucket->num_counters) | |
995 tmp_cum += histo_bucket->min_value; | |
996 /* If we have reached the last histogram entry counter, then add | |
997 in the entire cumulative value. */ | |
998 else | |
999 tmp_cum = cum + histo_bucket->cum_value; | |
1000 | |
1001 /* Next walk through successive working set entries and fill in | |
1002 the statistics for any whose size we have reached by accumulating | |
1003 this histogram counter. */ | |
1004 while (ws_ix < NUM_GCOV_WORKING_SETS | |
1005 && tmp_cum >= working_set_cum_values[ws_ix]) | |
1006 { | |
1007 gcov_working_sets[ws_ix].num_counters = count; | |
1008 gcov_working_sets[ws_ix].min_counter | |
1009 = histo_bucket->min_value; | |
1010 ws_ix++; | |
1011 } | |
1012 } | |
1013 /* Finally, update the running cumulative value since we were | |
1014 using a temporary above. */ | |
1015 cum += histo_bucket->cum_value; | |
1016 } | |
1017 gcov_nonruntime_assert (ws_ix == NUM_GCOV_WORKING_SETS); | |
1018 } | |
1019 #endif /* IN_GCOV <= 0 && !IN_LIBGCOV */ |