Reputation: 87
I'm trying to use Brendan Gregg's flamegraph, and I'm trying to fold/collapse my stacks with the stack trace/diagsession I got from application insight/azure profiler, but I can't get it to generate what I want.
I'm aware perfview and visual studio have their own flame graph, but I would prefer to utilize his visualizations.
Most of the errors I get are generally because it can't pick up the stack count (0)
or some type of regular expression issue.
The code also says I should be able to export the CSV file on Visual Studio if I have a diagsession/stack trace, but I can't find the option to do so.
Here is the code provided:
#!/usr/bin/perl -w
#
# stackcollapse-vsprof.pl
#
# Parses the CSV file containing a call tree from a visual studio profiler and produces an output suitable for flamegraph.pl.
#
# USAGE: perl stackcollapse-vsprof.pl infile > outfile
#
# WORKFLOW:
#
# This example assumes you have visual studio 2015 installed.
#
# 1. Profile C++ your application using visual studio
# 2. On visual studio, choose export the call tree as csv
# 3. Generate a flamegraph: perl stackcollapse-vsprof CallTreeSummary.csv | perl flamegraph.pl > result_vsprof.svg
#
# INPUT EXAMPLE :
#
# Level,Function Name,Inclusive Samples,Exclusive Samples,Inclusive Samples %,Exclusive Samples %,Module Name,
# 1,"main","8,735",0,100.00,0.00,"an_executable.exe",
# 2,"testing::UnitTest::Run","8,735",0,100.00,0.00,"an_executable.exe",
# 3,"boost::trim_end_iter_select<std::iterator<std::val<std::types<char> > >,boost::is_classifiedF>",306,16,3.50,0.18,"an_executable.exe",
#
# OUTPUT EXAMPLE :
#
# main;testing::UnitTest::Run;boost::trim_end_iter_select<std::iterator<std::val<std::types<char>>>,boost::is_classifiedF> 306
use strict;
sub massage_function_names;
sub parse_integer;
sub print_stack_trace;
# data initialization
my @stack = ();
my $line_number = 0;
my $previous_samples = 0;
my $num_args = $#ARGV + 1;
if ($num_args != 1) {
print "$ARGV[0]\n";
print "Usage : stackcollapse-vsprof.pl <in.cvs> > out.txt\n";
exit;
}
my $input_csv_file = $ARGV[0];
my $line_parser_rx = qr{
^\s*(\d+?), # level in the stack
("[^"]+" | [^,]+), # function name (beware of spaces)
("[^"]+" | [^,]+), # number of samples (beware of locale number formatting)
}ox;
open(my $fh, '<', $input_csv_file) or die "Can't read file '$input_csv_file' [$!]\n";
while (my $current_line = <$fh>){
$line_number = $line_number + 1;
# to discard first line which typically contains headers
next if $line_number == 1;
next if $current_line =~ /^\s*$/o;
($current_line =~ $line_parser_rx) or die "Error in regular expression at line $line_number : $current_line\n";
my $level = int $1;
my $function = massage_function_names($2);
my $samples = parse_integer($3);
my $stack_len = @stack;
#print "[DEBUG] $line_number : $level $function $samples $stack_len\n";
next if not $level;
($level <= $stack_len + 1) or die "Error in stack at line $line_number : $current_line\n";
if ($level <= $stack_len) {
print_stack_trace(\@stack, $previous_samples);
my $to_remove = $level - $stack_len - 1;
splice(@stack, $to_remove);
}
$stack_len < 1000 or die "Stack overflow at line $line_number";
push(@stack, $function);
$previous_samples = $samples;
}
print_stack_trace(\@stack, $previous_samples);
sub massage_function_names {
return ($_[0] =~ s/\s*|^"|"$//gro);
}
sub parse_integer {
return int ($_[0] =~ s/[., ]|^"|"$//gro);
}
sub print_stack_trace {
my ($stack_ref, $sample) = @_;
my $stack_trace = join(";", @$stack_ref);
print "$stack_trace $sample\n";
}
Upvotes: 1
Views: 178
Reputation: 3322
Instead of abruptly exiting the script when encountering an error, you can handle errors more gracefully. For example, you can skip problematic lines and continue processing the rest of the file, or you can log errors for further analysis.
#!/usr/bin/perl -w
use strict;
use warnings;
# Subroutine to parse CSV line
sub parse_csv_line {
my ($line) = @_;
my @fields = split(',', $line);
return \@fields;
}
# Subroutine to handle errors
sub handle_error {
my ($message) = @_;
print STDERR "Error: $message\n";
}
# Subroutine to process each line of the CSV file
sub process_csv_line {
my ($line_number, $line) = @_;
# Skip header line and empty lines
return if $line_number == 1 || $line =~ /^\s*$/o;
my $fields = parse_csv_line($line);
# Ensure the line has expected number of fields
if (@$fields < 7) {
handle_error("Invalid number of fields at line $line_number: $line");
return;
}
my ($level, $function, $samples) = @$fields[0, 1, 2];
# Remove quotes and leading/trailing whitespace from function name
$function =~ s/^\s*|\"$//g;
# Validate and parse numeric fields
unless ($level =~ /^\d+$/ && $samples =~ /^\d+$/) {
handle_error("Invalid numeric value at line $line_number: $line");
return;
}
return ($level, $function, $samples);
}
# Main subroutine
sub main {
my ($input_csv_file) = @ARGV;
# Validate input arguments
unless ($input_csv_file) {
handle_error("Missing input CSV file argument");
return;
}
open(my $fh, '<', $input_csv_file) or die "Can't read file '$input_csv_file' [$!]\n";
my @stack = ();
my $line_number = 0;
my $previous_samples = 0;
while (my $line = <$fh>) {
$line_number++;
# Process CSV line
my ($level, $function, $samples) = process_csv_line($line_number, $line);
next unless defined $level && defined $function && defined $samples;
my $stack_len = @stack;
next if not $level;
($level <= $stack_len + 1) or die "Error in stack at line $line_number : $line\n";
if ($level <= $stack_len) {
print_stack_trace(\@stack, $previous_samples);
my $to_remove = $level - $stack_len - 1;
splice(@stack, $to_remove);
}
$stack_len < 1000 or die "Stack overflow at line $line_number";
push(@stack, $function);
$previous_samples = $samples;
}
print_stack_trace(\@stack, $previous_samples);
close($fh);
}
# Subroutine to print stack trace
sub print_stack_trace {
my ($stack_ref, $sample) = @_;
my $stack_trace = join(";", @$stack_ref);
print "$stack_trace $sample\n";
}
# Run the main subroutine
main();
In Visual Studio, after profiling your application, you typically have an option to export the profiling data. Look for an option like "Export Call Tree" or "Export Performance Report". This should generate the CSV file that you can then use with the script.
Reference:
Upvotes: 0