OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gcc-4.5.1/] [gcc/] [libgcov.c] - Blame information for rev 859

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 280 jeremybenn
/* 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, 2004, 2005, 2008, 2009
5
   Free Software Foundation, Inc.
6
 
7
This file is part of GCC.
8
 
9
GCC is free software; you can redistribute it and/or modify it under
10
the terms of the GNU General Public License as published by the Free
11
Software Foundation; either version 3, or (at your option) any later
12
version.
13
 
14
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15
WARRANTY; without even the implied warranty of MERCHANTABILITY or
16
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17
for more details.
18
 
19
Under Section 7 of GPL version 3, you are granted additional
20
permissions described in the GCC Runtime Library Exception, version
21
3.1, as published by the Free Software Foundation.
22
 
23
You should have received a copy of the GNU General Public License and
24
a copy of the GCC Runtime Library Exception along with this program;
25
see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
26
<http://www.gnu.org/licenses/>.  */
27
 
28
#include "tconfig.h"
29
#include "tsystem.h"
30
#include "coretypes.h"
31
#include "tm.h"
32
 
33
#if defined(inhibit_libc)
34
#define IN_LIBGCOV (-1)
35
#else
36
#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
37
#include <stdio.h>
38
#define IN_LIBGCOV 1
39
#if defined(L_gcov)
40
#define GCOV_LINKAGE /* nothing */
41
#endif
42
#endif
43
#include "gcov-io.h"
44
 
45
#if defined(inhibit_libc)
46
/* If libc and its header files are not available, provide dummy functions.  */
47
 
48
#ifdef L_gcov
49
void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
50
void __gcov_flush (void) {}
51
#endif
52
 
53
#ifdef L_gcov_merge_add
54
void __gcov_merge_add (gcov_type *counters  __attribute__ ((unused)),
55
                       unsigned n_counters __attribute__ ((unused))) {}
56
#endif
57
 
58
#ifdef L_gcov_merge_single
59
void __gcov_merge_single (gcov_type *counters  __attribute__ ((unused)),
60
                          unsigned n_counters __attribute__ ((unused))) {}
61
#endif
62
 
63
#ifdef L_gcov_merge_delta
64
void __gcov_merge_delta (gcov_type *counters  __attribute__ ((unused)),
65
                         unsigned n_counters __attribute__ ((unused))) {}
66
#endif
67
 
68
#else
69
 
70
#include <string.h>
71
#if GCOV_LOCKED
72
#include <fcntl.h>
73
#include <errno.h>
74
#include <sys/stat.h>
75
#endif
76
 
77
#ifdef L_gcov
78
#include "gcov-io.c"
79
 
80
/* Chain of per-object gcov structures.  */
81
static struct gcov_info *gcov_list;
82
 
83
/* A program checksum allows us to distinguish program data for an
84
   object file included in multiple programs.  */
85
static gcov_unsigned_t gcov_crc32;
86
 
87
/* Size of the longest file name. */
88
static size_t gcov_max_filename = 0;
89
 
90
#ifdef TARGET_POSIX_IO
91
/* Make sure path component of the given FILENAME exists, create
92
   missing directories. FILENAME must be writable.
93
   Returns zero on success, or -1 if an error occurred.  */
94
 
95
static int
96
create_file_directory (char *filename)
97
{
98
  char *s;
99
 
100
  for (s = filename + 1; *s != '\0'; s++)
101
    if (IS_DIR_SEPARATOR(*s))
102
      {
103
        char sep = *s;
104
        *s  = '\0';
105
 
106
        /* Try to make directory if it doesn't already exist.  */
107
        if (access (filename, F_OK) == -1
108
            && mkdir (filename, 0755) == -1
109
            /* The directory might have been made by another process.  */
110
            && errno != EEXIST)
111
          {
112
            fprintf (stderr, "profiling:%s:Cannot create directory\n",
113
                     filename);
114
            *s = sep;
115
            return -1;
116
          };
117
 
118
        *s = sep;
119
      };
120
  return 0;
121
}
122
#endif
123
 
124
/* Check if VERSION of the info block PTR matches libgcov one.
125
   Return 1 on success, or zero in case of versions mismatch.
126
   If FILENAME is not NULL, its value used for reporting purposes
127
   instead of value from the info block.  */
128
 
129
static int
130
gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
131
              const char *filename)
132
{
133
  if (version != GCOV_VERSION)
134
    {
135
      char v[4], e[4];
136
 
137
      GCOV_UNSIGNED2STRING (v, version);
138
      GCOV_UNSIGNED2STRING (e, GCOV_VERSION);
139
 
140
      fprintf (stderr,
141
               "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
142
               filename? filename : ptr->filename, e, v);
143
      return 0;
144
    }
145
  return 1;
146
}
147
 
148
/* Dump the coverage counts. We merge with existing counts when
149
   possible, to avoid growing the .da files ad infinitum. We use this
150
   program's checksum to make sure we only accumulate whole program
151
   statistics to the correct summary. An object file might be embedded
152
   in two separate programs, and we must keep the two program
153
   summaries separate.  */
154
 
155
static void
156
gcov_exit (void)
157
{
158
  struct gcov_info *gi_ptr;
159
  struct gcov_summary this_program;
160
  struct gcov_summary all;
161
  struct gcov_ctr_summary *cs_ptr;
162
  const struct gcov_ctr_info *ci_ptr;
163
  unsigned t_ix;
164
  gcov_unsigned_t c_num;
165
  const char *gcov_prefix;
166
  int gcov_prefix_strip = 0;
167
  size_t prefix_length;
168
  char *gi_filename, *gi_filename_up;
169
 
170
  memset (&all, 0, sizeof (all));
171
  /* Find the totals for this execution.  */
172
  memset (&this_program, 0, sizeof (this_program));
173
  for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
174
    {
175
      ci_ptr = gi_ptr->counts;
176
      for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
177
        {
178
          if (!((1 << t_ix) & gi_ptr->ctr_mask))
179
            continue;
180
 
181
          cs_ptr = &this_program.ctrs[t_ix];
182
          cs_ptr->num += ci_ptr->num;
183
          for (c_num = 0; c_num < ci_ptr->num; c_num++)
184
            {
185
              cs_ptr->sum_all += ci_ptr->values[c_num];
186
              if (cs_ptr->run_max < ci_ptr->values[c_num])
187
                cs_ptr->run_max = ci_ptr->values[c_num];
188
            }
189
          ci_ptr++;
190
        }
191
    }
192
 
193
  /* Get file name relocation prefix.  Non-absolute values are ignored. */
194
  gcov_prefix = getenv("GCOV_PREFIX");
195
  if (gcov_prefix && IS_ABSOLUTE_PATH (gcov_prefix))
196
    {
197
      /* Check if the level of dirs to strip off specified. */
198
      char *tmp = getenv("GCOV_PREFIX_STRIP");
199
      if (tmp)
200
        {
201
          gcov_prefix_strip = atoi (tmp);
202
          /* Do not consider negative values. */
203
          if (gcov_prefix_strip < 0)
204
            gcov_prefix_strip = 0;
205
        }
206
 
207
      prefix_length = strlen(gcov_prefix);
208
 
209
      /* Remove an unnecessary trailing '/' */
210
      if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1]))
211
        prefix_length--;
212
    }
213
  else
214
    prefix_length = 0;
215
 
216
  /* Allocate and initialize the filename scratch space.  */
217
  gi_filename = (char *) alloca (prefix_length + gcov_max_filename + 1);
218
  if (prefix_length)
219
    memcpy (gi_filename, gcov_prefix, prefix_length);
220
  gi_filename_up = gi_filename + prefix_length;
221
 
222
  /* Now merge each file.  */
223
  for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
224
    {
225
      struct gcov_summary this_object;
226
      struct gcov_summary object, program;
227
      gcov_type *values[GCOV_COUNTERS];
228
      const struct gcov_fn_info *fi_ptr;
229
      unsigned fi_stride;
230
      unsigned c_ix, f_ix, n_counts;
231
      struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
232
      int error = 0;
233
      gcov_unsigned_t tag, length;
234
      gcov_position_t summary_pos = 0;
235
      gcov_position_t eof_pos = 0;
236
 
237
      memset (&this_object, 0, sizeof (this_object));
238
      memset (&object, 0, sizeof (object));
239
 
240
      /* Build relocated filename, stripping off leading
241
         directories from the initial filename if requested. */
242
      if (gcov_prefix_strip > 0)
243
        {
244
          int level = 0;
245
          const char *fname = gi_ptr->filename;
246
          const char *s;
247
 
248
          /* Skip selected directory levels. */
249
          for (s = fname + 1; (*s != '\0') && (level < gcov_prefix_strip); s++)
250
            if (IS_DIR_SEPARATOR(*s))
251
              {
252
                fname = s;
253
                level++;
254
              };
255
 
256
          /* Update complete filename with stripped original. */
257
          strcpy (gi_filename_up, fname);
258
        }
259
      else
260
        strcpy (gi_filename_up, gi_ptr->filename);
261
 
262
      /* Totals for this object file.  */
263
      ci_ptr = gi_ptr->counts;
264
      for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
265
        {
266
          if (!((1 << t_ix) & gi_ptr->ctr_mask))
267
            continue;
268
 
269
          cs_ptr = &this_object.ctrs[t_ix];
270
          cs_ptr->num += ci_ptr->num;
271
          for (c_num = 0; c_num < ci_ptr->num; c_num++)
272
            {
273
              cs_ptr->sum_all += ci_ptr->values[c_num];
274
              if (cs_ptr->run_max < ci_ptr->values[c_num])
275
                cs_ptr->run_max = ci_ptr->values[c_num];
276
            }
277
 
278
          ci_ptr++;
279
        }
280
 
281
      c_ix = 0;
282
      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
283
        if ((1 << t_ix) & gi_ptr->ctr_mask)
284
          {
285
            values[c_ix] = gi_ptr->counts[c_ix].values;
286
            c_ix++;
287
          }
288
 
289
      /* Calculate the function_info stride. This depends on the
290
         number of counter types being measured.  */
291
      fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
292
      if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
293
        {
294
          fi_stride += __alignof__ (struct gcov_fn_info) - 1;
295
          fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
296
        }
297
 
298
      if (!gcov_open (gi_filename))
299
        {
300
#ifdef TARGET_POSIX_IO
301
          /* Open failed likely due to missed directory.
302
             Create directory and retry to open file. */
303
          if (create_file_directory (gi_filename))
304
            {
305
              fprintf (stderr, "profiling:%s:Skip\n", gi_filename);
306
              continue;
307
            }
308
#endif
309
          if (!gcov_open (gi_filename))
310
            {
311
              fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
312
              continue;
313
            }
314
        }
315
 
316
      tag = gcov_read_unsigned ();
317
      if (tag)
318
        {
319
          /* Merge data from file.  */
320
          if (tag != GCOV_DATA_MAGIC)
321
            {
322
              fprintf (stderr, "profiling:%s:Not a gcov data file\n",
323
                       gi_filename);
324
              goto read_fatal;
325
            }
326
          length = gcov_read_unsigned ();
327
          if (!gcov_version (gi_ptr, length, gi_filename))
328
            goto read_fatal;
329
 
330
          length = gcov_read_unsigned ();
331
          if (length != gi_ptr->stamp)
332
            /* Read from a different compilation. Overwrite the file.  */
333
            goto rewrite;
334
 
335
          /* Merge execution counts for each function.  */
336
          for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
337
            {
338
              fi_ptr = (const struct gcov_fn_info *)
339
                      ((const char *) gi_ptr->functions + f_ix * fi_stride);
340
              tag = gcov_read_unsigned ();
341
              length = gcov_read_unsigned ();
342
 
343
              /* Check function.  */
344
              if (tag != GCOV_TAG_FUNCTION
345
                  || length != GCOV_TAG_FUNCTION_LENGTH
346
                  || gcov_read_unsigned () != fi_ptr->ident
347
                  || gcov_read_unsigned () != fi_ptr->checksum)
348
                {
349
                read_mismatch:;
350
                  fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
351
                           gi_filename,
352
                           f_ix + 1 ? "function" : "summaries");
353
                  goto read_fatal;
354
                }
355
 
356
              c_ix = 0;
357
              for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
358
                {
359
                  gcov_merge_fn merge;
360
 
361
                  if (!((1 << t_ix) & gi_ptr->ctr_mask))
362
                    continue;
363
 
364
                  n_counts = fi_ptr->n_ctrs[c_ix];
365
                  merge = gi_ptr->counts[c_ix].merge;
366
 
367
                  tag = gcov_read_unsigned ();
368
                  length = gcov_read_unsigned ();
369
                  if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
370
                      || length != GCOV_TAG_COUNTER_LENGTH (n_counts))
371
                    goto read_mismatch;
372
                  (*merge) (values[c_ix], n_counts);
373
                  values[c_ix] += n_counts;
374
                  c_ix++;
375
                }
376
              if ((error = gcov_is_error ()))
377
                goto read_error;
378
            }
379
 
380
          f_ix = ~0u;
381
          /* Check program & object summary */
382
          while (1)
383
            {
384
              int is_program;
385
 
386
              eof_pos = gcov_position ();
387
              tag = gcov_read_unsigned ();
388
              if (!tag)
389
                break;
390
 
391
              length = gcov_read_unsigned ();
392
              is_program = tag == GCOV_TAG_PROGRAM_SUMMARY;
393
              if (length != GCOV_TAG_SUMMARY_LENGTH
394
                  || (!is_program && tag != GCOV_TAG_OBJECT_SUMMARY))
395
                goto read_mismatch;
396
              gcov_read_summary (is_program ? &program : &object);
397
              if ((error = gcov_is_error ()))
398
                goto read_error;
399
              if (is_program && program.checksum == gcov_crc32)
400
                {
401
                  summary_pos = eof_pos;
402
                  goto rewrite;
403
                }
404
            }
405
        }
406
      goto rewrite;
407
 
408
    read_error:;
409
      fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
410
               : "profiling:%s:Error merging\n", gi_filename);
411
 
412
    read_fatal:;
413
      gcov_close ();
414
      continue;
415
 
416
    rewrite:;
417
      gcov_rewrite ();
418
      if (!summary_pos)
419
        memset (&program, 0, sizeof (program));
420
 
421
      /* Merge the summaries.  */
422
      f_ix = ~0u;
423
      for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
424
        {
425
          cs_obj = &object.ctrs[t_ix];
426
          cs_tobj = &this_object.ctrs[t_ix];
427
          cs_prg = &program.ctrs[t_ix];
428
          cs_tprg = &this_program.ctrs[t_ix];
429
          cs_all = &all.ctrs[t_ix];
430
 
431
          if ((1 << t_ix) & gi_ptr->ctr_mask)
432
            {
433
              if (!cs_obj->runs++)
434
                cs_obj->num = cs_tobj->num;
435
              else if (cs_obj->num != cs_tobj->num)
436
                goto read_mismatch;
437
              cs_obj->sum_all += cs_tobj->sum_all;
438
              if (cs_obj->run_max < cs_tobj->run_max)
439
                cs_obj->run_max = cs_tobj->run_max;
440
              cs_obj->sum_max += cs_tobj->run_max;
441
 
442
              if (!cs_prg->runs++)
443
                cs_prg->num = cs_tprg->num;
444
              else if (cs_prg->num != cs_tprg->num)
445
                goto read_mismatch;
446
              cs_prg->sum_all += cs_tprg->sum_all;
447
              if (cs_prg->run_max < cs_tprg->run_max)
448
                cs_prg->run_max = cs_tprg->run_max;
449
              cs_prg->sum_max += cs_tprg->run_max;
450
            }
451
          else if (cs_obj->num || cs_prg->num)
452
            goto read_mismatch;
453
 
454
          if (!cs_all->runs && cs_prg->runs)
455
            memcpy (cs_all, cs_prg, sizeof (*cs_all));
456
          else if (!all.checksum
457
                   && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
458
                   && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
459
            {
460
              fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
461
                       gi_filename, GCOV_LOCKED
462
                       ? "" : " or concurrent update without locking support");
463
              all.checksum = ~0u;
464
            }
465
        }
466
 
467
      c_ix = 0;
468
      for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
469
        if ((1 << t_ix) & gi_ptr->ctr_mask)
470
          {
471
            values[c_ix] = gi_ptr->counts[c_ix].values;
472
            c_ix++;
473
          }
474
 
475
      program.checksum = gcov_crc32;
476
 
477
      /* Write out the data.  */
478
      gcov_write_tag_length (GCOV_DATA_MAGIC, GCOV_VERSION);
479
      gcov_write_unsigned (gi_ptr->stamp);
480
 
481
      /* Write execution counts for each function.  */
482
      for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
483
        {
484
          fi_ptr = (const struct gcov_fn_info *)
485
                  ((const char *) gi_ptr->functions + f_ix * fi_stride);
486
 
487
          /* Announce function.  */
488
          gcov_write_tag_length (GCOV_TAG_FUNCTION, GCOV_TAG_FUNCTION_LENGTH);
489
          gcov_write_unsigned (fi_ptr->ident);
490
          gcov_write_unsigned (fi_ptr->checksum);
491
 
492
          c_ix = 0;
493
          for (t_ix = 0; t_ix < GCOV_COUNTERS; t_ix++)
494
            {
495
              gcov_type *c_ptr;
496
 
497
              if (!((1 << t_ix) & gi_ptr->ctr_mask))
498
                continue;
499
 
500
              n_counts = fi_ptr->n_ctrs[c_ix];
501
 
502
              gcov_write_tag_length (GCOV_TAG_FOR_COUNTER (t_ix),
503
                                     GCOV_TAG_COUNTER_LENGTH (n_counts));
504
              c_ptr = values[c_ix];
505
              while (n_counts--)
506
                gcov_write_counter (*c_ptr++);
507
 
508
              values[c_ix] = c_ptr;
509
              c_ix++;
510
            }
511
        }
512
 
513
      /* Object file summary.  */
514
      gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
515
 
516
      /* Generate whole program statistics.  */
517
      if (eof_pos)
518
        gcov_seek (eof_pos);
519
      gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
520
      if (!summary_pos)
521
        gcov_write_unsigned (0);
522
      if ((error = gcov_close ()))
523
          fprintf (stderr, error  < 0 ?
524
                   "profiling:%s:Overflow writing\n" :
525
                   "profiling:%s:Error writing\n",
526
                   gi_filename);
527
    }
528
}
529
 
530
/* Add a new object file onto the bb chain.  Invoked automatically
531
   when running an object file's global ctors.  */
532
 
533
void
534
__gcov_init (struct gcov_info *info)
535
{
536
  if (!info->version)
537
    return;
538
  if (gcov_version (info, info->version, 0))
539
    {
540
      const char *ptr = info->filename;
541
      gcov_unsigned_t crc32 = gcov_crc32;
542
      size_t filename_length =  strlen(info->filename);
543
 
544
      /* Refresh the longest file name information */
545
      if (filename_length > gcov_max_filename)
546
        gcov_max_filename = filename_length;
547
 
548
      do
549
        {
550
          unsigned ix;
551
          gcov_unsigned_t value = *ptr << 24;
552
 
553
          for (ix = 8; ix--; value <<= 1)
554
            {
555
              gcov_unsigned_t feedback;
556
 
557
              feedback = (value ^ crc32) & 0x80000000 ? 0x04c11db7 : 0;
558
              crc32 <<= 1;
559
              crc32 ^= feedback;
560
            }
561
        }
562
      while (*ptr++);
563
 
564
      gcov_crc32 = crc32;
565
 
566
      if (!gcov_list)
567
        atexit (gcov_exit);
568
 
569
      info->next = gcov_list;
570
      gcov_list = info;
571
    }
572
  info->version = 0;
573
}
574
 
575
/* Called before fork or exec - write out profile information gathered so
576
   far and reset it to zero.  This avoids duplication or loss of the
577
   profile information gathered so far.  */
578
 
579
void
580
__gcov_flush (void)
581
{
582
  const struct gcov_info *gi_ptr;
583
 
584
  gcov_exit ();
585
  for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
586
    {
587
      unsigned t_ix;
588
      const struct gcov_ctr_info *ci_ptr;
589
 
590
      for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
591
        if ((1 << t_ix) & gi_ptr->ctr_mask)
592
          {
593
            memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
594
            ci_ptr++;
595
          }
596
    }
597
}
598
 
599
#endif /* L_gcov */
600
 
601
#ifdef L_gcov_merge_add
602
/* The profile merging function that just adds the counters.  It is given
603
   an array COUNTERS of N_COUNTERS old counters and it reads the same number
604
   of counters from the gcov file.  */
605
void
606
__gcov_merge_add (gcov_type *counters, unsigned n_counters)
607
{
608
  for (; n_counters; counters++, n_counters--)
609
    *counters += gcov_read_counter ();
610
}
611
#endif /* L_gcov_merge_add */
612
 
613
#ifdef L_gcov_merge_ior
614
/* The profile merging function that just adds the counters.  It is given
615
   an array COUNTERS of N_COUNTERS old counters and it reads the same number
616
   of counters from the gcov file.  */
617
void
618
__gcov_merge_ior (gcov_type *counters, unsigned n_counters)
619
{
620
  for (; n_counters; counters++, n_counters--)
621
    *counters |= gcov_read_counter ();
622
}
623
#endif
624
 
625
#ifdef L_gcov_merge_single
626
/* The profile merging function for choosing the most common value.
627
   It is given an array COUNTERS of N_COUNTERS old counters and it
628
   reads the same number of counters from the gcov file.  The counters
629
   are split into 3-tuples where the members of the tuple have
630
   meanings:
631
 
632
   -- the stored candidate on the most common value of the measured entity
633
   -- counter
634
   -- total number of evaluations of the value  */
635
void
636
__gcov_merge_single (gcov_type *counters, unsigned n_counters)
637
{
638
  unsigned i, n_measures;
639
  gcov_type value, counter, all;
640
 
641
  gcc_assert (!(n_counters % 3));
642
  n_measures = n_counters / 3;
643
  for (i = 0; i < n_measures; i++, counters += 3)
644
    {
645
      value = gcov_read_counter ();
646
      counter = gcov_read_counter ();
647
      all = gcov_read_counter ();
648
 
649
      if (counters[0] == value)
650
        counters[1] += counter;
651
      else if (counter > counters[1])
652
        {
653
          counters[0] = value;
654
          counters[1] = counter - counters[1];
655
        }
656
      else
657
        counters[1] -= counter;
658
      counters[2] += all;
659
    }
660
}
661
#endif /* L_gcov_merge_single */
662
 
663
#ifdef L_gcov_merge_delta
664
/* The profile merging function for choosing the most common
665
   difference between two consecutive evaluations of the value.  It is
666
   given an array COUNTERS of N_COUNTERS old counters and it reads the
667
   same number of counters from the gcov file.  The counters are split
668
   into 4-tuples where the members of the tuple have meanings:
669
 
670
   -- the last value of the measured entity
671
   -- the stored candidate on the most common difference
672
   -- counter
673
   -- total number of evaluations of the value  */
674
void
675
__gcov_merge_delta (gcov_type *counters, unsigned n_counters)
676
{
677
  unsigned i, n_measures;
678
  gcov_type value, counter, all;
679
 
680
  gcc_assert (!(n_counters % 4));
681
  n_measures = n_counters / 4;
682
  for (i = 0; i < n_measures; i++, counters += 4)
683
    {
684
      /* last = */ gcov_read_counter ();
685
      value = gcov_read_counter ();
686
      counter = gcov_read_counter ();
687
      all = gcov_read_counter ();
688
 
689
      if (counters[1] == value)
690
        counters[2] += counter;
691
      else if (counter > counters[2])
692
        {
693
          counters[1] = value;
694
          counters[2] = counter - counters[2];
695
        }
696
      else
697
        counters[2] -= counter;
698
      counters[3] += all;
699
    }
700
}
701
#endif /* L_gcov_merge_delta */
702
 
703
#ifdef L_gcov_interval_profiler
704
/* If VALUE is in interval <START, START + STEPS - 1>, then increases the
705
   corresponding counter in COUNTERS.  If the VALUE is above or below
706
   the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased
707
   instead.  */
708
 
709
void
710
__gcov_interval_profiler (gcov_type *counters, gcov_type value,
711
                          int start, unsigned steps)
712
{
713
  gcov_type delta = value - start;
714
  if (delta < 0)
715
    counters[steps + 1]++;
716
  else if (delta >= steps)
717
    counters[steps]++;
718
  else
719
    counters[delta]++;
720
}
721
#endif
722
 
723
#ifdef L_gcov_pow2_profiler
724
/* If VALUE is a power of two, COUNTERS[1] is incremented.  Otherwise
725
   COUNTERS[0] is incremented.  */
726
 
727
void
728
__gcov_pow2_profiler (gcov_type *counters, gcov_type value)
729
{
730
  if (value & (value - 1))
731
    counters[0]++;
732
  else
733
    counters[1]++;
734
}
735
#endif
736
 
737
/* Tries to determine the most common value among its inputs.  Checks if the
738
   value stored in COUNTERS[0] matches VALUE.  If this is the case, COUNTERS[1]
739
   is incremented.  If this is not the case and COUNTERS[1] is not zero,
740
   COUNTERS[1] is decremented.  Otherwise COUNTERS[1] is set to one and
741
   VALUE is stored to COUNTERS[0].  This algorithm guarantees that if this
742
   function is called more than 50% of the time with one value, this value
743
   will be in COUNTERS[0] in the end.
744
 
745
   In any case, COUNTERS[2] is incremented.  */
746
 
747
static inline void
748
__gcov_one_value_profiler_body (gcov_type *counters, gcov_type value)
749
{
750
  if (value == counters[0])
751
    counters[1]++;
752
  else if (counters[1] == 0)
753
    {
754
      counters[1] = 1;
755
      counters[0] = value;
756
    }
757
  else
758
    counters[1]--;
759
  counters[2]++;
760
}
761
 
762
#ifdef L_gcov_one_value_profiler
763
void
764
__gcov_one_value_profiler (gcov_type *counters, gcov_type value)
765
{
766
  __gcov_one_value_profiler_body (counters, value);
767
}
768
#endif
769
 
770
#ifdef L_gcov_indirect_call_profiler
771
/* Tries to determine the most common value among its inputs. */
772
void
773
__gcov_indirect_call_profiler (gcov_type* counter, gcov_type value,
774
                               void* cur_func, void* callee_func)
775
{
776
  /* If the C++ virtual tables contain function descriptors then one
777
     function may have multiple descriptors and we need to dereference
778
     the descriptors to see if they point to the same function.  */
779
  if (cur_func == callee_func
780
      || (TARGET_VTABLE_USES_DESCRIPTORS && callee_func
781
          && *(void **) cur_func == *(void **) callee_func))
782
    __gcov_one_value_profiler_body (counter, value);
783
}
784
#endif
785
 
786
 
787
#ifdef L_gcov_average_profiler
788
/* Increase corresponding COUNTER by VALUE.  FIXME: Perhaps we want
789
   to saturate up.  */
790
 
791
void
792
__gcov_average_profiler (gcov_type *counters, gcov_type value)
793
{
794
  counters[0] += value;
795
  counters[1] ++;
796
}
797
#endif
798
 
799
#ifdef L_gcov_ior_profiler
800
/* Increase corresponding COUNTER by VALUE.  FIXME: Perhaps we want
801
   to saturate up.  */
802
 
803
void
804
__gcov_ior_profiler (gcov_type *counters, gcov_type value)
805
{
806
  *counters |= value;
807
}
808
#endif
809
 
810
#ifdef L_gcov_fork
811
/* A wrapper for the fork function.  Flushes the accumulated profiling data, so
812
   that they are not counted twice.  */
813
 
814
pid_t
815
__gcov_fork (void)
816
{
817
  __gcov_flush ();
818
  return fork ();
819
}
820
#endif
821
 
822
#ifdef L_gcov_execl
823
/* A wrapper for the execl function.  Flushes the accumulated profiling data, so
824
   that they are not lost.  */
825
 
826
int
827
__gcov_execl (const char *path, char *arg, ...)
828
{
829
  va_list ap, aq;
830
  unsigned i, length;
831
  char **args;
832
 
833
  __gcov_flush ();
834
 
835
  va_start (ap, arg);
836
  va_copy (aq, ap);
837
 
838
  length = 2;
839
  while (va_arg (ap, char *))
840
    length++;
841
  va_end (ap);
842
 
843
  args = (char **) alloca (length * sizeof (void *));
844
  args[0] = arg;
845
  for (i = 1; i < length; i++)
846
    args[i] = va_arg (aq, char *);
847
  va_end (aq);
848
 
849
  return execv (path, args);
850
}
851
#endif
852
 
853
#ifdef L_gcov_execlp
854
/* A wrapper for the execlp function.  Flushes the accumulated profiling data, so
855
   that they are not lost.  */
856
 
857
int
858
__gcov_execlp (const char *path, char *arg, ...)
859
{
860
  va_list ap, aq;
861
  unsigned i, length;
862
  char **args;
863
 
864
  __gcov_flush ();
865
 
866
  va_start (ap, arg);
867
  va_copy (aq, ap);
868
 
869
  length = 2;
870
  while (va_arg (ap, char *))
871
    length++;
872
  va_end (ap);
873
 
874
  args = (char **) alloca (length * sizeof (void *));
875
  args[0] = arg;
876
  for (i = 1; i < length; i++)
877
    args[i] = va_arg (aq, char *);
878
  va_end (aq);
879
 
880
  return execvp (path, args);
881
}
882
#endif
883
 
884
#ifdef L_gcov_execle
885
/* A wrapper for the execle function.  Flushes the accumulated profiling data, so
886
   that they are not lost.  */
887
 
888
int
889
__gcov_execle (const char *path, char *arg, ...)
890
{
891
  va_list ap, aq;
892
  unsigned i, length;
893
  char **args;
894
  char **envp;
895
 
896
  __gcov_flush ();
897
 
898
  va_start (ap, arg);
899
  va_copy (aq, ap);
900
 
901
  length = 2;
902
  while (va_arg (ap, char *))
903
    length++;
904
  va_end (ap);
905
 
906
  args = (char **) alloca (length * sizeof (void *));
907
  args[0] = arg;
908
  for (i = 1; i < length; i++)
909
    args[i] = va_arg (aq, char *);
910
  envp = va_arg (aq, char **);
911
  va_end (aq);
912
 
913
  return execve (path, args, envp);
914
}
915
#endif
916
 
917
#ifdef L_gcov_execv
918
/* A wrapper for the execv function.  Flushes the accumulated profiling data, so
919
   that they are not lost.  */
920
 
921
int
922
__gcov_execv (const char *path, char *const argv[])
923
{
924
  __gcov_flush ();
925
  return execv (path, argv);
926
}
927
#endif
928
 
929
#ifdef L_gcov_execvp
930
/* A wrapper for the execvp function.  Flushes the accumulated profiling data, so
931
   that they are not lost.  */
932
 
933
int
934
__gcov_execvp (const char *path, char *const argv[])
935
{
936
  __gcov_flush ();
937
  return execvp (path, argv);
938
}
939
#endif
940
 
941
#ifdef L_gcov_execve
942
/* A wrapper for the execve function.  Flushes the accumulated profiling data, so
943
   that they are not lost.  */
944
 
945
int
946
__gcov_execve (const char *path, char *const argv[], char *const envp[])
947
{
948
  __gcov_flush ();
949
  return execve (path, argv, envp);
950
}
951
#endif
952
#endif /* inhibit_libc */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.