[Tinyos-beta-commits]
CVS: tinyos-1.x/beta/TOSSIM-CC2420/PowerTOSSIM
README, NONE, 1.1 avr_cycle_counts.txt, NONE, 1.1 bb2asm.pl,
NONE, 1.1 bb2cycle.pl, NONE, 1.1 cilly.asm.exe, NONE,
1.1 compile.pl, NONE, 1.1 counter.ml, NONE, 1.1 cpuprof.py,
NONE, 1.1 fixnames.pl, NONE, 1.1 mica2_energy_model.txt, NONE,
1.1 msp430_cycle_counts.txt, NONE, 1.1 msp_cpuprof.py, NONE,
1.1 mypp.pl, NONE, 1.1 postprocess.py, NONE,
1.1 telosA_energy_model.txt, NONE, 1.1 telosB_energy_model.txt,
NONE, 1.1
Yang
overbored at users.sourceforge.net
Sat Mar 12 23:23:12 PST 2005
Update of /cvsroot/tinyos/tinyos-1.x/beta/TOSSIM-CC2420/PowerTOSSIM
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27290/PowerTOSSIM
Added Files:
README avr_cycle_counts.txt bb2asm.pl bb2cycle.pl
cilly.asm.exe compile.pl counter.ml cpuprof.py fixnames.pl
mica2_energy_model.txt msp430_cycle_counts.txt msp_cpuprof.py
mypp.pl postprocess.py telosA_energy_model.txt
telosB_energy_model.txt
Log Message:
Added support for PowerTOSSIM, including MSP430 CPU cycle counting.
Added specific support for Telos Revision A and B.
Updated the HPL to support starting/stopping.
--- NEW FILE: README ---
This directory contains various scripts for PowerTOSSIM, a power
simulation addon to TOSSIM. See
http://www.eecs.harvard.edu/~shnayder/ptossim/ for details and/or
email shnayder at eecs.harvard.edu if you have questions.
--- NEW FILE: avr_cycle_counts.txt ---
add 1
adc 1
adiw 2
sub 1
subi 1
sbc 1
sbci 1
sbiw 2
and 1
andi 1
or 1
ori 1
eor 1
com 1
neg 1
sbr 1
cbr 1
inc 1
dec 1
tst 1
clr 1
ser 1
mul 2
muls 2
mulsu 2
fmul 2
fmuls 2
fmulsu 2
rjmp 2
ijmp 2
eijmp 2
jmp 3
rcall 3.5
icall 3.5
eicall 4
call 4.5
ret 4.5
reti 4.5
cpse 2
cp 1
cpc 1
cpi 1
sbrc 2
sbrs 2
sbic 2
sbis 2
brbs 1.5
brbc 1.5
breq 1.5
brne 1.5
brcs 1.5
brcc 1.5
brsh 1.5
brlo 1.5
brmi 1.5
brpl 1.5
brge 1.5
brlt 1.5
brhs 1.5
brhc 1.5
brts 1.5
brtc 1.5
brvs 1.5
brvc 1.5
brie 1.5
brid 1.5
mov 1
movw 1
ldi 1
lds 2
ld 2
ld 2
ld 2
ld 2
ld 2
ld 2
ldd 2
ld 2
ld 2
ld 2
ldd 2
sts 2
st 2
st 2
st 2
st 2
st 2
st 2
std 2
st 2
st 2
st 2
std 2
lpm 3
lpm 3
lpm 3
elpm 3
elpm 3
elpm 3
spm 0
in 1
out 1
push 2
pop 2
lsl 1
lsr 1
rol 1
ror 1
asr 1
swap 1
bset 1
bclr 1
sbi 2
cbi 2
bst 1
bld 1
sec 1
clc 1
sen 1
cln 1
sez 1
clz 1
sei 1
cli 1
ses 1
cls 1
sev 1
clv 1
set 1
clt 1
seh 1
clh 1
break 1
nop 1
sleep 1
wdr 1
--- NEW FILE: bb2asm.pl ---
#!/usr/bin/perl
# A script to generate basic block->asm statement mappings
# Input:
# --- The basepath of local files (at the moment, the compiler is
# spitting out relative paths, while the debugging info has full
# names)
# --- cycle counts for each instruction type
# --- A BB dump
# --- The object file with debug symbols
# The bb_linenum_map lines look like:
#1 $TOSDIR/platform/pc/external_comm.c:228
#2 $TOSDIR/platform/pc/Nido.nc:115
# ....
# The cycle count file looks like:
# cls\t1
# sbi\t2
# brid\t1.5
# So fractional values are allowed (for instructions which can take
# varying numbers of cycles)
# Output: A file with BB number\tAVR cycle count pairs
# Line format: 'bb#\tcycle_count\n'
# Won't output a line if there isn't any info for it.
use Cwd 'realpath';
# Debugging flags
$DBG_OBJDUMP = 0;
$DBG_BBDUMP = 0;
$DBG_BB_CODE_MAP = 0;
$DBG_MAP_COMPUTE = 0;
$usage =
"Usage: bb2asm.pl basepath cycle_counts bb_linenum_map main.exe bb_cycle_map\n".
" basepath - path to add to start of relative filenames\n".
" cycle_counts - file with instruction->number of cycles map\n".
" bb_linenum_map - the basic block->line number mappings\n".
" main.exe - the mica2 assembly, with debugging symbols\n".
" bb_cycle_map - the output: a map of BB# -> AVR cycles\n\n";
die $usage if(scalar @ARGV != 5);
$basepath = shift @ARGV;
$cycle_counts = shift @ARGV;
$bb_dump = shift @ARGV;
$objfile = shift @ARGV;
$bb_cycle_map = shift @ARGV;
$me = `whoami`;
chomp($me);
# Do some checks
if($basepath =~ m|^[^/]|) {
die "Basepath must start with '/'\n" . $usage;
}
# Remove any trailing '/'
$basepath =~ s|/$||;
open (CYCLE_COUNTS, $cycle_counts) || die "Can't open $cycle_counts: $!";
while(<CYCLE_COUNTS>) {
chomp;
($opcode, $ncycles) = split /\t/;
$cycles{$opcode} = $ncycles;
}
close CYCLE_COUNTS;
# File must be compiled with -g for this to work!!!
open (OBJDUMP, "msp430-objdump -s -d -l $objfile |") || die "Can't run objdump on $objfile: $!";
while(<OBJDUMP>) {
chomp();
if(/^\//) {
($cur_file, $cur_line) = split /:/, $_;
# Get a canonical name out of this filename
unless ($path = realpath($cur_file)) {
warn "realpath '$cur_file' failed: $!\n";
$path = $cur_file; # just use the current path
}
$path =~ s|/.*$me/|~/|; # replace "/blah/blah/blah/username" with "~/"
$cur_file = $path;
} elsif( /^\s*$/ ) {
$cur_line = "";
} elsif($cur_line ne "") {
$asm{$cur_file}{$cur_line} .= "$_\n";
}
}
close OBJDUMP;
open (BBDUMP, $bb_dump) || die "Can't open $bb_dump: $!";
while(<BBDUMP>) {
chomp();
/^(\d+)\t([^:]*):(\d+)$/;
($bb, $file, $line) = ($1, $2, $3);
if($file =~ m|^[^/]| && $file !~ m|^\~|) {
die "This shouldn't happen!\n";
# Filename does not start with '/' or '~', so add the basepath
$file = $basepath . "/" . $file;
}
$bbinfo{$bb} = { "file" => $file,
"line" => $line,
"code" => "" };
$revmap{$file}{$line} = $bb;
}
close BBDUMP;
if($DBG_OBJDUMP) {
print "Line -> ASM mappings\n";
print "--------------------\n\n";
foreach $f (sort keys %asm) {
foreach $l (sort {$a <=> $b} keys %{$asm{$f}}) {
print "$f, $l\n";
print $asm{$f}{$l};
print "--------------------------\n\n";
}
}
}
if($DBG_BBDUMP) {
print "BB->file,line mappings\n";
foreach $bb (sort {$a <=> $b} keys %bbinfo) {
print $bb, ",", $bbinfo{$bb}{"file"}, ":",$bbinfo{$bb}{"line"},"\n";
}
print "--------------------------\n\n";
print "Reverse ( [file, line]->bb ) mappings\n";
foreach $f (sort keys %revmap) {
print "$f: ";
foreach $l (sort {$a <=> $b} keys %{$revmap{$f}}) {
print "($l,", $revmap{$f}{$l},") ";
}
print "\n";
}
}
foreach $f (sort keys %revmap) {
print "file = $f\n" if $DBG_MAP_COMPUTE;
@bb_lines = sort {$a <=> $b} keys %{$revmap{$f}};
@asm_lines = sort {$a <=> $b} keys %{$asm{$f}};
print "bb_lines = ", join(" ", @bb_lines), "\n" if $DBG_MAP_COMPUTE;
print "asm_lines = ", join(" ", @asm_lines), "\n" if $DBG_MAP_COMPUTE;
next if scalar(@asm_lines) == 0;
# Now go through and find the asm_lines that go with each
# bb_line
while($cur_bb_line = shift @bb_lines) {
print "bb_line = $cur_bb_line\n" if $DBG_MAP_COMPUTE;
# Get rid of any lines that aren't in a basic block
# This probably won't happen at all, but might at the start of
# a file
print "asm_line = '".$asm_lines[0]."'\n" if $DBG_MAP_COMPUTE;
while(defined($asm_lines[0]) && ($asm_lines[0] < $cur_bb_line)) {
shift @asm_lines;
}
if($bb_lines[0]) {
# Get all the lines till the next BB
while(defined($asm_lines[0]) &&
defined($bb_lines[0]) &&
($asm_lines[0] < $bb_lines[0]) ) {
$bb = $revmap{$f}{$cur_bb_line};
$bbinfo{$bb}{"code"} .= $asm{$f}{$asm_lines[0]};
shift @asm_lines;
}
} else {
# Last BB in the file, so get all the remaining lines
while(@asm_lines) {
$bb = $revmap{$f}{$cur_bb_line};
$bbinfo{$bb}{"code"} .= $asm{$f}{$asm_lines[0]};
shift @asm_lines;
}
}
}
}
if($DBG_BB_CODE_MAP) {
print "\n\nBB->Code map\n";
print "-------------------\n\n";
foreach $bb (sort {$a <=> $b} keys %bbinfo) {
print $bb, ",", $bbinfo{$bb}{"file"},":", $bbinfo{$bb}{"line"},"\n";
$code = $bbinfo{$bb}{"code"};
print $code;
print "Num cycles: ", &code_cycles($code), "\n";
print "-----------------\n\n";
}
}
open(OUTPUT, ">$bb_cycle_map") || die "Can't open $bb_cycle_map: $!";
foreach $bb (sort {$a <=> $b} keys %bbinfo) {
$code = $bbinfo{$bb}{"code"};
$cycles = &code_cycles($code);
print OUTPUT "$bb\t$cycles\n" unless ($cycles == 0);
}
close(OUTPUT) || die "Can't close $bb_cycle_map: $!";
sub code_cycles {
# rows are operand type, cols are opcode group
# corresponds to table 3-15
@fmt2tab =
([1, 3, 4],
[3, 4, 4],
[3, 4, 5],
[0, 4, 5],
[4, 5, 5],
[4, 5, 5],
[4, 5, 5]);
# rows are src operand type, cols are dst operand type
# corresponds to table 3-16
@fmt1tab =
([1, 2, 4, 4, 4],
[2, 3, 5, 5, 5],
[2, 3, 5, 5, 5],
[2, 3, 5, 5, 5],
[3, 3, 6, 6, 6],
[3, 3, 6, 6, 6],
[3, 3, 6, 6, 6]);
# Expansions of emulated instructions.
%emulated = (
'ret' => 'mov @sp+, pc',
'adc' => 'addc #0, dst',
'adc.b' => 'addc.b #0, dst',
'clrc' => 'bic #1, sr',
'clr' => 'mov #0, dst',
'clr.b' => 'mov.b #0, dst',
'decd' => 'sub #2, dst',
'decd.b' => 'sub.b #2, dst',
'inc' => 'add #1, dst',
'inc.b' => 'add.b #1, dst',
'incd' => 'add #2, dst',
'incd.b' => 'add.b #2, dst',
'inv' => 'xor #0xffff, dst',
'inv.b' => 'xor.b #0xff, dst',
'pop' => 'mov @sp+, dst',
'rla' => 'add dst, dst',
'rla.b' => 'add.b dst, dst',
'rlc' => 'addc dst, dst',
'rlc.b' => 'addc dst, dst',
);
# Takes a chunk of assembly code. Assumes that it's a basic block.
# Uses the $cycles{$opcode} map to get total number of cycles for it.
my($total) = 0;
my($code) = shift;
my(@lines) = split /\n/, $code;
foreach $line (@lines) {
next if($line =~ /^\s*$/ || $line =~ /\.\.\./); # Skip empty lines
@fields = split /\t/, $line;
$opcode = $fields[2];
$operand1 = $fields[3];
$operand2 = $fields[4];
# TODO add check back in
# if(not defined $cycles{$opcode}) {
# print STDERR "code = '$code'";
# print STDERR "line = '$line'";
# print STDERR "Fields: ", join('/', at fields), "\n";
# print STDERR "opcode = '$opcode'\n";
# die "no mapping for '$opcode'";
# }
# Sometimes, the operands might be stuck together (no tab)
@fakeOps = split /,/, $operand1;
if ($fakeOps[1] ne '') {
$operand1 = $fakeOps[0];
$operand2 = $fakeOps[1];
$fields[3] = $operand1;
$fields[4] = $operand2;
}
# Remove trailing comma from operand1
$operand1 =~ s/,$//;
$operand2 =~ s/;.*$//;
# Expand emulated instructions.
if ($emulated{$opcode} ne '') {
my $expansion = $emulated{$opcode};
#print "Expanding $opcode\n";
$expansion =~ s/dst/$operand1/g;
push @lines, "\t\t$expansion";
# print join "\n", @lines;
next;
}
# Cycle calculation based on info from:
# MSP430 User's Guide 2004
# Section 3.4.4: Instruction Cycles and Lengths
if ($opcode eq '' and $fields[1] =~ /^[\da-f]{2} 0[02]\s+$/) {
# This is a no-op, so skip it.
next;
} elsif ($opcode eq '' and ($fields[1] =~ /^[\da-f]{2} [\da-f]{2}\s+$/
or $fields[1] =~ /^\.\.\.\s*$/)) {
# TODO WHAT TO DO ABOUT THESE WEIRD THINGS?
next;
} elsif ($opcode =~ /^\.word$/) {
# TODO WHAT TO DO ABOUT THESE WEIRD THINGS?
next;
} elsif ($opcode =~ /^(jc|jge|jl|jmp|jn|jnc|jne|jnz|jz)$/) {
# Format-III instructions.
# All jumps require two cycles.
$count = 2;
#print "COUNT $count\n";
} elsif ($operand1 ne '' and $operand2 ne '') {
# Format-I instructions.
$operand1Type = getOperand1Type($operand1, $code, $line, $fields);
$_ = $operand2;
if (/^(r\d+|sr|pc|sp)$/) {
$operand2Type = 0;
} elsif (/^PC$/) {
$operand2Type = 1;
} elsif (/^(-?0x(\d|[a-fA-F])+|-?\d+)\((r\d+|sr|pc|sp)\)$/) {
$operand2Type = 2;
} elsif (/^(-?0x(\d|[a-fA-F])+|-?\d+)$/) {
$operand2Type = 3;
} elsif (/^&(-?0x(\d|[a-fA-F])+|-?\d+)$/) {
$operand2Type = 4;
} else {
print STDERR "CODE\n$code";
print STDERR "line = '$line'";
print STDERR "FIELDS\n",join('/', @fields),"\n";
die 'invalid operand 2 for format-I instruction';
}
$count = $fmt1tab[$operand1Type][$operand2Type];
} elsif ($operand2 eq '') {
# Format-II instructions.
$operandType = getOperand1Type($operand1, $code, $line, $fields);
$_ = $opcode;
if (/^(rra|rra.b|rrc|rrc.b|swpb|sxt)$/) {
$opcodeGroup = 0;
} elsif (/^push$/) {
$opcodeGroup = 1;
} elsif (/^call$/) {
$opcodeGroup = 2;
} else {
print STDERR "CODE\n$code";
print STDERR "LINE\n$line\n";
die 'invalid opcode for format-II instruction.';
}
if ($operandType == 3 and $opcodeGroup == 0) {
print STDERR "CODE\n$code";
print STDERR "line = '$line'";
die 'invalid opcode+operand for format-II instruction.'
}
$count = $fmt2tab[$operandType][$opcodeGroup];
#print "OPERANDTYPE $operandType\tOPCODE $opcodeGroup\tCOUNT $count\n";
} else {
print STDERR "CODE\n$code";
print STDERR "line = '$line'";
die 'unknown instruction format.';
}
#print "COUNT $count\tTOTAL $total\n";
$total += $count;
}
return $total;
}
sub getOperand1Type {
$operand = shift;
$code = shift;
$line = shift;
$fields = shift;
$_ = $operand;
if (/^(r\d+|sr|pc|sp)$/) {
$operandType = 0;
} elsif (/^\@(r\d+|sr|pc|sp)$/) {
$operandType = 1;
} elsif (/^\@(r\d+|sr|pc|sp)\+$/) {
$operandType = 2;
} elsif (/^#(-?0x(\d|[a-fA-F])+|-?\d+)$/) {
$operandType = 3;
} elsif (/^(-?0x(\d|[a-fA-F])+|-?\d+)\((r\d+|sr|pc|sp)\)$/) {
$operandType = 4;
} elsif (/^(-?0x(\d|[a-fA-F])+|-?\d+)$/) {
$operandType = 5;
} elsif (/^&(-?0x(\d|[a-fA-F])+|-?\d+)$/) {
$operandType = 6;
} else {
print STDERR "CODE\n$code";
print STDERR "LINE\n$line\n";
print STDERR "FIELDS\n",join('/', @fields),"\n";
print STDERR "OPERAND1\n",$operand,"\n";
die 'invalid operand-1 type'
}
return $operandType;
}
--- NEW FILE: bb2cycle.pl ---
#!/usr/bin/perl
# Script to take BB execution counts generated by TOSSIM and convert them to cycle
# counts
$usage =
"Usage: bb2cycle.pl bb_exec_cnt bb_cycle_map\n".
" bb_exec_cnt: The basic block execution counts output by TOSSIM\n".
" bb_cycle_map: The bb -> cycle count map generated by bb2asm.pl\n\n";
die $usage if(scalar @ARGV != 2);
$bb_exec_cnt = shift @ARGV;
$bb_cycle_map = shift @ARGV;
open(EXEC_CNT, $bb_exec_cnt) || die "Can't open $bb_exec_cnt: $!";
open(CYCLE_MAP, $bb_cycle_map) || die "Can't open $bb_cycle_map: $!";
while(<CYCLE_MAP>) {
($bb, $cnt) = split;
$cycles{$bb} = $cnt;
}
while(<EXEC_CNT>) {
($mote, $bb, $cnt) = split;
$total{$mote} += $cnt * $cycles{$bb};
}
foreach $mote (sort {$a <=> $b} keys %total) {
print "$mote\t", $total{$mote}, "\n";
}
close(EXEC_CNT);
close(CYCLE_MAP);
--- NEW FILE: cilly.asm.exe ---
ELF
ÓÿÑÃD$
D$ÓÿÑÃD$ÿÑÃD$Äÿáë
ìD$\$
,
ÿÿÿÿ¶.)Å9Õ¡
ÿÿÿÿ¶)ÈT
[...5532 lines suppressed...]
5
eapify__24
heck__28
_171
amlCil__215
__795
mlCparser__209
208
r__33
long
ob_2509
n_1295
compare_162
un_859
sh_recvar_name_1098
3
lPtranal__hose_globals_825
low_forward
bals
arser__fun_2716
method_vinst_1044
val_1010
parse__fun_2476
kup_125
amlCil__method_vvdec_5102
--- NEW FILE: compile.pl ---
#!/usr/bin/perl -w
# Script to compile an TinyOS app with CPU profiling support.
# Must be run from the base directory of the project (where the main
# makefile is)
# The 'make pc' and 'make mica2' commands should behave the same as with
# the TinyOS sample apps: create app.c and main.exe in the build/{platform}
# directories.
# cilly must be in your path.
use Cwd;
if($ARGV[0] eq "--nomake") {
$make = 0;
} else {
$make = 1;
}
$ROOT = $ENV{"TOS"} . "/beta/TOSSIM-CC2420/PowerTOSSIM";
$SCRIPTDIR="$ROOT";
$BASEDIR = getcwd();
$CYCLECOUNTS = "$ROOT/msp430_cycle_counts.txt";
$CILLY = "$SCRIPTDIR/cilly.asm.exe";
# system() returns 0 on success, hence the &&s
if($make) {
system("make pc sim,telosA") && die "Can't compile base app for pc!\n";
system("make telos") && die "Can't compile base app for telos!\n";
}
system("cd build/pc && $CILLY --doCounter --out app.cil.c app.c > bb_line_tmp") && die "cilly error\n";
# print "cwd = ", getcwd(), "\n";
system("$SCRIPTDIR/fixnames.pl build/pc/bb_line_tmp > build/pc/bb_linenum_map") && die "fixnames.pl error\n";
chdir("build/pc") || die "Can't chdir: $!\n";
system("$SCRIPTDIR/mypp.pl app.cil.c") && die "mypp.pl error\n";
print "****************************\n";
print "$SCRIPTDIR/bb2asm.pl $BASEDIR $CYCLECOUNTS bb_linenum_map ../telos/main.exe bb_cycle_map\n";
print "****************************\n";
system("$SCRIPTDIR/bb2asm.pl $BASEDIR $CYCLECOUNTS bb_linenum_map ../telos/main.exe bb_cycle_map") && die "bb2asm.pl error\n";
system("gcc -O3 -o a.out app.cil.mypp.c -lpthread -lm");
# Clean up
system("rm bb_line_tmp") && die "rm failed\n";
--- NEW FILE: counter.ml ---
(*
* counter.ml
*
* This file contains a CIL transformation that increments a counter
* at the beginning of each basic block.
*)
open Cil
let max_motes = 10000;; (* Waste RAM, but who cares? It's only a few megs. *)
let num_bbs = ref 0;;
let cur_bb = ref 0;;
let myType = Formatcil.cType
"int [%d:motes][%d:bbs]"
[("motes", Fd max_motes); ("bbs",Fd !num_bbs) ];;
let cntArr = makeGlobalVar "bb_count" myType;; (* (TArray(intType, Some (integer !num_bbs),[]));; *)
(* Just count the number of basic blocks in the file *)
class countbbClass = object
inherit nopCilVisitor
method vstmt (s: stmt) : stmt visitAction = begin
begin
match s.skind with
Instr instrs ->
num_bbs := !num_bbs + 1;
| _ -> ()
end;
DoChildren
end
end
class instrumentClass = object
inherit nopCilVisitor
method vstmt (s: stmt) : stmt visitAction = begin
begin
match s.skind with
Instr instrs -> begin
cur_bb := !cur_bb + 1;
print_string (string_of_int(!cur_bb) ^ "\t");
print_string (Pretty.sprint 76 (d_thisloc ()) );
print_string "\n";
(* Want "bb_count[" ^ string_of_int(!cur_bb) ^ "] = bb_count[!cur_bb] + 1;" *)
let ctrInc = Formatcil.cInstr
"%v:arr[%d:mote][%d:cnt] = %v:arr[%d:mote][%d:cnt] + 1; // BB # %d:cnt"
locUnknown
[ ("mote", Fd 42);
("cnt",Fd !cur_bb);
("arr", Fv cntArr)
];
(* let ctrInc =
Set (var ctrVar,
BinOp (PlusA, Lval (var ctrVar), integer 1, intType),
locUnknown)
Set (var ctrVar,
BinOp (PlusA, Lval (var ctrVar), integer !cur_bb, intType),
locUnknown) *)
in
s.skind <- Instr (ctrInc :: instrs);
end
| _ -> ()
end;
DoChildren
end
end
let main (f: file) : unit =
visitCilFile ((new countbbClass) :> cilVisitor) f;
(* print_string("DEBUG: There are " ^ string_of_int(!num_bbs) ^ " basic blocks\n"); *)
(* f.globals <- GVarDecl (ctrVar, locUnknown) :: f.globals; *)
visitCilFile ((new instrumentClass) :> cilVisitor) f;
f.globals <- GVarDecl (cntArr, locUnknown) :: f.globals
let feature : featureDescr = {
fd_name = "Counter";
fd_enabled = ref false;
fd_description = "increment a counter at the beginning of each basic block";
fd_extraopt = [];
fd_doit = main;
fd_post_check = true;
}
--- NEW FILE: cpuprof.py ---
#!/usr/bin/python
# Script to do convert the bb exec counts into some useful form.
# reads the files bb_cycle_map, bb_exec_cnt, bb_linenum_map in the
# current directory
import sys;
COUNT_BLOCKS = 0
if '--countbbs' in sys.argv:
COUNT_BLOCKS = 1
NUM_BLOCKS = 20 # Number of most expensive basic blocks to print
NUM_FILES = 20 # Number of most expensive files to print
nummotes = 0
cycle_map = {}
for line in open('bb_cycle_map').readlines():
(bb, cnt) = line.split('\t')
cycle_map[int(bb)] = float(cnt)
filecycles = {} # File->cycles mapping
exec_cnt = {}
# Skip the first line-it's a total that we don't need
for line in open('bb_exec_cnt').readlines():
if not line.startswith('mote'): # stupid me put totals in the file format
(mote, bb, cnt) = line.split()
mote = int(mote)
if mote > nummotes:
nummotes = mote
if not mote in exec_cnt:
exec_cnt[mote] = {}
exec_cnt[mote][int(bb)] = float(cnt)
nummotes += 1
linenum_map = {}
for line in open('bb_linenum_map').readlines():
(bb, l) = line.split('\t')
linenum_map[int(bb)] = l
def mycmp(a, b):
# Want to sort in reverse order, so exchange a, b
if COUNT_BLOCKS:
return cmp(exec_cnt[m][b], exec_cnt[m][a])
else:
return cmp(exec_cnt[m][b] * cycle_map.get(b,0),
exec_cnt[m][a] * cycle_map.get(a,0))
# Takes a dictionary. Returns the set of keys sorted by value
def sortdict(d):
keys = d.keys()
keys.sort(lambda a,b:cmp(d[a],d[b]))
return keys
if COUNT_BLOCKS:
print "Block counts:"
else:
print "Cycle counts:"
print " %12s%12s%12s%12s%12s%12s%12s" % ('App', 'System',
'Lib', 'Interfaces',
'Platform', 'Misc', 'Total')
for m in range(nummotes):
filecycles = {}
platform = 0
app = 0
system = 0
interfaces = 0
lib = 0
misc = 0
for bb in exec_cnt[m]:
if COUNT_BLOCKS:
cycles = exec_cnt[m][bb]
else: # Count cycles instead
cycles = cycle_map.get(bb,0) * exec_cnt[m][bb]
# Get the filename
t = linenum_map[bb].rfind(':')
filename = linenum_map[bb][:t]
if not filename in filecycles:
filecycles[filename] = cycles
else:
filecycles[filename] += cycles
if linenum_map[bb].find('/platform/') != -1:
# print 'platform: ', linenum_map[bb]
platform += cycles
elif linenum_map[bb].find('/tos/system') != -1:
# print 'system: ', linenum_map[bb]
system += cycles
elif linenum_map[bb].find('/tos/lib') != -1:
lib += cycles
elif linenum_map[bb].find('/tos/interfaces') != -1:
interfaces += cycles
elif linenum_map[bb].find('/apps/') != -1:
# print 'app: ', linenum_map[bb]
app += cycles
else:
# print 'misc: ', linenum_map[bb]
misc += cycles
print "%3d: %12s%12s%12s%12s%12s%12s%12s" % (m,app, system, lib,
interfaces, platform,
misc,
app+system+platform+misc)
# Now lets figure out the top K basic blocks for this mote:
blocks = exec_cnt[m].keys()
blocks.sort(mycmp)
print "Mote %d: %d most expensive BBs:" % (m, NUM_BLOCKS)
for bb in blocks[:NUM_BLOCKS]:
print "%6d%15.1f %s" % (bb, exec_cnt[m][bb], linenum_map[bb])
# And now the files
files = sortdict(filecycles)
files.reverse()
print "Mote %d: %d most expensive files:" % (m, NUM_FILES)
for f in files[:NUM_BLOCKS]:
print "%15.1f %s" % (filecycles[f], f)
--- NEW FILE: fixnames.pl ---
#!/usr/bin/perl -w
# Script to fix files... the automounter makes it nigh impossible to
# get canonical absolute pathnames, so we'll just strip out everything
# up to $USERNAME.
# Input lines of the format:
# number\tpath:number
# Output, same, except that the paths inside the home directory will
# all be of the form ~/blah/blah
use Cwd 'realpath';
$me = `whoami`;
chomp($me);
while(<>) {
chomp();
/^(\d+)\t([^:]*):(\d+)$/;
($bb, $file, $line) = ($1, $2, $3);
if(/^\d+\t:-1/) {
print "$_\n";
next;
}
$path = realpath($file) || die "fixname.pl: realpath '$file' failed: $!\n";
$path =~ s|/.*$me/|~/|; # replace "/blah/blah/blah/username" with "~/"
print "$bb\t$path:$line\n";
}
--- NEW FILE: mica2_energy_model.txt ---
# Energy model for the mica2
# see http://www.eecs.harvard.edu/~shnayder/ptossim/ for details
# Lines starting with '#' are comments
# Format: KEY\s+VALUE
# Unless otherwise specified, VALUE is a current in mA
# Value is always assumed to be a number
VOLTAGE 3.0
# CPU numbers:
# Idle mode is what the CPU is in when not actively executing, but
# no special action is taken. The per-active-cycle numbers are added
# on top of that
# Added .93mA to idle and active cpu power to account for the
# oscillator. Need to make it separate later...
#CPU_ACTIVE 8.0
CPU_ACTIVE 8.93
#CPU_IDLE 3.2
CPU_IDLE 4.13
CPU_ADC_NOISE_REDUCTION 1.0
CPU_POWER_DOWN 0.103
CPU_POWER_SAVE 0.110
CPU_STANDBY 0.216
CPU_EXTENDED_STANDBY 0.223
# The startup mode for the cpu
CPU_INIT 3.2
CPU_FREQ 4000000
# It's actually 7382800, but the simulator is hardcoded for 4Mhz, and
# the fixes for that aren't merged yet
#CPU_FREQ 7382800
# These are actual measured numbers
RADIO_RX 7.03
RADIO_TX_00 3.72
RADIO_TX_01 5.21
RADIO_TX_03 5.37
RADIO_TX_06 6.47
RADIO_TX_09 7.05
RADIO_TX_0F 8.47
RADIO_TX_60 11.57
RADIO_TX_80 13.77
RADIO_TX_C0 17.37
RADIO_TX_FF 21.48
RADIO_OFF 0
# These are interpolated from above
RADIO_TX_02 5.3
RADIO_TX_04 5.75
RADIO_TX_05 6.1
RADIO_TX_07 6.67
RADIO_TX_08 6.87
RADIO_TX_0A 7.33
RADIO_TX_0B 7.6
RADIO_TX_0C 7.93
RADIO_TX_0E 8.15
RADIO_TX_40 9.5
RADIO_TX_50 10.5
RADIO_TX_70 12.6
RADIO_TX_90 15.0
RADIO_TX_E0 19.5
# The default power mode (0x0F, but python doesn't like hex numbers in floats)
RADIO_DEFAULT_POWER 15.00
# LED
LED 2.2
#default to off
LED_INIT 0
# EEPROM
EEPROM_READ 6.24
EEPROM_WRITE 18.40
#ADC
# we thought it took power, so it's tracked, but it actually doesn't
ADC 0.0
# If the sensor board is plugged in, it draws this much current at all times
SENSOR_BOARD 0.69
# Sensors - don't actually use power beyond the general sensor board power
SENSOR_PHOTO 0
SENSOR_TEMP 0
--- NEW FILE: msp430_cycle_counts.txt ---
--- NEW FILE: msp_cpuprof.py ---
#!/usr/bin/python
# Script to do convert the bb exec counts into some useful form.
# reads the files bb_cycle_map, bb_exec_cnt, bb_linenum_map in the
# current directory
import sys;
COUNT_BLOCKS = 0
if '--countbbs' in sys.argv:
COUNT_BLOCKS = 1
NUM_BLOCKS = 20 # Number of most expensive basic blocks to print
NUM_FILES = 20 # Number of most expensive files to print
nummotes = 0
cycle_map = {}
for line in open('bb_cycle_map').readlines():
(bb, cnt) = line.split('\t')
cycle_map[int(bb)] = float(cnt)
filecycles = {} # File->cycles mapping
exec_cnt = {}
# Skip the first line-it's a total that we don't need
for line in open('bb_exec_cnt').readlines():
if not line.startswith('mote'): # stupid me put totals in the file format
(mote, bb, cnt) = line.split()
mote = int(mote)
if mote > nummotes:
nummotes = mote
if not mote in exec_cnt:
exec_cnt[mote] = {}
exec_cnt[mote][int(bb)] = float(cnt)
nummotes += 1
linenum_map = {}
for line in open('bb_linenum_map').readlines():
(bb, l) = line.split('\t')
linenum_map[int(bb)] = l
def mycmp(a, b):
# Want to sort in reverse order, so exchange a, b
if COUNT_BLOCKS:
return cmp(exec_cnt[m][b], exec_cnt[m][a])
else:
return cmp(exec_cnt[m][b] * cycle_map.get(b,0),
exec_cnt[m][a] * cycle_map.get(a,0))
# Takes a dictionary. Returns the set of keys sorted by value
def sortdict(d):
keys = d.keys()
keys.sort(lambda a,b:cmp(d[a],d[b]))
return keys
if COUNT_BLOCKS:
print "Block counts:"
else:
print "Cycle counts:"
print " %12s%12s%12s%12s%12s%12s%12s" % ('App', 'System',
'Lib', 'Interfaces',
'Platform', 'Misc', 'Total')
for m in range(nummotes):
filecycles = {}
platform = 0
app = 0
system = 0
interfaces = 0
lib = 0
misc = 0
for bb in exec_cnt[m]:
if COUNT_BLOCKS:
cycles = exec_cnt[m][bb]
else: # Count cycles instead
cycles = cycle_map.get(bb,0) * exec_cnt[m][bb]
# Get the filename
t = linenum_map[bb].rfind(':')
filename = linenum_map[bb][:t]
if not filename in filecycles:
filecycles[filename] = cycles
else:
filecycles[filename] += cycles
if linenum_map[bb].find('/platform/') != -1:
# print 'platform: ', linenum_map[bb]
platform += cycles
elif linenum_map[bb].find('/tos/system') != -1:
# print 'system: ', linenum_map[bb]
system += cycles
elif linenum_map[bb].find('/tos/lib') != -1:
lib += cycles
elif linenum_map[bb].find('/tos/interfaces') != -1:
interfaces += cycles
elif linenum_map[bb].find('/apps/') != -1:
# print 'app: ', linenum_map[bb]
app += cycles
else:
# print 'misc: ', linenum_map[bb]
misc += cycles
print "%3d: %12s%12s%12s%12s%12s%12s%12s" % (m,app, system, lib,
interfaces, platform,
misc,
app+system+platform+misc)
# Now lets figure out the top K basic blocks for this mote:
blocks = exec_cnt[m].keys()
blocks.sort(mycmp)
print "Mote %d: %d most expensive BBs:" % (m, NUM_BLOCKS)
for bb in blocks[:NUM_BLOCKS]:
print "%6d%15.1f %s" % (bb, exec_cnt[m][bb], linenum_map[bb])
# And now the files
files = sortdict(filecycles)
files.reverse()
print "Mote %d: %d most expensive files:" % (m, NUM_FILES)
for f in files[:NUM_BLOCKS]:
print "%15.1f %s" % (filecycles[f], f)
--- NEW FILE: mypp.pl ---
#!/usr/bin/perl -w
# A script to preprocess the code that's been run through cilly before
# compiling it. Fixes the number of basic blocks in several places
$usage = "Usage: mypp.pl file.c\n";
# Output is file.mypp.c
die $usage unless $ARGV[0];
$infile = $ARGV[0];
$outfile = $infile;
$outfile =~ s/\.c$/.mypp.c/;
die "ERROR: Not a .c file specified\n$usage" if($infile eq $outfile);
open (INPUT, $infile) || die "can't open $infile: $!";
$max = 0;
while(<INPUT>) {
if(/^\s*bb_count\[42\]\[(\d+)\]/) {
$max = $1 if ($1 > $max);
}
}
$max++; # Since things start with 0
print STDERR "There are $max basic blocks\n";
close INPUT;
# Now max contains the number of basic blocks
open (INPUT, $infile) || die "can't open $infile: $!";
open (OUTPUT, ">$outfile") || die "can't open $outfile: $!";
while(<INPUT>) {
if(/int POWERPROF_BB_EXEC_COUNT/) {
# Skip the declaration
print OUTPUT $_;
next;
}
s/bb_count\[10000\]\[0\]/bb_count\[10000\]\[$max\]/;
s/bb_count\[42\]/bb_count\[tos_state.current_node\]/g;
s/int POWERPROF_NUM_BBS/int POWERPROF_NUM_BBS = $max/;
s/POWERPROF_BB_EXEC_COUNT/bb_count\[mote\]\[bb\]/g;
print OUTPUT $_;
}
--- NEW FILE: postprocess.py ---
#!/usr/bin/python
# postprocess.py
# Author: Victor Shnayder <shnayder at eecs.harvard.edu>
# Postprocessing script that reads PowerTOSSIM state transition log and
# computes power and energy numbers.
from sys import argv
import sys
usage = """USAGE: postprocess.py [--help] [--debug] [--nosummary]
[--detail[=basename]] [--maxmotes N]
[--simple] [--sb={0|1}] --em file trace_file
--help: print this help message
--debug: turn on debugging output
--nosummary: avoid printing the summary to stdout
--detail[=basename]: for each mote, print a list of 'time\\tcurrent' pairs
to the file basename$moteid.dat (default basename='mote')
--em file: use the energy model in file
--sb={0|1}: Whether the motes have a sensor board or not. (default: 0)
--maxmotes: The maximum of number of motes to support. 1000 by default.
--simple: Use a simple output format, suitable for machine parsing
By default, uses energy model from energy_model.txt in the current directory,
prints summary.
"""
summary = 1
prettyprint = 1
detail = 0
lineno = 0 # The line number in the trace file
emfile = "energy_model.txt"
tracefile = ""
model = {} # The energy model (mappings such as CPU_ACTIVE->8.0)
state = [{}] # The current state of execution ([mote][component])
total = [{}] # The energy totals
# Hmm... might not actually want 1000 open files. I guess I could
# open and close each one after each write. Or just keep all the
# logs in memory and then write them out one at a time. For now, just
# open each file when necessary and leave it at that
data_file = []
basename = 'mote'
voltage = None
prev_current = []
prev_time = []
maxmotes = 1000
maxseen = 0
debug = 0
em = {} # The energy model
sb = 0 # Whether there's a sensor board
#components = ["radio", "cpu", "cpu_cycles", "adc", "sensor", "led", "eeprom"]
# Types of total we want to track
totals = ["cpu", "radio", "adc", "leds", "sensor", "eeprom"]
def quit(showusage=0, error="Illegal arguments"):
if error:
print >> sys.stderr, "Error: ", error, "\n"
if showusage:
print >> sys.stderr, usage
sys.exit()
# Handle arguments-this can be rewritten with a dictionary of lambdas, but
# that's for later (or I can just use an existing module)
def parse_args():
global summary, maxmotes, emfile, tracefile, trace, argv, debug, basename
global detail, prettyprint, sb
argv = argv[1:]
while argv:
a=argv[0]
if a == "--help":
quit(1,"")
elif a == "--nosummary":
summary = 0
elif a == "--simple":
prettyprint = 0
elif a.startswith("--detail"):
detail = 1
x=a.rfind('=')
if x != -1:
basename = a[x+1:]
elif a.startswith("--sb="):
t = a[5:]
if t == "1":
sb = 1
elif t == "0":
sb = 0
else:
quit(1)
elif a == "--debug":
debug = 1
elif a == "--maxmotes":
argv = argv[1:] # Consume this argument
if not argv:
quit(1)
maxmotes = int(argv[0])
elif a == "--em":
argv=argv[1:] # Consume this argument
if not argv:
quit(1)
emfile = argv[0] # Get the filename parameter
else:
tracefile = a
argv = argv[1:]
if tracefile == "":
quit(1,"No tracefile specified")
try:
trace = open(tracefile)
except IOError:
quit(0,"Couldn't open trace file '"+tracefile+"'")
######### State initialization functions ##############
# Read energy model from file
def read_em():
global model,lineno,em
# Reads and parses the energy model file
try:
model = open(emfile)
except IOError:
quit(0,"Couldn't open energy model file '"+emfile+"'")
l = model.readline()
lineno += 1
while l:
l=l.strip()
# Parse the line, skipping comments, blank lines
if l == '' or l[0] == '#':
l = model.readline()
continue
# print "splitting line '%s'" % l
(k,v) = l.split()
em[k]=float(v)
l = model.readline()
lineno += 1
def initstate():
global state, total, voltage, prev_current, prev_time, data_file
read_em()
# initialize the various lists...
state = [None] * maxmotes
total = [None] * maxmotes
prev_current = [None] * maxmotes
prev_time = [0] * maxmotes
data_file = [None] * maxmotes
voltage = em['VOLTAGE']
for mote in range(maxmotes):
# Init each mote with base values
state[mote] = {'radio':{'on':0, 'tx':0,
'txpower':em['RADIO_DEFAULT_POWER']},
'cpu': 'IDLE',
'cpu_cycles':0,
'adc': 0,
'adc_on': 0,
# For the moment, all the same, but can be changed later
'sensor_board': sb,
'sensor': {},
'led': {},
'eeprom': {'read':0, 'write':0}}
total[mote] = {}
prev_current[mote]={}
for k in totals:
prev_current[mote][k] = 0
prev_current[mote]['total']=0
for t in totals:
total[mote][t] = 0
######################## Current computation #######################
def get_cpu_current(mote):
return em["CPU_"+state[mote]["cpu"]]
def get_sensor_current(mote):
mystate = state[mote]['sensor']
total = 0
# If the sensor board is plugged it draws a constant base current
if state[mote]['sensor_board']:
total += em.get('SENSOR_BOARD')
for (type,value) in mystate.items():
if value==1:
total += em.get("SENSOR_"+type, 0)
return total
def get_adc_current(mote):
# FIXME: if we discover that sampling actually takes energy
# in addition to the base cost, add it in if sampling.
if state[mote]['adc_on']:
return em['ADC']
else:
return 0
def tx_current(x):
""" Return the radio current for transmit power x """
return em["RADIO_TX_"+("%02X" % x)]
def get_radio_current(mote):
# Note that this sets the total power of the radio, so we have to include
# numbers like RADIO_ON.
#the state is: {'on':ON/OFF,'tx': TX/RX,'txpower':PowerLevel}
mystate = state[mote]['radio']
power = 0
if mystate['on']:
power += em['RADIO_ON']
if mystate['oscon']:
power += em['RADIO_OSCON']
if mystate['tx']:
power += tx_current(mystate['txpower'])
elif mystate['rx']:
power += em['RADIO_RX']
return power;
def get_leds_current(mote):
# Count how many leds are on:
numon = state[mote]['led'].values().count(1)
return numon * em['LED']
def get_eeprom_current(mote):
# Assumes that EEPROM can't read and write at the same time
# I believe that's correct
if state[mote]['eeprom']['read']:
return em['EEPROM_READ']
if state[mote]['eeprom']['write']:
return em['EEPROM_WRITE']
return 0
# There should probably be one entry for each key of the totals
# defined above
current_fn_map = {
'cpu': get_cpu_current,
'radio': get_radio_current,
'adc': get_adc_current,
'leds':get_leds_current,
'sensor':get_sensor_current,
'eeprom':get_eeprom_current}
def get_current(mote):
total = 0
for k in current_fn_map.keys():
total += current_fn_map[k](mote)
return total
def print_currents():
for m in range(maxseen+1):
print "mote %d: current %f" % (m, get_current(m))
######################## Event processing ##########################
# Add together a mote time from the trace (in CPU cycles)
# and a energy model time (in ms)
def time_add(motetime, emtime):
return motetime + emtime / 1000.0 * em.get("CPU_FREQ",7370000)
# The handlers should just update the state. Other functions are
# responsible for keeping track of totals.
def cpu_cycle_handler(mote, time, newstate):
# the cpu cycle messages always have a single number, which is
# the total since beginning of execution
global state
state[mote]['cpu_cycles'] = float(newstate[1])
def cpu_state_handler(mote, time, newstate):
# Here are the possible states, from PowerStateM.nc:
# char cpu_power_state[8][20] = {"IDLE", \
# "ADC_NOISE_REDUCTION", \
# "POWER_DOWN", \
# "POWER_SAVE", \
# "RESERVED", \
# "RESERVED", \
# "STANDBY", \
# "EXTENDED_STANDBY"}
# The energy model should have keys for each of the form CPU_`state`
global state
state[mote]["cpu"] = newstate[1]
def adc_handler(mote, time, newstate):
global state
#FIXME: The ADC has to be on for any ADC event to work-check this
action = newstate[1]
if action == 'SAMPLE':
state[mote]["adc"] = 1
elif action == 'DATA_READY':
state[mote]["adc"] = 0
elif action == 'ON':
state[mote]["adc_on"] = 1
elif action == 'OFF':
state[mote]["adc_on"] = 0
else:
quit(0,"Line %d: Syntax error: adc action %s unknown" % (lineno,action))
def radio_state_handler(mote, time, newstate):
"""
The radio is one of the more complicated pieces:
The possible values for newstate:
ON - turn radio on. As far as I can tell, goes back
to it's previous state
OFF - turn radio off.
TX - go into transmit mode. The transmit power is the same
as it was before (either the default, or the latest SetRFPower)
RX - go into receive mode
SetRFPower XX for some hex value of XX-there should be an
energy model entry for RADIO_TX_XX
Thus, the state for the radio is:
{'on':ON/OFF,'tx': TX/RX,'txpower':PowerLevel}
"""
global state
oldstate = state[mote]['radio']
op = newstate[1]
if op == "ON":
# Parameters are set to defaults when turning on
oldstate['on'] = 1
oldstate['oscon'] = 0
oldstate['tx'] = 0 # Defaults to RX mode
oldstate['txpower'] = em['RADIO_DEFAULT_POWER']
elif op == "OFF":
oldstate['on'] = 0
oldstate['oscon'] = 0
elif op == "SetRFPower":
oldstate['txpower'] = int(newstate[2],16) # must be a hex number
elif op == "TX":
# The mica(1) stack, doesn't explicitly turn radio on, so
# TX/RX transitions also turn it on. Should be valid for mica2
# as well, unless it tries to send while the radio is off, which
# probably qualifies as a bug
oldstate['on'] = 1
oldstate['oscon'] = 1
oldstate['tx'] = 1
elif op == "RX":
oldstate['on'] = 1
oldstate['oscon'] = 1
oldstate['tx'] = 0
elif op == "OSC_ON":
oldstate['on'] = 1
oldstate['oscon'] = 1
else:
quit(0,"Line %d: Syntax error: radio state %s unknown" % (lineno,op))
def led_state_handler(mote, time, newstate):
""" The state for the LEDs is pretty simple:
They start out off, and here we just keep track of which are on
in a dictionary. So the state[mote]['led'] looks like
{'RED':onoff, 'GREEN':onoff, 'YELLOW':onoff}
"""
global state
msg = newstate[1]
if msg.endswith("_OFF"):
state[mote]['led'][msg[:-4]]=0
else:
assert msg.endswith("_ON")
state[mote]['led'][msg[:-3]]=1
def sensor_state_handler(mote, time, newstate):
global state
# If we're doing sensor stuff, there must be a sensor board:
type = newstate[1]
action = newstate[2]
if action == 'ON':
state[mote]['sensor'][type] = 1
elif action == 'OFF':
state[mote]['sensor'][type] = 0
else:
quit(0, "Line %d: Syntax error: sensor state %s unknown"
% (lineno, action))
def eeprom_state_handler(mote, time, newstate):
global state
type = newstate[1]
action = newstate[2]
if type == 'READ':
if action == 'START':
state[mote]['eeprom']['read'] = 1
elif action == 'STOP':
state[mote]['eeprom']['read'] = 0
else:
quit(0, "Line %d: Syntax error: EEPROM READ action %s unknown"
% (lineno, action))
elif type == 'WRITE':
if action == 'START':
state[mote]['eeprom']['write'] = 1
elif action == 'STOP':
state[mote]['eeprom']['write'] = 0
else:
quit(0, "Line %d: Syntax error: EEPROM WRITE action %s unknown"
% (lineno, action))
else:
quit(0, "Line %d: Syntax error: EEPROM TYPE %s unknown"
% (lineno, type))
# A table of event type to the appropriate handler
event_handler = {'CPU_CYCLES' : cpu_cycle_handler,
'CPU_STATE' : cpu_state_handler,
'ADC' : adc_handler,
'RADIO_STATE' : radio_state_handler,
'LED_STATE' : led_state_handler,
'SENSOR_STATE': sensor_state_handler,
'EEPROM' : eeprom_state_handler}
def time_diff(t_from, t_to):
"""Returns the difference, in seconds from 't_from' to 't_to', where both
are expressed in cycles. Uses the CPU_FREQ energy model parameter"""
return (float(t_to) - float(t_from))/em['CPU_FREQ']
# Updates every total for every timestep. This is inefficient,
# because if the radio is on for 100 events, there's no need to do 100
# small adds But it's simpler this way. Can fix it (by making
# prev_time parametrized by total type) if it's a problem
def update_totals(time):
global total
for m in range(maxseen+1):
for t in totals:
td = time_diff(prev_time[m], time)
total[m][t] += td * prev_current[m][t] * voltage
def update_currents(time):
global prev_time, prev_current
for m in range(maxseen+1):
prev_time[m]=time
for t in totals:
prev_current[m][t] = current_fn_map[t](m)
def dump_currents(mote,time):
global data_file, debug
m=mote
if not data_file[m]:
# Open the file
data_file[m] = open(basename + str(m)+".dat", "w")
# Write the header
data_file[m].write("#%11s" % "time");
for x in ['total'] + totals:
data_file[m].write("%12s" % x)
data_file[m].write("\n")
if debug: print prev_current[m]['total'], get_current(m)
if prev_current[m]['total'] != get_current(m):
# To make a square wave, print the previous currents up to "just
# before now", then print the new currents
tm = float(time) / em['CPU_FREQ'] - 0.000001
data_file[m].write("%12f" % tm)
for t in ['total'] + totals:
c = float(prev_current[m][t])
data_file[m].write("%12f" % c)
data_file[m].write("\n");
tm = float(time)/em['CPU_FREQ']
c = get_current(m)
prev_current[m]['total'] = c
data_file[m].write("%12f%12f" % (tm,c))
for t in totals:
c = current_fn_map[t](m)
data_file[m].write("%12f" % c);
data_file[m].write("\n");
dbg_unknown_event_types = {}
# Takes a line, parses it, and performs the appropriate changes to the
# mote state and totals.
# The line format we expect consists of whitespace separated fields:
# DATA can consist of more than 1 field, but the rest must not
# junk POWER: Mote # STATE_TYPE {DATA...} at TIME(in cycles)
def handle_event(l):
global maxseen, detail
if debug: print lineno, l
event = l.split()
# Check if this is a power event
if event[1] != "POWER:":
return
mote = int(event[3])
if(mote > maxseen): maxseen = mote
time = event[-1]
# print "handling event: '%s'" % l
# print event
if event[4] in event_handler:
# Update the totals up to just before this event
update_totals(time)
# Update the state due to this event
event_handler[event[4]](mote,time,event[4:-2])
if detail:
# At this point, the state is updated, but still have the old
# current values
dump_currents(mote,time)
# Update the prev_current values
update_currents(time)
else:
global dbg_unknown_event_types
if not event[4] in dbg_unknown_event_types:
print "Don't know how to handle "+event[4]+" events"
dbg_unknown_event_types[event[4]] = 1
######################## "Main" code ###################
def print_summary():
global total
global maxseen
print "maxseen %d" % maxseen
for mote in range(maxseen+1):
sum = 0
if not prettyprint:
s = str(mote)+" "
for t in totals:
if prettyprint:
print "Mote %d, %s total: %f" % (mote, t, total[mote][t])
else:
s += "%.4f" % total[mote][t]
s += " "
sum += total[mote][t]
cpu_active_e = state[mote]['cpu_cycles'] * voltage * em['CPU_ACTIVE']/em['CPU_FREQ']
if prettyprint:
print "Mote %d, cpu_cycle total: %f" % (mote, cpu_active_e)
else:
s += "%.4f" % cpu_active_e
s += " "
sum += cpu_active_e
if prettyprint:
print "Mote %d, Total energy: %f\n" %(mote, sum)
else:
s += "%.4f" % sum
print s
if __name__=='__main__':
parse_args()
initstate()
lineno = 1
l=trace.readline()
while l:
handle_event(l)
lineno += 1
l = trace.readline()
if summary:
print_summary()
--- NEW FILE: telosA_energy_model.txt ---
# Energy model for the Telos
# see http://www.eecs.harvard.edu/~shnayder/ptossim/ for details
# Lines starting with '#' are comments
# Format: KEY\s+VALUE
# Unless otherwise specified, VALUE is a current in mA
# Value is always assumed to be a number
VOLTAGE 3.0
# CPU numbers:
# Idle mode is what the CPU is in when not actively executing, but
# no special action is taken. The per-active-cycle numbers are added
# on top of that
CPU_ACTIVE 1.8
CPU_IDLE 0.052
CPU_STANDBY 0.0024
# TODO correct these values
CPU_ADC_NOISE_REDUCTION 1.0
CPU_POWER_DOWN 0.103
CPU_POWER_SAVE 0.110
CPU_EXTENDED_STANDBY 0.223
# The startup mode for the cpu
# TODO correct these values
CPU_INIT 3.2
# This is probably incorrect, but the simulator is hardcoded for 4Mhz, and
# the fixes for that in powertossim aren't merged yet
CPU_FREQ 4000000
# These are from the datasheet.
# Some of the numbers Joe measured match somewhat closely, off by .3mA.
# E.g., RX = 20, TX_00 = 17.7
RADIO_RX 19.7
RADIO_TX_00 17.4
RADIO_TX_01 16.5
RADIO_TX_02 15.2
RADIO_TX_03 13.9
RADIO_TX_04 12.5
RADIO_TX_05 11.2
RADIO_TX_06 9.9
RADIO_TX_07 8.5
#RADIO_TX_08 0
#RADIO_TX_09 0
#RADIO_TX_0A 0
#RADIO_TX_0B 0
#RADIO_TX_0C 0
#RADIO_TX_0E 0
#RADIO_TX_0F 0
#RADIO_TX_40 0
#RADIO_TX_50 0
#RADIO_TX_60 0
#RADIO_TX_70 0
#RADIO_TX_80 0
#RADIO_TX_90 0
#RADIO_TX_C0 0
#RADIO_TX_E0 0
#RADIO_TX_FF 0
RADIO_ON 0
RADIO_OSCON 0
# The default power mode (0x0F, but python doesn't like hex numbers in floats)
RADIO_DEFAULT_POWER 0.0
# TODO correct all the numbers from this point on
# LED
LED 2.2
#default to off
LED_INIT 0
# EEPROM
EEPROM_READ 6.24
EEPROM_WRITE 18.40
#ADC
# we thought it took power, so it's tracked, but it actually doesn't
ADC 0.0
# If the sensor board is plugged in, it draws this much current at all times
SENSOR_BOARD 0.69
# Sensors - don't actually use power beyond the general sensor board power
SENSOR_PHOTO 0
SENSOR_TEMP 0
VOLTAGE 3.0
# Joe's message
#
# In each file, the first row is distance, the second row is average value,
# and the third row is standard deviation.
#
# recv - packet success rate
# lqi - lqi value as a function of the maximum value. ie: lqi of 1
# corresponds to 110, lqi of 0 corresponds to 65.
# rssi - signal strength in dBm, you will need to convert to the radio's
# native rssi values (see datasheet)
#
# here are power numbers for Telos:
# Mote Standby (RTC on) 5.1 uA
# MCU Idle (DCO on) 54.5 uA
# MCU Active 1.8 mA
# MCU + Radio RX 21.8 mA
# MCU + Radio TX (0dBm) 19.5 mA
# MCU + Flash Read 4.1 mA
# MCU + Flash Write 15.1 mA
#
# wakeup times may not be in current power tossim, but this is the time it
# takes to transition from power down to active, multiplied by the current
# consumed in that state gives you the power you waste by starting the radio
# or MCU... just something that would be nice to get in there eventually.
# MCU Wakeup 6 us
# Radio Wakeup 580 us
#
# I also have numbers for MicaZ:
#
# Mote Standby (RTC on) 27.0 uA
# MCU Idle (DCO on) 3.2 mA
# MCU Active 8.0 mA
# MCU + Radio RX 23.3 mA
# MCU + Radio TX (0dBm) 21.0 mA
# MCU + Flash Read 9.4 mA
# MCU + Flash Write 21.6 mA
#
# wakeup info:
# MCU Wakeup 180 us
# Radio Wakeup 860 us
#
# -Joe
#
#
#
# 1.0000000e+000 3.0000000e+000 9.0000000e+000 1.2000000e+001 1.5000000e+001 2.0000000e+001 2.5000000e+001 3.0000000e+001 3.5000000e+001 5.0000000e+001 5.5000000e+001 6.5000000e+001 7.5000000e+001 8.5000000e+001 9.5000000e+001 1.0500000e+002 1.1500000e+002 1.2500000e+002 1.3500000e+002 1.5000000e+002 1.7500000e+002 1.9000000e+002 2.0000000e+002 2.2500000e+002
# 1.0000000e+000 1.0000000e+000 1.0000000e+000 1.0000000e+000 1.0000000e+000 9.9830076e-001 9.9305679e-001 9.9191176e-001 9.7099573e-001 9.9012721e-001 8.9959527e-001 9.2864832e-001 6.7069641e-001 7.0898749e-001 7.7292225e-001 6.0699019e-001 4.8387097e-001 6.6836263e-001 5.0676507e-001 5.3571429e-001 3.6674146e-001 2.5000000e-001 1.2433862e-001 0.0000000e+000
# 0.0000000e+000 0.0000000e+000 0.0000000e+000 0.0000000e+000 0.0000000e+000 1.5217949e-006 1.5953405e-002 1.6717950e-002 8.5805197e-002 3.1202740e-002 1.5890991e-001 2.0383086e-001 2.7743986e-001 3.7399393e-001 2.5652034e-001 3.2716744e-001 1.1567529e-001 4.2758101e-001 3.1273977e-001 3.6186641e-001 2.9827014e-001 1.3517656e-001 2.6736732e-001 0.0000000e+000
#
#
#
# 1.0000000e+000 3.0000000e+000 9.0000000e+000 1.2000000e+001 1.5000000e+001 2.0000000e+001 2.5000000e+001 3.0000000e+001 3.5000000e+001 5.0000000e+001 5.5000000e+001 6.5000000e+001 7.5000000e+001 8.5000000e+001 9.5000000e+001 1.0500000e+002 1.1500000e+002 1.2500000e+002 1.3500000e+002 1.5000000e+002 1.7500000e+002 1.9000000e+002 2.0000000e+002 2.2500000e+002
# -5.0000000e+000 -3.6972666e+001 -3.7645155e+001 -5.2282295e+001 -5.8172419e+001 -5.9801555e+001 -6.2774638e+001 -6.8945321e+001 -7.0625093e+001 -7.1370049e+001 -7.0580249e+001 -7.1120391e+001 -7.0170213e+001 -7.1000000e+001 -7.0316849e+001 -7.1000000e+001 -7.0041593e+001 -7.1200000e+001 -7.6100000e+001 -7.8800000e+001 -8.0000000e+001 -8.0229282e+001 -8.2024194e+001 -8.5957447e+001
# 0.0000000e+000 5.4443280e+000 3.7133265e+000 2.3515942e+000 3.4909166e+000 3.8473819e+000 3.5159615e+000 4.1263230e+000 3.4460830e+000 4.5158536e+000 7.6943596e+000 1.3019756e+001 1.7342540e+001 2.1362796e+001 1.4857934e+001 3.2027754e+001 2.3495782e+001 1.4985474e+000 1.3997791e+001 8.3433746e+000 3.4261554e+000 7.9204145e+000 1.4034564e+001 2.0170351e+000
#
#
#
# 1.0000000e+000 3.0000000e+000 9.0000000e+000 1.2000000e+001 1.5000000e+001 2.0000000e+001 2.5000000e+001 3.0000000e+001 3.5000000e+001 5.0000000e+001 5.5000000e+001 6.5000000e+001 7.5000000e+001 8.5000000e+001 9.5000000e+001 1.0500000e+002 1.1500000e+002 1.2500000e+002 1.3500000e+002 1.5000000e+002 1.7500000e+002 1.9000000e+002 2.0000000e+002 2.2500000e+002
# 9.3167928e-001 9.3172050e-001 9.2838997e-001 9.2618378e-001 9.2710038e-001 9.2410780e-001 9.1113900e-001 9.0321637e-001 8.7807560e-001 8.9593267e-001 7.9572783e-001 8.3656970e-001 5.8661251e-001 6.6189559e-001 6.3550314e-001 4.9604161e-001 3.3056241e-001 5.3810073e-001 3.5478245e-001 4.4390572e-001 3.6915175e-001 2.7706553e-001 1.4657210e-001 0.0000000e+000
# 4.0700328e-003 3.8181885e-003 4.8851738e-003 6.6601911e-003 6.0063107e-003 7.7624898e-003 3.1499005e-002 3.9931096e-002 9.7546236e-002 4.1023312e-002 1.7006415e-001 1.2513008e-001 1.7504235e-001 2.8414129e-001 1.8009302e-001 2.0437215e-001 1.2140026e-001 2.5288831e-001 1.4113228e-001 1.9154149e-001 1.5625198e-001 1.0901758e-001 3.3693791e-002 0.0000000e+000
#
#
--- NEW FILE: telosB_energy_model.txt ---
# Energy model for the Telos
# see http://www.eecs.harvard.edu/~shnayder/ptossim/ for details
# Lines starting with '#' are comments
# Format: KEY\s+VALUE
# Unless otherwise specified, VALUE is a current in mA
# Value is always assumed to be a number
VOLTAGE 3.0
# CPU numbers:
# Idle mode is what the CPU is in when not actively executing, but
# no special action is taken. The per-active-cycle numbers are added
# on top of that
CPU_ACTIVE 1.8
CPU_IDLE 0.0545
CPU_STANDBY 0.0051
# TODO correct these values
CPU_ADC_NOISE_REDUCTION 1.0
CPU_POWER_DOWN 0.103
CPU_POWER_SAVE 0.110
CPU_EXTENDED_STANDBY 0.223
# The startup mode for the cpu
# TODO correct these values
CPU_INIT 3.2
# This is probably incorrect, but the simulator is hardcoded for 4Mhz, and
# the fixes for that in powertossim aren't merged yet
CPU_FREQ 4000000
# These are from the datasheet.
# Some of the numbers Joe measured match somewhat closely, off by .3mA.
# E.g., RX = 20, TX_00 = 17.7
RADIO_RX 19.7
RADIO_TX_00 17.4
RADIO_TX_01 16.5
RADIO_TX_02 15.2
RADIO_TX_03 13.9
RADIO_TX_04 12.5
RADIO_TX_05 11.2
RADIO_TX_06 9.9
RADIO_TX_07 8.5
#RADIO_TX_08 0
#RADIO_TX_09 0
#RADIO_TX_0A 0
#RADIO_TX_0B 0
#RADIO_TX_0C 0
#RADIO_TX_0E 0
#RADIO_TX_0F 0
#RADIO_TX_40 0
#RADIO_TX_50 0
#RADIO_TX_60 0
#RADIO_TX_70 0
#RADIO_TX_80 0
#RADIO_TX_90 0
#RADIO_TX_C0 0
#RADIO_TX_E0 0
#RADIO_TX_FF 0
RADIO_ON 0
RADIO_OSCON 0
# The default power mode (0x0F, but python doesn't like hex numbers in floats)
RADIO_DEFAULT_POWER 0.0
# TODO correct all the numbers from this point on
# LED
LED 2.2
#default to off
LED_INIT 0
# EEPROM
EEPROM_READ 6.24
EEPROM_WRITE 18.40
#ADC
# we thought it took power, so it's tracked, but it actually doesn't
ADC 0.0
# If the sensor board is plugged in, it draws this much current at all times
SENSOR_BOARD 0.69
# Sensors - don't actually use power beyond the general sensor board power
SENSOR_PHOTO 0
SENSOR_TEMP 0
VOLTAGE 3.0
# Joe's message
#
# In each file, the first row is distance, the second row is average value,
# and the third row is standard deviation.
#
# recv - packet success rate
# lqi - lqi value as a function of the maximum value. ie: lqi of 1
# corresponds to 110, lqi of 0 corresponds to 65.
# rssi - signal strength in dBm, you will need to convert to the radio's
# native rssi values (see datasheet)
#
# here are power numbers for Telos:
# Mote Standby (RTC on) 5.1 uA
# MCU Idle (DCO on) 54.5 uA
# MCU Active 1.8 mA
# MCU + Radio RX 21.8 mA
# MCU + Radio TX (0dBm) 19.5 mA
# MCU + Flash Read 4.1 mA
# MCU + Flash Write 15.1 mA
#
# wakeup times may not be in current power tossim, but this is the time it
# takes to transition from power down to active, multiplied by the current
# consumed in that state gives you the power you waste by starting the radio
# or MCU... just something that would be nice to get in there eventually.
# MCU Wakeup 6 us
# Radio Wakeup 580 us
#
# I also have numbers for MicaZ:
#
# Mote Standby (RTC on) 27.0 uA
# MCU Idle (DCO on) 3.2 mA
# MCU Active 8.0 mA
# MCU + Radio RX 23.3 mA
# MCU + Radio TX (0dBm) 21.0 mA
# MCU + Flash Read 9.4 mA
# MCU + Flash Write 21.6 mA
#
# wakeup info:
# MCU Wakeup 180 us
# Radio Wakeup 860 us
#
# -Joe
#
#
#
# 1.0000000e+000 3.0000000e+000 9.0000000e+000 1.2000000e+001 1.5000000e+001 2.0000000e+001 2.5000000e+001 3.0000000e+001 3.5000000e+001 5.0000000e+001 5.5000000e+001 6.5000000e+001 7.5000000e+001 8.5000000e+001 9.5000000e+001 1.0500000e+002 1.1500000e+002 1.2500000e+002 1.3500000e+002 1.5000000e+002 1.7500000e+002 1.9000000e+002 2.0000000e+002 2.2500000e+002
# 1.0000000e+000 1.0000000e+000 1.0000000e+000 1.0000000e+000 1.0000000e+000 9.9830076e-001 9.9305679e-001 9.9191176e-001 9.7099573e-001 9.9012721e-001 8.9959527e-001 9.2864832e-001 6.7069641e-001 7.0898749e-001 7.7292225e-001 6.0699019e-001 4.8387097e-001 6.6836263e-001 5.0676507e-001 5.3571429e-001 3.6674146e-001 2.5000000e-001 1.2433862e-001 0.0000000e+000
# 0.0000000e+000 0.0000000e+000 0.0000000e+000 0.0000000e+000 0.0000000e+000 1.5217949e-006 1.5953405e-002 1.6717950e-002 8.5805197e-002 3.1202740e-002 1.5890991e-001 2.0383086e-001 2.7743986e-001 3.7399393e-001 2.5652034e-001 3.2716744e-001 1.1567529e-001 4.2758101e-001 3.1273977e-001 3.6186641e-001 2.9827014e-001 1.3517656e-001 2.6736732e-001 0.0000000e+000
#
#
#
# 1.0000000e+000 3.0000000e+000 9.0000000e+000 1.2000000e+001 1.5000000e+001 2.0000000e+001 2.5000000e+001 3.0000000e+001 3.5000000e+001 5.0000000e+001 5.5000000e+001 6.5000000e+001 7.5000000e+001 8.5000000e+001 9.5000000e+001 1.0500000e+002 1.1500000e+002 1.2500000e+002 1.3500000e+002 1.5000000e+002 1.7500000e+002 1.9000000e+002 2.0000000e+002 2.2500000e+002
# -5.0000000e+000 -3.6972666e+001 -3.7645155e+001 -5.2282295e+001 -5.8172419e+001 -5.9801555e+001 -6.2774638e+001 -6.8945321e+001 -7.0625093e+001 -7.1370049e+001 -7.0580249e+001 -7.1120391e+001 -7.0170213e+001 -7.1000000e+001 -7.0316849e+001 -7.1000000e+001 -7.0041593e+001 -7.1200000e+001 -7.6100000e+001 -7.8800000e+001 -8.0000000e+001 -8.0229282e+001 -8.2024194e+001 -8.5957447e+001
# 0.0000000e+000 5.4443280e+000 3.7133265e+000 2.3515942e+000 3.4909166e+000 3.8473819e+000 3.5159615e+000 4.1263230e+000 3.4460830e+000 4.5158536e+000 7.6943596e+000 1.3019756e+001 1.7342540e+001 2.1362796e+001 1.4857934e+001 3.2027754e+001 2.3495782e+001 1.4985474e+000 1.3997791e+001 8.3433746e+000 3.4261554e+000 7.9204145e+000 1.4034564e+001 2.0170351e+000
#
#
#
# 1.0000000e+000 3.0000000e+000 9.0000000e+000 1.2000000e+001 1.5000000e+001 2.0000000e+001 2.5000000e+001 3.0000000e+001 3.5000000e+001 5.0000000e+001 5.5000000e+001 6.5000000e+001 7.5000000e+001 8.5000000e+001 9.5000000e+001 1.0500000e+002 1.1500000e+002 1.2500000e+002 1.3500000e+002 1.5000000e+002 1.7500000e+002 1.9000000e+002 2.0000000e+002 2.2500000e+002
# 9.3167928e-001 9.3172050e-001 9.2838997e-001 9.2618378e-001 9.2710038e-001 9.2410780e-001 9.1113900e-001 9.0321637e-001 8.7807560e-001 8.9593267e-001 7.9572783e-001 8.3656970e-001 5.8661251e-001 6.6189559e-001 6.3550314e-001 4.9604161e-001 3.3056241e-001 5.3810073e-001 3.5478245e-001 4.4390572e-001 3.6915175e-001 2.7706553e-001 1.4657210e-001 0.0000000e+000
# 4.0700328e-003 3.8181885e-003 4.8851738e-003 6.6601911e-003 6.0063107e-003 7.7624898e-003 3.1499005e-002 3.9931096e-002 9.7546236e-002 4.1023312e-002 1.7006415e-001 1.2513008e-001 1.7504235e-001 2.8414129e-001 1.8009302e-001 2.0437215e-001 1.2140026e-001 2.5288831e-001 1.4113228e-001 1.9154149e-001 1.5625198e-001 1.0901758e-001 3.3693791e-002 0.0000000e+000
#
#
More information about the Tinyos-beta-commits
mailing list