diff options
l---------[-rwxr-xr-x] | bin/dfatool | 492 |
1 files changed, 1 insertions, 491 deletions
diff --git a/bin/dfatool b/bin/dfatool index ce9224e..dc598c5 100755..120000 --- a/bin/dfatool +++ b/bin/dfatool @@ -1,491 +1 @@ -#!/usr/bin/env perl - -use strict; -use warnings; -use 5.020; - -use Getopt::Long; -use IO::Handle; -use Kratos::DFADriver; -use List::Util qw(max sum); -use Time::Progress; - -our $VERSION = '0.00'; -my %opt; - -GetOptions( - \%opt, - qw{ - baudrate=i - class=s - exclude-states=s@ - ignore-nested-calls - logging! - plot=s - no-cache - no-update - note=s - param-default=s@ - state-duration=i - shunt=f - trace-filter=s@ - trace-revisit=i - trigger-pin=i - trigger-port=s - voltage=f - with-lut! - offset=i - workload=s - zomg-fasta-nao - } -); - -if ( @ARGV < 2 ) { - show_usage(); -} - -@{ $opt{'exclude-states'} } - = split( qr{,}, join( q{,}, @{ $opt{'exclude-states'} // [] } ) ); -@{ $opt{'param-default'} } - = split( qr{,}, join( q{,}, @{ $opt{'param-default'} // [] } ) ); - -my ( $command, $model_file, @data_files ) = @ARGV; - -my $driver = Kratos::DFADriver->new( - baud_rate => $opt{baudrate} // 115200, - cache => $opt{'no-cache'} ? 0 : 1, - class_name => $opt{class}, - data_file => $data_files[0], - excluded_states => $opt{'exclude-states'} // [], - fast_analysis => $opt{'zomg-fasta-nao'} // 0, - filename_suffix => $opt{'note'}, - ignore_nested => $opt{'ignore-nested-calls'} // 0, - logging => $opt{logging} // 1, - state_duration => $opt{'state-duration'} // 1000, - trigger_pin => $opt{'trigger-pin'}, - trigger_port => $opt{'trigger-port'}, - merge_args => $opt{'plot'} - ? [ map { "--$_" } split( qr{,}, $opt{'plot'} ) ] - : [], - mimosa_offset => $opt{offset} // 130, - mimosa_shunt => $opt{shunt} // 330, - mimosa_voltage => $opt{voltage} // 3.60, - model_file => $model_file, - param_default => $opt{'param-default'} // [], - trace_filter => $opt{'trace-filter'} // [], - trace_revisit => $opt{'trace-revisit'} // 2, - with_lut => $opt{'with-lut'}, -); - -my %action = ( - autogen => sub { - - # nothing to do - }, - clean => sub { - $driver->launchpad_log_clean; - }, - enable => sub { - $driver->write_acc_files; - }, - disable => sub { - $driver->rm_acc_files; - }, - 'to-tikz' => sub { - say $driver->to_tikz; - }, - 'to-dfa' => sub { - say join( - "\n", - map { - join( ' -> ', map { "$_->[0]($_->[1],$_->[2])" } @{$_} ) - } $driver->runs - ); - }, - flash => sub { - say "Compiling Kratos and flashing Launchpad"; - $driver->launchpad_flash; - }, - maketest => sub { - $driver->write_test_files; - }, - rmtest => sub { - $driver->rm_test_files; - }, - reset => sub { - say "Resetting MSP430"; - $driver->launchpad_reset; - }, - log => sub { - say "Resetting MSP430"; - $driver->launchpad_reset; - say "Connecting to Launchpad"; - $driver->launchpad_log_init; - say "Starting measurement"; - $driver->mimosa->start; - say "Calibrating MIMOSA"; - $driver->mimosa->calibrate; - STDOUT->autoflush(1); - print "Waiting for sync"; - - while ( not $driver->launchpad_log_is_synced ) { - $driver->launchpad_log_read; - print q{.}; - } - print "\r\e[2KSynced with DriverEval app\n"; - my ( $iter, $run, $maxrun ) = $driver->launchpad_log_status; - my $timer = Time::Progress->new( - min => 0, - max => $maxrun - ); - while ( $run < 1 ) { - $driver->launchpad_log_read; - ( $iter, $run, $maxrun ) = $driver->launchpad_log_status; - } - while ( $driver->launchpad_log_is_synced ) { - $driver->launchpad_log_read; - ( $iter, $run, $maxrun ) = $driver->launchpad_log_status; - print $timer->report( -"\r\e[2K%40b %p (${run}/${maxrun}) %L elapsed %E remaining in iteration ${iter}", - $run - ); - if ( $run == $maxrun ) { - printf( "\r\e[2KIteration %d done after %d seconds\n", - $iter - 1, $timer->elapsed($run) ); - say "Stopping measurement"; - $driver->mimosa->stop; - say "Archiving files"; - $driver->archive_files; - return; - } - - if ( my @errors = $driver->launchpad_get_errors ) { - say "\r\e[2KErrors in iteration ${iter}, run ${run}"; - say join( "\n", @errors ); - say "Aborting measurement. Current run will not be saved."; - $driver->mimosa->kill; - exit 1; - } - } - }, - analyze => sub { - $driver->analyze(@data_files); - $driver->assess_model; - if ( $opt{workload} ) { - $driver->assess_workload( $opt{workload} ); - } - elsif ( not $opt{'no-update'} ) { - $driver->update_model; - } - }, - 'analyze-tex' => sub { - $driver->analyze(@data_files); - $driver->assess_model_tex; - }, - analyzesingle => sub { - if ( $opt{'no-cache'} or not $driver->log->load_cache ) { - say "Analyzing DriverEval iterations (this may take a while)"; - $driver->log->load_archive; - $driver->log->preprocess; - $driver->log->save_cache; - } - say "Processing"; - $driver->log->analyze; - $driver->assess_model; - if ( not $opt{'no-update'} ) { - $driver->update_model; - } - }, - crossvalidate => sub { - printf( "./dfatool crossvalidate %s %s\n", - $model_file, join( q{ }, @data_files ) ); - $driver->crossvalidate_model(@data_files); - }, - ls => sub { - for my $file (@data_files) { - my $log = $driver->log($file); - $log->load_archive; - my $setup = $log->setup; - say $file; - printf( - " %.2fV @ %3dΩ, %dms per state, max revisit %d\n", - $setup->{mimosa_voltage}, $setup->{mimosa_shunt}, - $setup->{state_duration}, $setup->{trace_revisit} - ); - if ( $setup->{excluded_states} and @{ $setup->{excluded_states} } ) - { - printf( " excluded states: %s\n", $setup->{excluded_states} ); - } - if ( $setup->{trace_filter} and @{ $setup->{trace_filter} } ) { - printf( " trace filter: %s\n", - join( q{ | }, @{ $setup->{trace_filter} } ) ); - } - } - }, - list => sub { - for my $file (@data_files) { - my $log = $driver->log($file); - if ( $opt{'no-cache'} or not $driver->log->load_cache ) { - $log->load_archive; - $log->preprocess; - $log->save_cache; - } - $log->analyze; - my $data = $log->data; - my $setup = $log->setup; - say $file; - printf( - " %.2fV @ %3dΩ, %dms per state, max revisit %d\n", - $setup->{mimosa_voltage}, $setup->{mimosa_shunt}, - $setup->{state_duration}, $setup->{trace_revisit} - ); - if ( $setup->{excluded_states} and @{ $setup->{excluded_states} } ) - { - printf( " excluded states: %s\n", $setup->{excluded_states} ); - } - if ( $setup->{trace_filter} and @{ $setup->{trace_filter} } ) { - printf( " trace filter: %s\n", - join( q{ | }, @{ $setup->{trace_filter} } ) ); - } - printf( " MIMOSA offset: %5s %5s %5s\n", 'inf', '100k', '1k' ); - for my $cal ( @{ $data->{calibration} } ) { - printf( " %5.f %5.f %5.f µW\n", - @{$cal}{qw{r0_err_uW r2_err_uW r1_err_uW}}, - ); - } - for my $state ( sort keys %{ $data->{aggregate}{state} } ) { - if ( $state ne 'UNINITIALIZED' ) { - my $val = $data->{aggregate}{state}{$state}; - printf( - " %15s : %.f±%.f = %.f, clip %.f%% ^ %.f%%\n", - $state, $val->{power}{mean}, - $val->{power}{std_inner}, $val->{power}{median}, - $val->{clip}{mean}, $val->{clip}{max} - ); - } - } - } - }, - show => sub { - for my $file (@data_files) { - my $log = $driver->log($file); - $log->load_archive; - if ( $opt{'no-cache'} or not $driver->log->load_cache ) { - $log->load_archive; - $log->preprocess; - $log->save_cache; - } - $log->analyze; - for my $trace ( @{ $log->data->{traces} } ) { - my ( @data, @widths ); - printf( '%3d', $trace->{id} ); - for my $elem ( @{ $trace->{trace} } ) { - if ( $elem->{isa} eq 'state' - and $elem->{name} ne 'UNINITIALIZED' ) - { - push( @widths, max( length( $elem->{name} ), 9 ) ); - printf( ' → %9s', $elem->{name} ); - my @powers - = map { $_->{uW_mean} } @{ $elem->{offline} }; - push( @data, sum(@powers) / @powers ); - } - elsif ( $elem->{isa} eq 'transition' ) { - my $args = join( q{, }, @{ $elem->{args} // [qw[?]] } ); - my $pstr = "$elem->{name}($args)"; - push( @widths, max( length($pstr), 9 ) ); - printf( ' → %9s', $pstr ); - my @energies - = map { $_->{uW_mean_delta_prev} * ( $_->{us} - 20 ) } - @{ $elem->{offline} }; - push( @data, sum(@energies) / @energies ); - } - } - print "\n "; - for my $i ( 0 .. $#data ) { - printf( " → \%$widths[$i]d", $data[$i] ); - } - print "\n"; - } - } - }, - reset => sub { - $driver->reset_model; - }, -); - -$SIG{INT} = $SIG{TERM} = sub { - say "\r\e[2KTerminating MIMOSA daemon"; - $driver->mimosa->kill; - say "Goodbye"; - exit 0; -}; - -sub show_usage { - say STDERR "Usage: $0 <action> <DFA driver file>"; - say STDERR 'Supported actions: ' . join( q{ }, sort keys %action ); - exit 1; -} - -if ( exists $action{$command} ) { - $action{$command}(); -} -elsif ( $command eq 'loop' ) { - $action{clean}(); - $action{enable}(); - $action{maketest}(); - $action{flash}(); - while (1) { - $action{log}(); - } -} -else { - show_usage(); -} - -__END__ - -=head1 NAME - -dfatool manages energy-aware DFA drivers for kratos and generates and runs -test programs to assess a device's energy usage. - -=head1 SYNOPSIS - -B<dfatool> [I<options>] enable|disable|maketest|rmtest|log|loop I<driver.json> - -B<dfatool> [I<options>] analyze|crossvalidate|ls|list|show -I<driver.json> I<data.tar> [I<moredata.tar ...>] - -=head1 VERSION - -=head1 DESCRIPTION - -TODO WARNING: rel_energy_next is unusable for transitions which frequently are -the last transition in a run - -=head1 COMMANDS - -=over - -=item B<enable> I<driver.json> - -Instruments the driver noted in I<driver.json> for energy accounting and state -and transition logging. Unconditionally uses static model attributes and only -relative energy values. Attributes whose power or energy values are not yet -known are set to zero. - -=item B<disable> I<driver.json> - -Removes accounting and logging instrumentation, thus turning the driver back -into an energy-unaware one. By default, each state may be visited up to two -times... - -=item B<maketest> I<driver.json> - -Creates a kratos application containing a test program for the driver. By -default, - -=back - -=head1 OPTIONS - -=over - -=back - -=head1 EXIT STATUS - -=head1 CONFIGURATION - -None. - -=head1 SOFTWARE DEPENDENCIES - -As of 2017-04, the following packages (and some more) are required on Debian -Sid: - - apt install libcarp-assert-more-perl libclass-accessor-perl libdatetime-perl - libdevice-serialport-perl libfile-slurp-perl libipc-run-perl libjson-perl - liblist-moreutils-perl libmath-cartesian-product-perl - libparse-recdescent-perl libtime-progress-perl libxml-libxml-perl - python3-matplotlib python3-numpy python3-scipy - -Required non-standard perl modules: - -=over - -=item * Carp::Assert::More - -=item * DateTIme - -=item * Device::SerialPort - -=item * File::Slurp - -=item * IPC::Run - -=item * List::MoreUtils - -=item * Math::Cartesian::Product - -=item * Parse::RecDescent - -=item * Time::Progress - -=item * XML::LibXML - -=back - -For analysis, the following programs and modules are required: - -=over - -=item * Python 3.5 with matplotlib, numpy and scipy modules - -=item * parallel (either GNU parallel or the one provided by moreutils) - -=back - -=head1 HARDWARE DEPENDENCIES - -Normal driver usage and analyses of generated data requires no external -hardware. For data collection (C<< dfatool loop >> and C<< dfatool log >>), the -following pieces are required: - -=over - -=item * An MSP430 Launchpad with the Device Under Test attached - -=item * MIMOSA - -=item * MIMOSA-Autocal - -=back - -=head1 BUGS AND LIMITATIONS - -To be determined. - -=head1 AUTHOR - -Copyright (C) 2016-2017 by Daniel Friesel E<lt>daniel.friesel@udo.eduE<gt> - -=head1 LICENSE - -You may use this program either according to the terms of the Perl license -(also known as the Artistic license) or under the following terms -(also knows as the Three-clause BSD License). - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors -may be used to endorse or promote products derived from this software without -specific prior written permission. +../lib
\ No newline at end of file |