perlcompiler-optimizationrecompile

run, save variable state, interrupt execution, and reload variables from the last state before the interrupt


I am researching a way to interrupt the execution of the Perl script below in a way that I can save at what point the interaction was and I can run the next time starting from this interaction. Basically I saw other people speaking "save Perl's execution in the state in which it was". I'm looking inside the script and trying to understand how I can extract the interaction number and print out to a file and then reinsert in the script as the initial index of the next starting running.

use strict;
use warnings;
sub powerset(&@) {
    my $callback = shift;
    my $bitmask = '';
    my $bytes = @_/8;
    {
       my @indices = grep vec($bitmask, $_, 1), 0..$#_;
       $callback->( @_[@indices] );
       ++vec($bitmask, $_, 8) and last for 0 .. $bytes;
       redo if @indices != @_;
    }
}
 
powerset { print "[@_]\n" } 1..5;
my $i = 0;

For sample: Let's say I want the powerset of a set of 1..50, and then at the time I interrupt the execution the last line printed on the output is [1 2 3 4 6 7 8 11 12 13 15 16 17]. Then on the second startup of the script execution I just want to iterate just about the respective indice to the line [1 2 3 4 6 7 8 11 12 13 15 16 17] that was printed, I do not want to redo the iterations that have already had the result printed on the first run of the Perl file.

My goal is to be able to start a first run of file.pl and then print the output in an out.txt file, perl file.pl > out.txt, and then move the out.txt file to another directory (ie delete out.txt from the current directory). Then I must be able to continue interaction from the respective index to the line [1 2 3 4 6 7 8 11 12 13 15 16 17] that has already been printed.

Note: I know: "to suspend the program, you'd type ^ z (= ctrl-z) 1 while the program is running. Then Type BG TO SEND THE (STOPPED) Process in The Background. To Resume It Again, Type FG (or fg in case you have severe backgrounded - Type Jobs to List Them). " But that's not quite what I expected.


Solution

  • Perhaps what you are looking for can be demonstrated with following code snippet implementing checkpoint approach.

    The code implements two functions to store/restore execution stage and data_set.

    If the code is interrupted in the middle of the execution, then following re-run will continue starting after completed stage by restoring saved earlier data_set.

    NOTE: for demonstration put exit after store_checkpoint($data) at the end of STAGE2. Run the script once, remove added exit and re-run the script once more.

    use strict;
    use warnings;
    use feature 'say';
    
    use YAML;
    use Data::Dumper;
    
    my $checkpoint = 'checkpoint.dat';
    my $data;
    
    restore_checkpoint() if -e $checkpoint;
    
    STAGE1:
    $data->{data_set} = [ title => 'scientist', age => 27, address => '123 street, NY 12345 USA' ];
    $data->{next_stage} = 'STAGE2';
    store_checkpoint($data);
    
    STAGE2:
    $data->{data_set} = [ title => 'professor', age => 45, address => '234 street, WA 98230 USA' ];
    $data->{next_stage} = 'STAGE3';
    store_checkpoint($data);
    
    STAGE3:
    $data->{data_set} = [ title => 'doctor', age => 53, address => '345 street, OK 56789 USA' ];
    $data->{next_stage} = 'STAGE4';
    store_checkpoint($data);
    
    STAGE4:
    $data->{data_set} = [ title => 'CEO', age => 38, address => '456 street, MA 54321 USA' ];
    $data->{next_stage} = 'STAGE5';
    store_checkpoint($data);
    
    STAGE5:
    say 'Done';
    
    
    sub store_checkpoint {
        my $data = shift;
        say 'INFO: save_checkpoint ' . $data->{next_stage};
        
        open my $fh, '>', $checkpoint
            or die "Couldn't open $checkpoint";
            
        say $fh Dump($data);
            
        close $fh;
    }
    
    sub restore_checkpoint {
    
        say 'INFO: restore_checkpoint';
        
        open my $fh, '<', $checkpoint
            or die "Couldn't open $checkpoint";
            
        my $yaml = do { local $/; <$fh> };
        
        close $fh;
        
        $data = Load($yaml);
        say Dumper($data);
        
        say 'INFO: continue stage ' . $data->{next_stage};
        
        goto $data->{next_stage};
    }