Hi.

The patch is about addition of 2 maps that significantly speed up
gcov for tramp3d from 2.0s to 0.2s.

Survives gcov.exp tests, I'm planning to install the patch in couple
of days.

Martin

gcc/ChangeLog:

2018-11-27  Martin Liska  <mli...@suse.cz>

        PR gcov-profile/88225
        * gcov.c(source_info::get_functions_at_location):
        Use newly added line_to_function_map.
        (source_info::add_function): New.
        (output_json_intermediate_file): Use a pointer return
        type for get_functions_at_location.
        (process_all_functions): Use add_function instead
        of direct push to a s->functions container.
        (release_structures): Release ident_to_fn.
        (read_graph_file): Register function into ident_to_fn.
        (read_count_file): Use the map.
        (output_lines): Handle pointer return type of
        get_functions_at_location.
---
 gcc/gcov.c | 112 ++++++++++++++++++++++++++++++-----------------------
 1 file changed, 64 insertions(+), 48 deletions(-)


diff --git a/gcc/gcov.c b/gcc/gcov.c
index 361b696ea78..5fb83c08179 100644
--- a/gcc/gcov.c
+++ b/gcc/gcov.c
@@ -358,7 +358,10 @@ struct source_info
   /* Default constructor.  */
   source_info ();
 
-  vector<function_info *> get_functions_at_location (unsigned line_num) const;
+  vector<function_info *> *get_functions_at_location (unsigned line_num) const;
+
+  /* Register a new function.  */
+  void add_function (function_info *fn);
 
   /* Index of the source_info in sources vector.  */
   unsigned index;
@@ -377,7 +380,10 @@ struct source_info
 
   /* Functions in this source file.  These are in ascending line
      number order.  */
-  vector <function_info *> functions;
+  vector<function_info *> functions;
+
+  /* Line number to functions map.  */
+  vector<vector<function_info *> *> line_to_function_map;
 };
 
 source_info::source_info (): index (0), name (NULL), file_time (),
@@ -385,21 +391,33 @@ source_info::source_info (): index (0), name (NULL), file_time (),
 {
 }
 
-vector<function_info *>
-source_info::get_functions_at_location (unsigned line_num) const
+/* Register a new function.  */
+void
+source_info::add_function (function_info *fn)
 {
-  vector<function_info *> r;
+  functions.push_back (fn);
 
-  for (vector<function_info *>::const_iterator it = functions.begin ();
-       it != functions.end (); it++)
-    {
-      if ((*it)->start_line == line_num && (*it)->src == index)
-	r.push_back (*it);
-    }
+  if (fn->start_line >= line_to_function_map.size ())
+    line_to_function_map.resize (fn->start_line + 1);
+
+  vector<function_info *> **slot = &line_to_function_map[fn->start_line];
+  if (*slot == NULL)
+    *slot = new vector<function_info *> ();
 
-  std::sort (r.begin (), r.end (), function_line_start_cmp ());
+  (*slot)->push_back (fn);
+}
+
+vector<function_info *> *
+source_info::get_functions_at_location (unsigned line_num) const
+{
+  if (line_num >= line_to_function_map.size ())
+    return NULL;
 
-  return r;
+  vector<function_info *> *slot = line_to_function_map[line_num];
+  if (slot != NULL)
+    std::sort (slot->begin (), slot->end (), function_line_start_cmp ());
+
+  return slot;
 }
 
 class name_map
@@ -438,6 +456,9 @@ public:
 /* Vector of all functions.  */
 static vector<function_info *> functions;
 
+/* Function ident to function_info * map.  */
+static map<unsigned, function_info *> ident_to_fn;
+
 /* Vector of source files.  */
 static vector<source_info> sources;
 
@@ -1121,19 +1142,20 @@ output_json_intermediate_file (json::array *json_files, source_info *src)
 
   for (unsigned line_num = 1; line_num <= src->lines.size (); line_num++)
     {
-      vector<function_info *> fns = src->get_functions_at_location (line_num);
+      vector<function_info *> *fns = src->get_functions_at_location (line_num);
 
-      /* Print first group functions that begin on the line.  */
-      for (vector<function_info *>::iterator it2 = fns.begin ();
-	   it2 != fns.end (); it2++)
-	{
-	  vector<line_info> &lines = (*it2)->lines;
-	  for (unsigned i = 0; i < lines.size (); i++)
-	    {
-	      line_info *line = &lines[i];
-	      output_intermediate_json_line (lineso, line, line_num + i);
-	    }
-	}
+      if (fns != NULL)
+	/* Print first group functions that begin on the line.  */
+	for (vector<function_info *>::iterator it2 = fns->begin ();
+	     it2 != fns->end (); it2++)
+	  {
+	    vector<line_info> &lines = (*it2)->lines;
+	    for (unsigned i = 0; i < lines.size (); i++)
+	      {
+		line_info *line = &lines[i];
+		output_intermediate_json_line (lineso, line, line_num + i);
+	      }
+	  }
 
       /* Follow with lines associated with the source file.  */
       if (line_num < src->lines.size ())
@@ -1256,7 +1278,7 @@ process_all_functions (void)
       if (!fn->counts.empty () || no_data_file)
 	{
 	  source_info *s = &sources[src];
-	  s->functions.push_back (fn);
+	  s->add_function (fn);
 
 	  /* Mark last line in files touched by function.  */
 	  for (unsigned block_no = 0; block_no != fn->blocks.size ();
@@ -1473,6 +1495,7 @@ release_structures (void)
   sources.resize (0);
   names.resize (0);
   functions.resize (0);
+  ident_to_fn.clear ();
 }
 
 /* Generate the names of the graph and data files.  If OBJECT_DIRECTORY
@@ -1691,6 +1714,8 @@ read_graph_file (void)
 
 	  fn = new function_info ();
 	  functions.push_back (fn);
+	  ident_to_fn[ident] = fn;
+
 	  fn->m_name = function_name;
 	  fn->ident = ident;
 	  fn->lineno_checksum = lineno_checksum;
@@ -1841,6 +1866,7 @@ read_count_file (void)
   unsigned tag;
   function_info *fn = NULL;
   int error = 0;
+  map<unsigned, function_info *>::iterator it;
 
   if (!gcov_open (da_file_name, 1))
     {
@@ -1890,21 +1916,11 @@ read_count_file (void)
       else if (tag == GCOV_TAG_FUNCTION && length == GCOV_TAG_FUNCTION_LENGTH)
 	{
 	  unsigned ident;
-
-	  /* Try to find the function in the list.  To speed up the
-	     search, first start from the last function found.  */
 	  ident = gcov_read_unsigned ();
-
 	  fn = NULL;
-	  for (vector<function_info *>::reverse_iterator it
-	       = functions.rbegin (); it != functions.rend (); it++)
-	    {
-	      if ((*it)->ident == ident)
-		{
-		  fn = *it;
-		  break;
-		}
-	    }
+	  it = ident_to_fn.find (ident);
+	  if (it != ident_to_fn.end ())
+	    fn = it->second;
 
 	  if (!fn)
 	    ;
@@ -3021,7 +3037,7 @@ output_lines (FILE *gcov_file, const source_info *src)
       source_lines.push_back (xstrdup (retval));
 
   unsigned line_start_group = 0;
-  vector<function_info *> fns;
+  vector<function_info *> *fns;
 
   for (unsigned line_num = 1; line_num <= source_lines.size (); line_num++)
     {
@@ -3037,18 +3053,18 @@ output_lines (FILE *gcov_file, const source_info *src)
       if (line_start_group == 0)
 	{
 	  fns = src->get_functions_at_location (line_num);
-	  if (fns.size () > 1)
+	  if (fns != NULL && fns->size () > 1)
 	    {
 	      /* It's possible to have functions that partially overlap,
 		 thus take the maximum end_line of functions starting
 		 at LINE_NUM.  */
-	      for (unsigned i = 0; i < fns.size (); i++)
-		if (fns[i]->end_line > line_start_group)
-		  line_start_group = fns[i]->end_line;
+	      for (unsigned i = 0; i < fns->size (); i++)
+		if ((*fns)[i]->end_line > line_start_group)
+		  line_start_group = (*fns)[i]->end_line;
 	    }
-	  else if (fns.size () == 1)
+	  else if (fns != NULL && fns->size () == 1)
 	    {
-	      function_info *fn = fns[0];
+	      function_info *fn = (*fns)[0];
 	      output_function_details (gcov_file, fn);
 	    }
 	}
@@ -3068,8 +3084,8 @@ output_lines (FILE *gcov_file, const source_info *src)
 
       if (line_start_group == line_num)
 	{
-	  for (vector<function_info *>::iterator it = fns.begin ();
-	       it != fns.end (); it++)
+	  for (vector<function_info *>::iterator it = fns->begin ();
+	       it != fns->end (); it++)
 	    {
 	      function_info *fn = *it;
 	      vector<line_info> &lines = fn->lines;

Reply via email to