2 # dqsub submits jobs using qsub with better options
3 # and is released under the terms of the GNU GPL version 3, or any
4 # later version, at your option. See the file README and COPYING for
6 # Copyright 2014 by Don Armstrong <don@donarmstrong.com>.
17 dqsub - submits jobs using qsub with better options
24 --queue, -q Queue to use
25 --interactive, -I call qsub interactively
27 --array array mode (one of 'chdir' or 'xargs' or '')
28 --array-from file to read arrays from (default STDIN)
30 --ppn processors per node to use
31 --mem memory to request
32 --dir Directory to run the script in (default current directory)
33 --debug, -d debugging level (Default 0)
34 --help, -h display this help
35 --man, -m display manual
43 This describes how dqsub will generate array jobs.
45 If no B<--array> is given, then the command and any additional
46 arguments given will be run using qsub.
48 If B<--array> is C<chdir>, then each line of the input given in
49 B<--array-from> will be used as a directory and the command and any
50 additional arguments given will run in each directory.
52 IF B<--array> is C<xargs>, then each line of the input given will be
53 considered to be an additional argument which will be given to the
54 command run in the current directory.
58 File to read array arguments from. If not provided, and B<--array> is
59 given, arguments will be read from STDIN.
63 Debug verbosity. (Default 0)
67 Display brief usage information.
82 use Cwd qw(getcwd abs_path);
85 my %options = (nodes => 1,
99 'array_from|array-from=s',
100 'array_slot_limit|array-slot-limit=i',
101 'ppn|processors-per-node=i',
104 'debug|d+','help|h|?','man|m');
106 # pod2usage() if $options{help};
107 # pod2usage({verbose=>2}) if $options{man};
109 $DEBUG = $options{debug};
112 if (not @ARGV and not $options{interactive}) {
113 push @USAGE_ERRORS,"You must provide a command to run";
115 if (defined $options{array} and $options{array} !~ /^(?:|chdir|xargs)$/i) {
116 push @USAGE_ERRORS,"--array must be one of chdir, xargs or '' if provided";
117 $options{array} = lc($options{array});
118 if ($options{array} eq '') {
119 $options{array} = undef;
122 if ($options{interactive} and @ARGV) {
123 push @USAGE_ERRORS,"Don't provide commands when you're asking for an interactive shell";
126 # pod2usage(join("\n",@USAGE_ERRORS)) if @USAGE_ERRORS;
127 print STDERR join("\n",@USAGE_ERRORS) and exit 1 if @USAGE_ERRORS;
129 # OK. Generate the options to qsub which we'll be using
130 my @qsub_options = generate_qsub_options(\%options);
132 if ($options{interactive}) {
133 print STDERR 'running: qsub '.join(' ',@qsub_options) if $DEBUG;
134 exec('qsub',@qsub_options);
137 if ($options{array}) {
138 @array = read_array_options(\%options) if $options{array};
139 # the -t option gives the range of elements for an array job
140 push @qsub_options,'-t','1-'. scalar @array;
141 if ($options{array_slot_limit}) {
142 $qsub_options[$#qsub_options] .= '%'.$options{array_slot_limit};
145 call_qsub(\@qsub_options,write_qsub_script(\%options,\@ARGV,\@array));
148 sub generate_qsub_options{
151 if (defined $options->{queue} and length $options->{queue}) {
152 push @qo,'-q',$options->{queue};
154 if (defined $options->{dir}) {
155 push @qo,'-d',abs_path($options->{dir});
157 push @qo,'-d',getcwd;
159 ## handle the -l options
161 push @l, 'nodes='.$options->{nodes};
162 if (defined $options->{ppn}) {
163 $l[$#l] .= ':ppn='.$options->{ppn};
165 if ($options->{mem}) {
166 push @l,'mem='.$options->{mem};
168 push @qo,'-l',join(',',@l) if @l;
169 if ($options->{interactive}) {
175 sub read_array_options{
178 if (defined $options->{array_from}) {
179 $fh = IO::File->new(defined $options->{array_from}) or
180 die "Unable to open $options->{array_from} for reading: $!";
191 my ($qsub_options,$script) = @_;
193 open $qsub_fh,'|-','qsub',@{$qsub_options},'-' or
194 die "Unable to start qsub: $!";
195 print {$qsub_fh} $script or
196 die "Unable to print to qsub: $!";
198 die "Unable to close qsub filehandle: $!";
201 sub write_qsub_script {
202 my ($opt,$arg,$array) = @_;
204 my $script = "#!/bin/bash\n";
205 my $command = join(' ',map {qq('$_')} @{$arg});
207 # this script was written by dqsub
209 if (defined $opt->{array}) {
210 my $array_opt = join("\n",@{$array});
212 OPT=\$(sed -n -e "\$PBS_ARRAYID p"<<'_HERE_DOC_END_'
217 if ($opt->{array} eq 'chdir') {
224 exec $command "\$OPT";
229 # there's no array, so just executing the command with arguments