This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [4.1 patch] relocate profile data file


Hi,
This is updated libgcov relocation patch. It includes:
 - info pages rewording
 - getenv moved to gcov_exit
 - full filename generating in gcov_exit not in callees
 - single alloca with respect to longest file name
 - create_file_directory is still there (see reasons below)

We try to keep libgcov error messages clear, distinguishing between directory creation failure and file open failure. It appears that routine gcov_open is not suitable to emit messages because it is originally silent. At the same time gcov_open's return value is not suitable to handle two failures in the caller because only one value reserved for error condition. Thus it is impossible to put directory creation into gcov_open without significant interface changes.

- Grigory

2005-05-04  Grigory Zagorodnev  <grigory.zagorodnev@intel.com>
	    H.J. Lu  <hongjiu.lu@intel.com>

	* libgcov.c (create_file_directory): New function.
	(gcov_max_filename): New static var. Keeps size
	of the longest file name.
	(gcov_exit): Always try to create directory for output
	file. Relocate each filename basing on environment vars.
	(__gcov_init): remember the longest file name.

	* tsystem.h: include filenames.h
	(DIR_SEPARATOR): Macro copied from system.h.
	(DIR_SEPARATOR_2): Likewise.

	* doc/gcov.texi (Cross-profiling): New node documenting
	cross-profiling management.

* doc/invoke.texi (-fprofile-arcs): xref to cross-profiling.


Index: gcc/libgcov.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/libgcov.c,v
retrieving revision 1.29
diff -c -3 -p -r1.29 libgcov.c
*** gcc/libgcov.c	28 Apr 2005 05:38:32 -0000	1.29
--- gcc/libgcov.c	6 May 2005 09:26:27 -0000
*************** static struct gcov_info *gcov_list;
*** 92,97 ****
--- 92,144 ----
     object file included in multiple programs.  */
  static gcov_unsigned_t gcov_crc32;
  
+ /* Size of the longest file name. */
+ static size_t gcov_max_filename = 0;
+ 
+ static int
+ create_file_directory (const char *filename, char sep)
+ {
+   char *dname;
+   char *r, *s;
+ 
+   /* Get a copy of the name so we can modify it. */
+   r = alloca(strlen(filename) + 1);
+   strcpy(r, filename);
+   
+   /* Split path- and file-names. */
+   s = strrchr(r, sep);
+   if (s)
+     *(s + 1) = '\0';
+ 
+   if (access (r, F_OK) == 0)
+     return 0;
+ 
+   /* Skip consecutive separators.  */
+   for (dname = r; *dname && *dname == sep; ++dname);
+   while (1)
+     {
+       char *s = strchr (dname, sep);
+       if (s == 0)
+         break;
+       *s = '\0';
+       /* Try to make directory if it doesn't already exist.  */
+       if (access (r, F_OK) == -1
+           && mkdir (r, 0755) == -1
+           /* The directory might have been made by another process.  */
+ 	  && errno != EEXIST)
+ 	{
+           *s = sep;
+           fprintf (stderr, "profiling:%s:Cannot create directory\n", r);
+ 	  return -1;
+ 	};
+       *s = sep;
+       /* Skip consecutive separators.  */
+       for (dname = s + 1; *dname && *dname == sep; ++dname)
+         ;
+     }
+   return 0;
+ }
+ 
  static int
  gcov_version (struct gcov_info *ptr, gcov_unsigned_t version)
  {
*************** gcov_exit (void)
*** 127,132 ****
--- 174,183 ----
    const struct gcov_ctr_info *ci_ptr;
    unsigned t_ix;
    gcov_unsigned_t c_num;
+   const char *gcov_prefix;
+   int gcov_prefix_strip = 0;
+   char *gi_filename, *gi_filename_up;
+   char dir_separator, *s;
  
    memset (&all, 0, sizeof (all));
    /* Find the totals for this execution.  */
*************** gcov_exit (void)
*** 151,156 ****
--- 202,244 ----
  	}
      }
  
+   /* Get file name relocation prefix. */
+   gcov_prefix = getenv("GCOV_PREFIX");
+   if (gcov_prefix)
+     {
+       /* Check if the level of dirs to strip off specified. */
+       char *tmp = getenv("GCOV_PREFIX_STRIP");
+       if (tmp)
+         {
+           gcov_prefix_strip = atoi (tmp);
+           /* Do not consider negative values. */
+           if (gcov_prefix_strip < 0)
+             gcov_prefix_strip = 0;
+         }
+     }
+   else 
+     gcov_prefix = "";
+ 
+   /* Detect directory separator for future use. */
+   s = strrchr (gcov_prefix, DIR_SEPARATOR);
+ #ifdef DIR_SEPARATOR_2
+   if (! s)
+     s = strrchr (gcov_prefix, DIR_SEPARATOR_2);
+ #endif
+   if (s)
+     dir_separator = *s;
+   else
+     dir_separator = DIR_SEPARATOR;
+ 
+   /* Allocate sufficient stack space for file name relocation. */
+   gi_filename = alloca( strlen(gcov_prefix) + gcov_max_filename + 1);
+ 
+   /* Store and mormalize filename prefix. */
+   strcpy (gi_filename, gcov_prefix);
+   gi_filename_up = gi_filename + strlen(gcov_prefix);
+   if (gi_filename_up > gi_filename && *(gi_filename_up - 1) == dir_separator)
+       gi_filename_up--;
+   
    /* Now merge each file.  */
    for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
      {
*************** gcov_exit (void)
*** 169,174 ****
--- 257,287 ----
        memset (&this_object, 0, sizeof (this_object));
        memset (&object, 0, sizeof (object));
        
+       /* Build relocated filename, stripping off leading 
+          directories from the initial filename if requested. */
+       if (gcov_prefix_strip > 0)
+         {
+           int level;
+           const char *fname = gi_ptr->filename;
+ 
+           /* Skip selected directory levels. */
+           for (level = gcov_prefix_strip; level > 0; level--)
+             if ((s = strchr(fname + 1, dir_separator)))
+ 	      fname = s;
+ 	    else
+ 	      break;
+ 
+           /* Update complete filename with stripped original. */
+           strcpy (gi_filename_up, fname);
+         }
+       else
+         strcpy (gi_filename_up, gi_ptr->filename);
+ 
+       /* It seems to be safe to update info block with the pointer 
+          to stack area - each block is used once within the loop
+          and will be unloaded after gcov_exit return. */
+       gi_ptr->filename = gi_filename;
+       
        /* Totals for this object file.  */
        ci_ptr = gi_ptr->counts;
        for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
*************** gcov_exit (void)
*** 205,211 ****
  	  fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
  	}
        
!       if (!gcov_open (gi_ptr->filename))
  	{
  	  fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
  	  continue;
--- 318,329 ----
  	  fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
  	}
        
!       if (create_file_directory (gi_ptr->filename, dir_separator))
! 	{
! 	  fprintf (stderr, "profiling:%s:Skip\n", gi_ptr->filename);
! 	  continue;
! 	}
!       else if (!gcov_open (gi_ptr->filename))
  	{
  	  fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
  	  continue;
*************** __gcov_init (struct gcov_info *info)
*** 458,463 ****
--- 576,586 ----
        
        if (!gcov_list)
  	atexit (gcov_exit);
+ 
+       /* Refresh the longest file name information */
+       ptr = info->filename + strlen(info->filename);
+       if (gcov_max_filename < (size_t)(ptr - info->filename))
+         gcov_max_filename = ptr - info->filename;
        
        info->next = gcov_list;
        gcov_list = info;
Index: gcc/tsystem.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/tsystem.h,v
retrieving revision 1.17
diff -c -3 -p -r1.17 tsystem.h
*** gcc/tsystem.h	29 Mar 2005 22:15:53 -0000	1.17
--- gcc/tsystem.h	6 May 2005 09:26:27 -0000
*************** extern int errno;
*** 131,134 ****
--- 131,145 ----
     unreachable default case of a switch.  Do not use gcc_assert(0).  */
  #define gcc_unreachable() (abort ())
  
+ /* Filename handling macros.  */
+ #include "filenames.h"
+ 
+ /* These should be phased out in favor of IS_DIR_SEPARATOR, where possible.  */
+ #ifndef DIR_SEPARATOR
+ # define DIR_SEPARATOR '/'
+ # ifdef HAVE_DOS_BASED_FILE_SYSTEM
+ #  define DIR_SEPARATOR_2 '\\'
+ # endif
+ #endif
+ 
  #endif /* ! GCC_TSYSTEM_H */
Index: gcc/doc/gcov.texi
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/doc/gcov.texi,v
retrieving revision 1.26
diff -c -3 -p -r1.26 gcov.texi
*** gcc/doc/gcov.texi	21 Mar 2005 12:31:10 -0000	1.26
--- gcc/doc/gcov.texi	6 May 2005 09:26:27 -0000
*************** test code coverage in your programs.
*** 42,47 ****
--- 42,48 ----
  * Invoking Gcov::       	How to use gcov.
  * Gcov and Optimization::       Using gcov with GCC optimization.
  * Gcov Data Files::             The files used by gcov.
+ * Cross-profiling::             Data file relocation.
  @end menu
  
  @node Gcov Intro
*************** information.
*** 531,533 ****
--- 532,569 ----
  The full details of the file format is specified in @file{gcov-io.h},
  and functions provided in that header file should be used to access the
  coverage files.
+ 
+ @node Cross-profiling
+ @section Data file relocation to support cross-profiling
+ 
+ Running the program will cause profile output to be generated.  For each 
+ source file compiled with @option{-fprofile-arcs}, an accompanying @file{.gcda} 
+ file will be placed in the object file directory. That implicitly requires 
+ running the program on the same system as it was built or having the same 
+ absolute directory structure on the target system. The program will try
+ to create the needed directory structure, if it is not already present.
+ 
+ To support cross-profiling, a program compiled with @option{-fprofile-arcs}
+ can relocate the data files based on two environment variables: 
+ 
+ @itemize @bullet
+ @item
+ GCOV_PREFIX contains the prefix to add to the absolute paths 
+ in the object file. The default is no prefix.
+ 
+ @item
+ GCOV_PREFIX_STRIP indicates the how many initial directory names to strip off
+ the hardwired absolute paths. Default value is 0.
+ @end itemize
+ 
+ For example, if the object file @file{/user/build/foo.o} was built with
+ @option{-fprofile-arcs}, the final executable will try to create the data file
+ @file{/user/build/foo.gcda} when running on the target system.  This will
+ fail if the corresponding directory does not exist and it is unable to create
+ it.  This can be overcome by, for example, setting the environment as
+ @samp{GCOV_PREFIX=/target/run} and @samp{GCOV_PREFIX_STRIP=1}.  Such a
+ setting will name the data file @file{/target/run/build/foo.gcda}.
+ 
+ You must move the data files to the expected directory tree in order to
+ use them for profile directed optimizations (@option{--use-profile}), or to
+ use the the @command{gcov} tool.
Index: gcc/doc/invoke.texi
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.613
diff -c -3 -p -r1.613 invoke.texi
*** gcc/doc/invoke.texi	5 May 2005 20:54:16 -0000	1.613
--- gcc/doc/invoke.texi	6 May 2005 09:26:27 -0000
*************** explicitly specified and it is not the f
*** 3422,3427 ****
--- 3422,3428 ----
  the basename of the source file.  In both cases any suffix is removed
  (e.g.@: @file{foo.gcda} for input file @file{dir/foo.c}, or
  @file{dir/foo.gcda} for output file specified as @option{-o dir/foo.o}).
+ @xref{Cross-profiling}.
  
  @cindex @command{gcov}
  @item --coverage

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]