aboutsummaryrefslogblamecommitdiff
path: root/Debug/poor-mans-profiler.sh
blob: d2393b296ec707c32796f6b75fab73a39bcf8966 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13












                                                                                                                       
      

                     














                                                                          









                                                          
 





























                                
 









                                                                                            
        
 


                                                                       
 
                      
 





















                                                                         
                                                        


                                              

           



                                                      






                                                 
              
 
                                       
 




                                                                                  
#!/bin/bash
#
# Poor man's sampling profiler for NuttX.
#
# The stack folding script was inspired by stackcollapse-gdb.pl from the FlameGraph project.
#
# Usage: Install flamegraph.pl in your PATH, define the variables below, configure your .gdbinit, run the script and go
#        have a coffee. When you're back, you'll see the flamegraph. Note that frequent calls to GDB significantly
#        interfere with normal operation of the target, which means that you can't profile real-time tasks with it.
#
# Requirements: ARM GDB with Python support
#

set -e
root=$(dirname $0)/..

function die()
{
    echo "$@"
    exit 1
}

function usage()
{
    echo "Invalid usage. Supported options:"
    cat $0 | sed -n 's/^\s*--\([^)\*]*\).*/\1/p' # Don't try this at home.
    exit 1
}

which flamegraph.pl > /dev/null || die "Install flamegraph.pl first"

#
# Parsing the arguments. Read this section for usage info.
#
nsamples=0
sleeptime=0.1    # Doctors recommend 7-8 hours a day
taskname=
elf=$root/Build/px4fmu-v2_default.build/firmware.elf
append=0
fgfontsize=5
fgwidth=1900

for i in "$@"
do
    case $i in
        --nsamples=*)
            nsamples="${i#*=}"
            ;;
        --sleeptime=*)
            sleeptime="${i#*=}"
            ;;
        --taskname=*)
            taskname="${i#*=}"
            ;;
        --elf=*)
            elf="${i#*=}"
            ;;
        --append)
            append=1
            ;;
        --fgfontsize=*)
            fgfontsize="${i#*=}"
            ;;
        --fgwidth=*)
            fgwidth="${i#*=}"
            ;;
        *)
            usage
            ;;
    esac
    shift
done

#
# Temporary files
#
stacksfile=/tmp/pmpn-stacks.log
foldfile=/tmp/pmpn-folded.txt
graphfile=/tmp/pmpn-flamegraph.svg

#
# Sampling if requested. Note that if $append is true, the stack file will not be rewritten.
#
cd $root

if [[ $nsamples > 0 && "$taskname" != "" ]]
then
    [[ $append = 0 ]] && (rm -f $stacksfile; echo "Old stacks removed")

    echo "Sampling..."

    for x in $(seq 1 $nsamples)
    do
        arm-none-eabi-gdb $exe --batch -ex "set print asm-demangle on" \
                                    -ex "source $root/Debug/Nuttx.py" \
                                    -ex "show mybt $taskname" \
            2> /dev/null \
            | sed -n 's/0\.0:\(#.*\)/\1/p' \
            >> $stacksfile
        echo -e '\n\n' >> $stacksfile
        echo -ne "\r$x/$nsamples"
        sleep $sleeptime
    done

    echo
    echo "Stacks saved to $stacksfile"
else
    echo "Sampling skipped - set 'nsamples' and 'taskname' to re-sample."
fi

#
# Folding the stacks.
#
[ -f $stacksfile ] || die "Where are the stack samples?"

cat $stacksfile | perl -e 'use File::Basename;
my $current = "";
my %stacks;
while(<>) {
  if(m/^#[0-9]*\s*0x[a-zA-Z0-9]*\s*in (.*) at (.*)/) {
    my $x = $1 eq "None" ? basename($2) : $1;
    if ($current eq "") { $current = $x; }
    else { $current = $x . ";" . $current; }
  } elsif(!($current eq "")) {
    $stacks{$current} += 1;
    $current = "";
  }
}
foreach my $k (sort { $a cmp $b } keys %stacks) {
  print "$k $stacks{$k}\n";
}' > $foldfile

echo "Folded stacks saved to $foldfile"

#
# Graphing.
#
cat $foldfile | flamegraph.pl --fontsize=$fgfontsize --width=$fgwidth > $graphfile
xdg-open $graphfile