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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [newlib-1.17.0/] [libgloss/] [mep/] [mep-bb.c] - Blame information for rev 822

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

Line No. Rev Author Line
1 148 jeremybenn
/*
2
 * Copyright (c) 2000-2001  Red Hat, Inc. All rights reserved.
3
 *
4
 * This copyrighted material is made available to anyone wishing to use, modify,
5
 * copy, or redistribute it subject to the terms and conditions of the BSD
6
 * License.  This program is distributed in the hope that it will be useful,
7
 * but WITHOUT ANY WARRANTY expressed or implied, including the implied
8
 * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  A copy
9
 * of this license is available at http://www.opensource.org/licenses. Any
10
 * Red Hat trademarks that are incorporated in the source code or documentation
11
 * are not subject to the BSD License and may only be used or replicated with
12
 * the express permission of Red Hat, Inc.
13
 */
14
 
15
/* Structure emitted by -a  */
16
struct bb
17
{
18
  long zero_word;
19
  const char *filename;
20
  long *counts;
21
  long ncounts;
22
  struct bb *next;
23
  const unsigned long *addresses;
24
 
25
  /* Older GCC's did not emit these fields.  */
26
  long nwords;
27
  const char **functions;
28
  const long *line_nums;
29
  const char **filenames;
30
  char *flags;
31
};
32
 
33
/* Simple minded basic block profiling output dumper for
34
   systems that don't provide tcov support.  At present,
35
   it requires atexit and stdio.  */
36
 
37
#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
38
#include <stdio.h>
39
#include <time.h>
40
char *ctime (const time_t *);
41
 
42
/*#include "gbl-ctors.h"*/
43
#include "gcov-io.h"
44
#include <string.h>
45
 
46
static struct bb *bb_head;
47
 
48
static int num_digits (long value, int base) __attribute__ ((const));
49
 
50
/* Return the number of digits needed to print a value */
51
/* __inline__ */ static int num_digits (long value, int base)
52
{
53
  int minus = (value < 0 && base != 16);
54
  unsigned long v = (minus) ? -value : value;
55
  int ret = minus;
56
 
57
  do
58
    {
59
      v /= base;
60
      ret++;
61
    }
62
  while (v);
63
 
64
  return ret;
65
}
66
 
67
void
68
__bb_exit_func (void)
69
{
70
  FILE *da_file, *file;
71
  long time_value;
72
  int i;
73
 
74
  if (bb_head == 0)
75
    return;
76
 
77
  i = strlen (bb_head->filename) - 3;
78
 
79
  if (!strcmp (bb_head->filename+i, ".da"))
80
    {
81
      /* Must be -fprofile-arcs not -a.
82
         Dump data in a form that gcov expects.  */
83
 
84
      struct bb *ptr;
85
 
86
      for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
87
        {
88
          int firstchar;
89
 
90
          /* Make sure the output file exists -
91
             but don't clobber exiting data.  */
92
          if ((da_file = fopen (ptr->filename, "a")) != 0)
93
            fclose (da_file);
94
 
95
          /* Need to re-open in order to be able to write from the start.  */
96
          da_file = fopen (ptr->filename, "r+b");
97
          /* Some old systems might not allow the 'b' mode modifier.
98
             Therefore, try to open without it.  This can lead to a race
99
             condition so that when you delete and re-create the file, the
100
             file might be opened in text mode, but then, you shouldn't
101
             delete the file in the first place.  */
102
          if (da_file == 0)
103
            da_file = fopen (ptr->filename, "r+");
104
          if (da_file == 0)
105
            {
106
              fprintf (stderr, "arc profiling: Can't open output file %s.\n",
107
                       ptr->filename);
108
              continue;
109
            }
110
 
111
          /* After a fork, another process might try to read and/or write
112
             the same file simultanously.  So if we can, lock the file to
113
             avoid race conditions.  */
114
 
115
          /* If the file is not empty, and the number of counts in it is the
116
             same, then merge them in.  */
117
          firstchar = fgetc (da_file);
118
          if (firstchar == EOF)
119
            {
120
              if (ferror (da_file))
121
                {
122
                  fprintf (stderr, "arc profiling: Can't read output file ");
123
                  perror (ptr->filename);
124
                }
125
            }
126
          else
127
            {
128
              long n_counts = 0;
129
 
130
              if (ungetc (firstchar, da_file) == EOF)
131
                rewind (da_file);
132
              if (__read_long (&n_counts, da_file, 8) != 0)
133
                {
134
                  fprintf (stderr, "arc profiling: Can't read output file %s.\n",
135
                           ptr->filename);
136
                  continue;
137
                }
138
 
139
              if (n_counts == ptr->ncounts)
140
                {
141
                  int i;
142
 
143
                  for (i = 0; i < n_counts; i++)
144
                    {
145
                      long v = 0;
146
 
147
                      if (__read_long (&v, da_file, 8) != 0)
148
                        {
149
                          fprintf (stderr, "arc profiling: Can't read output file %s.\n",
150
                                   ptr->filename);
151
                          break;
152
                        }
153
                      ptr->counts[i] += v;
154
                    }
155
                }
156
 
157
            }
158
 
159
          rewind (da_file);
160
 
161
          /* ??? Should first write a header to the file.  Preferably, a 4 byte
162
             magic number, 4 bytes containing the time the program was
163
             compiled, 4 bytes containing the last modification time of the
164
             source file, and 4 bytes indicating the compiler options used.
165
 
166
             That way we can easily verify that the proper source/executable/
167
             data file combination is being used from gcov.  */
168
 
169
          if (__write_long (ptr->ncounts, da_file, 8) != 0)
170
            {
171
 
172
              fprintf (stderr, "arc profiling: Error writing output file %s.\n",
173
                       ptr->filename);
174
            }
175
          else
176
            {
177
              int j;
178
              long *count_ptr = ptr->counts;
179
              int ret = 0;
180
              for (j = ptr->ncounts; j > 0; j--)
181
                {
182
                  if (__write_long (*count_ptr, da_file, 8) != 0)
183
                    {
184
                      ret=1;
185
                      break;
186
                    }
187
                  count_ptr++;
188
                }
189
              if (ret)
190
                fprintf (stderr, "arc profiling: Error writing output file %s.\n",
191
                         ptr->filename);
192
            }
193
 
194
          if (fclose (da_file) == EOF)
195
            fprintf (stderr, "arc profiling: Error closing output file %s.\n",
196
                     ptr->filename);
197
        }
198
 
199
      return;
200
    }
201
 
202
  /* Must be basic block profiling.  Emit a human readable output file.  */
203
 
204
  file = fopen ("bb.out", "a");
205
 
206
  if (!file)
207
    perror ("bb.out");
208
 
209
  else
210
    {
211
      struct bb *ptr;
212
 
213
      /* This is somewhat type incorrect, but it avoids worrying about
214
         exactly where time.h is included from.  It should be ok unless
215
         a void * differs from other pointer formats, or if sizeof (long)
216
         is < sizeof (time_t).  It would be nice if we could assume the
217
         use of rationale standards here.  */
218
 
219
      time ((void *) &time_value);
220
      fprintf (file, "Basic block profiling finished on %s\n", ctime ((void *) &time_value));
221
 
222
      /* We check the length field explicitly in order to allow compatibility
223
         with older GCC's which did not provide it.  */
224
 
225
      for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
226
        {
227
          int i;
228
          int func_p    = (ptr->nwords >= (long) sizeof (struct bb)
229
                           && ptr->nwords <= 1000
230
                           && ptr->functions);
231
          int line_p    = (func_p && ptr->line_nums);
232
          int file_p    = (func_p && ptr->filenames);
233
          int addr_p    = (ptr->addresses != 0);
234
          long ncounts  = ptr->ncounts;
235
          long cnt_max  = 0;
236
          long line_max = 0;
237
          long addr_max = 0;
238
          int file_len  = 0;
239
          int func_len  = 0;
240
          int blk_len   = num_digits (ncounts, 10);
241
          int cnt_len;
242
          int line_len;
243
          int addr_len;
244
 
245
          fprintf (file, "File %s, %ld basic blocks \n\n",
246
                   ptr->filename, ncounts);
247
 
248
          /* Get max values for each field.  */
249
          for (i = 0; i < ncounts; i++)
250
            {
251
              const char *p;
252
              int len;
253
 
254
              if (cnt_max < ptr->counts[i])
255
                cnt_max = ptr->counts[i];
256
 
257
              if (addr_p && (unsigned long) addr_max < ptr->addresses[i])
258
                addr_max = ptr->addresses[i];
259
 
260
              if (line_p && line_max < ptr->line_nums[i])
261
                line_max = ptr->line_nums[i];
262
 
263
              if (func_p)
264
                {
265
                  p = (ptr->functions[i]) ? (ptr->functions[i]) : "<none>";
266
                  len = strlen (p);
267
                  if (func_len < len)
268
                    func_len = len;
269
                }
270
 
271
              if (file_p)
272
                {
273
                  p = (ptr->filenames[i]) ? (ptr->filenames[i]) : "<none>";
274
                  len = strlen (p);
275
                  if (file_len < len)
276
                    file_len = len;
277
                }
278
            }
279
 
280
          addr_len = num_digits (addr_max, 16);
281
          cnt_len  = num_digits (cnt_max, 10);
282
          line_len = num_digits (line_max, 10);
283
 
284
          /* Now print out the basic block information.  */
285
          for (i = 0; i < ncounts; i++)
286
            {
287
              fprintf (file,
288
                       "    Block #%*d: executed %*ld time(s)",
289
                       blk_len, i+1,
290
                       cnt_len, ptr->counts[i]);
291
 
292
              if (addr_p)
293
                fprintf (file, " address= 0x%.*lx", addr_len,
294
                         ptr->addresses[i]);
295
 
296
              if (func_p)
297
                fprintf (file, " function= %-*s", func_len,
298
                         (ptr->functions[i]) ? ptr->functions[i] : "<none>");
299
 
300
              if (line_p)
301
                fprintf (file, " line= %*ld", line_len, ptr->line_nums[i]);
302
 
303
              if (file_p)
304
                fprintf (file, " file= %s",
305
                         (ptr->filenames[i]) ? ptr->filenames[i] : "<none>");
306
 
307
              fprintf (file, "\n");
308
            }
309
 
310
          fprintf (file, "\n");
311
          fflush (file);
312
        }
313
 
314
      fprintf (file, "\n\n");
315
      fclose (file);
316
    }
317
}
318
 
319
void
320
__bb_init_func (struct bb *blocks)
321
{
322
  /* User is supposed to check whether the first word is non-0,
323
     but just in case....  */
324
 
325
  if (blocks->zero_word)
326
    return;
327
 
328
  /* Initialize destructor.  */
329
  if (!bb_head)
330
    atexit (__bb_exit_func);
331
 
332
  /* Set up linked list.  */
333
  blocks->zero_word = 1;
334
  blocks->next = bb_head;
335
  bb_head = blocks;
336
}
337
 
338
/* Called before fork or exec - write out profile information gathered so
339
   far and reset it to zero.  This avoids duplication or loss of the
340
   profile information gathered so far.  */
341
void
342
__bb_fork_func (void)
343
{
344
  struct bb *ptr;
345
 
346
  __bb_exit_func ();
347
  for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
348
    {
349
      long i;
350
      for (i = ptr->ncounts - 1; i >= 0; i--)
351
        ptr->counts[i] = 0;
352
    }
353
}
354
 
355
#ifndef MACHINE_STATE_SAVE
356
#define MACHINE_STATE_SAVE(ID)
357
#endif
358
#ifndef MACHINE_STATE_RESTORE
359
#define MACHINE_STATE_RESTORE(ID)
360
#endif
361
 
362
/* Number of buckets in hashtable of basic block addresses.  */
363
 
364
#define BB_BUCKETS 311
365
 
366
/* Maximum length of string in file bb.in.  */
367
 
368
#define BBINBUFSIZE 500
369
 
370
struct bb_edge
371
{
372
  struct bb_edge *next;
373
  unsigned long src_addr;
374
  unsigned long dst_addr;
375
  unsigned long count;
376
};
377
 
378
enum bb_func_mode
379
{
380
  TRACE_KEEP = 0, TRACE_ON = 1, TRACE_OFF = 2
381
};
382
 
383
struct bb_func
384
{
385
  struct bb_func *next;
386
  char *funcname;
387
  char *filename;
388
  enum bb_func_mode mode;
389
};
390
 
391
/* This is the connection to the outside world.
392
   The BLOCK_PROFILER macro must set __bb.blocks
393
   and __bb.blockno.  */
394
 
395
struct {
396
  unsigned long blockno;
397
  struct bb *blocks;
398
} __bb;
399
 
400
/* Vars to store addrs of source and destination basic blocks
401
   of a jump.  */
402
 
403
static unsigned long bb_src = 0;
404
static unsigned long bb_dst = 0;
405
 
406
static FILE *bb_tracefile = (FILE *) 0;
407
static struct bb_edge **bb_hashbuckets = (struct bb_edge **) 0;
408
static struct bb_func *bb_func_head = (struct bb_func *) 0;
409
static unsigned long bb_callcount = 0;
410
static int bb_mode = 0;
411
 
412
static unsigned long *bb_stack = (unsigned long *) 0;
413
static size_t bb_stacksize = 0;
414
 
415
static int reported = 0;
416
 
417
/* Trace modes:
418
Always             :   Print execution frequencies of basic blocks
419
                       to file bb.out.
420
bb_mode & 1 != 0   :   Dump trace of basic blocks to file bbtrace[.gz]
421
bb_mode & 2 != 0   :   Print jump frequencies to file bb.out.
422
bb_mode & 4 != 0   :   Cut call instructions from basic block flow.
423
bb_mode & 8 != 0   :   Insert return instructions in basic block flow.
424
*/
425
 
426
#ifdef HAVE_POPEN
427
 
428
/*#include <sys/types.h>*/
429
#include <sys/stat.h>
430
/*#include <malloc.h>*/
431
 
432
/* Commands executed by gopen.  */
433
 
434
#define GOPENDECOMPRESS "gzip -cd "
435
#define GOPENCOMPRESS "gzip -c >"
436
 
437
/* Like fopen but pipes through gzip.  mode may only be "r" or "w".
438
   If it does not compile, simply replace gopen by fopen and delete
439
   '.gz' from any first parameter to gopen.  */
440
 
441
static FILE *
442
gopen (char *fn, char *mode)
443
{
444
  int use_gzip;
445
  char *p;
446
 
447
  if (mode[1])
448
    return (FILE *) 0;
449
 
450
  if (mode[0] != 'r' && mode[0] != 'w')
451
    return (FILE *) 0;
452
 
453
  p = fn + strlen (fn)-1;
454
  use_gzip = ((p[-1] == '.' && (p[0] == 'Z' || p[0] == 'z'))
455
              || (p[-2] == '.' && p[-1] == 'g' && p[0] == 'z'));
456
 
457
  if (use_gzip)
458
    {
459
      if (mode[0]=='r')
460
        {
461
          FILE *f;
462
          char *s = (char *) malloc (sizeof (char) * strlen (fn)
463
                                     + sizeof (GOPENDECOMPRESS));
464
          strcpy (s, GOPENDECOMPRESS);
465
          strcpy (s + (sizeof (GOPENDECOMPRESS)-1), fn);
466
          f = popen (s, mode);
467
          free (s);
468
          return f;
469
        }
470
 
471
      else
472
        {
473
          FILE *f;
474
          char *s = (char *) malloc (sizeof (char) * strlen (fn)
475
                                     + sizeof (GOPENCOMPRESS));
476
          strcpy (s, GOPENCOMPRESS);
477
          strcpy (s + (sizeof (GOPENCOMPRESS)-1), fn);
478
          if (!(f = popen (s, mode)))
479
            f = fopen (s, mode);
480
          free (s);
481
          return f;
482
        }
483
    }
484
 
485
  else
486
    return fopen (fn, mode);
487
}
488
 
489
static int
490
gclose (FILE *f)
491
{
492
  struct stat buf;
493
 
494
  if (f != 0)
495
    {
496
      if (!fstat (fileno (f), &buf) && S_ISFIFO (buf.st_mode))
497
        return pclose (f);
498
 
499
      return fclose (f);
500
    }
501
  return 0;
502
}
503
 
504
#endif /* HAVE_POPEN */
505
 
506
/* Called once per program.  */
507
 
508
static void
509
__bb_exit_trace_func (void)
510
{
511
  FILE *file = fopen ("bb.out", "a");
512
  struct bb_func *f;
513
  struct bb *b;
514
 
515
  if (!file)
516
    perror ("bb.out");
517
 
518
  if (bb_mode & 1)
519
    {
520
      if (!bb_tracefile)
521
        perror ("bbtrace");
522
      else
523
#ifdef HAVE_POPEN
524
        gclose (bb_tracefile);
525
#else
526
        fclose (bb_tracefile);
527
#endif /* HAVE_POPEN */
528
    }
529
 
530
  /* Check functions in `bb.in'.  */
531
 
532
  if (file)
533
    {
534
      long time_value;
535
      const struct bb_func *p;
536
      int printed_something = 0;
537
      struct bb *ptr;
538
      long blk;
539
 
540
      /* This is somewhat type incorrect.  */
541
      time ((void *) &time_value);
542
 
543
      for (p = bb_func_head; p != (struct bb_func *) 0; p = p->next)
544
        {
545
          for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
546
            {
547
              if (!ptr->filename || (p->filename != (char *) 0 && strcmp (p->filename, ptr->filename)))
548
                continue;
549
              for (blk = 0; blk < ptr->ncounts; blk++)
550
                {
551
                  if (!strcmp (p->funcname, ptr->functions[blk]))
552
                    goto found;
553
                }
554
            }
555
 
556
          if (!printed_something)
557
            {
558
              fprintf (file, "Functions in `bb.in' not executed during basic block profiling on %s\n", ctime ((void *) &time_value));
559
              printed_something = 1;
560
            }
561
 
562
          fprintf (file, "\tFunction %s", p->funcname);
563
          if (p->filename)
564
              fprintf (file, " of file %s", p->filename);
565
          fprintf (file, "\n" );
566
 
567
found:        ;
568
        }
569
 
570
      if (printed_something)
571
       fprintf (file, "\n");
572
 
573
    }
574
 
575
  if (bb_mode & 2)
576
    {
577
      if (!bb_hashbuckets)
578
        {
579
          if (!reported)
580
            {
581
              fprintf (stderr, "Profiler: out of memory\n");
582
              reported = 1;
583
            }
584
          return;
585
        }
586
 
587
      else if (file)
588
        {
589
          long time_value;
590
          int i;
591
          unsigned long addr_max = 0;
592
          unsigned long cnt_max  = 0;
593
          int cnt_len;
594
          int addr_len;
595
 
596
          /* This is somewhat type incorrect, but it avoids worrying about
597
             exactly where time.h is included from.  It should be ok unless
598
             a void * differs from other pointer formats, or if sizeof (long)
599
             is < sizeof (time_t).  It would be nice if we could assume the
600
             use of rationale standards here.  */
601
 
602
          time ((void *) &time_value);
603
          fprintf (file, "Basic block jump tracing");
604
 
605
          switch (bb_mode & 12)
606
            {
607
              case 0:
608
                fprintf (file, " (with call)");
609
              break;
610
 
611
              case 4:
612
                /* Print nothing.  */
613
              break;
614
 
615
              case 8:
616
                fprintf (file, " (with call & ret)");
617
              break;
618
 
619
              case 12:
620
                fprintf (file, " (with ret)");
621
              break;
622
            }
623
 
624
          fprintf (file, " finished on %s\n", ctime ((void *) &time_value));
625
 
626
          for (i = 0; i < BB_BUCKETS; i++)
627
            {
628
               struct bb_edge *bucket = bb_hashbuckets[i];
629
               for ( ; bucket; bucket = bucket->next )
630
                 {
631
                   if (addr_max < bucket->src_addr)
632
                     addr_max = bucket->src_addr;
633
                   if (addr_max < bucket->dst_addr)
634
                     addr_max = bucket->dst_addr;
635
                   if (cnt_max < bucket->count)
636
                     cnt_max = bucket->count;
637
                 }
638
            }
639
          addr_len = num_digits (addr_max, 16);
640
          cnt_len  = num_digits (cnt_max, 10);
641
 
642
          for ( i = 0; i < BB_BUCKETS; i++)
643
            {
644
               struct bb_edge *bucket = bb_hashbuckets[i];
645
               for ( ; bucket; bucket = bucket->next )
646
                 {
647
                   fprintf (file,
648
        "Jump from block 0x%.*lx to block 0x%.*lx executed %*lu time(s)\n",
649
                            addr_len, bucket->src_addr,
650
                            addr_len, bucket->dst_addr,
651
                            cnt_len, bucket->count);
652
                 }
653
            }
654
 
655
          fprintf (file, "\n");
656
 
657
        }
658
    }
659
 
660
   if (file)
661
     fclose (file);
662
 
663
   /* Free allocated memory.  */
664
 
665
   f = bb_func_head;
666
   while (f)
667
     {
668
       struct bb_func *old = f;
669
 
670
       f = f->next;
671
       if (old->funcname) free (old->funcname);
672
       if (old->filename) free (old->filename);
673
       free (old);
674
     }
675
 
676
   if (bb_stack)
677
     free (bb_stack);
678
 
679
   if (bb_hashbuckets)
680
     {
681
       int i;
682
 
683
       for (i = 0; i < BB_BUCKETS; i++)
684
         {
685
           struct bb_edge *old, *bucket = bb_hashbuckets[i];
686
 
687
           while (bucket)
688
             {
689
               old = bucket;
690
               bucket = bucket->next;
691
               free (old);
692
             }
693
         }
694
       free (bb_hashbuckets);
695
     }
696
 
697
   for (b = bb_head; b; b = b->next)
698
     if (b->flags) free (b->flags);
699
}
700
 
701
/* Called once per program.  */
702
 
703
static void
704
__bb_init_prg (void)
705
{
706
  FILE *file;
707
  char buf[BBINBUFSIZE];
708
  const char *p;
709
  const char *pos;
710
  enum bb_func_mode m;
711
  int i;
712
 
713
  /* Initialize destructor.  */
714
  atexit (__bb_exit_func);
715
 
716
  if (!(file = fopen ("bb.in", "r")))
717
    return;
718
 
719
  while(fgets (buf, BBINBUFSIZE, file) != 0)
720
    {
721
      i = strlen (buf);
722
      if (buf[i-1] == '\n')
723
        buf[--i] = '\0';
724
 
725
      p = buf;
726
      if (*p == '-')
727
        {
728
          m = TRACE_OFF;
729
          p++;
730
        }
731
      else
732
        {
733
          m = TRACE_ON;
734
        }
735
      if (!strcmp (p, "__bb_trace__"))
736
        bb_mode |= 1;
737
      else if (!strcmp (p, "__bb_jumps__"))
738
        bb_mode |= 2;
739
      else if (!strcmp (p, "__bb_hidecall__"))
740
        bb_mode |= 4;
741
      else if (!strcmp (p, "__bb_showret__"))
742
        bb_mode |= 8;
743
      else
744
        {
745
          struct bb_func *f = (struct bb_func *) malloc (sizeof (struct bb_func));
746
          if (f)
747
            {
748
              unsigned long l;
749
              f->next = bb_func_head;
750
              if ((pos = strchr (p, ':')))
751
                {
752
                  if (!(f->funcname = (char *) malloc (strlen (pos+1)+1)))
753
                    continue;
754
                  strcpy (f->funcname, pos+1);
755
                  l = pos-p;
756
                  if ((f->filename = (char *) malloc (l+1)))
757
                    {
758
                      strncpy (f->filename, p, l);
759
                      f->filename[l] = '\0';
760
                    }
761
                  else
762
                    f->filename = (char *) 0;
763
                }
764
              else
765
                {
766
                  if (!(f->funcname = (char *) malloc (strlen (p)+1)))
767
                    continue;
768
                  strcpy (f->funcname, p);
769
                  f->filename = (char *) 0;
770
                }
771
              f->mode = m;
772
              bb_func_head = f;
773
            }
774
         }
775
    }
776
  fclose (file);
777
 
778
#ifdef HAVE_POPEN 
779
 
780
  if (bb_mode & 1)
781
      bb_tracefile = gopen ("bbtrace.gz", "w");
782
 
783
#else
784
 
785
  if (bb_mode & 1)
786
      bb_tracefile = fopen ("bbtrace", "w");
787
 
788
#endif /* HAVE_POPEN */
789
 
790
  if (bb_mode & 2)
791
    {
792
      bb_hashbuckets = (struct bb_edge **)
793
                   malloc (BB_BUCKETS * sizeof (struct bb_edge *));
794
      if (bb_hashbuckets)
795
        /* Use a loop here rather than calling bzero to avoid having to
796
           conditionalize its existance.  */
797
        for (i = 0; i < BB_BUCKETS; i++)
798
          bb_hashbuckets[i] = 0;
799
    }
800
 
801
  if (bb_mode & 12)
802
    {
803
      bb_stacksize = 10;
804
      bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack));
805
    }
806
 
807
  /* Initialize destructor.  */
808
  atexit (__bb_exit_trace_func);
809
}
810
 
811
/* Called upon entering a basic block.  */
812
 
813
void
814
__bb_trace_func (void)
815
{
816
  struct bb_edge *bucket;
817
 
818
  MACHINE_STATE_SAVE("1")
819
 
820
  if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
821
    goto skip;
822
 
823
  bb_dst = __bb.blocks->addresses[__bb.blockno];
824
  __bb.blocks->counts[__bb.blockno]++;
825
 
826
  if (bb_tracefile)
827
    {
828
      fwrite (&bb_dst, sizeof (unsigned long), 1, bb_tracefile);
829
    }
830
 
831
  if (bb_hashbuckets)
832
    {
833
      struct bb_edge **startbucket, **oldnext;
834
 
835
      oldnext = startbucket
836
        = & bb_hashbuckets[ (((int) bb_src*8) ^ (int) bb_dst) % BB_BUCKETS ];
837
      bucket = *startbucket;
838
 
839
      for (bucket = *startbucket; bucket;
840
           oldnext = &(bucket->next), bucket = *oldnext)
841
        {
842
          if (bucket->src_addr == bb_src
843
              && bucket->dst_addr == bb_dst)
844
            {
845
              bucket->count++;
846
              *oldnext = bucket->next;
847
              bucket->next = *startbucket;
848
              *startbucket = bucket;
849
              goto ret;
850
            }
851
        }
852
 
853
      bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
854
 
855
      if (!bucket)
856
        {
857
          if (!reported)
858
            {
859
              fprintf (stderr, "Profiler: out of memory\n");
860
              reported = 1;
861
            }
862
        }
863
 
864
      else
865
        {
866
          bucket->src_addr = bb_src;
867
          bucket->dst_addr = bb_dst;
868
          bucket->next = *startbucket;
869
          *startbucket = bucket;
870
          bucket->count = 1;
871
        }
872
    }
873
 
874
ret:
875
  bb_src = bb_dst;
876
 
877
skip:
878
  ;
879
 
880
  MACHINE_STATE_RESTORE("1")
881
 
882
}
883
 
884
/* Called when returning from a function and `__bb_showret__' is set.  */
885
 
886
static void
887
__bb_trace_func_ret (void)
888
{
889
  struct bb_edge *bucket;
890
 
891
  if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
892
    goto skip;
893
 
894
  if (bb_hashbuckets)
895
    {
896
      struct bb_edge **startbucket, **oldnext;
897
 
898
      oldnext = startbucket
899
        = & bb_hashbuckets[ (((int) bb_dst * 8) ^ (int) bb_src) % BB_BUCKETS ];
900
      bucket = *startbucket;
901
 
902
      for (bucket = *startbucket; bucket;
903
           oldnext = &(bucket->next), bucket = *oldnext)
904
        {
905
          if (bucket->src_addr == bb_dst
906
               && bucket->dst_addr == bb_src)
907
            {
908
              bucket->count++;
909
              *oldnext = bucket->next;
910
              bucket->next = *startbucket;
911
              *startbucket = bucket;
912
              goto ret;
913
            }
914
        }
915
 
916
      bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
917
 
918
      if (!bucket)
919
        {
920
          if (!reported)
921
            {
922
              fprintf (stderr, "Profiler: out of memory\n");
923
              reported = 1;
924
            }
925
        }
926
 
927
      else
928
        {
929
          bucket->src_addr = bb_dst;
930
          bucket->dst_addr = bb_src;
931
          bucket->next = *startbucket;
932
          *startbucket = bucket;
933
          bucket->count = 1;
934
        }
935
    }
936
 
937
ret:
938
  bb_dst = bb_src;
939
 
940
skip:
941
  ;
942
 
943
}
944
 
945
/* Called upon entering the first function of a file.  */
946
 
947
static void
948
__bb_init_file (struct bb *blocks)
949
{
950
 
951
  const struct bb_func *p;
952
  long blk, ncounts = blocks->ncounts;
953
  const char **functions = blocks->functions;
954
 
955
  /* Set up linked list.  */
956
  blocks->zero_word = 1;
957
  blocks->next = bb_head;
958
  bb_head = blocks;
959
 
960
  blocks->flags = 0;
961
  if (!bb_func_head
962
      || !(blocks->flags = (char *) malloc (sizeof (char) * blocks->ncounts)))
963
    return;
964
 
965
  for (blk = 0; blk < ncounts; blk++)
966
    blocks->flags[blk] = 0;
967
 
968
  for (blk = 0; blk < ncounts; blk++)
969
    {
970
      for (p = bb_func_head; p; p = p->next)
971
        {
972
          if (!strcmp (p->funcname, functions[blk])
973
              && (!p->filename || !strcmp (p->filename, blocks->filename)))
974
            {
975
              blocks->flags[blk] |= p->mode;
976
            }
977
        }
978
    }
979
 
980
}
981
 
982
/* Called when exiting from a function.  */
983
 
984
void
985
__bb_trace_ret (void)
986
{
987
 
988
  MACHINE_STATE_SAVE("2")
989
 
990
  if (bb_callcount)
991
    {
992
      if ((bb_mode & 12) && bb_stacksize > bb_callcount)
993
        {
994
          bb_src = bb_stack[bb_callcount];
995
          if (bb_mode & 8)
996
            __bb_trace_func_ret ();
997
        }
998
 
999
      bb_callcount -= 1;
1000
    }
1001
 
1002
  MACHINE_STATE_RESTORE("2")
1003
 
1004
}
1005
 
1006
/* Called when entering a function.  */
1007
 
1008
void
1009
__bb_init_trace_func (struct bb *blocks, unsigned long blockno)
1010
{
1011
  static int trace_init = 0;
1012
 
1013
  MACHINE_STATE_SAVE("3")
1014
 
1015
  if (!blocks->zero_word)
1016
    {
1017
      if (!trace_init)
1018
        {
1019
          trace_init = 1;
1020
          __bb_init_prg ();
1021
        }
1022
      __bb_init_file (blocks);
1023
    }
1024
 
1025
  if (bb_callcount)
1026
    {
1027
 
1028
      bb_callcount += 1;
1029
 
1030
      if (bb_mode & 12)
1031
        {
1032
          if (bb_callcount >= bb_stacksize)
1033
            {
1034
              size_t newsize = bb_callcount + 100;
1035
 
1036
              bb_stack = (unsigned long *) realloc (bb_stack, newsize);
1037
              if (! bb_stack)
1038
                {
1039
                  if (!reported)
1040
                    {
1041
                      fprintf (stderr, "Profiler: out of memory\n");
1042
                      reported = 1;
1043
                    }
1044
                  bb_stacksize = 0;
1045
                  goto stack_overflow;
1046
                }
1047
              bb_stacksize = newsize;
1048
            }
1049
          bb_stack[bb_callcount] = bb_src;
1050
 
1051
          if (bb_mode & 4)
1052
            bb_src = 0;
1053
 
1054
        }
1055
 
1056
stack_overflow:;
1057
 
1058
    }
1059
 
1060
  else if (blocks->flags && (blocks->flags[blockno] & TRACE_ON))
1061
    {
1062
      bb_callcount = 1;
1063
      bb_src = 0;
1064
 
1065
      if (bb_stack)
1066
          bb_stack[bb_callcount] = bb_src;
1067
    }
1068
 
1069
  MACHINE_STATE_RESTORE("3")
1070
}
1071
 

powered by: WebSVN 2.1.0

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