libgcov: Fix gcov overlap bugs of divide to 0

Message ID 20231026032515.2061065-1-xionghuluo@tencent.com
State Accepted
Headers
Series libgcov: Fix gcov overlap bugs of divide to 0 |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Xionghu Luo Oct. 26, 2023, 3:25 a.m. UTC
  Fix the long lasting issue of `gcov-tool overlap  xxx yyy`,
divide to 0 caused the output shows a lot of nans, another problem
is the counts in file are never acculated leads to incorrect results.

Signed-off-by: Xionghu Luo <xionghuluo@tencent.com>

libgcc/ChangeLog:

	* libgcov-util.c (compute_one_gcov): Avoid divide to 0.
	(accumulate_sum_counts): New.
	(calculate_overlap): Call accumulate_sum_countes.
---
 libgcc/libgcov-util.c | 58 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 54 insertions(+), 4 deletions(-)
  

Comments

Xionghu Luo Oct. 27, 2023, 2:02 a.m. UTC | #1
+cc maintainers.


On 2023/10/26 11:25, Xionghu Luo wrote:
> Fix the long lasting issue of `gcov-tool overlap  xxx yyy`,
> divide to 0 caused the output shows a lot of nans, another problem
> is the counts in file are never acculated leads to incorrect results.
> 
> Signed-off-by: Xionghu Luo <xionghuluo@tencent.com>
> 
> libgcc/ChangeLog:
> 
> 	* libgcov-util.c (compute_one_gcov): Avoid divide to 0.
> 	(accumulate_sum_counts): New.
> 	(calculate_overlap): Call accumulate_sum_countes.
> ---
>   libgcc/libgcov-util.c | 58 ++++++++++++++++++++++++++++++++++++++++---
>   1 file changed, 54 insertions(+), 4 deletions(-)
> 
> diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c
> index d547c103cab..26a02e66567 100644
> --- a/libgcc/libgcov-util.c
> +++ b/libgcc/libgcov-util.c
> @@ -1072,6 +1072,8 @@ compute_one_gcov (const struct gcov_info *gcov_info1,
>   
>     for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
>       {
> +      double func_1 = 0.0;
> +      double func_2 = 0.0;
>         double func_cum_1 = 0.0;
>         double func_cum_2 = 0.0;
>         double func_val = 0.0;
> @@ -1096,11 +1098,15 @@ compute_one_gcov (const struct gcov_info *gcov_info1,
>   					       ci_ptr2->values[c_num],
>   					       sum_1, sum_2);
>   
> -	      func_cum_1 += ci_ptr1->values[c_num] / sum_1;
> -	      func_cum_2 += ci_ptr2->values[c_num] / sum_2;
> +	      if (sum_1)
> +		func_1 = ci_ptr1->values[c_num] / sum_1;
> +	      func_cum_1 += func_1;
> +	      if (sum_2)
> +		func_2 = ci_ptr2->values[c_num] / sum_2;
> +	      func_cum_2 += func_2;
>   	      nonzero = 1;
> -	      if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold
> -		  || ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold)
> +	      if (func_1 >= overlap_hot_threshold
> +		  || func_2 >= overlap_hot_threshold)
>   		hot = 1;
>   	    }
>   	}
> @@ -1322,6 +1328,47 @@ matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2)
>     return 1;
>   }
>   
> +static int
> +accumuate_sum_counts (const struct gcov_info *gcov_info1,
> +		      const struct gcov_info *gcov_info2)
> +{
> +  gcc_assert (gcov_info1 || gcov_info2);
> +  unsigned f_ix;
> +
> +  if (gcov_info1)
> +    {
> +      gcov_type cum_1 = 0;
> +      for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
> +	{
> +	  const struct gcov_fn_info *gfi_ptr = gcov_info1->functions[f_ix];
> +	  if (!gfi_ptr || gfi_ptr->key != gcov_info1)
> +	    continue;
> +	  const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
> +	  unsigned c_num;
> +	  for (c_num = 0; c_num < ci_ptr->num; c_num++)
> +	    cum_1 += ci_ptr->values[c_num];
> +	}
> +      overlap_sum_1 = cum_1;
> +    }
> +
> +  if (gcov_info2)
> +    {
> +      gcov_type cum_2 = 0;
> +      for (f_ix = 0; f_ix < gcov_info2->n_functions; f_ix++)
> +	{
> +	  const struct gcov_fn_info *gfi_ptr = gcov_info2->functions[f_ix];
> +	  if (!gfi_ptr || gfi_ptr->key != gcov_info2)
> +	    continue;
> +	  const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
> +	  unsigned c_num;
> +	  for (c_num = 0; c_num < ci_ptr->num; c_num++)
> +	    cum_2 += ci_ptr->values[c_num];
> +	}
> +      overlap_sum_2 = cum_2;
> +    }
> +  return 0;
> +}
> +
>   /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
>      GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
>      match and 1.0 meaning a perfect match.  */
> @@ -1410,6 +1457,9 @@ calculate_overlap (struct gcov_info *gcov_list1,
>         if (overlap_func_level)
>           printf("\n   processing %36s:\n", filename);
>   
> +      overlap_sum_1 = overlap_sum_2 = 0.0;
> +      accumuate_sum_counts (all_infos[i].obj1, all_infos[i].obj2);
> +
>         val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2,
>             overlap_sum_1, overlap_sum_2, &cum_1, &cum_2);
>
  

Patch

diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c
index d547c103cab..26a02e66567 100644
--- a/libgcc/libgcov-util.c
+++ b/libgcc/libgcov-util.c
@@ -1072,6 +1072,8 @@  compute_one_gcov (const struct gcov_info *gcov_info1,
 
   for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
     {
+      double func_1 = 0.0;
+      double func_2 = 0.0;
       double func_cum_1 = 0.0;
       double func_cum_2 = 0.0;
       double func_val = 0.0;
@@ -1096,11 +1098,15 @@  compute_one_gcov (const struct gcov_info *gcov_info1,
 					       ci_ptr2->values[c_num],
 					       sum_1, sum_2);
 
-	      func_cum_1 += ci_ptr1->values[c_num] / sum_1;
-	      func_cum_2 += ci_ptr2->values[c_num] / sum_2;
+	      if (sum_1)
+		func_1 = ci_ptr1->values[c_num] / sum_1;
+	      func_cum_1 += func_1;
+	      if (sum_2)
+		func_2 = ci_ptr2->values[c_num] / sum_2;
+	      func_cum_2 += func_2;
 	      nonzero = 1;
-	      if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold
-		  || ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold)
+	      if (func_1 >= overlap_hot_threshold
+		  || func_2 >= overlap_hot_threshold)
 		hot = 1;
 	    }
 	}
@@ -1322,6 +1328,47 @@  matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2)
   return 1;
 }
 
+static int
+accumuate_sum_counts (const struct gcov_info *gcov_info1,
+		      const struct gcov_info *gcov_info2)
+{
+  gcc_assert (gcov_info1 || gcov_info2);
+  unsigned f_ix;
+
+  if (gcov_info1)
+    {
+      gcov_type cum_1 = 0;
+      for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
+	{
+	  const struct gcov_fn_info *gfi_ptr = gcov_info1->functions[f_ix];
+	  if (!gfi_ptr || gfi_ptr->key != gcov_info1)
+	    continue;
+	  const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
+	  unsigned c_num;
+	  for (c_num = 0; c_num < ci_ptr->num; c_num++)
+	    cum_1 += ci_ptr->values[c_num];
+	}
+      overlap_sum_1 = cum_1;
+    }
+
+  if (gcov_info2)
+    {
+      gcov_type cum_2 = 0;
+      for (f_ix = 0; f_ix < gcov_info2->n_functions; f_ix++)
+	{
+	  const struct gcov_fn_info *gfi_ptr = gcov_info2->functions[f_ix];
+	  if (!gfi_ptr || gfi_ptr->key != gcov_info2)
+	    continue;
+	  const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
+	  unsigned c_num;
+	  for (c_num = 0; c_num < ci_ptr->num; c_num++)
+	    cum_2 += ci_ptr->values[c_num];
+	}
+      overlap_sum_2 = cum_2;
+    }
+  return 0;
+}
+
 /* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
    GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
    match and 1.0 meaning a perfect match.  */
@@ -1410,6 +1457,9 @@  calculate_overlap (struct gcov_info *gcov_list1,
       if (overlap_func_level)
         printf("\n   processing %36s:\n", filename);
 
+      overlap_sum_1 = overlap_sum_2 = 0.0;
+      accumuate_sum_counts (all_infos[i].obj1, all_infos[i].obj2);
+
       val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2,
           overlap_sum_1, overlap_sum_2, &cum_1, &cum_2);