File Coverage

blib/lib/HPC/Runner/PBS.pm
Criterion Covered Total %
statement 42 85 49.4
branch 0 12 0.0
condition n/a
subroutine 14 17 82.3
pod n/a
total 56 114 49.1


line stmt bran cond sub pod time code
1             package HPC::Runner::PBS;
2              
3 1     1   13656 use File::Path qw(make_path remove_tree);
  1         2  
  1         79  
4 1     1   621 use File::Temp qw/ tempfile tempdir /;
  1         17007  
  1         60  
5 1     1   403 use IO::File;
  1         739  
  1         110  
6 1     1   420 use IO::Select;
  1         1078  
  1         36  
7 1     1   4 use Cwd;
  1         1  
  1         40  
8 1     1   419 use IPC::Open3;
  1         1989  
  1         45  
9 1     1   6 use Symbol;
  1         1  
  1         38  
10 1     1   572 use Template;
  1         14098  
  1         35  
11 1     1   756 use Log::Log4perl qw(:easy);
  1         48201  
  1         9  
12 1     1   2064 use DateTime;
  1         82845  
  1         37  
13 1     1   532 use Data::Dumper;
  1         4295  
  1         69  
14 1     1   8 use List::Util qw/shuffle/;
  1         1  
  1         74  
15             # use IPC::Cmd qw/can_run/;
16              
17 1     1   587 use Moose;
  1         330713  
  1         6  
18 1     1   4770 use namespace::autoclean;
  1         1  
  1         9  
19              
20             extends 'HPC::Runner::Scheduler';
21             #extends 'HPC::Runner::Slurm';
22             with 'MooseX::SimpleConfig';
23              
24             our $VERSION = '0.11';
25              
26             # For pretty man pages!
27             $ENV{TERM}='xterm-256color';
28              
29             =encoding utf-8
30              
31             =head1 NAME
32              
33             HPC::Runner::PBS - Submit jobs to a PBS job scheduler.
34              
35             =head1 DESCRIPTION
36              
37             HPC::Runner::PBS is a wrapper around qsub and can be used to submit arbirtary bash commands to PBS.
38              
39             It has two levels of management. The first is the main qsub command, and the second is the actual job, which runs commands in parallel, controlled by HPC::Runner::Threads or HPC::Runner::MCE.
40              
41             It supports job dependencies. Put in the command 'wait' to tell PBS that some job or jobs depend on some other jobs completion. Put in the command 'newnode' to tell HPC::Runner::PBS to submit the job to a new node.
42              
43             The only necessary option is the --infile, and --queue if you wish to run on a queue besides s48.
44              
45             The bulk of this code is extended from HPC::Runner::Slurm.
46              
47             =head2 queue
48              
49             Same as the partition in HPC::Runner::Slurm
50              
51             =cut
52              
53             has 'queue' => (
54             is => 'rw',
55             isa => 'Str|Undef',
56             required => 0,
57             documentation => q{PBS queue for job submission. Defaults is none, pbs decides.},
58             predicate => 'has_queue',
59             clearer => 'clear_queue',
60             );
61              
62             has '+partition' =>(
63             isa => 'Str | Undef',
64             #alias => 'queue',
65             #predicate => 'has_queue',
66             #clearer => 'clear_queue',
67             );
68              
69             =head2 walltime
70              
71             Define PBS walltime
72              
73             =cut
74              
75             has 'walltime' => (
76             is => 'rw',
77             isa => 'Str',
78             required => 1,
79             default => '04:00:00',
80             predicate => 'has_walltime',
81             clearer => 'clear_walltime,'
82             );
83              
84             =head2 mem
85              
86             =cut
87              
88             has 'mem' => (
89             is => 'rw',
90             isa => 'Str|Undef',
91             predicate => 'has_mem',
92             clearer => 'clear_mem',
93             required => 0,
94             documentation => q{Supply a memory limit},
95             );
96              
97             =head2 template_file
98              
99             actual template file
100              
101             One is generated here for you, but you can always supply your own with --template_file /path/to/template
102              
103             =cut
104              
105             has '+template_file' => (
106             is => 'rw',
107             isa => 'Str',
108             default => sub {
109             my $self = shift;
110              
111             my($fh, $filename) = tempfile();
112              
113             my $tt =<<EOF;
114             #!/bin/bash
115             #
116             #PBS -N [% JOBNAME %]
117             [% IF self.has_queue %]
118             #PBS -q [% self.queue %]
119             [% END %]
120             #PBS -l nodes=1:ppn=[% CPU %]
121             [% IF self.has_walltime %]
122             #PBS -l walltime=[% self.walltime %]
123             [% END %]
124             #PBS -j oe
125             #PBS -o localhost:[% OUT %]
126             [% IF self.has_mem %]
127             #PBS -l mem=[% self.mem %]
128             [% END %]
129              
130             [% IF AFTEROK %]
131             #PBS -W depend=afterok:[% AFTEROK %]
132             [% END %]
133              
134             [% IF MODULE %]
135             [% FOR d = MODULE %]
136             module load [% d %]
137             [% END %]
138             [% END %]
139              
140             [% COMMAND %]
141             EOF
142              
143             print $fh $tt;
144             $DB::single=2;
145             return $filename;
146             },
147             );
148              
149             =head1 SUBROUTINES/METHODS
150              
151             =cut
152              
153             =head2 run()
154              
155             First sub called
156             Calling system module load * does not work within a screen session!
157              
158             =cut
159              
160             sub BUILD {
161 0     0     my $self = shift;
162 0           $self->logname('pbs_logs');
163 0           $self->log($self->init_log);
164             }
165              
166             sub get_nodes {
167 0     0     my($self) = @_;
168              
169             #$self->partition($self->queue) if $self->partition eq "";
170              
171 0           $DB::single=2;
172              
173 0           $self->nodelist([]);
174              
175 0           $DB::single=2;
176             }
177              
178             =head2 submit_slurm()
179              
180             Submit jobs to PBS using qsub
181              
182             Uses almost the same logic as submit_slurm, so we'll keep that.
183              
184             This subroutine was just about 100% from the following perlmonks discussions. All that I did was add in some logging.
185              
186             http://www.perlmonks.org/?node_id=151886
187             You can use the script at the top to test the runner. Just download it, make it executable, and put it in the infile as
188              
189             perl command.pl 1
190             perl command.pl 2
191             #so on and so forth
192              
193             =cut
194              
195             sub submit_slurm{
196 0     0     my $self = shift;
197              
198 0           my ($infh,$outfh,$errfh);
199 0           $errfh = gensym(); # if you uncomment this line, $errfh will
200             # never be initialized for you and you
201             # will get a warning in the next print
202             # line.
203 0           my $cmdpid;
204 0           eval{
205 0           $cmdpid = open3($infh, $outfh, $errfh, "qsub ".$self->slurmfile);
206             };
207 0 0         die $@ if $@;
208              
209 0           my $sel = new IO::Select; # create a select object
210 0           $sel->add($outfh,$errfh); # and add the fhs
211              
212 0           my($stdout, $stderr, $jobid);
213              
214 0           while(my @ready = $sel->can_read) {
215 0           foreach my $fh (@ready) { # loop through them
216 0           my $line;
217             # read up to 4096 bytes from this fh.
218 0           my $len = sysread $fh, $line, 4096;
219 0 0         if(not defined $len){
    0          
220             # There was an error reading
221             #$self->log->fatal("Error from child: $!");
222 0           $self->log_main_messages('fatal', "Error from child: $!");
223             } elsif ($len == 0){
224             # Finished reading from this FH because we read
225             # 0 bytes. Remove this handle from $sel.
226 0           $sel->remove($fh);
227 0           next;
228             } else { # we read data alright
229 0 0         if($fh == $outfh) {
    0          
230 0           $stdout .= $line;
231             #$self->log->info($line);
232 0           $self->log_main_messages('debug', $line);
233             } elsif($fh == $errfh) {
234 0           $stderr .= $line;
235             #$self->log->error($line);
236 0           $self->log_main_messages('error', "There was an error!\n".$line);
237             } else {
238             #$self->log->fatal("Shouldn't be here!\n");
239 0           $self->log_main_messages('fatal', "We shouldn't be here, something has gone wrong\n");
240             }
241             }
242             }
243             }
244              
245 0           waitpid($cmdpid, 1);
246 0           my $exitcode = $?;
247              
248             #($jobid) = $stdout =~ m/(\w.*)$/ if $stdout;
249 0           ($jobid) = $stdout;
250 0           chomp($jobid);
251              
252 0 0         if(!$jobid){
253 0           print "No job was submitted! Please check your things!\nFull error is:\t$stderr\n$stdout\nEnd Job error";
254 0           print "Submit scripts will be written, but will not be submitted to the queue. Please look at your files in ".$self->outdir." for more information\n";
255 0           $self->submit_to_slurm(0);
256             }
257             else{
258 0           push(@{$self->jobref->[-1]}, $jobid);
  0            
259 0           print "Submitting job ".$self->slurmfile."\n\tWith PBS jobid $jobid\n";
260             }
261             #Fix for jobs not showing up...
262 0           sleep(5);
263             }
264              
265              
266             __PACKAGE__->meta->make_immutable;
267              
268             1;
269              
270             __END__
271              
272              
273             =head1 SYNOPSIS
274              
275             use HPC::Runner::PBS;
276              
277             =head1 AUTHOR
278              
279             Jillian Rowe E<lt>jillian.e.rowe@gmail.comE<gt>
280              
281             =head1 Acknowledgements
282              
283             This module was originally developed at and for NYU Abu Dhabi in the Center for Genomics and Systems Biology.
284             With approval from NYUAD, this information was generalized and put on github, for which
285             the authors would like to express their gratitude.
286              
287             =head1 COPYRIGHT
288              
289             Copyright 2015- Jillian Rowe
290              
291             =head1 LICENSE
292              
293             This library is free software; you can redistribute it and/or modify
294             it under the same terms as Perl itself.
295              
296             =head1 SEE ALSO
297              
298             =cut