public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [gcov] Merge arc counts
@ 2002-08-09 15:32 Nathan Sidwell
  2002-08-09 18:44 ` Jan Hubicka
  2002-08-12 14:06 ` Richard Henderson
  0 siblings, 2 replies; 4+ messages in thread
From: Nathan Sidwell @ 2002-08-09 15:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: mark, jh

[-- Attachment #1: Type: text/plain, Size: 808 bytes --]

Hi,
this patch changes __bb_exit_func to merge arc counts into the .da files,
rather than appending a new record for each execution. This has the
advantage of not eating your disk space. I also tidied up some unused
globals and header files which appear left over from -a coverage days.

Merging like this does affect the value of the maximum count
across the whole program. The value in the .da file is now that
seen after accumulating all the data. Previously the value used
by predict.c was the sum of the maxima on each program run.

booted & tested on i686-pc-linux-gnu, ok?

nathan
-- 
Dr Nathan Sidwell   ::   http://www.codesourcery.com   ::   CodeSourcery LLC
         'But that's a lie.' - 'Yes it is. What's your point?'
nathan@codesourcery.com : http://www.cs.bris.ac.uk/~nathan/ : nathan@acm.org

[-- Attachment #2: bb_exit.patch --]
[-- Type: text/plain, Size: 14948 bytes --]

2002-08-09  Nathan Sidwell  <nathan@codesourcery.com>

	* libgcc2.c (L_bb): Remove unneeded #includes.
	(__global_counters, __gthreads_active): Remove unused globals.
	(__bb_exit_func): Merge counts into files rather than appending.

Index: libgcc2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/libgcc2.c,v
retrieving revision 1.145
diff -c -3 -p -r1.145 libgcc2.c
*** libgcc2.c	30 Jul 2002 23:55:08 -0000	1.145
--- libgcc2.c	9 Aug 2002 22:09:30 -0000
***************
*** 1,7 ****
  /* More subroutines needed by GCC output code on some machines.  */
  /* Compile this one with gcc.  */
  /* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
!    2000, 2001  Free Software Foundation, Inc.
  
  This file is part of GCC.
  
--- 1,7 ----
  /* More subroutines needed by GCC output code on some machines.  */
  /* Compile this one with gcc.  */
  /* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
!    2000, 2001, 2002  Free Software Foundation, Inc.
  
  This file is part of GCC.
  
*************** struct bb_function_info {
*** 1243,1249 ****
    const char *name;
  };
  
! /* Structure emitted by -a  */
  struct bb
  {
    long zero_word;
--- 1243,1249 ----
    const char *name;
  };
  
! /* Structure emitted by --profile-arcs  */
  struct bb
  {
    long zero_word;
*************** struct bb
*** 1259,1272 ****
  
  #ifndef inhibit_libc
  
! /* Simple minded basic block profiling output dumper for
!    systems that don't provide tcov support.  At present,
!    it requires atexit and stdio.  */
  
  #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
  #include <stdio.h>
  
- #include "gbl-ctors.h"
  #include "gcov-io.h"
  #include <string.h>
  #ifdef TARGET_HAS_F_SETLKW
--- 1259,1269 ----
  
  #ifndef inhibit_libc
  
! /* Arc profile dumper. Requires atexit and stdio.  */
  
  #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
  #include <stdio.h>
  
  #include "gcov-io.h"
  #include <string.h>
  #ifdef TARGET_HAS_F_SETLKW
*************** struct bb
*** 1274,1462 ****
  #include <errno.h>
  #endif
  
! #include <gthr.h>
! 
  static struct bb *bb_head;
  
! int __global_counters = 0, __gthreads_active = 0;
  
  void
  __bb_exit_func (void)
  {
-   FILE *da_file;
    struct bb *ptr;
!   long n_counters_p = 0;
!   gcov_type max_counter_p = 0;
!   gcov_type sum_counters_p = 0;
! 
!   if (bb_head == 0)
!     return;
! 
!   /* Calculate overall "statistics".  */
  
!   for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
      {
        int i;
! 
!       n_counters_p += ptr->ncounts;
! 
!       for (i = 0; i < ptr->ncounts; i++)
  	{
! 	  sum_counters_p += ptr->counts[i];
! 
! 	  if (ptr->counts[i] > max_counter_p)
! 	    max_counter_p = ptr->counts[i];
  	}
!     }
! 
!   for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
!     {
!       gcov_type max_counter_o = 0;
!       gcov_type sum_counters_o = 0;
!       int i;
! 
!       /* Calculate the per-object statistics.  */
! 
!       for (i = 0; i < ptr->ncounts; i++)
! 	{
! 	  sum_counters_o += ptr->counts[i];
! 
! 	  if (ptr->counts[i] > max_counter_o)
! 	    max_counter_o = ptr->counts[i];
! 	}
! 
!       /* open the file for appending, creating it if necessary.  */
!       da_file = fopen (ptr->filename, "ab");
!       /* Some old systems might not allow the 'b' mode modifier.
!          Therefore, try to open without it.  This can lead to a race
!          condition so that when you delete and re-create the file, the
!          file might be opened in text mode, but then, you shouldn't
!          delete the file in the first place.  */
!       if (da_file == 0)
! 	da_file = fopen (ptr->filename, "a");
!       if (da_file == 0)
  	{
  	  fprintf (stderr, "arc profiling: Can't open output file %s.\n",
  		   ptr->filename);
  	  continue;
  	}
  
        /* After a fork, another process might try to read and/or write
           the same file simultanously.  So if we can, lock the file to
           avoid race conditions.  */
! #if defined (TARGET_HAS_F_SETLKW)
!       {
! 	struct flock s_flock;
! 
! 	s_flock.l_type = F_WRLCK;
! 	s_flock.l_whence = SEEK_SET;
! 	s_flock.l_start = 0;
! 	s_flock.l_len = 1;
! 	s_flock.l_pid = getpid ();
  
! 	while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
! 	       && errno == EINTR);
!       }
! #endif
! 
!       if (__write_long (-123, da_file, 4) != 0)	/* magic */
  	{
! 	  fprintf (stderr, "arc profiling: Error writing output file %s.\n",
! 		   ptr->filename);
  	}
!       else
  	{
  
! 	  struct bb_function_info *fn_info;
! 	  gcov_type *count_ptr = ptr->counts;
! 	  int i;
! 	  int count_functions = 0;
! 
! 	  for (fn_info = ptr->function_infos; fn_info->arc_count != -1;
! 	       fn_info++)
! 	    count_functions++;
! 
! 	  /* number of functions in this block.  */
! 	  __write_long (count_functions, da_file, 4);
! 
  	  /* length of extra data in bytes.  */
! 	  __write_long ((4 + 8 + 8) + (4 + 8 + 8), da_file, 4);
  
! 	  /* overall statistics.  */
! 	  /* number of counters.  */
! 	  __write_long (n_counters_p, da_file, 4);
  	  /* sum of counters.  */
! 	  __write_gcov_type (sum_counters_p, da_file, 8);
  	  /* maximal counter.  */
! 	  __write_gcov_type (max_counter_p, da_file, 8);
  
  	  /* per-object statistics.  */
  	  /* number of counters.  */
! 	  __write_long (ptr->ncounts, da_file, 4);
  	  /* sum of counters.  */
! 	  __write_gcov_type (sum_counters_o, da_file, 8);
  	  /* maximal counter.  */
! 	  __write_gcov_type (max_counter_o, da_file, 8);
! 
! 	  /* write execution counts for each function.  */
  
  	  for (fn_info = ptr->function_infos; fn_info->arc_count != -1;
  	       fn_info++)
  	    {
! 	      /* new function.  */
! 	      if (__write_gcov_string
! 		  (fn_info->name, strlen (fn_info->name), da_file, -1) != 0)
! 		{
! 		  fprintf (stderr,
! 			   "arc profiling: Error writing output file %s.\n",
! 			   ptr->filename);
! 		  break;
! 		}
! 
! 	      if (__write_long (fn_info->checksum, da_file, 4) != 0)
! 		{
! 		  fprintf (stderr,
! 			   "arc profiling: Error writing output file %s.\n",
! 			   ptr->filename);
! 		  break;
! 		}
! 
! 	      if (__write_long (fn_info->arc_count, da_file, 4) != 0)
! 		{
! 		  fprintf (stderr,
! 			   "arc profiling: Error writing output file %s.\n",
! 			   ptr->filename);
! 		  break;
! 		}
! 
  	      for (i = fn_info->arc_count; i > 0; i--, count_ptr++)
! 		{
! 		  if (__write_gcov_type (*count_ptr, da_file, 8) != 0)
! 		    break;
! 		}
! 
! 	      if (i)		/* there was an error */
! 		{
! 		  fprintf (stderr,
! 			   "arc profiling: Error writing output file %s.\n",
! 			   ptr->filename);
! 		  break;
! 		}
  	    }
  	}
  
!       if (fclose (da_file) != 0)
! 	fprintf (stderr, "arc profiling: Error closing output file %s.\n",
! 		 ptr->filename);
      }
  }
  
  void
  __bb_init_func (struct bb *blocks)
  {
-   /* User is supposed to check whether the first word is non-0,
-      but just in case....  */
- 
    if (blocks->zero_word)
      return;
  
--- 1271,1521 ----
  #include <errno.h>
  #endif
  
! /* Chain of per-object file bb structures. */
  static struct bb *bb_head;
  
! /* Dump the coverage counts. We merge with existing counts when
!    possible, to avoid growing the .da files ad infinitum.  */
  
  void
  __bb_exit_func (void)
  {
    struct bb *ptr;
!   gcov_type program_sum = 0;
!   gcov_type program_max = 0;
!   unsigned program_arcs = 0;
! #if defined (TARGET_HAS_F_SETLKW)
!   struct flock s_flock;
  
!   s_flock.l_type = F_WRLCK;
!   s_flock.l_whence = SEEK_SET;
!   s_flock.l_start = 0;
!   s_flock.l_len = 0; /* Until EOF. */
!   s_flock.l_pid = getpid ();
! #endif
!   
!   for (ptr = bb_head; ptr; ptr = ptr->next)
      {
+       FILE *da_file;
+       gcov_type object_max = 0;
+       gcov_type object_sum = 0;
+       long object_functions = 0;
        int i;
!       int merging = 0;
!       int error = 0;
!       struct bb_function_info *fn_info;
!       gcov_type *count_ptr;
!       
!       /* Open for modification */
!       da_file = fopen (ptr->filename, "r+b");
!       
!       if (da_file)
! 	merging = 1;
!       else
  	{
! 	  /* Try for appending */
! 	  da_file = fopen (ptr->filename, "ab");
! 	  /* Some old systems might not allow the 'b' mode modifier.
!              Therefore, try to open without it.  This can lead to a
!              race condition so that when you delete and re-create the
!              file, the file might be opened in text mode, but then,
!              you shouldn't delete the file in the first place.  */
! 	  if (!da_file)
! 	    da_file = fopen (ptr->filename, "a");
  	}
!       
!       if (!da_file)
  	{
  	  fprintf (stderr, "arc profiling: Can't open output file %s.\n",
  		   ptr->filename);
+ 	  ptr->filename = 0;
  	  continue;
  	}
  
+ #if defined (TARGET_HAS_F_SETLKW)
        /* After a fork, another process might try to read and/or write
           the same file simultanously.  So if we can, lock the file to
           avoid race conditions.  */
!       while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
! 	     && errno == EINTR)
! 	continue;
! #endif
!       
!       for (fn_info = ptr->function_infos; fn_info->arc_count != -1; fn_info++)
! 	object_functions++;
  
!       if (merging)
  	{
! 	  /* Merge data from file.  */
! 	  long tmp_long;
! 	  gcov_type tmp_gcov;
! 	  
! 	  if (/* magic */
! 	      (__read_long (&tmp_long, da_file, 4) || tmp_long != -123l)
! 	      /* functions in object file.  */
! 	      || (__read_long (&tmp_long, da_file, 4)
! 		  || tmp_long != object_functions)
! 	      /* extension block, skipped */
! 	      || (__read_long (&tmp_long, da_file, 4)
! 		  || fseek (da_file, tmp_long, SEEK_CUR)))
! 	    {
! 	    read_error:;
! 	      fprintf (stderr, "arc profiling: Error merging output file %s.\n",
! 		       ptr->filename);
! 	      clearerr (da_file);
! 	    }
! 	  else
! 	    {
! 	      /* Merge execution counts for each function.  */
! 	      count_ptr = ptr->counts;
! 	      
! 	      for (fn_info = ptr->function_infos; fn_info->arc_count != -1;
! 		   fn_info++)
! 		{
! 		  if (/* function name delim */
! 		      (__read_long (&tmp_long, da_file, 4)
! 		       || tmp_long != -1)
! 		      /* function name length */
! 		      || (__read_long (&tmp_long, da_file, 4)
! 			  || tmp_long != (long) strlen (fn_info->name))
! 		      /* skip string */
! 		      || fseek (da_file, ((tmp_long + 1) + 3) & ~3, SEEK_CUR)
! 		      /* function name delim */
! 		      || (__read_long (&tmp_long, da_file, 4)
! 			  || tmp_long != -1))
! 		    goto read_error;
! 
! 		  if (/* function checksum */
! 		      (__read_long (&tmp_long, da_file, 4)
! 		       || tmp_long != fn_info->checksum)
! 		      /* arc count */
! 		      || (__read_long (&tmp_long, da_file, 4)
! 			  || tmp_long != fn_info->arc_count))
! 		    goto read_error;
! 		  
! 		  for (i = fn_info->arc_count; i > 0; i--, count_ptr++)
! 		    if (__read_gcov_type (&tmp_gcov, da_file, 8))
! 		      goto read_error;
! 		    else
! 		      *count_ptr += tmp_gcov;
! 		}
! 	    }
! 	  fseek (da_file, 0, SEEK_SET);
  	}
!       
!       /* Calculate the per-object statistics.  */
!       for (i = 0; i < ptr->ncounts; i++)
  	{
+ 	  object_sum += ptr->counts[i];
  
! 	  if (ptr->counts[i] > object_max)
! 	    object_max = ptr->counts[i];
! 	}
!       program_sum += object_sum;
!       if (program_max < object_max)
! 	program_max = object_max;
!       program_arcs += ptr->ncounts;
!       
!       /* Write out the data. */
!       if (/* magic */
! 	  __write_long (-123, da_file, 4)
! 	  /* number of functions in object file.  */
! 	  || __write_long (object_functions, da_file, 4)
  	  /* length of extra data in bytes.  */
! 	  || __write_long ((4 + 8 + 8) + (4 + 8 + 8), da_file, 4)
  
! 	  /* whole program statistics. Write per-object now, rewrite later */
! 	  /* number of instrumented arcs.  */
! 	  || __write_long (ptr->ncounts, da_file, 4)
  	  /* sum of counters.  */
! 	  || __write_gcov_type (object_sum, da_file, 8)
  	  /* maximal counter.  */
! 	  || __write_gcov_type (object_max, da_file, 8)
  
  	  /* per-object statistics.  */
  	  /* number of counters.  */
! 	  || __write_long (ptr->ncounts, da_file, 4)
  	  /* sum of counters.  */
! 	  || __write_gcov_type (object_sum, da_file, 8)
  	  /* maximal counter.  */
! 	  || __write_gcov_type (object_max, da_file, 8))
! 	{
! 	write_error:;
! 	  fprintf (stderr, "arc profiling: Error writing output file %s.\n",
! 		   ptr->filename);
! 	  error = 1;
! 	}
!       else
! 	{
! 	  /* Write execution counts for each function.  */
! 	  count_ptr = ptr->counts;
  
  	  for (fn_info = ptr->function_infos; fn_info->arc_count != -1;
  	       fn_info++)
  	    {
! 	      if (__write_gcov_string (fn_info->name,
! 				       strlen (fn_info->name), da_file, -1)
! 		  || __write_long (fn_info->checksum, da_file, 4)
! 		  || __write_long (fn_info->arc_count, da_file, 4))
! 		goto write_error;
! 	      
  	      for (i = fn_info->arc_count; i > 0; i--, count_ptr++)
! 		if (__write_gcov_type (*count_ptr, da_file, 8))
! 		  goto write_error; /* RIP Edsger Dijkstra */
  	    }
  	}
  
!       if (fclose (da_file))
! 	{
! 	  fprintf (stderr, "arc profiling: Error closing output file %s.\n",
! 		   ptr->filename);
! 	  error = 1;
! 	}
!       if (error)
! 	ptr->filename = 0;
      }
+ 
+   /* Upate whole program statistics.  */
+   for (ptr = bb_head; ptr; ptr = ptr->next)
+     if (ptr->filename)
+       {
+ 	FILE *da_file;
+ 	
+ 	da_file = fopen (ptr->filename, "r+b");
+ 	if (!da_file)
+ 	  {
+ 	    fprintf (stderr, "arc profiling: Cannot reopen %s.\n",
+ 		     ptr->filename);
+ 	    continue;
+ 	  }
+       
+ #if defined (TARGET_HAS_F_SETLKW)
+ 	while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
+ 	       && errno == EINTR)
+ 	  continue;
+ #endif
+ 	
+ 	if (fseek (da_file, 4 * 3, SEEK_SET)
+ 	    /* number of instrumented arcs.  */
+ 	    || __write_long (program_arcs, da_file, 4)
+ 	    /* sum of counters.  */
+ 	    || __write_gcov_type (program_sum, da_file, 8)
+ 	    /* maximal counter.  */
+ 	    || __write_gcov_type (program_max, da_file, 8))
+ 	  fprintf (stderr, "arc profiling: Error updating program header %s.\n",
+ 		   ptr->filename);
+ 	if (fclose (da_file))
+ 	  fprintf (stderr, "arc profiling: Error reclosing %s\n",
+ 		   ptr->filename);
+       }
  }
  
+ /* Add a new object file onto the bb chain.  Invoked automatically
+    when running an object file's global ctors.  */
+ 
  void
  __bb_init_func (struct bb *blocks)
  {
    if (blocks->zero_word)
      return;
  
*************** __bb_init_func (struct bb *blocks)
*** 1473,1478 ****
--- 1532,1538 ----
  /* Called before fork or exec - write out profile information gathered so
     far and reset it to zero.  This avoids duplication or loss of the
     profile information gathered so far.  */
+ 
  void
  __bb_fork_func (void)
  {

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [gcov] Merge arc counts
  2002-08-09 15:32 [gcov] Merge arc counts Nathan Sidwell
@ 2002-08-09 18:44 ` Jan Hubicka
  2002-08-12 14:06 ` Richard Henderson
  1 sibling, 0 replies; 4+ messages in thread
From: Jan Hubicka @ 2002-08-09 18:44 UTC (permalink / raw)
  To: Nathan Sidwell; +Cc: gcc-patches, mark, jh

> Hi,
> this patch changes __bb_exit_func to merge arc counts into the .da files,
> rather than appending a new record for each execution. This has the
> advantage of not eating your disk space. I also tidied up some unused
> globals and header files which appear left over from -a coverage days.
> 
> Merging like this does affect the value of the maximum count
> across the whole program. The value in the .da file is now that
> seen after accumulating all the data. Previously the value used
> by predict.c was the sum of the maxima on each program run.
> 
> booted & tested on i686-pc-linux-gnu, ok?

It looks OK for me, but I can not approve it.
The purpose for appending records is that the data can be analysed in
more sophisphicated ways (there are several methods of merging the
counts in more sensitive way dicussed in the literature or it may be
usefull to have the data on how much the program behaviour changes from
one run to annother.  At the moment the such data are unused and in
number of applications they can be even in future, so it definitly makes
sense to have the merging at least as an option.
Please try to keep the "old" way functional so we can experiment with it
later easilly.

Honza
> 
> nathan
> -- 
> Dr Nathan Sidwell   ::   http://www.codesourcery.com   ::   CodeSourcery LLC
>          'But that's a lie.' - 'Yes it is. What's your point?'

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [gcov] Merge arc counts
  2002-08-09 15:32 [gcov] Merge arc counts Nathan Sidwell
  2002-08-09 18:44 ` Jan Hubicka
@ 2002-08-12 14:06 ` Richard Henderson
  2002-08-13  5:14   ` Nathan Sidwell
  1 sibling, 1 reply; 4+ messages in thread
From: Richard Henderson @ 2002-08-12 14:06 UTC (permalink / raw)
  To: Nathan Sidwell; +Cc: gcc-patches, mark, jh

On Fri, Aug 09, 2002 at 11:32:25PM +0100, Nathan Sidwell wrote:
> 	* libgcc2.c (L_bb): Remove unneeded #includes.
> 	(__global_counters, __gthreads_active): Remove unused globals.
> 	(__bb_exit_func): Merge counts into files rather than appending.

Ok.



r~

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [gcov] Merge arc counts
  2002-08-12 14:06 ` Richard Henderson
@ 2002-08-13  5:14   ` Nathan Sidwell
  0 siblings, 0 replies; 4+ messages in thread
From: Nathan Sidwell @ 2002-08-13  5:14 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Nathan Sidwell, gcc-patches, mark, jh

[-- Attachment #1: Type: text/plain, Size: 639 bytes --]

Richard Henderson wrote:
> 
> On Fri, Aug 09, 2002 at 11:32:25PM +0100, Nathan Sidwell wrote:
> >       * libgcc2.c (L_bb): Remove unneeded #includes.
> >       (__global_counters, __gthreads_active): Remove unused globals.
> >       (__bb_exit_func): Merge counts into files rather than appending.
> 
> Ok.
I've installed this slightly different version, which works when appending,
and fixes a slight bootstrap Makefile problem.

nathan

-- 
Dr Nathan Sidwell :: Computer Science Department :: Bristol University
           The voices in my head told me to say this
nathan@acm.org  http://www.cs.bris.ac.uk/~nathan/  nathan@cs.bris.ac.uk

[-- Attachment #2: gcov.patch --]
[-- Type: text/plain, Size: 17083 bytes --]

2002-08-13  Nathan Sidwell  <nathan@codesourcery.com>

	* libgcc2.c (L_bb): Remove unneeded #includes.
	(__global_counters, __gthreads_active): Remove unused globals.
	(__bb_exit_func): Merge counts into files rather than appending.
	* Makefile.in (INTERNAL_CFLAGS): Move COVERAGE_FLAGS from here ...
	(ALL_CFLAGS): ... to here.

Index: libgcc2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/libgcc2.c,v
retrieving revision 1.145
diff -c -3 -p -r1.145 libgcc2.c
*** libgcc2.c	30 Jul 2002 23:55:08 -0000	1.145
--- libgcc2.c	10 Aug 2002 16:21:34 -0000
***************
*** 1,7 ****
  /* More subroutines needed by GCC output code on some machines.  */
  /* Compile this one with gcc.  */
  /* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
!    2000, 2001  Free Software Foundation, Inc.
  
  This file is part of GCC.
  
--- 1,7 ----
  /* More subroutines needed by GCC output code on some machines.  */
  /* Compile this one with gcc.  */
  /* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
!    2000, 2001, 2002  Free Software Foundation, Inc.
  
  This file is part of GCC.
  
*************** struct bb_function_info {
*** 1243,1249 ****
    const char *name;
  };
  
! /* Structure emitted by -a  */
  struct bb
  {
    long zero_word;
--- 1243,1249 ----
    const char *name;
  };
  
! /* Structure emitted by --profile-arcs  */
  struct bb
  {
    long zero_word;
*************** struct bb
*** 1259,1272 ****
  
  #ifndef inhibit_libc
  
! /* Simple minded basic block profiling output dumper for
!    systems that don't provide tcov support.  At present,
!    it requires atexit and stdio.  */
  
  #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
  #include <stdio.h>
  
- #include "gbl-ctors.h"
  #include "gcov-io.h"
  #include <string.h>
  #ifdef TARGET_HAS_F_SETLKW
--- 1259,1269 ----
  
  #ifndef inhibit_libc
  
! /* Arc profile dumper. Requires atexit and stdio.  */
  
  #undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch.  */
  #include <stdio.h>
  
  #include "gcov-io.h"
  #include <string.h>
  #ifdef TARGET_HAS_F_SETLKW
*************** struct bb
*** 1274,1462 ****
  #include <errno.h>
  #endif
  
! #include <gthr.h>
! 
  static struct bb *bb_head;
  
! int __global_counters = 0, __gthreads_active = 0;
  
  void
  __bb_exit_func (void)
  {
-   FILE *da_file;
    struct bb *ptr;
!   long n_counters_p = 0;
!   gcov_type max_counter_p = 0;
!   gcov_type sum_counters_p = 0;
! 
!   if (bb_head == 0)
!     return;
  
!   /* Calculate overall "statistics".  */
  
!   for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
      {
-       int i;
- 
-       n_counters_p += ptr->ncounts;
- 
        for (i = 0; i < ptr->ncounts; i++)
  	{
! 	  sum_counters_p += ptr->counts[i];
  
! 	  if (ptr->counts[i] > max_counter_p)
! 	    max_counter_p = ptr->counts[i];
  	}
      }
! 
!   for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
      {
!       gcov_type max_counter_o = 0;
!       gcov_type sum_counters_o = 0;
!       int i;
! 
!       /* Calculate the per-object statistics.  */
! 
!       for (i = 0; i < ptr->ncounts; i++)
  	{
! 	  sum_counters_o += ptr->counts[i];
! 
! 	  if (ptr->counts[i] > max_counter_o)
! 	    max_counter_o = ptr->counts[i];
  	}
! 
!       /* open the file for appending, creating it if necessary.  */
!       da_file = fopen (ptr->filename, "ab");
!       /* Some old systems might not allow the 'b' mode modifier.
!          Therefore, try to open without it.  This can lead to a race
!          condition so that when you delete and re-create the file, the
!          file might be opened in text mode, but then, you shouldn't
!          delete the file in the first place.  */
!       if (da_file == 0)
! 	da_file = fopen (ptr->filename, "a");
!       if (da_file == 0)
  	{
  	  fprintf (stderr, "arc profiling: Can't open output file %s.\n",
  		   ptr->filename);
  	  continue;
  	}
  
        /* After a fork, another process might try to read and/or write
           the same file simultanously.  So if we can, lock the file to
           avoid race conditions.  */
! #if defined (TARGET_HAS_F_SETLKW)
!       {
! 	struct flock s_flock;
! 
! 	s_flock.l_type = F_WRLCK;
! 	s_flock.l_whence = SEEK_SET;
! 	s_flock.l_start = 0;
! 	s_flock.l_len = 1;
! 	s_flock.l_pid = getpid ();
! 
! 	while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
! 	       && errno == EINTR);
!       }
  #endif
  
!       if (__write_long (-123, da_file, 4) != 0)	/* magic */
  	{
! 	  fprintf (stderr, "arc profiling: Error writing output file %s.\n",
! 		   ptr->filename);
  	}
!       else
  	{
  
! 	  struct bb_function_info *fn_info;
! 	  gcov_type *count_ptr = ptr->counts;
! 	  int i;
! 	  int count_functions = 0;
! 
! 	  for (fn_info = ptr->function_infos; fn_info->arc_count != -1;
! 	       fn_info++)
! 	    count_functions++;
! 
! 	  /* number of functions in this block.  */
! 	  __write_long (count_functions, da_file, 4);
! 
  	  /* length of extra data in bytes.  */
! 	  __write_long ((4 + 8 + 8) + (4 + 8 + 8), da_file, 4);
  
! 	  /* overall statistics.  */
! 	  /* number of counters.  */
! 	  __write_long (n_counters_p, da_file, 4);
  	  /* sum of counters.  */
! 	  __write_gcov_type (sum_counters_p, da_file, 8);
  	  /* maximal counter.  */
! 	  __write_gcov_type (max_counter_p, da_file, 8);
  
  	  /* per-object statistics.  */
  	  /* number of counters.  */
! 	  __write_long (ptr->ncounts, da_file, 4);
  	  /* sum of counters.  */
! 	  __write_gcov_type (sum_counters_o, da_file, 8);
  	  /* maximal counter.  */
! 	  __write_gcov_type (max_counter_o, da_file, 8);
! 
! 	  /* write execution counts for each function.  */
  
  	  for (fn_info = ptr->function_infos; fn_info->arc_count != -1;
  	       fn_info++)
  	    {
! 	      /* new function.  */
! 	      if (__write_gcov_string
! 		  (fn_info->name, strlen (fn_info->name), da_file, -1) != 0)
! 		{
! 		  fprintf (stderr,
! 			   "arc profiling: Error writing output file %s.\n",
! 			   ptr->filename);
! 		  break;
! 		}
! 
! 	      if (__write_long (fn_info->checksum, da_file, 4) != 0)
! 		{
! 		  fprintf (stderr,
! 			   "arc profiling: Error writing output file %s.\n",
! 			   ptr->filename);
! 		  break;
! 		}
! 
! 	      if (__write_long (fn_info->arc_count, da_file, 4) != 0)
! 		{
! 		  fprintf (stderr,
! 			   "arc profiling: Error writing output file %s.\n",
! 			   ptr->filename);
! 		  break;
! 		}
! 
  	      for (i = fn_info->arc_count; i > 0; i--, count_ptr++)
! 		{
! 		  if (__write_gcov_type (*count_ptr, da_file, 8) != 0)
! 		    break;
! 		}
! 
! 	      if (i)		/* there was an error */
! 		{
! 		  fprintf (stderr,
! 			   "arc profiling: Error writing output file %s.\n",
! 			   ptr->filename);
! 		  break;
! 		}
  	    }
  	}
  
!       if (fclose (da_file) != 0)
! 	fprintf (stderr, "arc profiling: Error closing output file %s.\n",
! 		 ptr->filename);
      }
  }
  
  void
  __bb_init_func (struct bb *blocks)
  {
-   /* User is supposed to check whether the first word is non-0,
-      but just in case....  */
- 
    if (blocks->zero_word)
      return;
  
--- 1271,1538 ----
  #include <errno.h>
  #endif
  
! /* Chain of per-object file bb structures. */
  static struct bb *bb_head;
  
! /* Dump the coverage counts. We merge with existing counts when
!    possible, to avoid growing the .da files ad infinitum.  */
  
  void
  __bb_exit_func (void)
  {
    struct bb *ptr;
!   int i;
!   gcov_type program_sum = 0;
!   gcov_type program_max = 0;
!   long program_arcs = 0;
!   gcov_type merged_sum = 0;
!   gcov_type merged_max = 0;
!   long merged_arcs = 0;
!   
! #if defined (TARGET_HAS_F_SETLKW)
!   struct flock s_flock;
  
!   s_flock.l_type = F_WRLCK;
!   s_flock.l_whence = SEEK_SET;
!   s_flock.l_start = 0;
!   s_flock.l_len = 0; /* Until EOF. */
!   s_flock.l_pid = getpid ();
! #endif
  
!   /* Non-merged stats for this program.  */
!   for (ptr = bb_head; ptr; ptr = ptr->next)
      {
        for (i = 0; i < ptr->ncounts; i++)
  	{
! 	  program_sum += ptr->counts[i];
  
! 	  if (ptr->counts[i] > program_max)
! 	    program_max = ptr->counts[i];
  	}
+       program_arcs += ptr->ncounts;
      }
!   
!   for (ptr = bb_head; ptr; ptr = ptr->next)
      {
!       FILE *da_file;
!       gcov_type object_max = 0;
!       gcov_type object_sum = 0;
!       long object_functions = 0;
!       int merging = 0;
!       int error = 0;
!       struct bb_function_info *fn_info;
!       gcov_type *count_ptr;
!       
!       /* Open for modification */
!       da_file = fopen (ptr->filename, "r+b");
!       
!       if (da_file)
! 	merging = 1;
!       else
  	{
! 	  /* Try for appending */
! 	  da_file = fopen (ptr->filename, "ab");
! 	  /* Some old systems might not allow the 'b' mode modifier.
!              Therefore, try to open without it.  This can lead to a
!              race condition so that when you delete and re-create the
!              file, the file might be opened in text mode, but then,
!              you shouldn't delete the file in the first place.  */
! 	  if (!da_file)
! 	    da_file = fopen (ptr->filename, "a");
  	}
!       
!       if (!da_file)
  	{
  	  fprintf (stderr, "arc profiling: Can't open output file %s.\n",
  		   ptr->filename);
+ 	  ptr->filename = 0;
  	  continue;
  	}
  
+ #if defined (TARGET_HAS_F_SETLKW)
        /* After a fork, another process might try to read and/or write
           the same file simultanously.  So if we can, lock the file to
           avoid race conditions.  */
!       while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
! 	     && errno == EINTR)
! 	continue;
  #endif
+       for (fn_info = ptr->function_infos; fn_info->arc_count != -1; fn_info++)
+ 	object_functions++;
  
!       if (merging)
  	{
! 	  /* Merge data from file.  */
! 	  long tmp_long;
! 	  gcov_type tmp_gcov;
! 	  
! 	  if (/* magic */
! 	      (__read_long (&tmp_long, da_file, 4) || tmp_long != -123l)
! 	      /* functions in object file.  */
! 	      || (__read_long (&tmp_long, da_file, 4)
! 		  || tmp_long != object_functions)
! 	      /* extension block, skipped */
! 	      || (__read_long (&tmp_long, da_file, 4)
! 		  || fseek (da_file, tmp_long, SEEK_CUR)))
! 	    {
! 	    read_error:;
! 	      fprintf (stderr, "arc profiling: Error merging output file %s.\n",
! 		       ptr->filename);
! 	      clearerr (da_file);
! 	    }
! 	  else
! 	    {
! 	      /* Merge execution counts for each function.  */
! 	      count_ptr = ptr->counts;
! 	      
! 	      for (fn_info = ptr->function_infos; fn_info->arc_count != -1;
! 		   fn_info++)
! 		{
! 		  if (/* function name delim */
! 		      (__read_long (&tmp_long, da_file, 4)
! 		       || tmp_long != -1)
! 		      /* function name length */
! 		      || (__read_long (&tmp_long, da_file, 4)
! 			  || tmp_long != (long) strlen (fn_info->name))
! 		      /* skip string */
! 		      || fseek (da_file, ((tmp_long + 1) + 3) & ~3, SEEK_CUR)
! 		      /* function name delim */
! 		      || (__read_long (&tmp_long, da_file, 4)
! 			  || tmp_long != -1))
! 		    goto read_error;
! 
! 		  if (/* function checksum */
! 		      (__read_long (&tmp_long, da_file, 4)
! 		       || tmp_long != fn_info->checksum)
! 		      /* arc count */
! 		      || (__read_long (&tmp_long, da_file, 4)
! 			  || tmp_long != fn_info->arc_count))
! 		    goto read_error;
! 		  
! 		  for (i = fn_info->arc_count; i > 0; i--, count_ptr++)
! 		    if (__read_gcov_type (&tmp_gcov, da_file, 8))
! 		      goto read_error;
! 		    else
! 		      *count_ptr += tmp_gcov;
! 		}
! 	    }
! 	  fseek (da_file, 0, SEEK_SET);
  	}
!       
!       /* Calculate the per-object statistics.  */
!       for (i = 0; i < ptr->ncounts; i++)
  	{
+ 	  object_sum += ptr->counts[i];
  
! 	  if (ptr->counts[i] > object_max)
! 	    object_max = ptr->counts[i];
! 	}
!       merged_sum += object_sum;
!       if (merged_max < object_max)
! 	merged_max = object_max;
!       merged_arcs += ptr->ncounts;
!       
!       /* Write out the data. */
!       if (/* magic */
! 	  __write_long (-123, da_file, 4)
! 	  /* number of functions in object file.  */
! 	  || __write_long (object_functions, da_file, 4)
  	  /* length of extra data in bytes.  */
! 	  || __write_long ((4 + 8 + 8) + (4 + 8 + 8), da_file, 4)
  
! 	  /* whole program statistics. If merging write per-object
! 	     now, rewrite later */
! 	  /* number of instrumented arcs.  */
! 	  || __write_long (merging ? ptr->ncounts : program_arcs, da_file, 4)
  	  /* sum of counters.  */
! 	  || __write_gcov_type (merging ? object_sum : program_sum, da_file, 8)
  	  /* maximal counter.  */
! 	  || __write_gcov_type (merging ? object_max : program_max, da_file, 8)
  
  	  /* per-object statistics.  */
  	  /* number of counters.  */
! 	  || __write_long (ptr->ncounts, da_file, 4)
  	  /* sum of counters.  */
! 	  || __write_gcov_type (object_sum, da_file, 8)
  	  /* maximal counter.  */
! 	  || __write_gcov_type (object_max, da_file, 8))
! 	{
! 	write_error:;
! 	  fprintf (stderr, "arc profiling: Error writing output file %s.\n",
! 		   ptr->filename);
! 	  error = 1;
! 	}
!       else
! 	{
! 	  /* Write execution counts for each function.  */
! 	  count_ptr = ptr->counts;
  
  	  for (fn_info = ptr->function_infos; fn_info->arc_count != -1;
  	       fn_info++)
  	    {
! 	      if (__write_gcov_string (fn_info->name,
! 				       strlen (fn_info->name), da_file, -1)
! 		  || __write_long (fn_info->checksum, da_file, 4)
! 		  || __write_long (fn_info->arc_count, da_file, 4))
! 		goto write_error;
! 	      
  	      for (i = fn_info->arc_count; i > 0; i--, count_ptr++)
! 		if (__write_gcov_type (*count_ptr, da_file, 8))
! 		  goto write_error; /* RIP Edsger Dijkstra */
  	    }
  	}
  
!       if (fclose (da_file))
! 	{
! 	  fprintf (stderr, "arc profiling: Error closing output file %s.\n",
! 		   ptr->filename);
! 	  error = 1;
! 	}
!       if (error || !merging)
! 	ptr->filename = 0;
      }
+ 
+   /* Upate whole program statistics.  */
+   for (ptr = bb_head; ptr; ptr = ptr->next)
+     if (ptr->filename)
+       {
+ 	FILE *da_file;
+ 	
+ 	da_file = fopen (ptr->filename, "r+b");
+ 	if (!da_file)
+ 	  {
+ 	    fprintf (stderr, "arc profiling: Cannot reopen %s.\n",
+ 		     ptr->filename);
+ 	    continue;
+ 	  }
+ 	
+ #if defined (TARGET_HAS_F_SETLKW)
+ 	while (fcntl (fileno (da_file), F_SETLKW, &s_flock)
+ 	       && errno == EINTR)
+ 	  continue;
+ #endif
+ 	
+ 	if (fseek (da_file, 4 * 3, SEEK_SET)
+ 	    /* number of instrumented arcs.  */
+ 	    || __write_long (program_arcs, da_file, 4)
+ 	    /* sum of counters.  */
+ 	    || __write_gcov_type (program_sum, da_file, 8)
+ 	    /* maximal counter.  */
+ 	    || __write_gcov_type (program_max, da_file, 8))
+ 	  fprintf (stderr, "arc profiling: Error updating program header %s.\n",
+ 		   ptr->filename);
+ 	if (fclose (da_file))
+ 	  fprintf (stderr, "arc profiling: Error reclosing %s\n",
+ 		   ptr->filename);
+       }
  }
  
+ /* Add a new object file onto the bb chain.  Invoked automatically
+    when running an object file's global ctors.  */
+ 
  void
  __bb_init_func (struct bb *blocks)
  {
    if (blocks->zero_word)
      return;
  
*************** __bb_init_func (struct bb *blocks)
*** 1473,1478 ****
--- 1549,1555 ----
  /* Called before fork or exec - write out profile information gathered so
     far and reset it to zero.  This avoids duplication or loss of the
     profile information gathered so far.  */
+ 
  void
  __bb_fork_func (void)
  {
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.930
diff -c -3 -p -r1.930 Makefile.in
*** Makefile.in	9 Aug 2002 08:51:27 -0000	1.930
--- Makefile.in	10 Aug 2002 16:21:48 -0000
*************** all.indirect: $(ALL)
*** 594,606 ****
  # IN_GCC distinguishes between code compiled into GCC itself and other
  # programs built during a bootstrap.
  # autoconf inserts -DCROSS_COMPILE if we are building a cross compiler.
! INTERNAL_CFLAGS = -DIN_GCC @CROSS@ $(COVERAGE_FLAGS)
  
  # This is the variable actually used when we compile.
  # If you change this line, you probably also need to change the definition
  # of HOST_CFLAGS in build-make to match.
  ALL_CFLAGS = $(X_CFLAGS) $(T_CFLAGS) \
!   $(CFLAGS) $(INTERNAL_CFLAGS) $(WARN_CFLAGS) $(XCFLAGS) @DEFS@
  
  # Likewise.
  ALL_CPPFLAGS = $(CPPFLAGS) $(X_CPPFLAGS) $(T_CPPFLAGS)
--- 594,606 ----
  # IN_GCC distinguishes between code compiled into GCC itself and other
  # programs built during a bootstrap.
  # autoconf inserts -DCROSS_COMPILE if we are building a cross compiler.
! INTERNAL_CFLAGS = -DIN_GCC @CROSS@
  
  # This is the variable actually used when we compile.
  # If you change this line, you probably also need to change the definition
  # of HOST_CFLAGS in build-make to match.
  ALL_CFLAGS = $(X_CFLAGS) $(T_CFLAGS) \
!   $(CFLAGS) $(INTERNAL_CFLAGS) $(COVERAGE_FLAGS) $(WARN_CFLAGS) $(XCFLAGS) @DEFS@
  
  # Likewise.
  ALL_CPPFLAGS = $(CPPFLAGS) $(X_CPPFLAGS) $(T_CPPFLAGS)

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2002-08-13 12:14 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-08-09 15:32 [gcov] Merge arc counts Nathan Sidwell
2002-08-09 18:44 ` Jan Hubicka
2002-08-12 14:06 ` Richard Henderson
2002-08-13  5:14   ` Nathan Sidwell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).