aboutsummaryrefslogtreecommitdiff
path: root/Debug/poor-mans-profiler.sh
diff options
context:
space:
mode:
authorPavel Kirienko <pavel.kirienko@gmail.com>2015-01-17 02:25:26 +0300
committerLorenz Meier <lm@inf.ethz.ch>2015-01-21 14:54:23 +0100
commitd1abf9c133bfe865f9648a88610d92a78f787f21 (patch)
treed65c8d2572ae08584f61f70c67f2fa2de49b6137 /Debug/poor-mans-profiler.sh
parent1898b51c740dba2b3dd979980775f25c982dea1e (diff)
downloadpx4-firmware-d1abf9c133bfe865f9648a88610d92a78f787f21.tar.gz
px4-firmware-d1abf9c133bfe865f9648a88610d92a78f787f21.tar.bz2
px4-firmware-d1abf9c133bfe865f9648a88610d92a78f787f21.zip
Poor man's profiler - proper stack folder that handles generic C++ types
Diffstat (limited to 'Debug/poor-mans-profiler.sh')
-rwxr-xr-xDebug/poor-mans-profiler.sh137
1 files changed, 113 insertions, 24 deletions
diff --git a/Debug/poor-mans-profiler.sh b/Debug/poor-mans-profiler.sh
index 460b28d0a..7657e4dc7 100755
--- a/Debug/poor-mans-profiler.sh
+++ b/Debug/poor-mans-profiler.sh
@@ -84,7 +84,7 @@ gdberrfile=/tmp/pmpn-gdberr.log
#
cd $root
-if [[ $nsamples > 0 && "$taskname" != "" ]]
+if [[ $nsamples > 0 ]]
then
[[ $append = 0 ]] && (rm -f $stacksfile; echo "Old stacks removed")
@@ -92,12 +92,20 @@ then
for x in $(seq 1 $nsamples)
do
- arm-none-eabi-gdb $elf --batch -ex "set print asm-demangle on" \
- -ex "source $root/Debug/Nuttx.py" \
- -ex "show mybt $taskname" \
- 2> $gdberrfile \
- | sed -n 's/0\.0:\(#.*\)/\1/p' \
- >> $stacksfile
+ if [[ "$taskname" = "" ]]
+ then
+ arm-none-eabi-gdb $elf --batch -ex "set print asm-demangle on" -ex bt \
+ 2> $gdberrfile \
+ | sed -n 's/\(#.*\)/\1/p' \
+ >> $stacksfile
+ else
+ arm-none-eabi-gdb $elf --batch -ex "set print asm-demangle on" \
+ -ex "source $root/Debug/Nuttx.py" \
+ -ex "show mybt $taskname" \
+ 2> $gdberrfile \
+ | sed -n 's/0\.0:\(#.*\)/\1/p' \
+ >> $stacksfile
+ fi
echo -e '\n\n' >> $stacksfile
echo -ne "\r$x/$nsamples"
sleep $sleeptime
@@ -106,7 +114,7 @@ then
echo
echo "Stacks saved to $stacksfile"
else
- echo "Sampling skipped - set 'nsamples' and 'taskname' to re-sample."
+ echo "Sampling skipped - set 'nsamples' to re-sample."
fi
#
@@ -114,22 +122,103 @@ fi
#
[ -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 at " . basename($2));
- 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
+cat $stacksfile | python -c "
+#
+# This stack folder correctly handles C++ types.
+#
+
+from __future__ import print_function, division
+import fileinput, collections, os
+
+def enforce(x, msg='Invalid input'):
+ if not x:
+ raise Exception(msg)
+
+def split_first_part_with_parens(line):
+ LBRACES = {'(':'()', '<':'<>', '[':'[]', '{':'{}'}
+ RBRACES = {')':'()', '>':'<>', ']':'[]', '}':'{}'}
+ braces = collections.defaultdict(int)
+ out = ''
+ for ch in line:
+ out += ch
+ # special cases
+ if out.endswith('operator>') or out.endswith('operator->'): # gotta love c++
+ braces['<>'] += 1
+ if out.endswith('operator<'):
+ braces['<>'] -= 1
+ # counting parens
+ if ch in LBRACES.keys():
+ braces[LBRACES[ch]] += 1
+ if ch in RBRACES.keys():
+ braces[RBRACES[ch]] -= 1
+ # sanity check
+ for v in braces.values():
+ enforce(v >= 0, 'Unaligned braces: ' + str(dict(braces)))
+ # termination condition
+ if ch == ' ' and sum(braces.values()) == 0:
+ break
+ out = out.strip()
+ return out, line[len(out):]
+
+def parse(line):
+ def take_path(line, output):
+ line = line.strip()
+ if line.startswith('at '):
+ line = line[3:].strip()
+ if line:
+ output['file_full_path'] = line.rsplit(':', 1)[0].strip()
+ output['file_base_name'] = os.path.basename(output['file_full_path'])
+ output['line'] = int(line.rsplit(':', 1)[1])
+ return output
+
+ def take_args(line, output):
+ line = line.lstrip()
+ if line[0] == '(':
+ output['args'], line = split_first_part_with_parens(line)
+ return take_path(line.lstrip(), output)
+
+ def take_function(line, output):
+ output['function'], line = split_first_part_with_parens(line.lstrip())
+ return take_args(line.lstrip(), output)
+
+ def take_mem_loc(line, output):
+ line = line.lstrip()
+ if line.startswith('0x'):
+ end = line.find(' ')
+ num = line[:end]
+ output['memloc'] = int(num, 16)
+ line = line[end:].lstrip()
+ end = line.find(' ')
+ enforce(line[:end] == 'in')
+ line = line[end:].lstrip()
+ return take_function(line, output)
+
+ def take_frame_num(line, output):
+ line = line.lstrip()
+ enforce(line[0] == '#')
+ end = line.find(' ')
+ num = line[1:end]
+ output['frame_num'] = int(num)
+ return take_mem_loc(line[end:], output)
+
+ return take_frame_num(line, {})
+
+stacks = collections.defaultdict(int)
+current = ''
+
+for line in fileinput.input():
+ line = line.strip()
+ if line:
+ inf = parse(line)
+ fun = inf['function']
+ current = (fun + ';' + current) if current else fun
+ elif current:
+ stacks[current] += 1
+ current = ''
+
+for s, f in sorted(stacks.items(), key=lambda (s, f): s):
+ print(s, f)
+" > $foldfile
echo "Folded stacks saved to $foldfile"