]>
Commit | Line | Data |
---|---|---|
23af32e6 NS |
1 | /* Routines required for instrumenting a program. */ |
2 | /* Compile this one with gcc. */ | |
3 | /* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, | |
4 | 2000, 2001, 2002, 2003 Free Software Foundation, Inc. | |
5 | ||
6 | This file is part of GCC. | |
7 | ||
8 | GCC is free software; you can redistribute it and/or modify it under | |
9 | the terms of the GNU General Public License as published by the Free | |
10 | Software Foundation; either version 2, or (at your option) any later | |
11 | version. | |
12 | ||
13 | In addition to the permissions in the GNU General Public License, the | |
14 | Free Software Foundation gives you unlimited permission to link the | |
15 | compiled version of this file into combinations with other programs, | |
16 | and to distribute those combinations without any restriction coming | |
17 | from the use of this file. (The General Public License restrictions | |
18 | do apply in other respects; for example, they cover modification of | |
19 | the file, and distribution when not linked into a combine | |
20 | executable.) | |
21 | ||
22 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
23 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
24 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
25 | for more details. | |
26 | ||
27 | You should have received a copy of the GNU General Public License | |
28 | along with GCC; see the file COPYING. If not, write to the Free | |
29 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA | |
30 | 02111-1307, USA. */ | |
31 | ||
32 | /* It is incorrect to include config.h here, because this file is being | |
33 | compiled for the target, and hence definitions concerning only the host | |
34 | do not apply. */ | |
35 | ||
36 | #include "tconfig.h" | |
37 | #include "tsystem.h" | |
38 | #include "coretypes.h" | |
39 | #include "tm.h" | |
40 | ||
474f141e NS |
41 | #if defined(inhibit_libc) |
42 | #define IN_LIBGCOV (-1) | |
43 | #else | |
23af32e6 NS |
44 | #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */ |
45 | #include <stdio.h> | |
474f141e NS |
46 | #define IN_LIBGCOV 1 |
47 | #if defined(L_gcov) | |
48 | #define GCOV_LINKAGE /* nothing */ | |
49 | #endif | |
50 | #endif | |
51 | #include "gcov-io.h" | |
52 | ||
53 | #if defined(inhibit_libc) | |
54 | /* If libc and its header files are not available, provide dummy functions. */ | |
55 | ||
56 | #ifdef L_gcov | |
57 | void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {} | |
58 | void __gcov_flush (void) {} | |
59 | #endif | |
60 | ||
61 | #ifdef L_gcov_merge_add | |
62 | void __gcov_merge_add (gcov_type *counters __attribute__ ((unused)), | |
63 | unsigned n_counters __attribute__ ((unused))) {} | |
64 | #endif | |
65 | ||
af166e5d ZD |
66 | #ifdef L_gcov_merge_single |
67 | void __gcov_merge_single (gcov_type *counters __attribute__ ((unused)), | |
68 | unsigned n_counters __attribute__ ((unused))) {} | |
69 | #endif | |
70 | ||
71 | #ifdef L_gcov_merge_delta | |
72 | void __gcov_merge_delta (gcov_type *counters __attribute__ ((unused)), | |
73 | unsigned n_counters __attribute__ ((unused))) {} | |
74 | #endif | |
75 | ||
474f141e | 76 | #else |
23af32e6 | 77 | |
23af32e6 | 78 | #include <string.h> |
474f141e | 79 | #if GCOV_LOCKED |
23af32e6 NS |
80 | #include <fcntl.h> |
81 | #include <errno.h> | |
82 | #endif | |
09780dfb ZD |
83 | |
84 | #ifdef L_gcov | |
ca29da43 | 85 | #include "gcov-io.c" |
23af32e6 NS |
86 | |
87 | /* Chain of per-object gcov structures. */ | |
88 | static struct gcov_info *gcov_list; | |
89 | ||
90 | /* A program checksum allows us to distinguish program data for an | |
91 | object file included in multiple programs. */ | |
9b514d25 | 92 | static gcov_unsigned_t gcov_crc32; |
23af32e6 NS |
93 | |
94 | static void | |
9b514d25 | 95 | gcov_version_mismatch (struct gcov_info *ptr, gcov_unsigned_t version) |
23af32e6 | 96 | { |
9b514d25 | 97 | gcov_unsigned_t expected = GCOV_VERSION; |
23af32e6 NS |
98 | unsigned ix; |
99 | char e[4], v[4]; | |
100 | ||
101 | for (ix = 4; ix--; expected >>= 8, version >>= 8) | |
102 | { | |
103 | e[ix] = expected; | |
104 | v[ix] = version; | |
105 | } | |
106 | ||
107 | fprintf (stderr, | |
108 | "profiling:%s:Version mismatch - expected %.4s got %.4s\n", | |
109 | ptr->filename, e, v); | |
110 | } | |
111 | ||
112 | /* Dump the coverage counts. We merge with existing counts when | |
113 | possible, to avoid growing the .da files ad infinitum. We use this | |
114 | program's checksum to make sure we only accumulate whole program | |
115 | statistics to the correct summary. An object file might be embedded | |
116 | in two separate programs, and we must keep the two program | |
117 | summaries separate. */ | |
118 | ||
119 | static void | |
120 | gcov_exit (void) | |
121 | { | |
cdb23767 NS |
122 | struct gcov_info *gi_ptr; |
123 | struct gcov_summary this_program; | |
124 | struct gcov_summary all; | |
125 | ||
126 | memset (&all, 0, sizeof (all)); | |
127 | /* Find the totals for this execution. */ | |
128 | memset (&this_program, 0, sizeof (this_program)); | |
129 | for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) | |
d101590b | 130 | { |
cdb23767 NS |
131 | const struct gcov_ctr_info *ci_ptr; |
132 | struct gcov_ctr_summary *cs_ptr; | |
133 | unsigned t_ix; | |
134 | ||
135 | for (t_ix = 0, ci_ptr = gi_ptr->counts, cs_ptr = this_program.ctrs; | |
9b514d25 | 136 | t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++, cs_ptr++) |
cdb23767 NS |
137 | if ((1 << t_ix) & gi_ptr->ctr_mask) |
138 | { | |
139 | const gcov_type *c_ptr; | |
9b514d25 | 140 | gcov_unsigned_t c_num; |
cdb23767 NS |
141 | |
142 | cs_ptr->num += ci_ptr->num; | |
143 | for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++) | |
144 | { | |
145 | cs_ptr->sum_all += *c_ptr; | |
146 | if (cs_ptr->run_max < *c_ptr) | |
147 | cs_ptr->run_max = *c_ptr; | |
148 | } | |
149 | ci_ptr++; | |
150 | } | |
d101590b | 151 | } |
cdb23767 | 152 | |
f9da5064 | 153 | /* Now merge each file. */ |
cdb23767 | 154 | for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) |
23af32e6 | 155 | { |
cdb23767 NS |
156 | struct gcov_summary this_object; |
157 | struct gcov_summary object, program; | |
158 | gcov_type *values[GCOV_COUNTERS]; | |
159 | const struct gcov_fn_info *fi_ptr; | |
160 | unsigned fi_stride; | |
161 | unsigned c_ix, t_ix, f_ix; | |
162 | const struct gcov_ctr_info *ci_ptr; | |
163 | struct gcov_ctr_summary *cs_ptr; | |
164 | struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all; | |
7d63a2fa | 165 | int error = 0; |
546d2adb | 166 | int merging; |
9b514d25 | 167 | gcov_unsigned_t tag, length; |
7d63a2fa | 168 | gcov_position_t summary_pos = 0; |
cdb23767 NS |
169 | |
170 | /* Totals for this object file. */ | |
171 | memset (&this_object, 0, sizeof (this_object)); | |
172 | for (t_ix = c_ix = 0, | |
173 | ci_ptr = gi_ptr->counts, cs_ptr = this_object.ctrs; | |
9b514d25 | 174 | t_ix != GCOV_COUNTERS_SUMMABLE; t_ix++, cs_ptr++) |
cdb23767 NS |
175 | if ((1 << t_ix) & gi_ptr->ctr_mask) |
176 | { | |
177 | const gcov_type *c_ptr; | |
9b514d25 | 178 | gcov_unsigned_t c_num; |
cdb23767 NS |
179 | |
180 | cs_ptr->num += ci_ptr->num; | |
181 | values[c_ix] = ci_ptr->values; | |
182 | for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++) | |
183 | { | |
184 | cs_ptr->sum_all += *c_ptr; | |
185 | if (cs_ptr->run_max < *c_ptr) | |
186 | cs_ptr->run_max = *c_ptr; | |
187 | } | |
188 | c_ix++; | |
189 | ci_ptr++; | |
190 | } | |
191 | ||
192 | /* Calculate the function_info stride. This depends on the | |
193 | number of counter types being measured. */ | |
194 | fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned); | |
195 | if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned)) | |
cb9e4555 | 196 | { |
cdb23767 NS |
197 | fi_stride += __alignof__ (struct gcov_fn_info) - 1; |
198 | fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1); | |
cb9e4555 | 199 | } |
546d2adb | 200 | |
cdb23767 NS |
201 | /* Open for modification, if possible */ |
202 | merging = gcov_open (gi_ptr->filename, 0); | |
546d2adb | 203 | if (!merging) |
23af32e6 | 204 | { |
cdb23767 | 205 | fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename); |
23af32e6 NS |
206 | continue; |
207 | } | |
546d2adb NS |
208 | |
209 | if (merging > 0) | |
23af32e6 NS |
210 | { |
211 | /* Merge data from file. */ | |
94de45d9 | 212 | if (gcov_read_unsigned () != GCOV_DATA_MAGIC) |
23af32e6 NS |
213 | { |
214 | fprintf (stderr, "profiling:%s:Not a gcov data file\n", | |
cdb23767 | 215 | gi_ptr->filename); |
23af32e6 | 216 | read_fatal:; |
546d2adb | 217 | gcov_close (); |
23af32e6 NS |
218 | continue; |
219 | } | |
94de45d9 NS |
220 | length = gcov_read_unsigned (); |
221 | if (length != GCOV_VERSION) | |
23af32e6 | 222 | { |
cdb23767 | 223 | gcov_version_mismatch (gi_ptr, length); |
23af32e6 NS |
224 | goto read_fatal; |
225 | } | |
226 | ||
227 | /* Merge execution counts for each function. */ | |
796621e8 NS |
228 | for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; |
229 | f_ix--; | |
cdb23767 NS |
230 | fi_ptr = (const struct gcov_fn_info *) |
231 | ((const char *) fi_ptr + fi_stride)) | |
23af32e6 | 232 | { |
94de45d9 NS |
233 | tag = gcov_read_unsigned (); |
234 | length = gcov_read_unsigned (); | |
23af32e6 | 235 | |
f9da5064 | 236 | /* Check function. */ |
796621e8 | 237 | if (tag != GCOV_TAG_FUNCTION |
474f141e | 238 | || length != GCOV_TAG_FUNCTION_LENGTH |
796621e8 NS |
239 | || gcov_read_unsigned () != fi_ptr->ident |
240 | || gcov_read_unsigned () != fi_ptr->checksum) | |
23af32e6 NS |
241 | { |
242 | read_mismatch:; | |
cdb23767 NS |
243 | fprintf (stderr, "profiling:%s:Merge mismatch for %s\n", |
244 | gi_ptr->filename, | |
796621e8 | 245 | f_ix + 1 ? "function" : "summaries"); |
23af32e6 NS |
246 | goto read_fatal; |
247 | } | |
cb9e4555 | 248 | |
cdb23767 NS |
249 | for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++) |
250 | if ((1 << t_ix) & gi_ptr->ctr_mask) | |
251 | { | |
474f141e NS |
252 | unsigned n_counts = fi_ptr->n_ctrs[c_ix]; |
253 | gcov_merge_fn merge = gi_ptr->counts[c_ix].merge; | |
cdb23767 NS |
254 | |
255 | tag = gcov_read_unsigned (); | |
256 | length = gcov_read_unsigned (); | |
cdb23767 | 257 | if (tag != GCOV_TAG_FOR_COUNTER (t_ix) |
474f141e | 258 | || length != GCOV_TAG_COUNTER_LENGTH (n_counts)) |
cdb23767 | 259 | goto read_mismatch; |
09780dfb ZD |
260 | (*merge) (values[c_ix], n_counts); |
261 | values[c_ix] += n_counts; | |
cdb23767 | 262 | c_ix++; |
cb9e4555 | 263 | } |
94de45d9 NS |
264 | if ((error = gcov_is_error ())) |
265 | goto read_error; | |
23af32e6 NS |
266 | } |
267 | ||
474f141e | 268 | /* Check program & object summary */ |
7d63a2fa | 269 | while (1) |
23af32e6 | 270 | { |
9b514d25 | 271 | gcov_position_t base = gcov_position (); |
474f141e NS |
272 | int is_program; |
273 | ||
94de45d9 | 274 | tag = gcov_read_unsigned (); |
7d63a2fa NS |
275 | if (!tag) |
276 | break; | |
474f141e NS |
277 | length = gcov_read_unsigned (); |
278 | is_program = tag == GCOV_TAG_PROGRAM_SUMMARY; | |
279 | if (length != GCOV_TAG_SUMMARY_LENGTH | |
280 | || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY)) | |
23af32e6 | 281 | goto read_mismatch; |
474f141e | 282 | gcov_read_summary (is_program ? &program : &object); |
94de45d9 | 283 | if ((error = gcov_is_error ())) |
7d63a2fa NS |
284 | goto read_error; |
285 | if (is_program && program.checksum == gcov_crc32) | |
94de45d9 | 286 | { |
7d63a2fa NS |
287 | summary_pos = base; |
288 | goto rewrite; | |
94de45d9 | 289 | } |
23af32e6 | 290 | } |
7d63a2fa NS |
291 | if (!gcov_is_eof ()) |
292 | { | |
293 | read_error:; | |
294 | fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n" | |
295 | : "profiling:%s:Error merging\n", gi_ptr->filename); | |
296 | goto read_fatal; | |
297 | } | |
298 | rewrite:; | |
474f141e | 299 | gcov_rewrite (); |
23af32e6 | 300 | } |
cdb23767 NS |
301 | else |
302 | memset (&object, 0, sizeof (object)); | |
7d63a2fa | 303 | if (!summary_pos) |
cdb23767 | 304 | memset (&program, 0, sizeof (program)); |
23af32e6 | 305 | |
cdb23767 | 306 | /* Merge the summaries. */ |
796621e8 | 307 | f_ix = ~0u; |
cdb23767 NS |
308 | for (t_ix = c_ix = 0, |
309 | cs_obj = object.ctrs, cs_tobj = this_object.ctrs, | |
310 | cs_prg = program.ctrs, cs_tprg = this_program.ctrs, | |
311 | cs_all = all.ctrs; | |
9b514d25 | 312 | t_ix != GCOV_COUNTERS_SUMMABLE; |
cdb23767 NS |
313 | t_ix++, cs_obj++, cs_tobj++, cs_prg++, cs_tprg++, cs_all++) |
314 | { | |
315 | if ((1 << t_ix) & gi_ptr->ctr_mask) | |
316 | { | |
317 | if (!cs_obj->runs++) | |
318 | cs_obj->num = cs_tobj->num; | |
319 | else if (cs_obj->num != cs_tobj->num) | |
320 | goto read_mismatch; | |
321 | cs_obj->sum_all += cs_tobj->sum_all; | |
322 | if (cs_obj->run_max < cs_tobj->run_max) | |
323 | cs_obj->run_max = cs_tobj->run_max; | |
324 | cs_obj->sum_max += cs_tobj->run_max; | |
325 | ||
326 | if (!cs_prg->runs++) | |
327 | cs_prg->num = cs_tprg->num; | |
328 | else if (cs_prg->num != cs_tprg->num) | |
329 | goto read_mismatch; | |
330 | cs_prg->sum_all += cs_tprg->sum_all; | |
331 | if (cs_prg->run_max < cs_tprg->run_max) | |
332 | cs_prg->run_max = cs_tprg->run_max; | |
333 | cs_prg->sum_max += cs_tprg->run_max; | |
334 | ||
335 | values[c_ix] = gi_ptr->counts[c_ix].values; | |
336 | c_ix++; | |
337 | } | |
338 | else if (cs_obj->num || cs_prg->num) | |
339 | goto read_mismatch; | |
340 | ||
341 | if (!cs_all->runs && cs_prg->runs) | |
342 | memcpy (cs_all, cs_prg, sizeof (*cs_all)); | |
343 | else if (!all.checksum | |
344 | && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs) | |
345 | && memcmp (cs_all, cs_prg, sizeof (*cs_all))) | |
346 | { | |
347 | fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s", | |
348 | gi_ptr->filename, GCOV_LOCKED | |
349 | ? "" : " or concurrent update without locking support"); | |
350 | all.checksum = ~0u; | |
351 | } | |
352 | } | |
353 | ||
354 | program.checksum = gcov_crc32; | |
23af32e6 NS |
355 | |
356 | /* Write out the data. */ | |
9b514d25 | 357 | gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION); |
23af32e6 NS |
358 | |
359 | /* Write execution counts for each function. */ | |
cdb23767 NS |
360 | for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--; |
361 | fi_ptr = (const struct gcov_fn_info *) | |
362 | ((const char *) fi_ptr + fi_stride)) | |
23af32e6 NS |
363 | { |
364 | /* Announce function. */ | |
474f141e | 365 | gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH); |
796621e8 | 366 | gcov_write_unsigned (fi_ptr->ident); |
cdb23767 | 367 | gcov_write_unsigned (fi_ptr->checksum); |
cb9e4555 | 368 | |
cdb23767 NS |
369 | for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++) |
370 | if ((1 << t_ix) & gi_ptr->ctr_mask) | |
371 | { | |
474f141e | 372 | unsigned n_counts = fi_ptr->n_ctrs[c_ix]; |
cdb23767 NS |
373 | gcov_type *c_ptr; |
374 | ||
474f141e NS |
375 | gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix), |
376 | GCOV_TAG_COUNTER_LENGTH (n_counts)); | |
cdb23767 | 377 | c_ptr = values[c_ix]; |
474f141e NS |
378 | while (n_counts--) |
379 | gcov_write_counter (*c_ptr++); | |
cdb23767 | 380 | values[c_ix] = c_ptr; |
cdb23767 NS |
381 | c_ix++; |
382 | } | |
23af32e6 NS |
383 | } |
384 | ||
385 | /* Object file summary. */ | |
94de45d9 | 386 | gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object); |
23af32e6 | 387 | |
d101590b | 388 | /* Generate whole program statistics. */ |
474f141e | 389 | gcov_seek (summary_pos); |
cdb23767 NS |
390 | gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program); |
391 | if ((error = gcov_close ())) | |
cdb23767 NS |
392 | fprintf (stderr, error < 0 ? |
393 | "profiling:%s:Overflow writing\n" : | |
394 | "profiling:%s:Error writing\n", | |
395 | gi_ptr->filename); | |
23af32e6 | 396 | } |
23af32e6 NS |
397 | } |
398 | ||
399 | /* Add a new object file onto the bb chain. Invoked automatically | |
400 | when running an object file's global ctors. */ | |
401 | ||
402 | void | |
403 | __gcov_init (struct gcov_info *info) | |
404 | { | |
405 | if (!info->version) | |
406 | return; | |
407 | if (info->version != GCOV_VERSION) | |
408 | gcov_version_mismatch (info, info->version); | |
409 | else | |
410 | { | |
411 | const char *ptr = info->filename; | |
9b514d25 | 412 | gcov_unsigned_t crc32 = gcov_crc32; |
23af32e6 NS |
413 | |
414 | do | |
415 | { | |
416 | unsigned ix; | |
9b514d25 | 417 | gcov_unsigned_t value = *ptr << 24; |
23af32e6 NS |
418 | |
419 | for (ix = 8; ix--; value <<= 1) | |
420 | { | |
9b514d25 | 421 | gcov_unsigned_t feedback; |
23af32e6 NS |
422 | |
423 | feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0; | |
424 | crc32 <<= 1; | |
425 | crc32 ^= feedback; | |
426 | } | |
427 | } | |
428 | while (*ptr++); | |
429 | ||
430 | gcov_crc32 = crc32; | |
431 | ||
432 | if (!gcov_list) | |
433 | atexit (gcov_exit); | |
434 | ||
435 | info->next = gcov_list; | |
436 | gcov_list = info; | |
437 | } | |
438 | info->version = 0; | |
439 | } | |
440 | ||
441 | /* Called before fork or exec - write out profile information gathered so | |
442 | far and reset it to zero. This avoids duplication or loss of the | |
443 | profile information gathered so far. */ | |
444 | ||
445 | void | |
446 | __gcov_flush (void) | |
447 | { | |
cdb23767 | 448 | const struct gcov_info *gi_ptr; |
23af32e6 NS |
449 | |
450 | gcov_exit (); | |
cdb23767 | 451 | for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next) |
23af32e6 | 452 | { |
cdb23767 NS |
453 | unsigned t_ix; |
454 | const struct gcov_ctr_info *ci_ptr; | |
23af32e6 | 455 | |
cdb23767 NS |
456 | for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++) |
457 | if ((1 << t_ix) & gi_ptr->ctr_mask) | |
458 | { | |
459 | memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num); | |
460 | ci_ptr++; | |
461 | } | |
23af32e6 NS |
462 | } |
463 | } | |
01e60c33 | 464 | |
09780dfb ZD |
465 | #endif /* L_gcov */ |
466 | ||
467 | #ifdef L_gcov_merge_add | |
468 | /* The profile merging function that just adds the counters. It is given | |
469 | an array COUNTERS of N_COUNTERS old counters and it reads the same number | |
470 | of counters from the gcov file. */ | |
471 | void | |
9b514d25 | 472 | __gcov_merge_add (gcov_type *counters, unsigned n_counters) |
09780dfb ZD |
473 | { |
474 | for (; n_counters; counters++, n_counters--) | |
475 | *counters += gcov_read_counter (); | |
476 | } | |
477 | #endif /* L_gcov_merge_add */ | |
478 | ||
af166e5d ZD |
479 | #ifdef L_gcov_merge_single |
480 | /* The profile merging function for choosing the most common value. It is given | |
481 | an array COUNTERS of N_COUNTERS old counters and it reads the same number | |
482 | of counters from the gcov file. The counters are split into 3-tuples | |
483 | where the members of the tuple have meanings: | |
484 | -- the stored candidate on the most common value of the measured entity | |
485 | -- counter | |
486 | -- total number of evaluations of the value */ | |
487 | void | |
488 | __gcov_merge_single (gcov_type *counters, unsigned n_counters) | |
489 | { | |
490 | unsigned i, n_measures; | |
491 | gcov_type value, counter, all; | |
492 | ||
493 | if (n_counters % 3) | |
494 | abort (); | |
495 | ||
496 | n_measures = n_counters / 3; | |
497 | for (i = 0; i < n_measures; i++, counters += 3) | |
498 | { | |
499 | value = gcov_read_counter (); | |
500 | counter = gcov_read_counter (); | |
501 | all = gcov_read_counter (); | |
502 | ||
503 | if (counters[0] == value) | |
504 | counters[1] += counter; | |
505 | else if (counter > counters[1]) | |
506 | { | |
507 | counters[0] = value; | |
508 | counters[1] = counter - counters[1]; | |
509 | } | |
510 | else | |
511 | counters[1] -= counter; | |
512 | counters[2] += all; | |
513 | } | |
514 | } | |
515 | #endif /* L_gcov_merge_single */ | |
516 | ||
517 | #ifdef L_gcov_merge_delta | |
518 | /* The profile merging function for choosing the most common difference between | |
519 | two consecutive evaluations of the value. It is given an array COUNTERS of | |
520 | N_COUNTERS old counters and it reads the same number of counters from the | |
521 | gcov file. The counters are split into 4-tuples where the members of the | |
522 | tuple have meanings: | |
523 | -- the last value of the measured entity | |
524 | -- the stored candidate on the most common difference | |
525 | -- counter | |
526 | -- total number of evaluations of the value */ | |
527 | void | |
528 | __gcov_merge_delta (gcov_type *counters, unsigned n_counters) | |
529 | { | |
530 | unsigned i, n_measures; | |
531 | gcov_type last, value, counter, all; | |
532 | ||
533 | if (n_counters % 4) | |
534 | abort (); | |
535 | ||
536 | n_measures = n_counters / 4; | |
537 | for (i = 0; i < n_measures; i++, counters += 4) | |
538 | { | |
539 | last = gcov_read_counter (); | |
540 | value = gcov_read_counter (); | |
541 | counter = gcov_read_counter (); | |
542 | all = gcov_read_counter (); | |
543 | ||
544 | if (counters[1] == value) | |
545 | counters[2] += counter; | |
546 | else if (counter > counters[2]) | |
547 | { | |
548 | counters[1] = value; | |
549 | counters[2] = counter - counters[2]; | |
550 | } | |
551 | else | |
552 | counters[2] -= counter; | |
553 | counters[3] += all; | |
554 | } | |
555 | } | |
556 | #endif /* L_gcov_merge_delta */ | |
557 | ||
01e60c33 | 558 | #endif /* inhibit_libc */ |