gcov: emit hotness colors to easily find hot code.

Message ID 50807548-6581-0a2b-e4b3-44abb0fa76a4@suse.cz
State New
Headers show
Series
  • gcov: emit hotness colors to easily find hot code.
Related show

Commit Message

Martin Liška Sept. 12, 2018, 12:36 p.m.
Hi.

This is follow-up of:
https://gcc.gnu.org/ml/gcc/2018-08/msg00162.html

I'm suggesting to introduce using colors in order to indicate hotness
of lines. Legend is printed at the very beginning of the output file.
Example: https://pasteboard.co/HDxK4Nm.png

Patch survives gcov.exp test-suite. Will install next week if no objections.

Martin

gcc/ChangeLog:

2018-09-12  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.
---
 gcc/doc/gcov.texi |  8 ++++++-
 gcc/gcov.c        | 56 +++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 56 insertions(+), 8 deletions(-)

Comments

David Malcolm Sept. 17, 2018, 6:41 p.m. | #1
On Wed, 2018-09-12 at 14:36 +0200, Martin Liška wrote:
> Hi.

> 

> This is follow-up of:

> https://gcc.gnu.org/ml/gcc/2018-08/msg00162.html

> 

> I'm suggesting to introduce using colors in order to indicate hotness

> of lines. Legend is printed at the very beginning of the output file.

> Example: https://pasteboard.co/HDxK4Nm.png


One comment: color seems to be being used for two different purposes:
(a) in the left-hand column (presumably the profile count), where e.g.
lines that are 0 are being marked as red
(b) in the middle column (the line number), lines that are > 50% are
being marked as red.

So red seems to be being used both for very hot lines (for the line
number), and for unexecuted lines (for the profile count).

Perhaps the "hotness legend" could instead say something like:

Colorization: profile count: blah blah blah
Colorization: line numbers: hotness: > 50 % > 20% > 10%

to explain both colorization schemes?  (I'm not in love with the above
wording, but hopefully the idea makes sense).

> Patch survives gcov.exp test-suite. Will install next week if no

> objections.

> 

> Martin

> 

> gcc/ChangeLog:

> 

> 2018-09-12  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.

> ---

>  gcc/doc/gcov.texi |  8 ++++++-

>  gcc/gcov.c        | 56 +++++++++++++++++++++++++++++++++++++++++--

> ----

>  2 files changed, 56 insertions(+), 8 deletions(-)

> 

>
Martin Liška Sept. 18, 2018, 10:51 a.m. | #2
On 9/17/18 8:41 PM, David Malcolm wrote:
> On Wed, 2018-09-12 at 14:36 +0200, Martin Liška wrote:

>> Hi.

>>

>> This is follow-up of:

>> https://gcc.gnu.org/ml/gcc/2018-08/msg00162.html

>>

>> I'm suggesting to introduce using colors in order to indicate hotness

>> of lines. Legend is printed at the very beginning of the output file.

>> Example: https://pasteboard.co/HDxK4Nm.png

> 

> One comment: color seems to be being used for two different purposes:

> (a) in the left-hand column (presumably the profile count), where e.g.

> lines that are 0 are being marked as red

> (b) in the middle column (the line number), lines that are > 50% are

> being marked as red.

> 

> So red seems to be being used both for very hot lines (for the line

> number), and for unexecuted lines (for the profile count).


Thanks for review David.

Yes, it's used for 2 purposes.

> 

> Perhaps the "hotness legend" could instead say something like:

> 

> Colorization: profile count: blah blah blah

> Colorization: line numbers: hotness: > 50 % > 20% > 10%

> 

> to explain both colorization schemes?  (I'm not in love with the above

> wording, but hopefully the idea makes sense).


I welcome that, now one can see:

        -:    0:Colorization: profile count: zero coverage (exceptional) zero coverage (unexceptional) unexecuted block
        -:    0:Colorization: line numbers: hotness: > 50% > 20% > 10%
...

Hope it's an improvement.

Martin

> 

>> Patch survives gcov.exp test-suite. Will install next week if no

>> objections.

>>

>> Martin

>>

>> gcc/ChangeLog:

>>

>> 2018-09-12  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.

>> ---

>>  gcc/doc/gcov.texi |  8 ++++++-

>>  gcc/gcov.c        | 56 +++++++++++++++++++++++++++++++++++++++++--

>> ----

>>  2 files changed, 56 insertions(+), 8 deletions(-)

>>

>>
From 3e826e7b4b09a7130ee88122d54fb35ad41b044f Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>

Date: Tue, 18 Sep 2018 12:48:16 +0200
Subject: [PATCH] Improve colorization legen in gcov reports.

gcc/ChangeLog:

2018-09-18  Martin Liska  <mliska@suse.cz>

	* gcov.c (output_lines): Print colorization legend
	for both flag_use_colors and flag_use_hotness_colors.
	Reword the help.
---
 gcc/gcov.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/gcc/gcov.c b/gcc/gcov.c
index c09d5060053..0de14dc52af 100644
--- a/gcc/gcov.c
+++ b/gcc/gcov.c
@@ -2935,9 +2935,19 @@ output_lines (FILE *gcov_file, const source_info *src)
   FILE *source_file;
   const char *retval;
 
-  /* Print legend of color hotness syntax.  */
+  /* Print colorization legend.  */
+  if (flag_use_colors)
+    fprintf (gcov_file, "%s",
+	     DEFAULT_LINE_START "Colorization: profile count: " \
+	     SGR_SEQ (COLOR_BG_CYAN) "zero coverage (exceptional)" SGR_RESET \
+	     " " \
+	     SGR_SEQ (COLOR_BG_RED) "zero coverage (unexceptional)" SGR_RESET \
+	     " " \
+	     SGR_SEQ (COLOR_BG_MAGENTA) "unexecuted block" SGR_RESET "\n");
+
   if (flag_use_hotness_colors)
-    fprintf (gcov_file, "%s", DEFAULT_LINE_START "Hotness legend: " \
+    fprintf (gcov_file, "%s",
+	     DEFAULT_LINE_START "Colorization: line numbers: hotness: " \
 	     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");
-- 
2.18.0

Patch

diff --git a/gcc/doc/gcov.texi b/gcc/doc/gcov.texi
index 98f4a876293..3b1b38aebfa 100644
--- a/gcc/doc/gcov.texi
+++ b/gcc/doc/gcov.texi
@@ -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
diff --git a/gcc/gcov.c b/gcc/gcov.c
index 6a24a320046..64ab85c981f 100644
--- a/gcc/gcov.c
+++ b/gcc/gcov.c
@@ -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);