summaryrefslogtreecommitdiff
path: root/lib/MIMOSA/Log.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/MIMOSA/Log.pm')
-rw-r--r--lib/MIMOSA/Log.pm398
1 files changed, 0 insertions, 398 deletions
diff --git a/lib/MIMOSA/Log.pm b/lib/MIMOSA/Log.pm
deleted file mode 100644
index 270bbb2..0000000
--- a/lib/MIMOSA/Log.pm
+++ /dev/null
@@ -1,398 +0,0 @@
-package MIMOSA::Log;
-
-use strict;
-use warnings;
-use 5.020;
-
-use Archive::Tar;
-use Carp;
-use File::Slurp qw(read_file read_dir write_file);
-use JSON;
-use List::Util qw(sum);
-
-#use Statistics::Basic::Mean;
-#use Statistics::Basic::StdDev;
-
-our $VERSION = '0.00';
-my $CACHE_VERSION = 6;
-
-sub new {
- my ( $class, %opt ) = @_;
-
- my $self = \%opt;
-
- $self->{tmpdir} = "/tmp/kratos-dfa-mim-$$";
-
- if ( $opt{tmpsuffix} ) {
- $self->{tmpdir} .= "-$opt{tmpsuffix}";
- }
-
- bless( $self, $class );
-
- return $self;
-}
-
-sub tar {
- my ($self) = @_;
-
- $self->{tar} //= Archive::Tar->new( $self->{data_file} );
-
- return $self->{tar};
-}
-
-sub setup {
- my ($self) = @_;
-
- return $self->{setup};
-}
-
-sub load {
- return new(@_);
-}
-
-sub DESTROY {
- my ($self) = @_;
-
- if ( -d $self->{tmpdir} ) {
- for my $file ( read_dir( $self->{tmpdir} ) ) {
- unlink("$self->{tmpdir}/$file");
- }
- rmdir( $self->{tmpdir} );
- }
-}
-
-sub load_archive {
- my ($self) = @_;
-
- my $tmpdir = $self->{tmpdir};
-
- my @filelist = $self->tar->list_files;
- my @mim_files = sort grep { m{ \. mim $ }x } @filelist;
- my @json_files = map { ( split( qr{[.]}, $_ ) )[0] . '.json' } @mim_files;
-
- if ( $self->{fast_analysis} ) {
- splice( @mim_files, 4 );
- splice( @json_files, 4 );
- }
-
- $self->{filelist} = [@filelist];
- $self->{mim_files} = [@mim_files];
- $self->{mim_results} = [@json_files];
-
- $self->{log}{traces} = JSON->new->decode(
- $self->tar->get_content('src/apps/DriverEval/DriverLog.json') );
- $self->{setup} = JSON->new->decode( $self->tar->get_content('setup.json') );
-
- mkdir($tmpdir);
-
- for my $file (@mim_files) {
- $self->tar->extract_file( $file, "${tmpdir}/${file}" );
- }
-}
-
-sub load_cache {
- my ($self) = @_;
- my $tmpdir = $self->{tmpdir};
- my ( $dirname, $basename )
- = ( $self->{data_file} =~ m{ ^ (.*) / ([^/]+) . tar $ }x );
- my $cachefile = "${dirname}/cache/${basename}.json";
-
- if ( -e $cachefile ) {
- mkdir($tmpdir);
- write_file( $self->json_name, read_file($cachefile) );
- my $json = JSON->new->decode( read_file($cachefile) );
- if ( $json->{version} != $CACHE_VERSION ) {
- return 0;
- }
- $self->{setup} = $json->{setup};
- return 1;
- }
- return 0;
-}
-
-sub save_cache {
- my ($self) = @_;
- my $tmpdir = $self->{tmpdir};
- my ( $dirname, $basename )
- = ( $self->{data_file} =~ m{ ^ (.*) / ([^/]+) . tar $ }x );
- my $cachefile = "${dirname}/cache/${basename}.json";
-
- if ( not -d "${dirname}/cache" ) {
- mkdir("${dirname}/cache");
- }
-
- write_file( $cachefile, read_file( $self->json_name ) );
-}
-
-sub num_iterations {
- my ($self) = @_;
-
- return scalar @{ $self->{mim_files} };
-}
-
-sub sched_trigger_count {
- my ($self) = @_;
-
- if ( not $self->{sched_trigger_count} ) {
- $self->{sched_trigger_count} = 0;
- for my $run ( @{ $self->{log}{traces} } ) {
- $self->{sched_trigger_count} += @{ $run->{trace} };
- }
- }
-
- return $self->{sched_trigger_count};
-}
-
-sub merge {
- my ( $self, $file ) = @_;
-
- if ( not -e $file ) {
- return "Does not exist";
- }
-
- my $data = JSON->new->decode( read_file($file) );
- my $trig_count = $data->{triggers};
- if ( $self->sched_trigger_count != $trig_count ) {
- return sprintf( 'Expected %d trigger edges, got %d',
- $self->sched_trigger_count, $trig_count );
- }
-
- #printf("calibration check at: %.f±%.f %.f±%.f %.f±%.f\n",
- # $data->{calibration}{r0_mean},
- # $data->{calibration}{r0_std},
- # $data->{calibration}{r2_mean},
- # $data->{calibration}{r2_std},
- # $data->{calibration}{r1_mean},
- # $data->{calibration}{r1_std},
- #);
-
- # verify that state duration really is < 1.5 * setup{state_duration} and >
- # 0.5 * setup{state_duration}. otherwise we may have missed a trigger,
- # which wasn't detected earlier because of duplicate triggers elsewhere.
- my $data_idx = 0;
- for my $run ( @{ $self->{log}{traces} } ) {
- my $prev_elem = { name => q{} };
- for my $trace_elem ( @{ $run->{trace} } ) {
- my $log_elem = $data->{trace}[$data_idx];
- if ( $log_elem->{isa} eq 'state'
- and $trace_elem->{name} ne 'UNINITIALIZED'
- and $log_elem->{us} > $self->{setup}{state_duration} * 1500
- and $prev_elem->{name} ne 'txDone'
- and $prev_elem->{name} ne 'rxDone'
- and $prev_elem->{name} ne 'epilogue' )
- {
- return sprintf(
-'State %s (trigger index %d) took %.1f ms longer than expected',
- $trace_elem->{name},
- $data_idx,
- ( $log_elem->{us} / 1000 ) - $self->{setup}{state_duration}
- );
- }
- if ( $log_elem->{isa} eq 'state'
- and $trace_elem->{name} ne 'UNINITIALIZED'
- and $trace_elem->{name} ne 'TX'
- and $trace_elem->{name} ne 'RX'
- and $log_elem->{us} < $self->{setup}{state_duration} * 500 )
- {
- return sprintf(
-'State %s (trigger index %d) was %.1f ms shorter than expected',
- $trace_elem->{name},
- $data_idx,
- $self->{setup}{state_duration} - ( $log_elem->{us} / 1000 )
- );
- }
- $prev_elem = $trace_elem;
- $data_idx++;
- }
- }
-
- $data_idx = 0;
- for my $run ( @{ $self->{log}{traces} } ) {
- for my $trace_elem ( @{ $run->{trace} } ) {
- if ( $data->{trace}[$data_idx]{isa} ne $trace_elem->{isa} ) {
- croak();
- }
- delete $data->{trace}[$data_idx]{isa};
- push( @{ $trace_elem->{offline} }, $data->{trace}[$data_idx] );
- $data_idx++;
- }
- }
-
- push( @{ $self->{log}{calibration} }, $data->{calibration} );
-
- return;
-}
-
-sub preprocess {
- my ($self) = @_;
- my $tmpdir = $self->{tmpdir};
- my @files = @{ $self->{mim_files} };
- my $shunt = $self->{setup}{mimosa_shunt};
- my $voltage = $self->{setup}{mimosa_voltage};
- my @errmap;
-
- @files = map { "${tmpdir}/$_" } @files;
-
- if ( qx{parallel --version 2> /dev/null} =~ m{GNU parallel} ) {
- system( qw(parallel ../dfatool/bin/analyze.py),
- $voltage, $shunt, ':::', @files );
- }
- else {
- system( qw(parallel ../dfatool/bin/analyze.py),
- $voltage, $shunt, '--', @files );
- }
-
- for my $i ( 0 .. $#{ $self->{mim_results} } ) {
- my $file = $self->{mim_results}[$i];
- my $error = $self->merge("${tmpdir}/${file}");
-
- if ($error) {
- say "${file}: ${error}";
- push( @errmap, $i );
- }
- }
-
- if ( @errmap == @files ) {
- die("All MIMOSA measurements were erroneous. Aborting.\n");
- }
-
- $self->{log}{model} = $self->{model};
- $self->{log}{errmap} = \@errmap;
- $self->{log}{setup} = $self->{setup};
- $self->{log}{version} = $CACHE_VERSION;
- write_file( $self->json_name,
- JSON->new->convert_blessed->encode( $self->{log} ) );
-}
-
-sub analyze {
- my ( $self, @extra_files ) = @_;
- my $tmpdir = $self->{tmpdir};
-
- @extra_files = grep { $_ ne $self->json_name } @extra_files;
-
- for my $file ( $self->json_name, @extra_files ) {
- my $json = JSON->new->decode( read_file($file) );
- $json->{model} = $self->{model};
-
-# fix for incomplete json files: transitions can also depend on global parameters
- for my $run ( @{ $json->{traces} } ) {
- for my $i ( 0 .. $#{ $run->{trace} } ) {
- $run->{trace}[$i]{parameter}
- //= $run->{trace}[ $i - 1 ]{parameter};
- }
- }
-
- write_file( $file, JSON->new->convert_blessed->encode($json) );
- }
-
- system( '../dfatool/bin/merge.py', @{ $self->{merge_args} // [] },
- $self->json_name, @extra_files );
-
- my $json = JSON->new->decode( read_file( $self->json_name ) );
-
- $self->{aggregate} = $json->{aggregate};
-
- # debug
- write_file( "/tmp/DriverLog.json", JSON->new->pretty->encode($json) );
-}
-
-sub validate {
- my ( $self, @extra_files ) = @_;
- my $tmpdir = $self->{tmpdir};
-
- @extra_files = grep { $_ ne $self->json_name } @extra_files;
-
- for my $file ( $self->json_name, @extra_files ) {
- my $json = JSON->new->decode( read_file($file) );
- $json->{model} = $self->{model};
- my @errmap = @{ $json->{errmap} // [] };
-
-# fix for incomplete json files: transitions can also depend on global parameters
- for my $run ( @{ $json->{traces} } ) {
- for my $i ( 0 .. $#{ $run->{trace} } ) {
- $run->{trace}[$i]{parameter}
- //= $run->{trace}[ $i - 1 ]{parameter};
- }
- }
-
- # online durations count current state + next transition, but we
- # only want to analyze current state -> substract next transition.
- # Note that we can only do this on online data which has
- # corresponding offline data, i.e. where the offline data was not
- # erroneous
- for my $run ( @{ $json->{traces} } ) {
- if ( exists $run->{total_energy} ) {
-
- # splice changes the array (and thus the indices). so we need to
- # start removing elements at the end
- for my $erridx ( reverse @errmap ) {
- splice( @{ $run->{total_energy} }, $erridx, 1 );
- }
- }
- for my $i ( 0 .. $#{ $run->{trace} } ) {
- for my $erridx ( reverse @errmap ) {
- splice( @{ $run->{trace}[$i]{online} }, $erridx, 1 );
- }
- if ( $run->{trace}[$i]{isa} eq 'state' ) {
- for my $j ( 0 .. $#{ $run->{trace}[$i]{online} } ) {
- $run->{trace}[$i]{online}[$j]{time}
- -= $run->{trace}[ $i + 1 ]{offline}[$j]{us};
- }
- }
- }
- }
-
- write_file( $file, JSON->new->convert_blessed->encode($json) );
- }
-
- system( '../dfatool/bin/merge.py', @{ $self->{merge_args} // [] },
- '--validate', $self->json_name, @extra_files );
-
- my $json = JSON->new->decode( read_file( $self->json_name ) );
-
- $self->{aggregate} = $json->{aggregate};
-
- # debug
- write_file( "/tmp/DriverLog.json", JSON->new->pretty->encode($json) );
-}
-
-sub crossvalidate {
- my ( $self, @extra_files ) = @_;
- my $tmpdir = $self->{tmpdir};
-
- @extra_files = grep { $_ ne $self->json_name } @extra_files;
-
- for my $file ( $self->json_name, @extra_files ) {
- my $json = JSON->new->decode( read_file($file) );
- $json->{model} = $self->{model};
-
-# fix for incomplete json files: transitions can also depend on global parameters
- for my $run ( @{ $json->{traces} } ) {
- for my $i ( 0 .. $#{ $run->{trace} } ) {
- $run->{trace}[$i]{parameter}
- //= $run->{trace}[ $i - 1 ]{parameter};
- }
- }
-
- write_file( $file, JSON->new->convert_blessed->encode($json) );
- }
-
- system( '../dfatool/bin/merge.py', @{ $self->{merge_args} // [] },
- '--crossvalidate', $self->json_name, @extra_files );
-}
-
-sub data {
- my ($self) = @_;
- my $tmpdir = $self->{tmpdir};
- my $json = JSON->new->decode( read_file( $self->json_name ) );
- return $json;
-}
-
-sub json_name {
- my ($self) = @_;
- my $tmpdir = $self->{tmpdir};
-
- return "${tmpdir}/DriverLog.json";
-}
-
-1;