File Coverage

blib/lib/HPC/Runner/Slurm.pm
Criterion Covered Total %
statement 42 132 31.8
branch 0 40 0.0
condition 0 6 0.0
subroutine 14 16 87.5
pod n/a
total 56 194 28.8


line stmt bran cond sub pod time code
1             package HPC::Runner::Slurm;
2              
3 1     1   13698 use File::Path qw(make_path remove_tree);
  1         1  
  1         72  
4 1     1   625 use File::Temp qw/ tempfile tempdir /;
  1         15833  
  1         54  
5 1     1   474 use IO::File;
  1         679  
  1         97  
6 1     1   417 use IO::Select;
  1         1045  
  1         42  
7 1     1   5 use Cwd;
  1         1  
  1         43  
8 1     1   877 use IPC::Open3;
  1         1932  
  1         66  
9 1     1   5 use Symbol;
  1         1  
  1         38  
10 1     1   453 use Template;
  1         14800  
  1         50  
11 1     1   801 use Log::Log4perl qw(:easy);
  1         35178  
  1         7  
12 1     1   1372 use DateTime;
  1         89356  
  1         37  
13 1     1   587 use Data::Dumper;
  1         4449  
  1         59  
14 1     1   6 use List::Util qw/shuffle/;
  1         1  
  1         76  
15              
16 1     1   534 use Moose;
  1         312432  
  1         7  
17 1     1   4910 use namespace::autoclean;
  1         2  
  1         9  
18             extends 'HPC::Runner::Scheduler';
19             with 'MooseX::SimpleConfig';
20              
21             # For pretty man pages!
22             $ENV{TERM}='xterm-256color';
23             our $VERSION = '2.56';
24              
25             =head1 NAME
26              
27             HPC::Runner::Slurm - Job Submission to Slurm
28              
29             =head1 SYNOPSIS
30              
31             Please see the indepth documentation at L<HPC::Runner::Usage>.
32              
33             package Main;
34             extends 'HPC::Runner::Slurm';
35              
36             Main->new_with_options(infile => '/path/to/commands');
37              
38             This module is a wrapper around sbatch and can be used to submit arbirtary bash commands to slurm.
39              
40             It has two levels of management. The first is the main sbatch command, and the second is the actual job, which runs commands in parallel, controlled by HPC::Runner::Threads or HPC::Runner::MCE.
41              
42             It supports job dependencies. Put in the command 'wait' to tell slurm that some job or jobs depend on some other jobs completion. Put in the command 'newnode' to tell HPC::Runner::Slurm to submit the job to a new node.
43              
44             The only necessary option is the --infile.
45              
46             =head2 Submit Script
47              
48             cmd1
49             cmd2 && cmd3
50             cmd4 \
51             --option cmd4 \
52             #Tell HPC::Runner::Slurm to put in some job dependencies.
53             wait
54             cmd5
55             #Tell HPC::Runner::Slurm to pass things off to a new node, but this job doesn't depend on the previous
56             newnode
57             cmd6
58              
59             =head2 get_nodes
60              
61             Get the nodes from sinfo if not supplied
62              
63             If the nodelist is supplied partition must be supplied
64              
65             =cut
66              
67             sub get_nodes{
68 0     0     my($self) = @_;
69              
70 0           $DB::single=2;
71             # #Fix - had this backwards
72 0 0         return if $self->slurm_decides;
73 0 0 0       if($self->nodelist && !$self->partition){
74 0           print "If you define a nodelist you must define a partition!\n";
75 0           die;
76             }
77              
78 0           my @s = `sinfo -r`;
79 0           my $href;
80              
81 0           foreach my $s (@s) {
82 0           my @nodes = ();
83 0           my $noderef = [];
84 0 0         next if $s =~ m/^PARTITION/i;
85 0           my @t = ($s =~ /(\S+)/g);
86 0           $t[0] =~ s/\*//g;
87 0 0         next unless $t[1] =~ m/up/;
88              
89 0           my $nodes = $t[5];
90              
91             #list of nodes
92 0 0         if($nodes =~ m/\[/){
93 0           my($n) = ($nodes =~ m/\[(\S+)\]/g);
94 0           my @n = split(",", $n);
95              
96 0           foreach my $nt (@n) {
97 0 0         if($nt =~ m/-/){
98 0           my(@m) = ($nt =~ m/(\d+)-(\d+)/g);
99 0           push(@$noderef, ($m[0]..$m[1]));
100             }
101             else{
102 0           my($m) = ($nt =~ m/(\d+)/g);
103 0           push(@$noderef, $m);
104             }
105             }
106             }
107             else{ #only one node
108 0           my($m) = ($nodes =~ m/(\d+)/g);
109 0           push(@$noderef, $m);
110             }
111              
112 0 0         if(exists $href->{$t[0]}){
113 0           my $aref = $href->{$t[0]};
114 0 0         push(@$aref, @$noderef) if $noderef;
115 0           $href->{$t[0]} = $aref;
116             }
117             else{
118             # $href->{$t[0]} = \@nodes;
119 0           $href->{$t[0]} = $noderef;
120             }
121             }
122              
123             #Got the nodes lets find out which partition has the most nodes
124             #Unless we already have a defined partition, then we don't care
125              
126 0           my $holder = 0;
127 0           my $bpart;
128              
129 0           while(my($part, $nodes) = each %{$href}){
  0            
130 0 0         next unless $nodes;
131 0 0         next unless ref($nodes) eq "ARRAY";
132              
133 0           @$nodes = map { $part.$_ } @$nodes;
  0            
134              
135 0 0         if(scalar @$nodes > $holder){
136 0           $holder = scalar @$nodes;
137 0           $bpart = $part;
138             }
139             }
140              
141             #Allow for user defined partition and/or partition/nodelist
142             #Also randomize nodelist so we quit hammering the first node
143 0           $DB::single=2;
144              
145 0 0 0       if($self->partition && $self->nodelist){
    0          
146 0           $DB::single=2;
147 0           return;
148             }
149             elsif($self->partition){
150 0           $DB::single=2;
151 0           my @shuffle = shuffle @{$href->{$self->partition}};
  0            
152             # $self->nodelist($href->{$self->partition});
153 0           $self->nodelist(\@shuffle);
154 0           return;
155             }
156              
157 0           $self->partition($bpart);
158             # $self->nodelist($href->{$bpart});
159 0           my @shuffle = shuffle @{$href->{$bpart}};
  0            
160 0           $self->nodelist(\@shuffle);
161             }
162              
163              
164              
165             =head2 submit_slurm()
166              
167             Submit jobs to slurm queue using sbatch.
168              
169             This subroutine was just about 100% from the following perlmonks discussions. All that I did was add in some logging.
170              
171             http://www.perlmonks.org/?node_id=151886
172             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
173              
174             perl command.pl 1
175             perl command.pl 2
176             #so on and so forth
177              
178             =cut
179              
180             sub submit_slurm{
181 0     0     my $self = shift;
182              
183 0           my ($infh,$outfh,$errfh);
184 0           $errfh = gensym(); # if you uncomment this line, $errfh will
185             # never be initialized for you and you
186             # will get a warning in the next print
187             # line.
188 0           my $cmdpid;
189 0           eval{
190 0           $cmdpid = open3($infh, $outfh, $errfh, "sbatch ".$self->slurmfile);
191             };
192 0 0         die $@ if $@;
193              
194 0           my $sel = new IO::Select; # create a select object
195 0           $sel->add($outfh,$errfh); # and add the fhs
196              
197 0           my($stdout, $stderr, $jobid);
198              
199 0           while(my @ready = $sel->can_read) {
200 0           foreach my $fh (@ready) { # loop through them
201 0           my $line;
202             # read up to 4096 bytes from this fh.
203 0           my $len = sysread $fh, $line, 4096;
204 0 0         if(not defined $len){
    0          
205             # There was an error reading
206             #$self->log->fatal("Error from child: $!");
207 0           $self->log_main_messages('fatal', "Error from child: $!");
208             } elsif ($len == 0){
209             # Finished reading from this FH because we read
210             # 0 bytes. Remove this handle from $sel.
211 0           $sel->remove($fh);
212 0           next;
213             } else { # we read data alright
214 0 0         if($fh == $outfh) {
    0          
215 0           $stdout .= $line;
216             #$self->log->info($line);
217 0           $self->log_main_messages('debug', $line)
218             } elsif($fh == $errfh) {
219 0           $stderr .= $line;
220             #$self->log->error($line);
221 0           $self->log_main_messages('error', $line);
222             } else {
223             #$self->log->fatal("Shouldn't be here!\n");
224 0           $self->log_main_messages('fatal', "Shouldn't be here!");
225             }
226             }
227             }
228             }
229              
230 0           waitpid($cmdpid, 1);
231 0           my $exitcode = $?;
232              
233 0 0         ($jobid) = $stdout =~ m/Submitted batch job (\d.*)$/ if $stdout;
234 0 0         if(!$jobid){
235 0           print "No job was submitted! Please check to make sure you have loaded modules shared and slurm!\nFull error is:\t$stderr\n$stdout\nEnd Job error";
236 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";
237 0           $self->submit_to_slurm(0);
238             }
239             else{
240 0           push(@{$self->jobref->[-1]}, $jobid);
  0            
241 0           print "Submitting job ".$self->slurmfile."\n\tWith Slurm jobid $jobid\n";
242             }
243             }
244              
245             =head1 AUTHOR
246              
247             Jillian Rowe, C<< <jillian.e.rowe at gmail.com> >>
248              
249             =head1 BUGS
250              
251             Please report any bugs or feature requests to C<bug-runner-init at rt.cpan.org>, or through
252             the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=HPC-Runner-Slurmm>. I will be notified, and then you'll
253             automatically be notified of progress on your bug as I make changes.
254              
255              
256             =head1 SUPPORT
257              
258             You can find documentation for this module with the perldoc command.
259              
260             perldoc HPC::Runner::Slurm
261              
262              
263             You can also look for information at:
264              
265             =over 4
266              
267             =item * RT: CPAN's request tracker (report bugs here)
268              
269             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=HPC-Runner-Slurm>
270              
271             =item * AnnoCPAN: Annotated CPAN documentation
272              
273             L<http://annocpan.org/dist/HPC-Runner-Slurm>
274              
275             =item * CPAN Ratings
276              
277             L<http://cpanratings.perl.org/d/HPC-Runner-Slurm>
278              
279             =item * Search CPAN
280              
281             L<http://search.cpan.org/dist/HPC-Runner-Slurm/>
282              
283             =back
284              
285             =head1 Acknowledgements
286              
287             Before Version 2.41
288              
289             This module was originally developed at and for Weill Cornell Medical
290             College in Qatar within ITS Advanced Computing Team. With approval from
291             WCMC-Q, this information was generalized and put on github, for which
292             the authors would like to express their gratitude.
293              
294             As of Version 2.41:
295              
296             This modules continuing development is supported by NYU Abu Dhabi in the Center for Genomics and Systems Biology.
297             With approval from NYUAD, this information was generalized and put on bitbucket, for which
298             the authors would like to express their gratitude.
299              
300              
301             =head1 LICENSE AND COPYRIGHT
302              
303             Copyright 2014 Weill Cornell Medical College in Qatar.
304              
305             This program is free software; you can redistribute it and/or modify it
306             under the terms of the the Artistic License (2.0). You may obtain a
307             copy of the full license at:
308              
309             L<http://www.perlfoundation.org/artistic_license_2_0>
310              
311             Any use, modification, and distribution of the Standard or Modified
312             Versions is governed by this Artistic License. By using, modifying or
313             distributing the Package, you accept this license. Do not use, modify,
314             or distribute the Package, if you do not accept this license.
315              
316             If your Modified Version has been derived from a Modified Version made
317             by someone other than you, you are nevertheless required to ensure that
318             your Modified Version complies with the requirements of this license.
319              
320             This license does not grant you the right to use any trademark, service
321             mark, tradename, or logo of the Copyright Holder.
322              
323             This license includes the non-exclusive, worldwide, free-of-charge
324             patent license to make, have made, use, offer to sell, sell, import and
325             otherwise transfer the Package with respect to any patent claims
326             licensable by the Copyright Holder that are necessarily infringed by the
327             Package. If you institute patent litigation (including a cross-claim or
328             counterclaim) against any party alleging that the Package constitutes
329             direct or contributory patent infringement, then this Artistic License
330             to you shall terminate on the date that such litigation is filed.
331              
332             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
333             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
334             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
335             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
336             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
337             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
338             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
339             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
340              
341              
342             =cut
343              
344             __PACKAGE__->meta->make_immutable;
345             #use namespace::autoclean;
346              
347             1;