From 8f7e96b06f1b43c98eb2edb718ded16f373425ab Mon Sep 17 00:00:00 2001 From: adamdunkels Date: Fri, 19 Mar 2010 22:01:34 +0000 Subject: [PATCH] Tools for parsing and plotting a power trace from Contiki --- tools/powertrace/Makefile.powertrace | 48 +++++++++++++++++++ tools/powertrace/parse-node-power | 55 +++++++++++++++++++++ tools/powertrace/parse-power-data | 71 ++++++++++++++++++++++++++++ tools/powertrace/parse-sniff-data | 43 +++++++++++++++++ tools/powertrace/plot-power | 31 ++++++++++++ 5 files changed, 248 insertions(+) create mode 100644 tools/powertrace/Makefile.powertrace create mode 100755 tools/powertrace/parse-node-power create mode 100755 tools/powertrace/parse-power-data create mode 100755 tools/powertrace/parse-sniff-data create mode 100644 tools/powertrace/plot-power diff --git a/tools/powertrace/Makefile.powertrace b/tools/powertrace/Makefile.powertrace new file mode 100644 index 000000000..712151bac --- /dev/null +++ b/tools/powertrace/Makefile.powertrace @@ -0,0 +1,48 @@ +ifdef LOG +powertrace-parse: + cat $(LOG) | grep -a "P " | $(CONTIKI)/tools/powertrace/parse-power-data > powertrace-data + cat $(LOG) | grep -a "P " | $(CONTIKI)/tools/powertrace/parse-node-power | sort -nr > powertrace-node-data + cat $(LOG) | $(CONTIKI)/tools/powertrace/parse-sniff-data | sort -n > powertrace-sniff-data +else #LOG +powertrace-parse: + @echo LOG must be defined to point to the powertrace log file to parse +endif #LOG + +powertrace-plot: + gnuplot $(CONTIKI)/tools/powertrace/plot-power || echo gnupot failed + +powertrace-show: + gv powertrace-power.eps + gv powertrace-node-power.eps + gv powertrace-sniff-power.eps + +powertrace-all: powertrace-parse powertrace-plot powertrace-show + +powertrace-help: + @echo Contiki powertrace is a tool that helps with collecting power data + @echo from motes. The data can be collected from a testbed or from a Cooja + @echo simulation. The powertrace data consists of lines of text that include + @echo the capital letter P followed by a list of numbers that contain the + @echo measured time that mote peripherals were switched on. + @echo + @echo A powertrace data file can be parsed and plotted with build-in + @echo powertrace scripts. + @echo + @echo To parse a data file with powertrace data, run: + @echo + @echo make powertrace-parse LOG=logfile + @echo + @echo to plot the parsed data, do: + @echo + @echo make powertrace-plot + @echo + @echo this produces two files called powertrace-power.eps and + @echo powertrace-node-power.eps. To show these files, run: + @echo + @echo make powertrace-show + @echo + @echo For convenience, all three above make targets can be combined into + @echo one: + @echo + @echo make powertrace-all LOG=logfile + @echo diff --git a/tools/powertrace/parse-node-power b/tools/powertrace/parse-node-power new file mode 100755 index 000000000..adfe8b422 --- /dev/null +++ b/tools/powertrace/parse-node-power @@ -0,0 +1,55 @@ +#!/usr/bin/perl + +$max_seq = 0; + +for($i = 0; $i < 1000; $i++) { + $max_radio[$i] = 0; + $min_radio[$i] = 10000; +} + +while(<>) { + + if(/P (\d+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+) (\d+)/) { + $node = $1; + $seq = $2; + $cpu = $3; + $lpm = $4; + $tx = $5; + $rx = $6; + $idle_tx = $7; + $idle_rx = $8; + + $nodes{$node} = 1; + + $radio_now = $tx + $rx; + $idle_now = $idle_tx + $idle_rx; + $cpu_now = $lpm + $cpu; + $dutycycle = $radio_now / $cpu_now; + + $dutycycle_for_node[$node][$seq] = $dutycycle; + $idle_for_node[$node][$seq] = $idle_now / $cpu_now; + + if($seq > $max_seq) { + $max_seq = $seq; + } + } +} + +foreach $j (keys %nodes) { + $avg = 0; + for($i = 0; $i < $max_seq; $i++) { + $avg += $dutycycle_for_node[$j][$i]; + } + $idle_avg = 0; + for($i = 0; $i < $max_seq; $i++) { + $idle_avg += $idle_for_node[$j][$i]; + } + print $avg / $max_seq . " " . $idle_avg / $max_seq . " $j\n"; + + $total_avg += $avg; + $total_idle += $idle_avg; +} +print "\n"; + +print STDERR "Idle percentage " . $total_idle / $total_avg . "\n"; +#print STDERR "Mean duty cycle " . 100 * $mean / $num_mean . "\n"; diff --git a/tools/powertrace/parse-power-data b/tools/powertrace/parse-power-data new file mode 100755 index 000000000..558d0bb3b --- /dev/null +++ b/tools/powertrace/parse-power-data @@ -0,0 +1,71 @@ +#!/usr/bin/perl + +$max_seq = 0; + +for($i = 0; $i < 1000; $i++) { + $max_radio[$i] = 0; + $min_radio[$i] = 10000; +} + +while(<>) { + + if(/P (\d+) (\d+) (\d+) (\d+) (\d+) (\d+)/) { + $node = $1; + $seq = $2; + $cpu = $3; + $lpm = $4; + $tx = $5; + $rx = $6; + + $nodes{$node} = 1; + + $radio_now = $tx + $rx; + $cpu_now = $lpm + $cpu; + $dutycycle = $radio_now / $cpu_now; + + $dutycycle_for_node[$node][$seq] = $dutycycle; + +# print STDERR "Node $node Seq $seq duty cycle " . ($tx + $rx)/($lpm + $cpu) . ", " . ($tx + $rx) . "/" . ($lpm + $cpu) . "\n"; + $radio[$seq] += $radio_now; + $time[$seq] += $cpu_now; + + if($seq >= 0) { + $mean += $dutycycle; + $num_mean++; + } + + if($dutycycle > $max_radio[$seq]) { + $max_radio[$seq] = $dutycycle; + } + + if($dutycycle < $min_radio[$seq]) { + $min_radio[$seq] = $dutycycle; + } + if($seq > $max_seq) { + $max_seq = $seq; + } + + } +} + +for($i = 0; $i < $max_seq; $i++) { + if($time[$i] != 0) { + print "$i " . $radio[$i] / $time[$i] . " " . $min_radio[$i] . " ". $max_radio[$i] . " "; + foreach $j (keys %nodes) { + print $dutycycle_for_node[$j][$i] . " "; + } + print "\n"; + } +} + +foreach $j (keys %nodes) { + $avg = 0; + for($i = 0; $i < $max_seq; $i++) { + $avg += $dutycycle_for_node[$j][$i]; + } + print STDERR "Node $j avg duty cycle " . 100 * $avg / $max_seq . "\n"; +} + +if($num_mean != 0) { + print STDERR "Mean duty cycle " . 100 * $mean / $num_mean . "\n"; +} diff --git a/tools/powertrace/parse-sniff-data b/tools/powertrace/parse-sniff-data new file mode 100755 index 000000000..0c0731272 --- /dev/null +++ b/tools/powertrace/parse-sniff-data @@ -0,0 +1,43 @@ +#!/usr/bin/perl + +while(<>) { + + if(/([IO]) (\d+) (\d+) (\d+) (\d+) (\d+).(\d+) (\d+) (\d+)/) { + $type = $1; + $node = $2; + $seq = $3; + $channel = $4; + $packettype = $5; + $esender1 = $6; + $esender2 = $7; + $tx = $8; + $rx = $9; + + if($type cmp "I") { + $channel .= "-tx"; + } else { + $channel .= "-rx"; + } + + if($packettype == 1) { + $channel .= "-ack" + } + + $tx_for_channel{$channel} += $tx; + $rx_for_channel{$channel} += $rx; + $total += $rx + $tx; + + if($forwarding) { + $forward += $tx + $rx; + } else { + $final += $tx + $rx; + } + + } +} + +foreach $c (keys %tx_for_channel) { + print "$c " . $tx_for_channel{$c}/$total . " " . $rx_for_channel{$c}/$total . "\n"; +} + +print STDERR "Final / forward = " . $final / $total . "/" . $forward / $total . "\n"; diff --git a/tools/powertrace/plot-power b/tools/powertrace/plot-power new file mode 100644 index 000000000..04e7aea28 --- /dev/null +++ b/tools/powertrace/plot-power @@ -0,0 +1,31 @@ +set key top right + +set data style boxes +set pointsize 2 + +set ylabel "Radio duty cycle (%)" +set xlabel "Time (s)" +set terminal postscript eps enhanced "Helvetica" 16 lw 4 dl 5 + +set output "powertrace-power.eps" +set title "Average radio duty cycle (percent) over time" +plot [0:] [0:] 'powertrace-data' using ($1*10):($2*100) with lines notitle + +set output "powertrace-node-power.eps" +set boxwidth 0.3 +set title "Per-node radio duty cycle" +set ylabel "Radio duty cycle (%)" +set xlabel "Node number" +plot [-1:] [0:] 'powertrace-node-data' using 0:(100*$1) with boxes fs solid title "Total", \ +'' using ($0 + 0.4):(100*$2) with boxes fs solid title "Idle", \ +'' using 0:(100*$1):3 with labels center offset 0,1 notitle + + +set key top left +set boxwidth 0.6 +set output "powertrace-sniff-power.eps" +set title "Per-channel radio usage" +set ylabel "Percent (%)" +set xlabel "Channel number" +plot [:] [0:] 'powertrace-sniff-data' using 0:(100 * ($3 + $2)) with boxes title "Listen", \ +'' using 0:(100 * $2):xticlabel(1) with boxes title "Transmission"