OSDN Git Service

* libgcov.c (create_file_directory): New function. Create
authornathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 10 May 2005 16:10:54 +0000 (16:10 +0000)
committernathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 10 May 2005 16:10:54 +0000 (16:10 +0000)
directory for the given file name.
(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 to get IS_DIR_SEPARATOR
* doc/gcov.texi (Cross-profiling): New node documenting
cross-profiling management.
* doc/invoke.texi (-fprofile-arcs): Add xref to cross-profiling.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@99523 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/doc/gcov.texi
gcc/doc/invoke.texi
gcc/libgcov.c
gcc/tsystem.h

index e54a84d..5152682 100644 (file)
@@ -1,3 +1,18 @@
+2005-05-11  Grigory Zagorodnev  <grigory.zagorodnev@intel.com>
+            H.J. Lu  <hongjiu.lu@intel.com   
+
+       * libgcov.c (create_file_directory): New function. Create
+       directory for the given file name.
+       (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 to get IS_DIR_SEPARATOR
+       * doc/gcov.texi (Cross-profiling): New node documenting
+       cross-profiling management.
+       * doc/invoke.texi (-fprofile-arcs): Add xref to cross-profiling.
+
 2005-05-10  Eric Botcazou  <ebotcazou@libertysurf.fr>
 
        * config/sparc/sparc.c (mem_min_alignment): Do not rely
index bfe4a3d..d932ab9 100644 (file)
@@ -42,6 +42,7 @@ test code coverage in your programs.
 * 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
@@ -531,3 +532,42 @@ information.
 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. Prefix must be absolute as well, otherwise its 
+value is ignored. 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.
+
+@emph{Note:} GCOV_PREFIX_STRIP has no effect if GCOV_PREFIX is undefined, empty
+or non-absolute.
+@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 7c2c49e..d95b354 100644 (file)
@@ -3427,6 +3427,7 @@ explicitly specified and it is not the final executable, otherwise it is
 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 8061383..8b478a7 100644 (file)
@@ -88,8 +88,49 @@ static struct gcov_info *gcov_list;
    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;
+
+/* Make sure path compenent of the given FILENAME exists, create 
+   missing directories. FILENAME must be writable. 
+   Returns zero on success, or -1 if an error occurred.  */
+
+static int
+create_file_directory (char *filename)
+{
+  char *s;
+
+  for (s = filename + 1; *s != '\0'; s++)
+    if (IS_DIR_SEPARATOR(*s))
+      {
+        char sep = *s;
+       *s  = '\0';
+
+        /* Try to make directory if it doesn't already exist.  */
+        if (access (filename, F_OK) == -1
+            && mkdir (filename, 0755) == -1
+            /* The directory might have been made by another process.  */
+           && errno != EEXIST)
+         {
+            fprintf (stderr, "profiling:%s:Cannot create directory\n",
+                    filename);
+            *s = sep;
+           return -1;
+         };
+        
+       *s = sep;
+      };
+  return 0;
+}
+
+/* Check if VERSION of the info block PTR matches libgcov one.
+   Return 1 on success, or zero in case of versions mismatch.
+   If FILENAME is not NULL, its value used for reporting purposes 
+   instead of value from the info block.  */
+   
 static int
-gcov_version (struct gcov_info *ptr, gcov_unsigned_t version)
+gcov_version (struct gcov_info *ptr, gcov_unsigned_t version,
+             const char *filename)
 {
   if (version != GCOV_VERSION)
     {
@@ -100,7 +141,7 @@ gcov_version (struct gcov_info *ptr, gcov_unsigned_t version)
       
       fprintf (stderr,
               "profiling:%s:Version mismatch - expected %.4s got %.4s\n",
-              ptr->filename, e, v);
+              filename? filename : ptr->filename, e, v);
       return 0;
     }
   return 1;
@@ -123,6 +164,10 @@ gcov_exit (void)
   const struct gcov_ctr_info *ci_ptr;
   unsigned t_ix;
   gcov_unsigned_t c_num;
+  const char *gcov_prefix;
+  int gcov_prefix_strip = 0;
+  size_t prefix_length;
+  char *gi_filename, *gi_filename_up;
 
   memset (&all, 0, sizeof (all));
   /* Find the totals for this execution.  */
@@ -147,6 +192,33 @@ gcov_exit (void)
        }
     }
 
+  /* Get file name relocation prefix.  Non-absolute values are ignored. */
+  gcov_prefix = getenv("GCOV_PREFIX");
+  if (gcov_prefix && IS_ABSOLUTE_PATH (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;
+        }
+      
+      prefix_length = strlen(gcov_prefix);
+
+      /* Remove an unneccesary trailing '/' */
+      if (IS_DIR_SEPARATOR (gcov_prefix[prefix_length - 1]))
+       prefix_length--;
+    }
+  
+  /* Allocate and initialize the filename scratch space.  */
+  gi_filename = alloca (prefix_length + gcov_max_filename + 1);
+  if (prefix_length)
+    memcpy (gi_filename, gcov_prefix, prefix_length);
+  gi_filename_up = gi_filename + prefix_length;
+  
   /* Now merge each file.  */
   for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
     {
@@ -165,6 +237,28 @@ gcov_exit (void)
       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 = 0;
+          const char *fname = gi_ptr->filename;
+          const char *s;
+
+          /* Skip selected directory levels. */
+         for (s = fname + 1; (*s != '\0') && (level < gcov_prefix_strip); s++)
+           if (IS_DIR_SEPARATOR(*s))
+             {
+               fname = s;
+               level++;
+             };
+
+          /* Update complete filename with stripped original. */
+          strcpy (gi_filename_up, fname);
+        }
+      else
+        strcpy (gi_filename_up, gi_ptr->filename);
+
       /* Totals for this object file.  */
       ci_ptr = gi_ptr->counts;
       for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
@@ -201,10 +295,20 @@ gcov_exit (void)
          fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
        }
       
-      if (!gcov_open (gi_ptr->filename))
+      if (!gcov_open (gi_filename))
        {
-         fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
-         continue;
+         /* Open failed likely due to missed directory.
+            Create directory and retry to open file. */
+          if (create_file_directory (gi_filename))
+           {
+             fprintf (stderr, "profiling:%s:Skip\n", gi_filename);
+             continue;
+           }
+         if (!gcov_open (gi_filename))
+           {
+              fprintf (stderr, "profiling:%s:Cannot open\n", gi_filename);
+             continue;
+           }
        }
 
       tag = gcov_read_unsigned ();
@@ -214,11 +318,11 @@ gcov_exit (void)
          if (tag != GCOV_DATA_MAGIC)
            {
              fprintf (stderr, "profiling:%s:Not a gcov data file\n",
-                      gi_ptr->filename);
+                      gi_filename);
              goto read_fatal;
            }
          length = gcov_read_unsigned ();
-         if (!gcov_version (gi_ptr, length))
+         if (!gcov_version (gi_ptr, length, gi_filename))
            goto read_fatal;
 
          length = gcov_read_unsigned ();
@@ -242,7 +346,7 @@ gcov_exit (void)
                {
                read_mismatch:;
                  fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
-                          gi_ptr->filename,
+                          gi_filename,
                           f_ix + 1 ? "function" : "summaries");
                  goto read_fatal;
                }
@@ -301,7 +405,7 @@ gcov_exit (void)
       
     read_error:;
       fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
-              : "profiling:%s:Error merging\n", gi_ptr->filename);
+              : "profiling:%s:Error merging\n", gi_filename);
              
     read_fatal:;
       gcov_close ();
@@ -352,7 +456,7 @@ gcov_exit (void)
                   && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
            {
              fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
-                      gi_ptr->filename, GCOV_LOCKED
+                      gi_filename, GCOV_LOCKED
                       ? "" : " or concurrent update without locking support");
              all.checksum = ~0u;
            }
@@ -417,7 +521,7 @@ gcov_exit (void)
          fprintf (stderr, error  < 0 ?
                   "profiling:%s:Overflow writing\n" :
                   "profiling:%s:Error writing\n",
-                  gi_ptr->filename);
+                  gi_filename);
     }
 }
 
@@ -429,11 +533,16 @@ __gcov_init (struct gcov_info *info)
 {
   if (!info->version)
     return;
-  if (gcov_version (info, info->version))
+  if (gcov_version (info, info->version, 0))
     {
       const char *ptr = info->filename;
       gcov_unsigned_t crc32 = gcov_crc32;
-  
+      size_t filename_length =  strlen(info->filename);
+
+      /* Refresh the longest file name information */
+      if (filename_length > gcov_max_filename)
+        gcov_max_filename = filename_length;
+      
       do
        {
          unsigned ix;
index 1ed0cde..bc8384e 100644 (file)
@@ -131,4 +131,7 @@ extern int errno;
    unreachable default case of a switch.  Do not use gcc_assert(0).  */
 #define gcc_unreachable() (abort ())
 
+/* Filename handling macros.  */
+#include "filenames.h"
+
 #endif /* ! GCC_TSYSTEM_H */