Hi.

Following patch enables to generate more parallel profiles for applications
that do intensive # of invocations. There's some discussion in the PR.

So one example:

$ gcc -fprofile-generate=/tmp/slavia/%p/%q{CPU}/ empty.c -O2 && ./a.out
$ l /tmp/slavia/22234/x86_64/empty.gcda
-rw-r--r-- 1 marxin users 172 May 18 13:20 /tmp/slavia/22234/x86_64/empty.gcda

Ready for trunk?
Thanks,
Martin

gcc/ChangeLog:

2018-05-18  Martin Liska  <mli...@suse.cz>

        PR gcov-profile/47618
        * opts.c (expand_profile_data_prefix): New function.
        (finish_options): Use it.

libgcc/ChangeLog:

2018-05-18  Martin Liska  <mli...@suse.cz>

        PR gcov-profile/47618
        * libgcov-driver-system.c (replace_filename_variables):
        New function.
        (gcov_exit_open_gcda_file): Use it.
---
 gcc/opts.c                     | 35 ++++++++++++++++++++
 libgcc/libgcov-driver-system.c | 73 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 108 insertions(+)


diff --git a/gcc/opts.c b/gcc/opts.c
index 33efcc0d6e7..fc337a9463f 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -690,6 +690,38 @@ default_options_optimization (struct gcc_options *opts,
 			 lang_mask, handlers, loc, dc);
 }
 
+/* Expand variables in x_profile_data_prefix.
+   Currently we support following options:
+
+   %w - current working directory
+   */
+
+static void
+expand_profile_data_prefix (gcc_options *opts)
+{
+  if (opts->x_profile_data_prefix != NULL)
+    {
+      const char *needle = "%w";
+      unsigned needle_strlen = strlen (needle);
+      while (true)
+	{
+	  char *p = CONST_CAST (char *, strstr (opts->x_profile_data_prefix,
+						needle));
+	  if (p)
+	    {
+	      *p = '\0';
+	      char *r = concat (opts->x_profile_data_prefix, getpwd (),
+				p + needle_strlen, NULL);
+
+	      free (CONST_CAST (char *, opts->x_profile_data_prefix));
+	      opts->x_profile_data_prefix = r;
+	    }
+	  else
+	    break;
+      }
+    }
+}
+
 /* After all options at LOC have been read into OPTS and OPTS_SET,
    finalize settings of those options and diagnose incompatible
    combinations.  */
@@ -1059,6 +1091,9 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
   if (opts->x_align_labels > MAX_CODE_ALIGN_VALUE)
     error_at (loc, "-falign-labels=%d is not between 0 and %d",
 	      opts->x_align_labels, MAX_CODE_ALIGN_VALUE);
+
+  /* Expand variables in x_profile_data_prefix.  */
+  expand_profile_data_prefix (opts);
 }
 
 #define LEFT_COLUMN	27
diff --git a/libgcc/libgcov-driver-system.c b/libgcc/libgcov-driver-system.c
index 0df44239363..d45ac4b31ba 100644
--- a/libgcc/libgcov-driver-system.c
+++ b/libgcc/libgcov-driver-system.c
@@ -128,6 +128,77 @@ create_file_directory (char *filename)
 #endif
 }
 
+/* Replace filename variables in FILENAME.  We currently support expansion:
+
+   %p - process ID
+   %q{ENV} - value of environment variable ENV
+   */
+
+static char *
+replace_filename_variables (char *filename)
+{
+  char buffer[16];
+  char empty[] = "";
+  for (char *p = filename; *p != '\0'; p++)
+    {
+      unsigned length = strlen (filename);
+      if (*p == '%' && *(p + 1) != '\0')
+	{
+	  unsigned start = p - filename;
+	  p++;
+	  char *replacement = NULL;
+	  switch (*p)
+	    {
+	    case 'p':
+	      sprintf (buffer, "%d", getpid ());
+	      replacement = buffer;
+	      p++;
+	      break;
+	    case 'q':
+	      if (*(p + 1) == '{')
+		{
+		  p += 2;
+		  char *e = strchr (p, '}');
+		  if (e)
+		    {
+		      *e = '\0';
+		      replacement = getenv (p);
+		      if (replacement == NULL)
+			replacement = empty;
+		      p = e + 1;
+		    }
+		  else
+		    return filename;
+		}
+	      break;
+	    default:
+	      return filename;
+	    }
+
+	  /* Concat beginning of the path, replacement and
+	     ending of the path.  */
+	  unsigned end = length - (p - filename);
+	  unsigned repl_length = strlen (replacement);
+
+	  char *buffer = (char *)xmalloc (start + end + repl_length + 1);
+	  char *buffer_ptr = buffer;
+	  memcpy (buffer_ptr, filename, start);
+	  buffer_ptr += start;
+	  memcpy (buffer_ptr, replacement, repl_length);
+	  buffer_ptr += repl_length;
+	  memcpy (buffer_ptr, p, end);
+	  buffer_ptr += end;
+	  *buffer_ptr = '\0';
+
+	  free (filename);
+	  filename = buffer;
+	  p = buffer + start + repl_length;
+	}
+    }
+
+  return filename;
+}
+
 static void
 allocate_filename_struct (struct gcov_filename *gf)
 {
@@ -216,6 +287,8 @@ gcov_exit_open_gcda_file (struct gcov_info *gi_ptr,
     }
   strcpy (dst, fname);
 
+  gf->filename = replace_filename_variables (gf->filename);
+
   if (!gcov_open (gf->filename))
     {
       /* Open failed likely due to missed directory.

Reply via email to