aboutsummaryrefslogtreecommitdiff
path: root/gprofng
diff options
context:
space:
mode:
authorVladimir Mezentsev <vladimir.mezentsev@oracle.com>2024-01-10 16:44:32 -0800
committerVladimir Mezentsev <vladimir.mezentsev@oracle.com>2024-01-12 12:23:20 -0800
commitcc76856b8f4e6e71f86375b16378406712352bbd (patch)
treed6ceb5f36789c65cd2ffa8d4e028a0a4e7494234 /gprofng
parentb83808a8a2265371ea78c05771dde3d6a6b81115 (diff)
downloadbinutils-cc76856b8f4e6e71f86375b16378406712352bbd.zip
binutils-cc76856b8f4e6e71f86375b16378406712352bbd.tar.gz
binutils-cc76856b8f4e6e71f86375b16378406712352bbd.tar.bz2
gprofng: fix 3 bugzillas against gp-display-html
Fix two cases where gp-display-html terminates prematurely because the input format is not recognized. This problem occurs in the function overview and caller-callee parts of the code. The fix consists of new regular expressions and a different approach in handling the input from gp-display-text. Also fix a performance problem in the caller-callee part that has a noticeable impact on the performance for large applications. gprofng/ChangeLog 2024-01-10 Ruud van der Pas <ruud.vanderpas@oracle.com> PR gprofng/30438 PR gprofng/30439 PR gprofng/30942 * gp-display-html/gp-display-html.in: fixes the issues.
Diffstat (limited to 'gprofng')
-rw-r--r--gprofng/gp-display-html/gp-display-html.in1086
1 files changed, 763 insertions, 323 deletions
diff --git a/gprofng/gp-display-html/gp-display-html.in b/gprofng/gp-display-html/gp-display-html.in
index 394aef0..6f37ca2 100644
--- a/gprofng/gp-display-html/gp-display-html.in
+++ b/gprofng/gp-display-html/gp-display-html.in
@@ -1,5 +1,5 @@
#!/usr/bin/env perl
-# Copyright (C) 2021-2024 Free Software Foundation, Inc.
+# Copyright (C) 2021-2023 Free Software Foundation, Inc.
# Contributed by Oracle.
#
# This file is part of GNU Binutils.
@@ -65,6 +65,11 @@ my $TRUE = 1;
my $FALSE = 0;
#------------------------------------------------------------------------------
+# The total number of functions to be processed.
+#------------------------------------------------------------------------------
+my $g_total_function_count = 0;
+
+#------------------------------------------------------------------------------
# Used to ensure correct alignment of columns.
#------------------------------------------------------------------------------
my $g_max_length_first_metric;
@@ -75,7 +80,7 @@ my $g_max_length_first_metric;
my $g_path_to_tools;
#------------------------------------------------------------------------------
-# Code debugging flag
+# Code debugging flag.
#------------------------------------------------------------------------------
my $g_test_code = $FALSE;
@@ -100,6 +105,7 @@ my $g_addressing_mode = "64 bit";
my $g_less_than_regex = '<';
my $g_html_less_than_regex = '&lt;';
my $g_endbr_inst_regex = 'endbr[32|64]';
+ my $g_rm_surrounding_spaces_regex = '^\s+|\s+$';
#------------------------------------------------------------------------------
# For consistency, use a global variable.
@@ -1115,6 +1121,9 @@ sub main
%LINUX_vDSO = %{ $LINUX_vDSO_ref };
%function_view_structure = %{ $function_view_structure_ref };
+ $msg = "found " . $g_total_function_count . " functions to process";
+ gp_message ("verbose", $subr_name, $msg);
+
for my $keys (0 .. $#function_info)
{
for my $fields (keys %{$function_info[$keys]})
@@ -4001,7 +4010,7 @@ sub extract_info_from_map_xml
my $result_VA;
my $va_executable_in_hex;
- $msg = "- unable to open file $input_map_xml_file for reading:";
+ $msg = " - unable to open file $input_map_xml_file for reading:";
open (MAP_XML, "<", $input_map_xml_file)
or die ($subr_name . $msg . " " . $!);
@@ -4924,8 +4933,9 @@ sub function_info
{
$line = $_;
chomp ($line);
+ $line =~ s/ -- no functions found//;
-# gp_message ("debug", $subr_name, "FUNC_FILE: input line = $line");
+ gp_message ("debug", $subr_name, "FUNC_FILE: input line = $line");
$line_n++;
if ($line =~ /$line_regex/) # field 2|3 needs to be \S in case of -ve sign
@@ -5164,7 +5174,8 @@ sub function_info
$segment = $1;
$offset = $2;
$address_decimal = bigint::hex ($offset); # decimal
- $full_address_field = '@'.$segment.":".$offset; # e.g. @2:0x0003f280
+## $full_address_field = '@'.$segment.":".$offset; # e.g. @2:0x0003f280
+ $full_address_field = $segment.":".$offset; # e.g. @2:0x0003f280
$order[$index_val]{"addressobj"} = $address_decimal;
$order[$index_val]{"addressobjtext"} = $full_address_field;
}
@@ -5260,6 +5271,7 @@ sub generate_caller_callee
my $input_string = ${ $input_string_ref };
my @caller_callee_data = ();
+ my $caller_callee_data_ref;
my $outfile;
my $input_line;
@@ -5278,6 +5290,9 @@ sub generate_caller_callee
my $elements_in_name;
my $full_hex_address;
my $hex_address;
+ my $msg;
+
+ my $remainder2;
my $file_title;
my $page_title;
@@ -5325,7 +5340,9 @@ sub generate_caller_callee
or die ("unable to open $outfile for writing - '$!'");
gp_message ("debug", $subr_name, "opened file $outfile for writing");
- gp_message ("debug", $subr_name, "building caller-callee file $outfile");
+ $msg = "building caller-callee file " . $outfile;
+ gp_message ("debug", $subr_name, $msg);
+ gp_message ("verbose", $subr_name, $msg);
#------------------------------------------------------------------------------
# Generate some of the structures used in the HTML output.
@@ -5337,14 +5354,21 @@ sub generate_caller_callee
$page_title = "Caller Callee View";
$size_text = "h2";
$position_text = "center";
- $html_title_header = ${ generate_a_header (\$page_title, \$size_text, \$position_text) };
+ $html_title_header = ${ generate_a_header (\$page_title,
+ \$size_text,
+ \$position_text) };
#------------------------------------------------------------------------------
-# Read all of the file into array with the name caller_callee_data.
+# Read all of the file into an array with the name caller_callee_data.
#------------------------------------------------------------------------------
chomp (@caller_callee_data = <CALLER_CALLEE_IN>);
#------------------------------------------------------------------------------
+# Remove a legacy redundant string, if any.
+#------------------------------------------------------------------------------
+ @caller_callee_data = @{ remove_redundant_string (\@caller_callee_data)};
+
+#------------------------------------------------------------------------------
# Typical structure of the input file:
#
# Current metrics: address:name:e.totalcpu:e.cycles:e+insts:e+llm
@@ -5405,73 +5429,75 @@ sub generate_caller_callee
# Since this data is all in memory and relatively small, the performance should
# not suffer much, but it does improve the readability of the code.
#------------------------------------------------------------------------------
- gp_message ("debug", $subr_name, "determine the maximum length of the first field");
-
$g_max_length_first_metric = 0;
+
my @hex_addresses = ();
+ my @metrics_array = ();
+ my @length_first_metric = ();
my @special_marker = ();
my @the_function_name = ();
my @the_metrics = ();
- my @length_first_metric = ();
+
+ my $find_hex_address_regex = '\s*(\d+:0x[a-fA-F0-9]+)\s+(.*)';
+ my $find_metric_values_regex = '\)\s+\[.*\]\s+(\d+';
+ $find_metric_values_regex .= '[\.\d\ ]*)|\)\s+(\d+[\.\d\ ]*)';
+ my $find_marker_regex = '(^\*).*';
+
+ my @html_block_prologue;
+ my @html_code_function_block;
+ my $marker;
+ my $list_with_metrics;
+ my $reduced_line;
+
+ $msg = "loop over the caller-callee data - number of lines = ";
+ $msg .= ($#caller_callee_data + 1);
+ gp_message ("debugXL", $subr_name, $msg);
for (my $line = 0; $line <= $#caller_callee_data; $line++)
{
- my $input_line = $caller_callee_data[$line];
+ $input_line = $caller_callee_data[$line];
+ $reduced_line = $input_line;
- if ($input_line =~ /$line_of_interest_regex/)
+ $msg = "line = " . $line . " input_line = " . $input_line;
+ gp_message ("debugXL", $subr_name, $msg);
+
+ if ($input_line =~ /$find_hex_address_regex/)
+#------------------------------------------------------------------------------
+# This is an input line of interest.
+#------------------------------------------------------------------------------
{
- if (defined ($1) and defined ($2) and defined ($3))
+ my ($hex_address_ref, $marker_ref, $reduced_line_ref,
+ $list_with_metrics_ref) =
+ split_function_data_line (\$input_line);
+
+ $hex_address = ${ $hex_address_ref };
+ $marker = ${ $marker_ref };
+ $reduced_line = ${ $reduced_line_ref };
+ $list_with_metrics = ${ $list_with_metrics_ref };
+
+ $msg = "RESULT full_hex_address = " . $hex_address;
+ $msg .= " -- metric values = " . $list_with_metrics;
+ $msg .= " -- marker = " . $marker;
+ $msg .= " -- function name = " . $reduced_line;
+ gp_message ("debugXL", $subr_name, $msg);
+
#------------------------------------------------------------------------------
-# This is a line of interest, since it has the address, the function name and
-# the values for the metrics. Examples of valid lines are:
-#
-# 2:0x00005028 *xfree_large 0. 0
-# 12:0x0004c2b0 munmap 0.143 6402086
-# 7:0x0001b2df <static>@0x1b2df (<libgomp.so.1.0.0>) 0. 0
-#
-# The function name marked with a * is the current target.
+# Store the address and marker.
#------------------------------------------------------------------------------
+ push (@the_function_name, $reduced_line);
+ push (@hex_addresses, $hex_address);
+ if ($marker eq "*")
{
- my $full_hex_address = $1;
- my $marker = $2;
- my $remaining_line = $3;
-
- if ($full_hex_address =~ /$get_hex_address_regex/)
- {
- $hex_address = "0x" . $2;
- push (@hex_addresses, $hex_address);
- gp_message ("debugXL", $subr_name, "pushed $hex_address");
- }
- else
- {
- my $msg = "full_hex_address = $full_hex_address has an unknown format";
- gp_message ("assertion", $subr_name, $msg);
- }
- if ($marker eq "*")
- {
- push (@special_marker, "*");
- }
- else
- {
- push (@special_marker, "X");
- }
+ push (@special_marker, "*");
}
else
{
- my $msg = "input_line = $input_line has an unknown format";
- gp_message ("assertion", $subr_name, $msg);
+ push (@special_marker, "X");
}
-
- my @fields_in_line = split (" ", $input_line);
-
#------------------------------------------------------------------------------
-# We stripped the address and marker (if any), off, so this string starts with
-# the function name.
+# Processing of the metrics.
#------------------------------------------------------------------------------
- my $remainder = $3;
- my $number_of_fields = scalar (@fields_in_line);
- my $words_in_function_name = $number_of_fields - $number_of_metrics - 1;
- my @remainder_array = split (" ", $remainder);
+ @metrics_array = split (" ", $list_with_metrics);
#------------------------------------------------------------------------------
# If the first metric is 0. (or 0, depending on the locale), the calculation
@@ -5481,62 +5507,38 @@ sub generate_caller_callee
# first metric (ZZZ) and then compute the length. This makes things clearer.
# I hope ;-)
#------------------------------------------------------------------------------
- my $first_metric = $remainder_array[$words_in_function_name];
- if ($first_metric =~ /^0$decimal_separator$/)
- {
- gp_message ("debugXL", $subr_name, "fixed up $first_metric");
- $first_metric = "0.ZZZ";
- }
- push (@length_first_metric, length ($first_metric));
-
- my $txt = "words in function name = $words_in_function_name ";
- $txt .= "first_metric = $first_metric length = ";
- $txt .= length ($first_metric);
- gp_message ("debugXL", $subr_name, $txt);
-
-#------------------------------------------------------------------------------
-# Generate the regex for the metrics.
-#
-# TBD: This should be an attribute of the function and be done once only.
-#------------------------------------------------------------------------------
- my $m_regex = '(\S+';
- for my $f (2 .. $words_in_function_name)
- {
- $m_regex .= '\s+\S+';
- }
-#------------------------------------------------------------------------------
-# This last part captures all the metric values.
-#------------------------------------------------------------------------------
- $m_regex .= $get_metric_field_regex;
- gp_message ("debugXL", $subr_name, "m_regex = $m_regex");
- gp_message ("debugXL", $subr_name, "remainder = $remainder");
-
- if ($remainder =~ /$m_regex/)
- {
- my $func_name = $1;
- my $its_metrics = $2;
- my $msg = "found the info - func_name = " . $func_name .
- " its metrics = " . $its_metrics;
- gp_message ("debugXL", $subr_name, $msg);
-
- push (@the_function_name, $func_name);
- push (@the_metrics, $its_metrics);
- }
- else
- {
- my $msg = "remainder string $remainder has an unrecognized format";
- gp_message ("assertion", $subr_name, $msg);
- }
-
- $g_max_length_first_metric = max ($g_max_length_first_metric, length ($first_metric));
+ my $first_metric = $metrics_array[0];
+ $msg = "first metric found = " . $first_metric;
+ gp_message ("debugXL", $subr_name, $msg);
+ if ($first_metric =~ /^0$decimal_separator$/)
+ {
+ $first_metric = "0.ZZZ";
+ $msg = "fixed up $first_metric";
+ gp_message ("debugXL", $subr_name, $msg);
+ }
+ $g_max_length_first_metric = max ($g_max_length_first_metric,
+ length ($first_metric));
- my $msg = "first_metric = $first_metric " .
- "g_max_length_first_metric = $g_max_length_first_metric";
+ $msg = "first_metric = $first_metric " .
+ "g_max_length_first_metric = $g_max_length_first_metric";
gp_message ("debugXL", $subr_name, $msg);
+ push (@length_first_metric, length ($first_metric));
+ push (@the_metrics, $list_with_metrics);
}
}
- gp_message ("debugXL", $subr_name, "final: g_max_length_first_metric = $g_max_length_first_metric");
- gp_message ("debugXL", $subr_name, "#hex_addresses = $#hex_addresses");
+
+ $msg = "the following function names have been found";
+ gp_message ("debugM", $subr_name, $msg);
+ for my $i (0 .. $#the_function_name)
+ {
+ $msg = "the_function_name{" . $i . "] = " . $the_function_name[$i];
+ gp_message ("debugM", $subr_name, $msg);
+ }
+
+ $msg = "final: g_max_length_first_metric = " . $g_max_length_first_metric;
+ gp_message ("debugM", $subr_name, $msg);
+ $msg = "\$#hex_addresses = " . $#hex_addresses;
+ gp_message ("debugM", $subr_name, $msg);
#------------------------------------------------------------------------------
# Main loop over the input data.
@@ -5545,16 +5547,19 @@ sub generate_caller_callee
my $index_end = -1; # 0
for (my $line = 0; $line <= $#caller_callee_data; $line++)
{
- my $input_line = $caller_callee_data[$line];
+ $input_line = $caller_callee_data[$line];
if ($input_line =~ /$header_name_regex/)
{
$scan_header = $TRUE;
- gp_message ("debugXL", $subr_name, "line = $line encountered start of the header scan_header = $scan_header first = $first");
+ $msg = "line = " . $line . " encountered start of the header";
+ $msg .= " scan_header = " . $scan_header . " first = " . $first;
+ gp_message ("debugXL", $subr_name, $msg);
}
- elsif (($input_line =~ /$sorted_by_regex/) or ($input_line =~ /$current_regex/))
+ elsif (($input_line =~ /$sorted_by_regex/) or
+ ($input_line =~ /$current_regex/))
{
- my $msg = "line = " . $line . " captured top level header: " .
+ $msg = "line = " . $line . " captured top level header: " .
"input_line = " . $input_line;
gp_message ("debugXL", $subr_name, $msg);
@@ -5567,10 +5572,15 @@ sub generate_caller_callee
$scan_caller_callee_data = $TRUE;
$data_function_block .= $separator . $input_line;
- my $msg = "line = $line updated index_end = $index_end";
+ $msg = "line = $line updated index_end = $index_end";
+ gp_message ("debugXL", $subr_name, $msg);
+ $msg = "line = $line input_line = " . $input_line;
+ gp_message ("debugXL", $subr_name, $msg);
+ $msg = "line = $line data_function_block = " . $data_function_block;
gp_message ("debugXL", $subr_name, $msg);
}
- elsif (($input_line =~ /$empty_line_regex/) and ($scan_caller_callee_data))
+ elsif (($input_line =~ /$empty_line_regex/) and
+ ($scan_caller_callee_data))
{
#------------------------------------------------------------------------------
# An empty line is interpreted as the end of the current block and we process
@@ -5579,33 +5589,44 @@ sub generate_caller_callee
$first = $FALSE;
$scan_caller_callee_data = $FALSE;
- gp_message ("debugXL", $subr_name, "new block");
- gp_message ("debugXL", $subr_name, "line = $line index_start = $index_start");
- gp_message ("debugXL", $subr_name, "line = $line index_end = $index_end");
- gp_message ("debugXL", $subr_name, "line = $line data_function_block = $data_function_block");
+ $msg = "new block";
+ gp_message ("debugXL", $subr_name, $msg);
+ $msg = "line = " . $line . " index_start = " . $index_start;
+ gp_message ("debugXL", $subr_name, $msg);
+ $msg = "line = " . $line . " index_end = " . $index_end;
+ gp_message ("debugXL", $subr_name, $msg);
+
+ $msg = "line = " . $line . " data_function_block = ";
+ $msg .= $data_function_block;
+ gp_message ("debugXL", $subr_name, $msg);
push (@function_blocks, $data_function_block);
+
+## $msg = " generating the html blocks (";
+## $msg .= $index_start . " - " . $index_end .")";
+## gp_message ("verbose", $subr_name, $msg);
+
my ($html_block_prologue_ref, $html_code_function_block_ref) =
- generate_html_function_blocks (
- \$index_start,
- \$index_end,
- \@hex_addresses,
- \@the_metrics,
- \@length_first_metric,
- \@special_marker,
- \@the_function_name,
- \$separator,
- $number_of_metrics_ref,
- \$data_function_block,
- $function_info_ref,
- $function_view_structure_ref);
-
- my @html_block_prologue = @{ $html_block_prologue_ref };
- my @html_code_function_block = @{ $html_code_function_block_ref };
+ generate_html_function_blocks (
+ \$index_start,
+ \$index_end,
+ \@hex_addresses,
+ \@the_metrics,
+ \@length_first_metric,
+ \@special_marker,
+ \@the_function_name,
+ \$separator,
+ $number_of_metrics_ref,
+ \$data_function_block,
+ $function_info_ref,
+ $function_view_structure_ref);
+
+ @html_block_prologue = @{ $html_block_prologue_ref };
+ @html_code_function_block = @{ $html_code_function_block_ref };
for my $lines (0 .. $#html_code_function_block)
{
- my $msg = "final html_code_function_block[" . $lines . "] = " .
+ $msg = "final html_code_function_block[" . $lines . "] = " .
$html_code_function_block[$lines];
gp_message ("debugXL", $subr_name, $msg);
}
@@ -5618,8 +5639,10 @@ sub generate_caller_callee
$index_start = $index_end + 1;
$index_end = $index_start - 1;
- gp_message ("debugXL", $subr_name, "line = $line reset index_start = $index_start");
- gp_message ("debugXL", $subr_name, "line = $line reset index_end = $index_end");
+ $msg = "line = " . $line . " reset index_start = " . $index_start;
+ gp_message ("debugXL", $subr_name, $msg);
+ $msg = "line = " . $line . " reset index_end = " . $index_end;
+ gp_message ("debugXL", $subr_name, $msg);
}
#------------------------------------------------------------------------------
@@ -5679,18 +5702,26 @@ sub generate_caller_callee
#------------------------------------------------------------------------------
# Parse and process the individual function blocks.
#------------------------------------------------------------------------------
+ $msg = "Parse and process function blocks - total blocks = ";
+ $msg .= $#function_blocks + 1;
+ gp_message ("verbose", $subr_name, $msg);
+
for my $i (0 .. $#function_blocks)
{
- my $msg = "function_blocks[" . $i . "] = ". $function_blocks[$i];
+ $msg = "process function block " . $i;
+ gp_message ("debugXL", $subr_name, $msg);
+
+ $msg = "function_blocks[" . $i . "] = ". $function_blocks[$i];
gp_message ("debugXL", $subr_name, $msg);
#------------------------------------------------------------------------------
-# This split produces an empty first field. This is why skip this.
+# This split produces an empty first field. This is why we skip this in the
+# loop below.
#------------------------------------------------------------------------------
my @entries = split ($separator, $function_blocks[$i]);
#------------------------------------------------------------------------------
-# An example of @entries:
-# <empty>
+# An example of the content of array @entries:
+# <empty line>
# 6:0x0003ad20 drand48 0.100 0.084 768240570 0
# 6:0x0003af50 *erand48_r 0.080 0.084 768240570 0
# 6:0x0003b160 __drand48_iterate 0.020 0. 0 0
@@ -5699,67 +5730,54 @@ sub generate_caller_callee
{
my $input_line = $entries[$k];
- my $msg = "input_line = entries[" . $k . "] = ". $entries[$k];
+ $msg = "input_line = entries[" . $k . "] = ". $entries[$k];
gp_message ("debugXL", $subr_name, $msg);
- @fields = split (" ", $input_line);
+ my ($hex_address_ref, $marker_ref, $reduced_line_ref,
+ $list_with_metrics_ref) =
+ split_function_data_line (\$input_line);
- $no_of_fields = $#fields + 1;
- $elements_in_name = $no_of_fields - $number_of_metrics - 1;
+ $full_hex_address = ${ $hex_address_ref };
+ $marker_target_function = ${ $marker_ref };
+ $routine = ${ $reduced_line_ref };
+ $all_metrics = ${ $list_with_metrics_ref };
-#------------------------------------------------------------------------------
-# TBD: Too restrictive.
-# CHECK CODE IN GENERATE_CALLER_CALLEE
-#------------------------------------------------------------------------------
- if ($elements_in_name == 1)
- {
- $name_regex = '\s*(\d+:0x[a-fA-F0-9]+)\s+([\s\*])(\S+)\s+(.*)';
- }
- elsif ($elements_in_name == 2)
- {
- $name_regex = '\s*(\d+:0x[a-fA-F0-9]+)\s+([\s\*])((\S+)\s+(\S+))\s+(.*)';
- }
- else
-#------------------------------------------------------------------------------
-# TBD: Handle this better in case a function entry has more than 2 words.
-#------------------------------------------------------------------------------
+ $msg = "RESULT full_hex_address = " . $full_hex_address;
+ $msg .= " -- metric values = " . $all_metrics;
+ $msg .= " -- marker = " . $marker_target_function;
+ $msg .= " -- function name = " . $routine;
+ gp_message ("debugXL", $subr_name, $msg);
+
+ $metrics_length = length ($all_metrics);
+ $max_metrics_length = max ($max_metrics_length, $metrics_length);
+
+ if ($full_hex_address =~ /(\d+):0x(\S+)/)
{
- my $msg = "$elements_in_name elements in name exceeds limit";
- gp_message ("assertion", $subr_name, $msg);
+ $hex_address = "0x" . $2;
}
+ push (@marker, $marker_target_function);
- if ($input_line =~ /$name_regex/)
- {
- $full_hex_address = $1;
- $marker_target_function = $2;
- $routine = $3;
- if ($elements_in_name == 1)
- {
- $all_metrics = $4;
- }
- elsif ($elements_in_name == 2)
- {
- $all_metrics = $6;
- }
+ push (@address_field, $hex_address);
+ push (@address_field, $full_hex_address);
+ $msg = "pushed " . $full_hex_address;
+ $msg .= " to array address_field";
+ gp_message ("debugXL", $subr_name, $msg);
- $metrics_length = length ($all_metrics);
- $max_metrics_length = max ($max_metrics_length, $metrics_length);
+ $modified_line = $all_metrics . " " . $routine;
+ gp_message ("debugXL", $subr_name, "xxxxxxx = $modified_line");
- if ($full_hex_address =~ /(\d+):0x(\S+)/)
- {
- $hex_address = "0x" . $2;
- }
- push (@marker, $marker_target_function);
- push (@address_field, $hex_address);
- $modified_line = $all_metrics . " " . $routine;
- push (@metric_values, $all_metrics);
- gp_message ("debugXL", $subr_name, "xxxxxxx = $modified_line");
- push (@function_names, $routine);
- }
+ push (@metric_values, $all_metrics);
+ $msg = "pushed " . $all_metrics . " to array metric_values";
+ gp_message ("debugXL", $subr_name, $msg);
+
+ push (@function_names, $routine);
+ $msg = "pushed " . $routine . " to array function_names";
+ gp_message ("debugXL", $subr_name, $msg);
}
$total_header_lines = $#header_lines + 1;
- gp_message ("debugXL", $subr_name, "total_header_lines = $total_header_lines");
+ $msg = "total_header_lines = " . $total_header_lines;
+ gp_message ("debugXL", $subr_name, $msg);
gp_message ("debugXL", $subr_name, "Final output");
for my $i (keys @header_lines)
@@ -5768,57 +5786,79 @@ sub generate_caller_callee
}
for my $i (0 .. $#function_names)
{
- my $msg = $metric_values[$i] . " " . $marker[$i] .
- $function_names[$i] . "(" . $address_field[$i] . ")";
+ $msg = $metric_values[$i] . " " . $marker[$i];
+ $msg .= $function_names[$i] . " (" . $address_field[$i] . ")";
gp_message ("debugXL", $subr_name, $msg);
}
#------------------------------------------------------------------------------
# Check if this function has multiple occurrences.
# TBD: Replace by the function call for this.
#------------------------------------------------------------------------------
- gp_message ("debugXL", $subr_name, "check for multiple occurrences");
+ $msg = "check for multiple occurrences - function_names = ";
+ $msg .= ($#function_names + 1);
+ gp_message ("debugXL", $subr_name, $msg);
+
for my $i (0 .. $#function_names)
{
my $current_address = $address_field[$i];
my $found_a_match;
my $ref_index;
my $alt_name;
+ my $addr_offset;
+
$routine = $function_names[$i];
$alt_name = $routine;
gp_message ("debugXL", $subr_name, "checking for routine = $routine");
if (exists ($g_multi_count_function{$routine}))
{
-
#------------------------------------------------------------------------------
-# TBD: Scan all of the function_info list. Or beter: add index to g_multi_count_function!!
+# TBD: Scan all of the function_info list. Or beter: add index to
+# g_multi_count_function.
#------------------------------------------------------------------------------
$found_a_match = $FALSE;
- gp_message ("debugXL", $subr_name, "$routine: occurrences = $g_function_occurrences{$routine}");
+
+ $msg = $routine . ": occurrences = ";
+ $msg .= $g_function_occurrences{$routine};
+ gp_message ("debugXL", $subr_name, $msg);
+
for my $ref (keys @{ $g_map_function_to_index{$routine} })
{
$ref_index = $g_map_function_to_index{$routine}[$ref];
- gp_message ("debugXL", $subr_name, "$routine: retrieving duplicate entry at ref_index = $ref_index");
- gp_message ("debugXL", $subr_name, "$routine: function_info[$ref_index]{'alt_name'} = $function_info[$ref_index]{'alt_name'}");
+ $msg = $routine . ": retrieving duplicate entry at ";
+ $msg .= "ref_index = " . $ref_index;
+ gp_message ("debugXL", $subr_name, $msg);
+ $msg = $routine . ": function_info[" . $ref_index;
+ $msg .= "]{alt_name} = ";
+ $msg .= $function_info[$ref_index]{'alt_name'};
+ gp_message ("debugXL", $subr_name, $msg);
- my $addr_offset = $function_info[$ref_index]{"addressobjtext"};
- gp_message ("debugXL", $subr_name, "$routine: addr_offset = $addr_offset");
+ $addr_offset = $function_info[$ref_index]{"addressobjtext"};
+ $msg = $routine . ": addr_offset = " . $addr_offset;
+ gp_message ("debugXL", $subr_name, $msg);
$addr_offset =~ s/$get_addr_offset_regex//;
- gp_message ("debugXL", $subr_name, "$routine: addr_offset = $addr_offset");
+ $msg = $routine . ": addr_offset = " . $addr_offset;
+ gp_message ("debugXL", $subr_name, $msg);
+
if ($addr_offset eq $current_address)
{
$found_a_match = $TRUE;
last;
}
}
- gp_message ("debugXL", $subr_name, "$function_info[$ref_index]{'alt_name'} is the actual function for i = $i $found_a_match");
+ $msg = $function_info[$ref_index]{'alt_name'};
+ $msg .= " is the actual function for i = " . $i . " ";
+ $msg .= $found_a_match;
+ gp_message ("debugXL", $subr_name, $msg);
+
$alt_name = $function_info[$ref_index]{'alt_name'};
}
gp_message ("debugXL", $subr_name, "alt_name = $alt_name");
}
- gp_message ("debugXL", $subr_name, "completed check for multiple occurrences");
+ $msg = "completed the check for multiple occurrences";
+ gp_message ("debugXL", $subr_name, $msg);
#------------------------------------------------------------------------------
# Figure out the column width. Since the columns in the header may include
@@ -5834,8 +5874,23 @@ sub generate_caller_callee
# $i = 3 35 42
for my $i (keys @word_index_values)
{
- gp_message ("debugXL", $subr_name, "i = $i $word_index_values[$i][0] $word_index_values[$i][1]");
+ $msg = "i = " . $i . " " . $word_index_values[$i][0] . " ";
+ $msg .= $word_index_values[$i][1];
+ gp_message ("debugXL", $subr_name, $msg);
}
+
+#------------------------------------------------------------------------------
+# Empty the buffers before processing the next block with data.
+#------------------------------------------------------------------------------
+ @function_names = ();
+ @metric_values = ();
+ @address_field = ();
+ @marker = ();
+
+ $msg = "erased contents of arrays function_names, metric_values, ";
+ $msg .= "address_field, and marker";
+ gp_message ("debugXL", $subr_name, $msg);
+
}
push (@html_metric_sort_header, "<i>");
@@ -5870,6 +5925,9 @@ sub generate_caller_callee
close (CALLER_CALLEE_OUT);
+ $msg = "the caller-callee information has been generated";
+ gp_message ("verbose", $subr_name, $msg);
+
return (0);
} #-- End of subroutine generate_caller_callee
@@ -6845,6 +6903,7 @@ sub generate_function_level_info
my $gp_display_text_cmd;
my $gp_functions_cmd;
my $ignore_value;
+ my $msg;
my $script_pc_metrics;
my $outputdir = append_forward_slash ($input_string);
@@ -6903,6 +6962,7 @@ sub generate_function_level_info
#------------------------------------------------------------------------------
# Empty header.
+# TBD: Is still needed? Also, add the header command.
#------------------------------------------------------------------------------
print SCRIPT_PC "# outfile $outputdir"."header\n";
print SCRIPT_PC "outfile $outputdir"."header\n";
@@ -7082,6 +7142,12 @@ sub generate_function_level_info
{
my $input_line = $input_data[$line];
+ $input_line =~ s/ -- no functions found//;
+ $input_data[$line] =~ s/ -- no functions found//;
+
+ $msg = "line = " . $line . " input_line = " . $input_line;
+ gp_message ("debugXL", $subr_name, $msg);
+
# if ($input_line =~ /^<Total>\s+.*/)
if ($input_line =~ /\s*(\d+:0x[a-fA-F0-9]+)\s+(\S+)\s+(.*)/)
{
@@ -8147,22 +8213,25 @@ sub get_function_info
my $line;
my $routine_flag;
my $value;
- my $whatever;
+ my $field;
my $df_flag;
my $address_decimal;
my $routine;
my $num_source_files = 0;
- my $number_of_functions = 0;
my $number_of_unique_functions = 0;
my $number_of_non_unique_functions = 0;
+ my $function_info_regex = '\s*(\S+[a-zA-Z\s]*):(.*)';
+ my $get_hex_address_regex = '(\d+):(0x\S+)';
#------------------------------------------------------------------------------
# Open the file generated using the -fsummary option.
#------------------------------------------------------------------------------
+ $msg = " - unable to open file $FSUMMARY_FILE for reading:";
open (FSUMMARY_FILE, "<", $FSUMMARY_FILE)
- or die ("$subr_name - unable to open $FSUMMARY_FILE for reading: '$!'");
- gp_message ("debug", $subr_name, "opened file $FSUMMARY_FILE for reading");
+ or die ($subr_name . $msg . " " . $!);
+ $msg = "opened file $FSUMMARY_FILE for reading";
+ gp_message ("debug", $subr_name, $msg);
#------------------------------------------------------------------------------
# This is the typical structure of the fsummary output:
@@ -8218,7 +8287,19 @@ sub get_function_info
{
$line = $_;
chomp ($line);
- gp_message ("debugXL", $subr_name, "line = $line");
+
+#------------------------------------------------------------------------------
+# Legacy issue to deal with. Up until somewhere between binutils 2.40 and 2.41,
+# gprofng display text might print the " -- no functions found" comment.
+# No, the two spaces after -- are not my typo ;-)
+#
+# Since then, this comment is no longer printed, but the safe approach is to
+# remove any occurrence upfront.
+#------------------------------------------------------------------------------
+ $line =~ s/ -- no functions found//;
+
+ $msg = "line = " . $line;
+ gp_message ("debugXL", $subr_name, $msg);
if ($line =~ /^\s*$/)
#------------------------------------------------------------------------------
@@ -8256,6 +8337,8 @@ sub get_function_info
# may show up in a function list.
#
# Here we determine the number of fields and store it.
+#
+# REVISIT This may not be needed anymore
#------------------------------------------------------------------------------
my @fields_in_name = split (" ", $routine);
$function_info[$i]{"fields in routine name"} = scalar (@fields_in_name);
@@ -8327,59 +8410,152 @@ sub get_function_info
}
#------------------------------------------------------------------------------
-# Expected format of an input line:
-# Exclusive Total CPU Time: 4.003 ( 34.7%)
-# or:
-# Source File: <absolute_path>/name_of_source_file
+# Example format of an input block, where $line is one of the following:
+# Exclusive Total CPU Time: 0.001 ( 0.0%)
+# Inclusive Total CPU Time: 0.001 ( 0.0%)
+# Size: 92
+# PC Address: 5:0x00125de0
+# Source File: (unknown)
+# Object File: (unknown)
+# Load Object: /usr/lib64/libc-2.28.so
+# Mangled Name:
+# Aliases: __brk
#------------------------------------------------------------------------------
$line =~ s/^\s+//;
+ if ($line =~ /$function_info_regex/)
+ {
+ if (defined ($1) and defined($2))
+ {
+ $field = $1;
+ $value = $2;
+ $value =~ s/$g_rm_surrounding_spaces_regex//g;
- my @input_fields = split (":", $line);
- my $no_of_elements = scalar (@input_fields);
-
- gp_message ("debugXL", $subr_name, "#input_fields = $#input_fields");
- gp_message ("debugXL", $subr_name, "no_of_elements = $no_of_elements");
- gp_message ("debugXL", $subr_name, "input_fields[0] = $input_fields[0]");
+ $msg = "initial - field = " . $field . " value = " . $value;
+ gp_message ("debugM", $subr_name, $msg);
+ }
+ else
+ {
+ $msg = "the input line pattern was not recognized";
+ gp_message ("warning", $subr_name, $msg);
+ gp_message ("debug", $subr_name, $msg);
+ $msg = "execution continues, but there may be a problem later";
+ gp_message ("warning", $subr_name, $msg);
+ gp_message ("debug", $subr_name, $msg);
- if ($no_of_elements == 1)
- {
- $whatever = $input_fields[0];
- $value = "";
- }
- elsif ($no_of_elements == 2)
- {
+ $field = "not recognized";
+ $value = "not recognized";
+ }
#------------------------------------------------------------------------------
-# Note that value may consist of multiple fields (e.g. 1.651 ( 95.4%)).
+# The field has no value.
#------------------------------------------------------------------------------
- $whatever = $input_fields[0];
- $value = $input_fields[1];
- }
- elsif ($no_of_elements == 3)
- {
+ if (length ($value) eq 0)
+## if ($value =~ /^\s+$/)
+## if (length ($2) gt 0)
+## if ($2 == " ")
+ {
+ if ($field eq "Mangled Name")
+ {
+ $value = $routine;
+
+ $msg = "no mangled name found - use the routine name ";
+ $msg .= $routine . " as the mangled name";
+ gp_message ("debugM", $subr_name, $msg);
+ }
+ else
+ {
+ $value = "no_value_given";
+
+ $msg = "no value was found for this field - set to ";
+ $msg .= $value;
+ gp_message ("debugM", $subr_name, $msg);
+ }
+ }
#------------------------------------------------------------------------------
-# Assumption: must be an address field. Restore the second colon.
+# Remove any leading whitespace characters.
#------------------------------------------------------------------------------
- $whatever = $input_fields[0];
- $value = $input_fields[1] . ":" . $input_fields[2];
- }
- else
- {
- $msg = "unexpected: number of fields = " . $no_of_elements;
- gp_message ("assertion", $subr_name, $msg);
- }
+ $value =~ s/$white_space_regex//;
#------------------------------------------------------------------------------
-# Remove any leading whitespace characters.
+# These are the final values that will be used.
#------------------------------------------------------------------------------
- $value =~ s/$white_space_regex//;
-
- gp_message ("debugXL", $subr_name, "whatever = $whatever value = $value");
+ $msg = "final - field = " . $field . " value = " . $value;
+ gp_message ("debugM", $subr_name, $msg);
- $function_info[$i]{$whatever} = $value;
+ $function_info[$i]{$field} = $value;
+ }
+## $value =~ s/$white_space_regex//;
+
+## \s*(\S+[a-zA-Z\s]*):\ *(.*)
+
+### my @input_fields = split (":", $line);
+### my $no_of_elements = scalar (@input_fields);
+
+### gp_message ("debugXL", $subr_name, "#input_fields = $#input_fields");
+### gp_message ("debugXL", $subr_name, "no_of_elements = $no_of_elements");
+### gp_message ("debugXL", $subr_name, "input_fields[0] = $input_fields[0]");
+
+### if ($no_of_elements == 1)
+#------------------------------------------------------------------------------
+# No value
+#------------------------------------------------------------------------------
+### {
+### $whatever = $input_fields[0];
+### $value = "";
+### }
+### elsif ($no_of_elements == 2)
+### {
+### #------------------------------------------------------------------------------
+### # Note that $value may consist of multiple fields (e.g. 1.651 ( 95.4%)).
+### #------------------------------------------------------------------------------
+### $whatever = $input_fields[0];
+### $value = $input_fields[1];
+### }
+### elsif ($no_of_elements == 3)
+### {
+### $whatever = $input_fields[0];
+### if ($whatever eq "PC Address")
+### #------------------------------------------------------------------------------
+### # Must be an address field. Restore the second colon.
+### #------------------------------------------------------------------------------
+### {
+### $value = $input_fields[1] . ":" . $input_fields[2];
+### }
+### elsif ($whatever eq "Mangled Name")
+### #------------------------------------------------------------------------------
+### # The mangled name includes a colon (:). Just copy the entire string.
+### #------------------------------------------------------------------------------
+### {
+### $value = $input_fields[2];
+### }
+### }
+### else
+### {
+### if ($whatever eq "Aliases")
+### #------------------------------------------------------------------------------
+### # The mangled name includes a colon (:). Just copy the entire string.
+### #------------------------------------------------------------------------------
+### {
+### $value = $input_fields[2];
+### }
+### else
+### {
+### $msg = "input line = " . $line;
+### gp_message ("debug", $subr_name, $msg);
+### for my $i (keys @input_fields)
+### {
+### $msg = "input_fields[$i] = " . $input_fields[$i];
+### gp_message ("debug", $subr_name, $msg);
+### }
+### $msg = "unexpected input: number of fields = " . $no_of_elements;
+### gp_message ("debug", $subr_name, $msg);
+### ## gp_message ("assertion", $subr_name, $msg);
+### }
+### }
+## $function_info[$i]{$field} = $value;
#------------------------------------------------------------------------------
# TBD: Seems to be not used anymore and can most likely be removed. Check this.
#------------------------------------------------------------------------------
- if ($whatever =~ /Source File/)
+ if ($field =~ /Source File/)
{
if (!exists ($source_files{$value}))
{
@@ -8388,7 +8564,7 @@ sub get_function_info
}
}
- if ($whatever =~ /PC Address/)
+ if ($field =~ /PC Address/)
{
my $segment;
my $offset;
@@ -8411,7 +8587,7 @@ sub get_function_info
# Construct the address field. Note that we use the hex address here.
# For example @2:0x0003f280
#------------------------------------------------------------------------------
- $full_address_field = '@'.$segment.":0x".$offset;
+ $full_address_field = $segment.":0x".$offset;
$function_info[$i]{"addressobj"} = $address_decimal;
$function_info[$i]{"addressobjtext"} = $full_address_field;
@@ -8432,7 +8608,7 @@ sub get_function_info
gp_message ("debugXL", $subr_name, $msg);
}
- $number_of_functions++;
+ $g_total_function_count++;
}
}
close (FSUMMARY_FILE);
@@ -8494,7 +8670,7 @@ sub get_function_info
# The address field has the following format: @<n>:<address_offset>
# We only care about the address offset.
#------------------------------------------------------------------------------
- if ($address_field =~ /(^@\d*:*)(.+)/)
+ if ($address_field =~ /$get_hex_address_regex/)
{
$address_offset = $2;
}
@@ -8719,20 +8895,23 @@ sub get_function_info
}
#------------------------------------------------------------------------------
-# TBD: Include in experiment data. Include names with multiple occurrences.
+# TBD: Include this info on the page with experiment data. Include names
+# with multiple occurrences.
#------------------------------------------------------------------------------
- $msg = "Number of source files : " .
+ $msg = "Number of source files : " .
$num_source_files;
gp_message ("debug", $subr_name, $msg);
- $msg = "Total number of functions: $number_of_functions";
+ $msg = "Total number of functions : " .
+ $g_total_function_count;
gp_message ("debug", $subr_name, $msg);
- $msg = "Number of functions functions with a unique name : " .
+ $msg = "Number of functions with a unique name : " .
$number_of_unique_functions;
gp_message ("debug", $subr_name, $msg);
- $msg = "Number of functions functions with more than one occurrence : " .
+ $msg = "Number of functions with more than one occurrence : " .
$number_of_non_unique_functions;
gp_message ("debug", $subr_name, $msg);
- my $multi_occurrences = $number_of_functions - $number_of_unique_functions;
+ my $multi_occurrences = $g_total_function_count -
+ $number_of_unique_functions;
$msg = "Total number of multiple occurences of the same function name : " .
$multi_occurrences;
gp_message ("debug", $subr_name, $msg);
@@ -9027,24 +9206,32 @@ sub get_index_function_info
my $hex_address = ${ $hex_address_ref };
my @function_info = @{ $function_info_ref };
-#------------------------------------------------------------------------------
-# Check if this function has multiple occurrences.
-#------------------------------------------------------------------------------
- gp_message ("debug", $subr_name, "check for multiple occurrences");
-
- my $current_address = $hex_address;
my $alt_name = $routine;
-
+ my $current_address = $hex_address;
my $found_a_match;
my $index_into_function_info;
+ my $msg;
my $target_tag;
+#------------------------------------------------------------------------------
+# Check if this function has multiple occurrences.
+#------------------------------------------------------------------------------
+ $msg = "check for multiple occurrences";
+ gp_message ("debugM", $subr_name, $msg);
+ $msg = "target routine name = " . $routine;
+ gp_message ("debugM", $subr_name, $msg);
+
if (not exists ($g_multi_count_function{$routine}))
{
#------------------------------------------------------------------------------
# There is only a single occurrence and it is straightforward to get the tag.
#--------------------------------------------------------------------------
## push (@final_function_names, $routine);
+## KANWEG for my $key (sort keys %g_map_function_to_index)
+## KANWEG {
+## KANWEG $msg = "g_map_function_to_index{". $key . "} = " . $g_map_function_to_index{$key};
+## KANWEG gp_message ("debugXL", $subr_name, $msg);
+## KANWEG }
if (exists ($g_map_function_to_index{$routine}))
{
$index_into_function_info = $g_map_function_to_index{$routine}[0];
@@ -11218,8 +11405,6 @@ sub preprocess_function_files
# TBD $outputdir .= "/";
- gp_message ("debug", $subr_name, "enter subroutine");
-
my %metric_description = %{ $metric_description_ref };
for my $m (keys %metric_description)
@@ -11876,7 +12061,7 @@ sub print_user_settings
sub print_version_info
{
print "$version_info\n";
- print "Copyright (C) 2024 Free Software Foundation, Inc.\n";
+ print "Copyright (C) 2023 Free Software Foundation, Inc.\n";
print "License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.\n";
print "This is free software: you are free to change and redistribute it.\n";
print "There is NO WARRANTY, to the extent permitted by law.\n";
@@ -12260,8 +12445,9 @@ sub process_function_files
#
# TBD: Remove the part regarding clones. Legacy.
#------------------------------------------------------------------------------
- my $replace_quote_regex = '"/\"';
my $find_clone_regex = '^(.*)(\s+--\s+cloned\s+version\s+\[)([^]]+)(\])';
+ my $remove_number_regex = '^\d+:';
+ my $replace_quote_regex = '"/\"';
my %addressobj_index = ();
my %function_address_info = ();
@@ -12480,6 +12666,11 @@ sub process_function_files
$function_info[$routine_index]{"srcline"} = "";
$address_field = $function_info[$routine_index]{"addressobjtext"};
+#------------------------------------------------------------------------------
+# Strip the internal number from the address field.
+#------------------------------------------------------------------------------
+ $address_field =~ s/$remove_number_regex//;
+
## $disfile = "file\.$routine_index\.dis";
$disfile = "file." . $routine_index . "." . $g_html_base_file_name{"disassembly"};
$srcfile = "";
@@ -12497,13 +12688,19 @@ sub process_function_files
$tmp = $routine;
$tmp =~ s/$replace_quote_regex//g;
print SCRIPT "# disasm \"$tmp\" $address_field\n";
- print SCRIPT "disasm \"$tmp\" $address_field\n";
+#------------------------------------------------------------------------------
+## TBD: adding the address is not supported. Need to find a way to figure
+## out the ID of the function.
+## print SCRIPT "disasm \"$tmp\" $address_field\n";
+## print SCRIPT "source \"$tmp\" $address_field\n";
+#------------------------------------------------------------------------------
+ print SCRIPT "disasm \"$tmp\"\n";
if ($srcfile=~/file/)
{
print SCRIPT "# outfile $outputdir"."$srcfile\n";
print SCRIPT "outfile $outputdir"."$srcfile\n";
print SCRIPT "# source \"$tmp\" $address_field\n";
- print SCRIPT "source \"$tmp\" $address_field\n";
+ print SCRIPT "source \"$tmp\"\n";
}
if ($routine =~ /$find_clone_regex/)
@@ -12645,10 +12842,12 @@ sub process_function_overview
my $hex_address;
my $html_line;
my $input_line;
+ my $marker;
my $name_regex;
my $no_of_fields;
my $metrics_length;
my $missing_digits;
+ my $msg;
my $remaining_part_header;
my $routine;
my $routine_length;
@@ -12679,6 +12878,9 @@ sub process_function_overview
my $zero_dot_at_end_regex = '[\w0-9' . $decimal_separator . ']*(0' . $decimal_separator . '$)';
my $backward_slash_regex = '\/';
+ $msg = "enter subroutine " . $subr_name;
+ gp_message ("debug", $subr_name, $msg);
+
#------------------------------------------------------------------------------
if (is_file_empty ($overview_file))
{
@@ -12707,6 +12909,11 @@ sub process_function_overview
gp_message ("debug", $subr_name, "read all of file $overview_file into memory");
#------------------------------------------------------------------------------
+# Remove a legacy redundant string, if any.
+#------------------------------------------------------------------------------
+ @function_data = @{ remove_redundant_string (\@function_data)};
+
+#------------------------------------------------------------------------------
# Parse the function view info and store the data.
#------------------------------------------------------------------------------
my $max_header_length = 0;
@@ -12722,6 +12929,8 @@ sub process_function_overview
for (my $line = 0; $line <= $#function_data; $line++)
{
$input_line = $function_data[$line];
+## $input_line =~ s/ -- no functions found//;
+
gp_message ("debugXL", $subr_name, "input_line = $input_line");
#------------------------------------------------------------------------------
@@ -12747,7 +12956,7 @@ sub process_function_overview
if (defined ($4))
{
$remaining_part_header = $4;
- my $msg = "remaining_part_header = $remaining_part_header";
+ $msg = "remaining_part_header = $remaining_part_header";
gp_message ("debugXL", $subr_name, $msg);
#------------------------------------------------------------------------------
@@ -12794,44 +13003,32 @@ sub process_function_overview
#------------------------------------------------------------------------------
if ($scan_function_data and (not ($input_line =~ /$empty_line_regex/)))
{
+ $msg = "detected a line with function data";
+ gp_message ("debugXL", $subr_name, $msg);
+
+ my ($hex_address_ref, $marker_ref, $reduced_line_ref,
+ $list_with_metrics_ref) =
+ split_function_data_line (\$input_line);
+
+ $full_hex_address = ${ $hex_address_ref };
+ $marker = ${ $marker_ref };
+ $routine = ${ $reduced_line_ref };
+ $all_metrics = ${ $list_with_metrics_ref };
+
+ $msg = "RESULT full_hex_address = " . $full_hex_address;
+ $msg .= " -- metric values = " . $all_metrics;
+ $msg .= " -- marker = " . $marker;
+ $msg .= " -- function name = " . $routine;
+ gp_message ("debugXL", $subr_name, $msg);
+
@fields = split (" ", $input_line);
$no_of_fields = $#fields + 1;
$elements_in_name = $no_of_fields - $number_of_metrics - 1;
- gp_message ("debugXL", $subr_name, "no_of_fields = $no_of_fields elements_in_name = $elements_in_name");
-
-#------------------------------------------------------------------------------
-# TBD: Handle this better in case a function entry has more than 2 words.
-# Build the regex dynamically and use eval to capture the correct group.
-# CHECK CODE IN GENERATE_CALLER_CALLEE
-#------------------------------------------------------------------------------
- if ($elements_in_name == 1)
- {
- $name_regex = '\s*(\d+:0x[a-fA-F0-9]+)\s+(\S+)\s+(.*)';
- }
- elsif ($elements_in_name == 2)
- {
- $name_regex = '\s*(\d+:0x[a-fA-F0-9]+)\s+((\S+)\s+(\S+))\s+(.*)';
- }
- else
- {
- gp_message ("error", $subr_name, "assertion error: $elements_in_name elements in name exceeds limit");
- }
-
- if ($input_line =~ /$name_regex/)
- {
- $full_hex_address = $1;
- $routine = $2;
-
- if ($elements_in_name == 1)
- {
- $all_metrics = $3;
- }
- elsif ($elements_in_name == 2)
- {
- $all_metrics = $5;
- }
+ $msg = "no_of_fields = " . $no_of_fields;
+ $msg .= " elements_in_name = " . $elements_in_name;
+ gp_message ("debugXL", $subr_name, $msg);
#------------------------------------------------------------------------------
# In case the last metric is 0. only, we append 3 extra characters that
@@ -12861,12 +13058,24 @@ sub process_function_overview
$max_metrics_length = max ($max_metrics_length, $metrics_length);
gp_message ("debugXL", $subr_name, "$routine all_metrics = $all_metrics metrics_length = $metrics_length");
+ $msg = "verify full_hex_address = " . $full_hex_address;
+ gp_message ("debugXL", $subr_name, $msg);
+
if ($full_hex_address =~ /$get_hex_address_regex/)
{
$hex_address = "0x" . $2;
}
+ else
+ {
+ $msg = "full_hex_address = $full_hex_address has the wrong format";
+ gp_message ("assertion", $subr_name, $msg);
+ }
+
+ push (@address_field, $full_hex_address);
+
+ $msg = "pushed full_hex_address = " . $full_hex_address;
+ gp_message ("debugXL", $subr_name, $msg);
- push (@address_field, $hex_address);
push (@metric_values, $all_metrics);
#------------------------------------------------------------------------------
@@ -12876,7 +13085,6 @@ sub process_function_overview
# The reason to decouple this is to avoid the code gets too complex here.
#------------------------------------------------------------------------------
push (@function_names, $routine);
- }
}
} #-- End of loop over the input lines
@@ -12902,6 +13110,11 @@ sub process_function_overview
# has the final name, the html function block, etc.
#------------------------------------------------------------------------------
+ for my $i (keys @address_field)
+ {
+ $msg = "address_field[" . $i ."] = " . $address_field[$i];
+ gp_message ("debugM", $subr_name, $msg);
+ }
#------------------------------------------------------------------------------
## TBD: Use get_index_function_info??!!
#------------------------------------------------------------------------------
@@ -12914,10 +13127,15 @@ sub process_function_overview
my $routine = $function_names[$i];
my $current_address = $address_field[$i];
- my $found_a_match = $FALSE;
my $final_function_name;
+ my $found_a_match = $FALSE;
+ my $msg;
my $ref_index;
+ $msg = "on entry - routine = " . $routine;
+ $msg .= " current_address = " . $current_address;
+ gp_message ("debugM", $subr_name, $msg);
+
#------------------------------------------------------------------------------
# Check if there are duplicate entries for this function. If there are, use
# the address to find the right match in the function_info structure.
@@ -12925,7 +13143,12 @@ sub process_function_overview
gp_message ("debugXL", $subr_name, "$routine: first check for multiple occurrences");
if (exists ($g_multi_count_function{$routine}))
{
- gp_message ("debugXL", $subr_name, "$routine: occurrences = $g_function_occurrences{$routine}");
+ $msg = "$g_multi_count_function{$routine} exists";
+ gp_message ("debugXL", $subr_name, $msg);
+ $msg = "g_function_occurrences{$routine} = ";
+ $msg .= $g_function_occurrences{$routine};
+ gp_message ("debugXL", $subr_name, $msg);
+
for my $ref (keys @{ $g_map_function_to_index{$routine} })
{
my $ref_index = $g_map_function_to_index{$routine}[$ref];
@@ -12972,7 +13195,7 @@ sub process_function_overview
# This should not happen. All we can do is print an error message and stop.
#------------------------------------------------------------------------------
{
- my $msg = "cannot find the index for $routine: found_a_match = ";
+ $msg = "cannot find the index for $routine: found_a_match = ";
$msg .= ($found_a_match == $TRUE) ? "TRUE" : "FALSE";
gp_message ("assertion", $subr_name, $msg);
}
@@ -13071,7 +13294,7 @@ sub process_function_overview
}
else
{
- my $msg = "keyword $target_keyword not found in $remaining_part_header";
+ $msg = "keyword $target_keyword not found in $remaining_part_header";
gp_message ("assertion", $subr_name, $msg);
}
@@ -13199,7 +13422,7 @@ sub process_function_overview
for my $i (0 .. $#function_view_array)
{
- my $msg = "function_view_array[$i] = $function_view_array[$i]";
+ $msg = "function_view_array[$i] = $function_view_array[$i]";
gp_message ("debugXL", $subr_name, $msg);
}
#------------------------------------------------------------------------------
@@ -13209,6 +13432,9 @@ sub process_function_overview
$function_view_structure{"metrics part"} = [@metrics_part];
$function_view_structure{"function table"} = [@function_view_array];
+ $msg = "leave subroutine " . $subr_name;
+ gp_message ("debug", $subr_name, $msg);
+
return (\%function_view_structure);
} #-- End of subroutine process_function_overview
@@ -13320,6 +13546,7 @@ sub process_metrics_data
my $metric_text;
my $metricdata;
my $metric_line;
+ my $msg;
my $summary_metrics;
my $detail_metrics;
@@ -13328,16 +13555,18 @@ sub process_metrics_data
if ($g_user_settings{"default_metrics"}{"current_value"} eq "off")
{
- gp_message ("debug", $subr_name, "g_user_settings{default_metrics}{current_value} = " . $g_user_settings{"default_metrics"}{"current_value"});
+ $msg = "g_user_settings{default_metrics}{current_value} = ";
+ $msg .= $g_user_settings{"default_metrics"}{"current_value"};
+ gp_message ("debug", $subr_name, $msg);
# get metrics
- $summary_metrics='';
- $detail_metrics='';
- $detail_metrics_system='';
- $call_metrics = '';
- $user_metrics=0;
- $system_metrics=0;
- $wall_metrics=0;
+ $summary_metrics = '';
+ $detail_metrics = '';
+ $detail_metrics_system = '';
+ $call_metrics = '';
+ $user_metrics = 0;
+ $system_metrics = 0;
+ $wall_metrics = 0;
my ($last_metric,$metric,$value,$i,$r);
@@ -13439,7 +13668,7 @@ sub process_metrics_data
if ($value>0) # Not interested in metrics contributing zero
{
$metric_value{$metric} = $value;
- my $msg = "metrictotals odd line rescued '$metric'=$value";
+ $msg = "metrictotals odd line rescued '$metric'=$value";
gp_message ("debug", $subr_name, $msg);
}
}
@@ -14521,11 +14750,12 @@ sub process_source
if (not $found_target)
{
my $msg;
- gp_message ("debug", $subr_name, "target function $routine not found");
- $msg = "function $routine not found in $base - " .
+ $msg = "target function $routine not found in $base - " .
"links to source code involving this function will not work";
+ gp_message ("debug", $subr_name, $msg);
gp_message ("warning", $subr_name, $msg);
+ $g_total_warning_count++;
return ($found_target);
}
@@ -15108,6 +15338,39 @@ sub process_user_options
} #-- End of subroutine process_user_options
#------------------------------------------------------------------------------
+# This function addresses a legacy issue.
+#
+# In binutils 2.40, the "gprofng display text" tool may add a string in the
+# function overviews. This did not add any value and was disruptive to the
+# output. It has been removed in 2.41, but in order to support the older
+# versions of gprofng, the string is removed before the data is processed.
+#
+# Note: the double space in "-- no" is not a typo in this code!
+#------------------------------------------------------------------------------
+sub remove_redundant_string
+{
+ my $subr_name = get_my_name ();
+
+ my ($target_array_ref) = @_;
+
+ my @target_array = @{ $target_array_ref };
+
+ my $msg;
+ my $redundant_string = " -- no functions found";
+
+ for (my $line = 0; $line <= $#target_array; $line++)
+ {
+ $target_array[$line] =~ s/$redundant_string//;
+ }
+
+ $msg = "removed any occurrence of " . $redundant_string;
+ gp_message ("debugM", $subr_name, $msg);
+
+ return (\@target_array);
+
+} #-- End of subroutine remove_redundant_string
+
+#------------------------------------------------------------------------------
# This is a hopefully temporary routine to disable/ignore selected user
# settings. As the functionality expands, this list will get shorter.
#------------------------------------------------------------------------------
@@ -15392,7 +15655,8 @@ sub set_default_metrics
# Decode the metric part of the input line. If a valid line, return the
# metric components. Otherwise return "skipped" in the metric_spec field.
#------------------------------------------------------------------------------
- my ($metric_spec, $metric_flavor, $metric_visibility, $metric_name, $metric_description) = extract_metric_specifics ($metric_line);
+ my ($metric_spec, $metric_flavor, $metric_visibility, $metric_name,
+ $metric_description) = extract_metric_specifics ($metric_line);
gp_message ("debug", $subr_name, "metric_spec = $metric_spec");
gp_message ("debug", $subr_name, "metric_flavor = $metric_flavor");
@@ -15832,6 +16096,182 @@ sub set_up_output_directory
} #-- End of subroutine set_up_output_directory
#------------------------------------------------------------------------------
+# Split a line with function data into 3 components.
+#------------------------------------------------------------------------------
+sub split_function_data_line
+{
+ my $subr_name = get_my_name ();
+
+ my ($input_line_ref) = @_;
+
+ my $input_line = ${ $input_line_ref };
+
+ my $decimal_separator = $g_locale_settings{"decimal_separator"};
+ my $full_hex_address;
+ my $function_name;
+ my $hex_address;
+ my $length_metric_list;
+ my $length_remainder;
+ my $length_target_string;
+ my $list_with_metrics;
+ my $marker;
+ my $msg;
+ my $reduced_line;
+ my $remainder;
+
+ my @hex_addresses = ();
+ my @special_marker = ();
+ my @the_function_name = ();
+
+ my $find_hex_address_regex = '\s*(\d+:0x[a-fA-F0-9]+)\s+(.*)';
+ my $find_marker_regex = '(^\*).*';
+ my $find_metrics_1_regex = '\)*\ +([0-9,' . $decimal_separator;
+ $find_metrics_1_regex .= '\ ]*$)';
+ my $find_metrics_2_regex = '\)*\ +\[.+\]\s+([0-9,' . $decimal_separator;
+ $find_metrics_2_regex = '\ ]*$)';
+ my $get_hex_address_regex = '(\d+):0x(\S+)';
+
+ $reduced_line = $input_line;
+
+ if ($input_line =~ /$find_hex_address_regex/)
+ {
+ if (defined ($1) )
+ {
+ $full_hex_address = $1;
+ $reduced_line =~ s/$full_hex_address//;
+
+ $msg = "full_hex_address = " . $full_hex_address;
+ gp_message ("debugXL", $subr_name, $msg);
+ $msg = "reduced_line = " . $reduced_line;
+ gp_message ("debugXL", $subr_name, $msg);
+ }
+ if (defined ($2) )
+ {
+ $remainder = $2;
+ $msg = "remainder = " . $remainder;
+ gp_message ("debugXL", $subr_name, $msg);
+
+ if (($remainder =~ /$find_metrics_1_regex/) or
+ ($remainder =~ /$find_metrics_2_regex/))
+ {
+ if (defined ($1))
+ {
+ $list_with_metrics = $1;
+ $msg = "before list_with_metrics = " . $list_with_metrics;
+ gp_message ("debugXL", $subr_name, $msg);
+
+ $list_with_metrics =~ s/$g_rm_surrounding_spaces_regex//g;
+ $msg = "after list_with_metrics = " . $list_with_metrics;
+ gp_message ("debugXL", $subr_name, $msg);
+
+#------------------------------------------------------------------------------
+# Remove the function name from the string.
+#------------------------------------------------------------------------------
+ $length_remainder = length ($remainder);
+ $length_metric_list = length ($list_with_metrics);
+
+ $msg = "length remainder = " . $length_remainder;
+ gp_message ("debugXL", $subr_name, $msg);
+
+ $msg = "length list_with_metrics = " . $length_metric_list;
+ gp_message ("debugXL", $subr_name, $msg);
+
+ $length_target_string = $length_remainder -
+ $length_metric_list - 1;
+ $function_name = substr ($remainder, 0,
+ $length_target_string, '');
+
+ $msg = "new function_name = " . $function_name;
+ gp_message ("debugXL", $subr_name, $msg);
+
+ $reduced_line = $function_name;
+ $reduced_line =~ s/$g_rm_surrounding_spaces_regex//g;
+
+ $msg = "reduced_line = " . $reduced_line;
+ gp_message ("debugXL", $subr_name, $msg);
+
+#------------------------------------------------------------------------------
+# In some lines, the function name has a "*" prepended. Isolate this marker
+# and later on remove it from the function name.
+# TBD: Can probably be done more efficiently.
+#------------------------------------------------------------------------------
+ if ($reduced_line =~ /$find_marker_regex/)
+ {
+ if (defined ($1))
+ {
+ $marker = $1;
+ $msg = "found the marker = " . $marker;
+ gp_message ("debugXL", $subr_name, $msg);
+ }
+ else
+ {
+ $msg = "first character in " . $reduced_line ;
+ $msg .= " is not expected";
+ gp_message ("assertion", $subr_name, $msg);
+ }
+ }
+ else
+ {
+ $marker = "X";
+ }
+ }
+ else
+ {
+ $msg = "failure to find metric values following the ";
+ $msg .= "function name";
+ gp_message ("assertion", $subr_name, $msg);
+ }
+ }
+ else
+ {
+ $msg = "cannot find metric values in remainder";
+ gp_message ("debugXL", $subr_name, $msg);
+ gp_message ("assertion", $subr_name, $msg);
+ }
+ }
+#------------------------------------------------------------------------------
+# We now have the 3 main objects from the input line. Next, they are processed
+# and stored.
+#------------------------------------------------------------------------------
+ if ($full_hex_address =~ /$get_hex_address_regex/)
+ {
+ if (defined ($1) and defined ($2))
+ {
+ $hex_address = "0x" . $2;
+ push (@hex_addresses, $full_hex_address);
+
+ $msg = "pushed full_hex_address = " . $full_hex_address;
+ gp_message ("debugXL", $subr_name, $msg);
+ }
+ }
+ else
+ {
+ $msg = "full_hex_address = $full_hex_address has an unknown format";
+ gp_message ("assertion", $subr_name, $msg);
+ }
+ if ($marker eq "*")
+ {
+ push (@special_marker, "*");
+ }
+ else
+ {
+ push (@special_marker, "X");
+ }
+
+ $reduced_line =~ s/^\*//;
+
+ $msg = "RESULT full_hex_address = " . $full_hex_address;
+ $msg .= " -- metric values = " . $list_with_metrics;
+ $msg .= " -- marker = " . $marker;
+ $msg .= " -- function name = " . $reduced_line;
+ gp_message ("debugXL", $subr_name, $msg);
+ }
+
+ return (\$full_hex_address, \$marker, \$reduced_line, \$list_with_metrics);
+
+} #-- End of subroutine split_function_data_line
+
+#------------------------------------------------------------------------------
# Routine to generate webfriendly names
#------------------------------------------------------------------------------
sub tag_name