This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [4.1 patch] relocate profile data file
Yet another attempt. This update includes:
- use IS_DIR_SEPARATOR instead of DIR_SEPARATOR{,_2}
- optimized disk traffic regarding to dir creation
- optimized memory usage in create_file_directory
- simplified string length comparison
- avoiding info structure modification
- user documentation updated with macro dependencies
Some notes below...
+ const char *gcov_prefix;
+ int gcov_prefix_strip = 0;
Now these are no longer global, there's really no need for the
gcov_ prefix
Right. These are not global; gcov_prefix is used as temporary local
variable regardless of its name.
you only look at GCOV_PREFIX_STRIP if GCOV_PREFIX is non-empty.
This is not documented. Maybe you should look at both independently,
and if GCOV_PREFIX is empty, but GCOV_PREFIX_STRIP is not set (but might
or might not be zero), then set the prefix to '.'. I think that
would match user expectation in that situation.
This usage model is logically correct but seems to be a bit complicated.
I'd suggest user to specify exact path to place data files on the target
system, more likely using absolute path prefix. Otherwise relocation is
meaningless. Implicitly allowing non-absolute paths we'll reach troubles
with application changing working directory back and forth. There is
more general question: should we allow relative GCOV_PREFIX at all?
User documentation has been updated with macro dependency information.
- Grigory
2005-05-06 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): 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 22:28:47 -0000
*************** static struct gcov_info *gcov_list;
*** 92,99 ****
object file included in multiple programs. */
static gcov_unsigned_t gcov_crc32;
static int
! gcov_version (struct gcov_info *ptr, gcov_unsigned_t version)
{
if (version != GCOV_VERSION)
{
--- 92,132 ----
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 (char *filename)
! {
! char *s;
!
! if (!filename || *filename == '\0')
! return -2;
!
! 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;
! }
!
! static int
! gcov_version (struct gcov_info *ptr, gcov_unsigned_t version, const char *filename)
{
if (version != GCOV_VERSION)
{
*************** gcov_version (struct gcov_info *ptr, gco
*** 104,110 ****
fprintf (stderr,
"profiling:%s:Version mismatch - expected %.4s got %.4s\n",
! ptr->filename, e, v);
return 0;
}
return 1;
--- 137,143 ----
fprintf (stderr,
"profiling:%s:Version mismatch - expected %.4s got %.4s\n",
! filename? filename : ptr->filename, e, v);
return 0;
}
return 1;
*************** gcov_exit (void)
*** 127,132 ****
--- 160,169 ----
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 *s;
memset (&all, 0, sizeof (all));
/* Find the totals for this execution. */
*************** gcov_exit (void)
*** 151,156 ****
--- 188,227 ----
}
}
+ /* Get file name relocation prefix. */
+ gcov_prefix = getenv("GCOV_PREFIX");
+ if (gcov_prefix && *gcov_prefix != '\0')
+ {
+ size_t prefix_length = strlen(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_strip = 0;
+
+ /* Allocate sufficient stack space for file name relocation. */
+ gi_filename = alloca( prefix_length + gcov_max_filename + 1);
+
+ /* Store and mormalize filename prefix. */
+ strcpy (gi_filename, gcov_prefix);
+ gi_filename_up = gi_filename + prefix_length;
+ if (gi_filename_up > gi_filename && IS_DIR_SEPARATOR(*(gi_filename_up - 1)))
+ gi_filename_up--;
+ }
+ else
+ {
+ /* Allocate sufficient stack space for file name with no prefix. */
+ gi_filename = alloca( gcov_max_filename + 1);
+ gi_filename_up = gi_filename;
+ };
+
/* Now merge each file. */
for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
{
*************** gcov_exit (void)
*** 169,174 ****
--- 240,266 ----
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;
+
+ /* 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++)
*************** gcov_exit (void)
*** 205,214 ****
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;
}
tag = gcov_read_unsigned ();
--- 297,316 ----
fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
}
! if (!gcov_open (gi_filename))
{
! /* 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 ();
*************** gcov_exit (void)
*** 218,228 ****
if (tag != GCOV_DATA_MAGIC)
{
fprintf (stderr, "profiling:%s:Not a gcov data file\n",
! gi_ptr->filename);
goto read_fatal;
}
length = gcov_read_unsigned ();
! if (!gcov_version (gi_ptr, length))
goto read_fatal;
length = gcov_read_unsigned ();
--- 320,330 ----
if (tag != GCOV_DATA_MAGIC)
{
fprintf (stderr, "profiling:%s:Not a gcov data file\n",
! gi_filename);
goto read_fatal;
}
length = gcov_read_unsigned ();
! if (!gcov_version (gi_ptr, length, gi_filename))
goto read_fatal;
length = gcov_read_unsigned ();
*************** gcov_exit (void)
*** 246,252 ****
{
read_mismatch:;
fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
! gi_ptr->filename,
f_ix + 1 ? "function" : "summaries");
goto read_fatal;
}
--- 348,354 ----
{
read_mismatch:;
fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
! gi_filename,
f_ix + 1 ? "function" : "summaries");
goto read_fatal;
}
*************** gcov_exit (void)
*** 305,311 ****
read_error:;
fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
! : "profiling:%s:Error merging\n", gi_ptr->filename);
read_fatal:;
gcov_close ();
--- 407,413 ----
read_error:;
fprintf (stderr, error < 0 ? "profiling:%s:Overflow merging\n"
! : "profiling:%s:Error merging\n", gi_filename);
read_fatal:;
gcov_close ();
*************** gcov_exit (void)
*** 356,362 ****
&& 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
? "" : " or concurrent update without locking support");
all.checksum = ~0u;
}
--- 458,464 ----
&& memcmp (cs_all, cs_prg, sizeof (*cs_all)))
{
fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
! gi_filename, GCOV_LOCKED
? "" : " or concurrent update without locking support");
all.checksum = ~0u;
}
*************** gcov_exit (void)
*** 421,427 ****
fprintf (stderr, error < 0 ?
"profiling:%s:Overflow writing\n" :
"profiling:%s:Error writing\n",
! gi_ptr->filename);
}
}
--- 523,529 ----
fprintf (stderr, error < 0 ?
"profiling:%s:Overflow writing\n" :
"profiling:%s:Error writing\n",
! gi_filename);
}
}
*************** __gcov_init (struct gcov_info *info)
*** 433,443 ****
{
if (!info->version)
return;
! if (gcov_version (info, info->version))
{
const char *ptr = info->filename;
gcov_unsigned_t crc32 = gcov_crc32;
!
do
{
unsigned ix;
--- 535,550 ----
{
if (!info->version)
return;
! 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: 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 22:28:47 -0000
*************** extern int errno;
*** 131,134 ****
--- 131,137 ----
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 */
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 22:28:47 -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,571 ----
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.
+
+ @emph{Note:} GCOV_PREFIX_STRIP has no effect if GCOV_PREFIX is undefined or empty.
+ @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 22:28:47 -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