gcov: emit hotness colors to easily find hot code.
authorMartin Liska <mliska@suse.cz>
Mon, 17 Sep 2018 08:49:09 +0000 (10:49 +0200)
committerMartin Liska <marxin@gcc.gnu.org>
Mon, 17 Sep 2018 08:49:09 +0000 (08:49 +0000)
2018-09-17  Martin Liska  <mliska@suse.cz>

* doc/gcov.texi: Document new option --use-hotness-colors.
* gcov.c (struct source_info): Declare new field.
(source_info::source_info): Set default for maximum_count.
(print_usage): Add new -q option.
(process_args): Process it.
(accumulate_line_info): Save src->maximum_count.
(output_line_beginning): Make color line number if
flag_use_hotness_colors is set.
(output_line_details): Pass default argument value.
(output_lines): Pass src->maximum_count.

From-SVN: r264360

gcc/ChangeLog
gcc/doc/gcov.texi
gcc/gcov.c

index db4c06541b8acee4daef92c84c176da65f8ea671..fb43ecaf4be98287251e51e40b363ad9249a1fca 100644 (file)
@@ -1,3 +1,16 @@
+2018-09-17  Martin Liska  <mliska@suse.cz>
+
+       * doc/gcov.texi: Document new option --use-hotness-colors.
+       * gcov.c (struct source_info): Declare new field.
+       (source_info::source_info): Set default for maximum_count.
+       (print_usage): Add new -q option.
+       (process_args): Process it.
+       (accumulate_line_info): Save src->maximum_count.
+       (output_line_beginning): Make color line number if
+       flag_use_hotness_colors is set.
+       (output_line_details): Pass default argument value.
+       (output_lines): Pass src->maximum_count.
+
 2018-09-17  Martin Liska  <mliska@suse.cz>
 
        * common/config/i386/i386-common.c (ix86_get_valid_option_values):
index 98f4a876293fc36b2bdb1527cf965b48c25c9a80..3b1b38aebfa2bf93ba22832a2593b16e24c34c97 100644 (file)
@@ -132,6 +132,7 @@ gcov [@option{-v}|@option{--version}] [@option{-h}|@option{--help}]
      [@option{-n}|@option{--no-output}]
      [@option{-o}|@option{--object-directory} @var{directory|file}]
      [@option{-p}|@option{--preserve-paths}]
+     [@option{-q}|@option{--use-hotness-colors}]
      [@option{-r}|@option{--relative-only}]
      [@option{-s}|@option{--source-prefix} @var{directory}]
      [@option{-t}|@option{--stdout}]
@@ -264,7 +265,6 @@ Use colors for lines of code that have zero coverage.  We use red color for
 non-exceptional lines and cyan for exceptional.  Same colors are used for
 basic blocks with @option{-a} option.
 
-
 @item -l
 @itemx --long-file-names
 Create long file names for included source files.  For example, if the
@@ -305,6 +305,12 @@ removed and unremoveable @file{..}
 components renamed to @samp{^}.  This is useful if sourcefiles are in several
 different directories.
 
+@item -q
+@itemx --use-hotness-colors
+
+Emit perf-like colored output for hot lines.  Legend of the color scale
+is printed at the very beginning of the output file.
+
 @item -r
 @itemx --relative-only
 Only output information about source files with a relative pathname
index 6a24a3200469e73d5d84f6c982f5227213db87c1..64ab85c981fe3d33773c15fcbefd71dc8162545e 100644 (file)
@@ -339,13 +339,16 @@ struct source_info
 
   coverage_info coverage;
 
+  /* Maximum line count in the source file.  */
+  unsigned int maximum_count;
+
   /* Functions in this source file.  These are in ascending line
      number order.  */
   vector <function_info *> functions;
 };
 
 source_info::source_info (): index (0), name (NULL), file_time (),
-  lines (), coverage (), functions ()
+  lines (), coverage (), maximum_count (0), functions ()
 {
 }
 
@@ -502,6 +505,10 @@ static int flag_verbose = 0;
 
 static int flag_use_colors = 0;
 
+/* Use perf-like colors to indicate hot lines.  */
+
+static int flag_use_hotness_colors = 0;
+
 /* Output count information for every basic block, not merely those
    that contain line number information.  */
 
@@ -839,6 +846,7 @@ print_usage (int error_p)
   fnotice (file, "  -n, --no-output                 Do not create an output file\n");
   fnotice (file, "  -o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
   fnotice (file, "  -p, --preserve-paths            Preserve all pathname components\n");
+  fnotice (file, "  -q, --use-hotness-colors        Emit perf-like colored output for hot lines\n");
   fnotice (file, "  -r, --relative-only             Only show data for relative sources\n");
   fnotice (file, "  -s, --source-prefix DIR         Source prefix to elide\n");
   fnotice (file, "  -t, --stdout                    Output to stdout instead of a file\n");
@@ -890,6 +898,7 @@ static const struct option options[] =
   { "display-progress",     no_argument,       NULL, 'd' },
   { "hash-filenames",      no_argument,       NULL, 'x' },
   { "use-colors",          no_argument,       NULL, 'k' },
+  { "use-hotness-colors",   no_argument,       NULL, 'q' },
   { 0, 0, 0, 0 }
 };
 
@@ -900,7 +909,7 @@ process_args (int argc, char **argv)
 {
   int opt;
 
-  const char *opts = "abcdfhijklmno:prs:tuvwx";
+  const char *opts = "abcdfhijklmno:pqrs:tuvwx";
   while ((opt = getopt_long (argc, argv, opts, options, NULL)) != -1)
     {
       switch (opt)
@@ -929,6 +938,9 @@ process_args (int argc, char **argv)
        case 'k':
          flag_use_colors = 1;
          break;
+       case 'q':
+         flag_use_hotness_colors = 1;
+         break;
        case 'm':
          flag_demangled_names = 1;
          break;
@@ -2580,6 +2592,9 @@ static void accumulate_line_info (line_info *line, source_info *src,
       /* Now, add the count of loops entirely on this line.  */
       count += get_cycles_count (*line);
       line->count = count;
+
+      if (line->count > src->maximum_count)
+       src->maximum_count = line->count;
     }
 
   if (line->exists && add_coverage)
@@ -2756,7 +2771,8 @@ output_line_beginning (FILE *f, bool exists, bool unexceptional,
                       bool has_unexecuted_block,
                       gcov_type count, unsigned line_num,
                       const char *exceptional_string,
-                      const char *unexceptional_string)
+                      const char *unexceptional_string,
+                      unsigned int maximum_count)
 {
   string s;
   if (exists)
@@ -2806,7 +2822,23 @@ output_line_beginning (FILE *f, bool exists, bool unexceptional,
       pad_count_string (s);
     }
 
-  fprintf (f, "%s:%5u", s.c_str (), line_num);
+  /* Format line number in output.  */
+  char buffer[16];
+  sprintf (buffer, "%5u", line_num);
+  string linestr (buffer);
+
+  if (flag_use_hotness_colors && maximum_count)
+    {
+      if (count * 2 > maximum_count) /* > 50%.  */
+       linestr.insert (0, SGR_SEQ (COLOR_BG_RED));
+      else if (count * 5 > maximum_count) /* > 20%.  */
+       linestr.insert (0, SGR_SEQ (COLOR_BG_YELLOW));
+      else if (count * 10 > maximum_count) /* > 10%.  */
+       linestr.insert (0, SGR_SEQ (COLOR_BG_GREEN));
+      linestr += SGR_RESET;
+    }
+
+  fprintf (f, "%s:%s", s.c_str (), linestr.c_str ());
 }
 
 static void
@@ -2839,7 +2871,7 @@ output_line_details (FILE *f, const line_info *line, unsigned line_num)
              output_line_beginning (f, line->exists,
                                     (*it)->exceptional, false,
                                     (*it)->count, line_num,
-                                    "%%%%%", "$$$$$");
+                                    "%%%%%", "$$$$$", 0);
              fprintf (f, "-block %2d", ix++);
              if (flag_verbose)
                fprintf (f, " (BB %u)", (*it)->id);
@@ -2902,6 +2934,15 @@ output_lines (FILE *gcov_file, const source_info *src)
   FILE *source_file;
   const char *retval;
 
+  /* Print legend of color hotness syntax.  */
+  if (flag_use_hotness_colors)
+    fprintf (gcov_file, "%s", DEFAULT_LINE_START "Hotness legend: " \
+            SGR_SEQ (COLOR_BG_RED) "> 50%" SGR_RESET " " \
+            SGR_SEQ (COLOR_BG_YELLOW) "> 20%" SGR_RESET " " \
+            SGR_SEQ (COLOR_BG_GREEN) "> 10%" SGR_RESET "\n");
+
+  fprintf (gcov_file, DEFAULT_LINE_START "Source:%s\n", src->coverage.name);
+
   fprintf (gcov_file, DEFAULT_LINE_START "Source:%s\n", src->coverage.name);
   if (!multiple_files)
     {
@@ -2964,7 +3005,7 @@ output_lines (FILE *gcov_file, const source_info *src)
         line so that tabs won't be messed up.  */
       output_line_beginning (gcov_file, line->exists, line->unexceptional,
                             line->has_unexecuted_block, line->count,
-                            line_num, "=====", "#####");
+                            line_num, "=====", "#####", src->maximum_count);
 
       print_source_line (gcov_file, source_lines, line_num);
       output_line_details (gcov_file, line, line_num);
@@ -3009,7 +3050,8 @@ output_lines (FILE *gcov_file, const source_info *src)
                                         line->unexceptional,
                                         line->has_unexecuted_block,
                                         line->count,
-                                        l, "=====", "#####");
+                                        l, "=====", "#####",
+                                        src->maximum_count);
 
                  print_source_line (gcov_file, source_lines, l);
                  output_line_details (gcov_file, line, l);