public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [3.4-BIB] Profile reading cleanup
@ 2002-11-08  3:59 Zdenek Dvorak
  2002-11-15 14:44 ` Richard Henderson
  0 siblings, 1 reply; 2+ messages in thread
From: Zdenek Dvorak @ 2002-11-08  3:59 UTC (permalink / raw)
  To: gcc-patches; +Cc: jh, rth

Hello,

this patch reworks reading of profile feedback into gcc. It should make
it faster,because it does not parse the file again and again for each
function. It also fixes several bugs when merging profiles (that never
really occured, because instrumented programs never produce such data,
but anyway they looked very strange).

Zdenek

Changelog:
	* Makefile.in (profile.o): Add hashtab.h dependency.
	* gcov-io.h (GCOV_SUMMARY_LENGTH): New.
	* profile.c: Include hashtab.h.
	(htab_counts_index_hash, htab_counts_index_eq, htab_counts_index_del,
	cleanup_counts_index, index_counts_file, struct section_reference,
	struct da_index_entry, counts_file_name, counts_file_index): New.
	(get_exec_counts, init_branch_prob): Modified.

Index: Makefile.in
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.939.2.13
diff -c -3 -p -r1.939.2.13 Makefile.in
*** Makefile.in	5 Nov 2002 19:11:50 -0000	1.939.2.13
--- Makefile.in	8 Nov 2002 11:10:28 -0000
*************** conflict.o : conflict.c $(CONFIG_H) $(SY
*** 1517,1523 ****
  profile.o : profile.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
     insn-config.h output.h $(REGS_H) $(EXPR_H) function.h \
     gcov-io.h gcov-iov.h toplev.h $(GGC_H) hard-reg-set.h $(BASIC_BLOCK_H) \
!    $(TARGET_H) langhooks.h profile.h libfuncs.h gt-profile.h
  loop.o : loop.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) flags.h $(LOOP_H) \
     insn-config.h $(REGS_H) hard-reg-set.h $(RECOG_H) $(EXPR_H) \
     real.h $(PREDICT_H) $(BASIC_BLOCK_H) function.h \
--- 1517,1523 ----
  profile.o : profile.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
     insn-config.h output.h $(REGS_H) $(EXPR_H) function.h \
     gcov-io.h gcov-iov.h toplev.h $(GGC_H) hard-reg-set.h $(BASIC_BLOCK_H) \
!    $(TARGET_H) langhooks.h profile.h libfuncs.h gt-profile.h $(HASHTAB_H)
  loop.o : loop.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) flags.h $(LOOP_H) \
     insn-config.h $(REGS_H) hard-reg-set.h $(RECOG_H) $(EXPR_H) \
     real.h $(PREDICT_H) $(BASIC_BLOCK_H) function.h \
Index: gcov-io.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/gcov-io.h,v
retrieving revision 1.16.8.3
diff -c -3 -p -r1.16.8.3 gcov-io.h
*** gcov-io.h	14 Oct 2002 17:24:01 -0000	1.16.8.3
--- gcov-io.h	8 Nov 2002 11:10:28 -0000
*************** gcov_write_length (file, place)
*** 453,458 ****
--- 453,459 ----
    return result;
  }
  
+ #define GCOV_SUMMARY_LENGTH 44
  static int
  gcov_read_summary (da_file, summary)
       FILE *da_file;
Index: profile.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/profile.c,v
retrieving revision 1.97.4.5
diff -c -3 -p -r1.97.4.5 profile.c
*** profile.c	14 Oct 2002 17:24:01 -0000	1.97.4.5
--- profile.c	8 Nov 2002 11:10:29 -0000
*************** Software Foundation, 59 Temple Place - S
*** 67,72 ****
--- 67,73 ----
  #include "profile.h"
  #include "libfuncs.h"
  #include "langhooks.h"
+ #include "hashtab.h"
  
  /* Additional information about the edges we need.  */
  struct edge_info {
*************** static void find_spanning_tree PARAMS ((
*** 144,149 ****
--- 145,155 ----
  static rtx gen_edge_profiler PARAMS ((int));
  static void instrument_edges PARAMS ((struct edge_list *));
  static void compute_branch_probabilities PARAMS ((void));
+ static hashval_t htab_counts_index_hash PARAMS ((const void *));
+ static int htab_counts_index_eq PARAMS ((const void *, const void *));
+ static void htab_counts_index_del PARAMS ((void *));
+ static void cleanup_counts_index PARAMS ((int));
+ static int index_counts_file PARAMS ((void));
  static gcov_type * get_exec_counts PARAMS ((void));
  static unsigned compute_checksum PARAMS ((void));
  static basic_block find_group PARAMS ((basic_block));
*************** instrument_edges (el)
*** 197,259 ****
    commit_edge_insertions_watch_calls ();
  }
  \f
  
! /* Computes hybrid profile for all matching entries in da_file.
!    Sets max_counter_in_program as a side effect.
!    FIXME: This is O(nfuncs^2). It should be reorganised to read the da
!    file once. */
  
! static gcov_type *
! get_exec_counts ()
  {
!   unsigned num_edges = 0;
!   basic_block bb;
!   gcov_type *profile;
!   char *function_name_buffer = NULL;
!   gcov_type max_count = 0;
!   gcov_type prog_sum_max = 0;
!   gcov_type prog_runs = 0;
!   unsigned seen_fn = 0; /* 0 = not seen fn, 1 = function now,
! 			   2 = seen fn, 3 = seen prog summaries */
!   unsigned magic, version;
!   unsigned ix;
!   const char *name = IDENTIFIER_POINTER
! 		      (DECL_ASSEMBLER_NAME (current_function_decl));
  
!   profile_info.max_counter_in_program = 0;
!   profile_info.count_profiles_merged = 0;
  
!   /* No .da file, no execution counts.  */
!   if (!da_file)
!     return 0;
  
!   /* Count the edges to be (possibly) instrumented.  */
  
!   FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
      {
!       edge e;
!       for (e = bb->succ; e; e = e->succ_next)
! 	if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree)
! 	  num_edges++;
      }
  
!   /* now read and combine all matching profiles.  */
  
-   profile = xmalloc (sizeof (gcov_type) * num_edges);
    rewind (da_file);
  
!   for (ix = 0; ix < num_edges; ix++)
!     profile[ix] = 0;
  
    if (gcov_read_unsigned (da_file, &magic) || magic != GCOV_DATA_MAGIC)
      {
        warning ("`%s' is not a gcov data file", da_file_name);
!     cleanup:;
!       fclose (da_file);
!       da_file = NULL;
!       free (profile);
!       free (function_name_buffer);
!       return 0;
      }
    if (gcov_read_unsigned (da_file, &version) || version != GCOV_VERSION)
      {
--- 203,310 ----
    commit_edge_insertions_watch_calls ();
  }
  \f
+ struct section_reference
+ {
+   long offset;
+   int owns_summary;
+   long *summary;
+ };
  
! struct da_index_entry
! {
!   /* We hash by  */
!   char *function_name;
!   unsigned section;
!   /* and store  */
!   unsigned checksum;
!   unsigned n_offsets;
!   struct section_reference *offsets;
! };
  
! static hashval_t
! htab_counts_index_hash (of)
!      const void *of;
  {
!   const struct da_index_entry *entry = of;
  
!   return htab_hash_string (entry->function_name) ^ entry->section;
! }
  
! static int
! htab_counts_index_eq (of1, of2)
!      const void *of1;
!      const void *of2;
! {
!   const struct da_index_entry *entry1 = of1;
!   const struct da_index_entry *entry2 = of2;
  
!   return !strcmp (entry1->function_name, entry2->function_name)
! 	  && entry1->section == entry2->section;
! }
  
! static void
! htab_counts_index_del (what)
!      void *what;
! {
!   struct da_index_entry *entry = what;
!   unsigned i;
! 
!   for (i = 0; i < entry->n_offsets; i++)
      {
!       struct section_reference *act = entry->offsets + i;
!       if (act->owns_summary)
! 	free (act->summary);
!     }
!   free (entry->function_name);
!   free (entry->offsets);
!   free (entry);
! }
! 
! static char *counts_file_name;
! static htab_t counts_file_index = NULL;
! 
! static void
! cleanup_counts_index (close_file)
!      int close_file;
! {
!   if (da_file && close_file)
!     {
!       fclose (da_file);
!       da_file = NULL;
      }
+   if (counts_file_name)
+     free (counts_file_name);
+   counts_file_name = NULL;
+   if (counts_file_index)
+     htab_delete (counts_file_index);
+   counts_file_index = NULL;
+ }
  
! static int
! index_counts_file ()
! {
!   char *function_name_buffer = NULL;
!   unsigned magic, version, ix, checksum;
!   long *summary;
! 
!   if (!da_file)
!     return 0;
!   counts_file_index = htab_create (10, htab_counts_index_hash, htab_counts_index_eq, htab_counts_index_del);
! 
!   /* No .da file, no data.  */
!   if (!da_file)
!     return 0;
! 
!   /* Now index all profile sections.  */
  
    rewind (da_file);
  
!   summary = NULL;
  
    if (gcov_read_unsigned (da_file, &magic) || magic != GCOV_DATA_MAGIC)
      {
        warning ("`%s' is not a gcov data file", da_file_name);
!       goto cleanup;
      }
    if (gcov_read_unsigned (da_file, &version) || version != GCOV_VERSION)
      {
*************** get_exec_counts ()
*** 273,280 ****
    while (1)
      {
        unsigned tag, length;
!       long base;
        
        if (gcov_read_unsigned (da_file, &tag)
  	  || gcov_read_unsigned (da_file, &length))
  	{
--- 324,332 ----
    while (1)
      {
        unsigned tag, length;
!       long offset;
        
+       offset = gcov_save_position (da_file);
        if (gcov_read_unsigned (da_file, &tag)
  	  || gcov_read_unsigned (da_file, &length))
  	{
*************** get_exec_counts ()
*** 284,374 ****
  	  warning ("`%s' is corrupted", da_file_name);
  	  goto cleanup;
  	}
-       base = gcov_save_position (da_file);
        if (tag == GCOV_TAG_FUNCTION)
  	{
- 	  unsigned checksum;
- 
- 	  if (seen_fn == 3)
- 	    {
- 	      profile_info.count_profiles_merged += prog_runs;
- 	      profile_info.max_counter_in_program += prog_sum_max;
- 	      if (!prog_runs)
- 		{
- 		  profile_info.count_profiles_merged++;
- 		  profile_info.max_counter_in_program += max_count;
- 		}
- 	      seen_fn = 0;
- 	    }
- 	  else if (seen_fn == 1)
- 	    seen_fn = 2;
- 	  
  	  if (gcov_read_string (da_file, &function_name_buffer, NULL)
  	      || gcov_read_unsigned (da_file, &checksum))
  	    goto corrupt;
! 	  
! 	  if (strcmp (name, function_name_buffer))
! 	    ;
! 	  else if (checksum != profile_info.current_function_cfg_checksum)
! 	    {
! 	    mismatch:;
! 	      warning ("profile mismatch for `%s'", current_function_name);
! 	      goto cleanup;
! 	    }
! 	  else
! 	    seen_fn = 1;
  	}
!       else if (tag == GCOV_TAG_PROGRAM_SUMMARY)
  	{
! 	  struct gcov_summary summary;
! 
! 	  if (gcov_read_summary (da_file, &summary))
  	    goto corrupt;
  
! 	  if (seen_fn == 1)
! 	    seen_fn = 2;
! 	  if (seen_fn == 2)
! 	    seen_fn = 3;
! 	  if (seen_fn == 3)
! 	    {
! 	      prog_runs += summary.runs;
! 	      prog_sum_max += summary.arc_sum_max;
! 	    }
  	}
!       else if (tag == GCOV_TAG_ARC_COUNTS)
  	{
! 	  unsigned num = length / 8;
! 
! 	  if (seen_fn == 1 && num != num_edges)
! 	    goto mismatch;
! 	  
! 	  for (ix = 0; ix != num; ix++)
  	    {
! 	      gcov_type count;
! 
! 	      if (gcov_read_counter (da_file, &count))
! 		goto corrupt;
! 	      if (count > max_count)
! 		max_count = count;
! 	      if (seen_fn == 1)
! 		profile[ix] = count;
  	    }
  	}
!       gcov_resync (da_file, base, length);
      }
  
!   if (seen_fn == 3)
      {
!       profile_info.count_profiles_merged += prog_runs;
!       profile_info.max_counter_in_program += prog_sum_max;
!       if (!prog_runs)
  	{
  	  profile_info.count_profiles_merged++;
  	  profile_info.max_counter_in_program += max_count;
  	}
      }
-   
-   free (function_name_buffer);
  
    if (rtl_dump_file)
      {
--- 336,525 ----
  	  warning ("`%s' is corrupted", da_file_name);
  	  goto cleanup;
  	}
        if (tag == GCOV_TAG_FUNCTION)
  	{
  	  if (gcov_read_string (da_file, &function_name_buffer, NULL)
  	      || gcov_read_unsigned (da_file, &checksum))
  	    goto corrupt;
! 	  continue;
  	}
!       if (tag == GCOV_TAG_PROGRAM_SUMMARY)
  	{
! 	  if (length != GCOV_SUMMARY_LENGTH)
  	    goto corrupt;
  
! 	  if (summary)
! 	    *summary = offset;
! 	  summary = NULL;
  	}
!       else
  	{
! 	  if (function_name_buffer)
  	    {
! 	      struct da_index_entry **slot, elt;
! 	      elt.function_name = function_name_buffer;
! 	      elt.section = tag;
! 
! 	      slot = (struct da_index_entry **)
! 		htab_find_slot (counts_file_index, &elt, INSERT);
! 	      if (*slot)
! 		{
! 		  if ((*slot)->checksum != checksum)
! 		    {
! 		      warning ("profile mismatch for `%s'", function_name_buffer);
! 		      goto cleanup;
! 		    }
! 		  (*slot)->n_offsets++;
! 		  (*slot)->offsets = xrealloc ((*slot)->offsets,
! 					       sizeof (long) * (*slot)->n_offsets);
! 		}
! 	      else
! 		{
! 		  *slot = xmalloc (sizeof (struct da_index_entry));
! 		  (*slot)->function_name = xstrdup (function_name_buffer);
! 		  (*slot)->section = tag;
! 		  (*slot)->checksum = checksum;
! 		  (*slot)->n_offsets = 1;
! 		  (*slot)->offsets = xmalloc (sizeof (long));
! 		}
! 	      (*slot)->offsets[(*slot)->n_offsets - 1].offset = offset;
! 	      if (summary)
! 		(*slot)->offsets[(*slot)->n_offsets - 1].owns_summary = 0;
! 	      else
! 		{
! 		  summary = xmalloc (sizeof (long));
! 		  *summary = -1;
! 		  (*slot)->offsets[(*slot)->n_offsets - 1].owns_summary = 1;
! 		}
! 	      (*slot)->offsets[(*slot)->n_offsets - 1].summary = summary;
  	    }
  	}
!       if (gcov_skip (da_file, length))
! 	goto corrupt;
      }
  
!   free (function_name_buffer);
! 
!   return 1;
! 
! cleanup:
!   cleanup_counts_index (1);
!   if (function_name_buffer)
!     free (function_name_buffer);
!   return 0;
! }
! 
! /* Computes hybrid profile for all matching entries in da_file.
!    Sets max_counter_in_program as a side effect.  */
! 
! static gcov_type *
! get_exec_counts ()
! {
!   unsigned num_edges = 0;
!   basic_block bb;
!   gcov_type *profile;
!   gcov_type max_count;
!   unsigned ix, i, tag, length, num;
!   const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
!   struct da_index_entry *entry, what;
!   struct section_reference *act;
!   gcov_type count;
!   struct gcov_summary summ;
! 
!   profile_info.max_counter_in_program = 0;
!   profile_info.count_profiles_merged = 0;
! 
!   /* No .da file, no execution counts.  */
!   if (!da_file)
!     return NULL;
!   if (!counts_file_index)
!     abort ();
! 
!   /* Count the edges to be (possibly) instrumented.  */
! 
!   FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
      {
!       edge e;
!       for (e = bb->succ; e; e = e->succ_next)
! 	if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree)
! 	  num_edges++;
!     }
! 
!   /* now read and combine all matching profiles.  */
! 
!   profile = xmalloc (sizeof (gcov_type) * num_edges);
! 
!   for (ix = 0; ix < num_edges; ix++)
!     profile[ix] = 0;
! 
!   what.function_name = (char *) name;
!   what.section = GCOV_TAG_ARC_COUNTS;
!   entry = htab_find (counts_file_index, &what);
!   if (!entry)
!     {
!       warning ("No profile for function '%s' found.", name);
!       goto cleanup;
!     }
!   
!   if (entry->checksum != profile_info.current_function_cfg_checksum)
!     {
!       warning ("profile mismatch for `%s'", current_function_name);
!       goto cleanup;
!     }
! 
!   for (i = 0; i < entry->n_offsets; i++)
!     {
!       act = entry->offsets + i;
! 
!       /* Read arc counters.  */
!       max_count = 0;
!       gcov_resync (da_file, act->offset, 0);
! 
!       if (gcov_read_unsigned (da_file, &tag)
! 	  || gcov_read_unsigned (da_file, &length)
! 	  || tag != GCOV_TAG_ARC_COUNTS)
! 	{
! 	  /* We have already passed through file, so any error means
! 	     something is rotten.  */
! 	  abort ();
! 	}
!       num = length / 8;
! 
!       if (num != num_edges)
! 	{
! 	  warning ("profile mismatch for `%s'", current_function_name);
! 	  goto cleanup;
! 	}
! 	  
!       for (ix = 0; ix != num; ix++)
! 	{
! 	  if (gcov_read_counter (da_file, &count))
! 	    abort ();
! 	  if (count > max_count)
! 	    max_count = count;
! 	  profile[ix] += count;
! 	}
! 
!       /* Read program summary.  */
!       if (*act->summary != -1)
! 	{
! 	  gcov_resync (da_file, *act->summary, 0);
! 	  if (gcov_read_unsigned (da_file, &tag)
! 	      || gcov_read_unsigned (da_file, &length)
! 	      || tag != GCOV_TAG_PROGRAM_SUMMARY
! 	      || gcov_read_summary (da_file, &summ))
! 	    abort ();
! 	  profile_info.count_profiles_merged += summ.runs;
! 	  profile_info.max_counter_in_program += summ.arc_sum_max;
! 	}
!       else
! 	summ.runs = 0;
!       if (!summ.runs)
  	{
  	  profile_info.count_profiles_merged++;
  	  profile_info.max_counter_in_program += max_count;
  	}
      }
  
    if (rtl_dump_file)
      {
*************** get_exec_counts ()
*** 378,383 ****
--- 529,539 ----
      }
  
    return profile;
+ 
+ cleanup:;
+   free (profile);
+   cleanup_counts_index (1);
+   return NULL;
  }
  \f
  
*************** init_branch_prob (filename)
*** 1232,1237 ****
--- 1388,1397 ----
        if (!da_file)
  	warning ("file %s not found, execution counts assumed to be zero",
  		 da_file_name);
+       if (counts_file_index && strcmp (da_file_name, counts_file_name))
+        	cleanup_counts_index (0);
+       if (index_counts_file ())
+ 	counts_file_name = xstrdup (da_file_name);
      }
  
    if (profile_arc_flag)

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [3.4-BIB] Profile reading cleanup
  2002-11-08  3:59 [3.4-BIB] Profile reading cleanup Zdenek Dvorak
@ 2002-11-15 14:44 ` Richard Henderson
  0 siblings, 0 replies; 2+ messages in thread
From: Richard Henderson @ 2002-11-15 14:44 UTC (permalink / raw)
  To: Zdenek Dvorak; +Cc: gcc-patches, jh

On Fri, Nov 08, 2002 at 12:59:45PM +0100, Zdenek Dvorak wrote:
> 	* Makefile.in (profile.o): Add hashtab.h dependency.
> 	* gcov-io.h (GCOV_SUMMARY_LENGTH): New.
> 	* profile.c: Include hashtab.h.
> 	(htab_counts_index_hash, htab_counts_index_eq, htab_counts_index_del,
> 	cleanup_counts_index, index_counts_file, struct section_reference,
> 	struct da_index_entry, counts_file_name, counts_file_index): New.
> 	(get_exec_counts, init_branch_prob): Modified.

Ok.


r~

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2002-11-15 22:44 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-11-08  3:59 [3.4-BIB] Profile reading cleanup Zdenek Dvorak
2002-11-15 14:44 ` Richard Henderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).