line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Makefile::Parallel; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
44079
|
use Makefile::Parallel::Grammar; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
use Log::Log4perl; |
5
|
|
|
|
|
|
|
use Proc::Simple; |
6
|
|
|
|
|
|
|
use Clone qw(clone); |
7
|
|
|
|
|
|
|
use Time::HiRes qw(gettimeofday tv_interval); |
8
|
|
|
|
|
|
|
use Time::Interval; |
9
|
|
|
|
|
|
|
use Time::Piece::ISO; |
10
|
|
|
|
|
|
|
use GraphViz; |
11
|
|
|
|
|
|
|
use Digest::MD5; |
12
|
|
|
|
|
|
|
use Data::Dumper; |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
use warnings; |
15
|
|
|
|
|
|
|
use strict; |
16
|
|
|
|
|
|
|
our $VERSION = '0.09'; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=encoding utf8 |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 NAME |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
Makefile::Parallel - A distributed parallel makefile |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
=head1 SYNOPSIS |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
This module should not be called directly. Please see the perldoc of |
27
|
|
|
|
|
|
|
the pmake program on the /examples directory of this distribution. |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=cut |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# Module Stuff |
32
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
33
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( 'all' => [ qw() ] ); |
34
|
|
|
|
|
|
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
our @EXPORT = qw( process_makefile ); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
my $logger; |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
my $queue; |
41
|
|
|
|
|
|
|
my $running = {}; # Holds the running ID's (ID -> info) |
42
|
|
|
|
|
|
|
my $finnished = {}; # Holds the finnished ID's (ID -> info) |
43
|
|
|
|
|
|
|
my $scheduler; # Holds the scheduler engine |
44
|
|
|
|
|
|
|
my $counter = 0; # Holds the order of the executed processes |
45
|
|
|
|
|
|
|
my $filename; # Holds the filename of the makefile |
46
|
|
|
|
|
|
|
my $debug; # TRUE if we got debug enabled |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# This stuff deals with the interruption (Ctrl + C) |
49
|
|
|
|
|
|
|
$SIG{INT} = \&process_interrupt; |
50
|
|
|
|
|
|
|
my $interrupted = 0; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=head1 process_makefile |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
Main function. Accepts a file to parse and a |
55
|
|
|
|
|
|
|
hash reference with options. |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
TODO: Document options |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=cut |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub process_makefile { |
62
|
|
|
|
|
|
|
my ($file, $options) = @_; |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# Set sensible defaults |
65
|
|
|
|
|
|
|
$options ||= {}; |
66
|
|
|
|
|
|
|
$options->{scheduler} ||= 'LOCAL'; |
67
|
|
|
|
|
|
|
$options->{local} ||= '1'; # Default CPU's on local mode |
68
|
|
|
|
|
|
|
$options->{dump} ||= 0; |
69
|
|
|
|
|
|
|
$options->{clean} ||= 0; |
70
|
|
|
|
|
|
|
$options->{clock} ||= 10; |
71
|
|
|
|
|
|
|
$options->{debug} ||= 0; |
72
|
|
|
|
|
|
|
$options->{continue} ||= 0; |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
# TODO: Give more flexibility |
75
|
|
|
|
|
|
|
if($options->{scheduler} eq 'PBS') { |
76
|
|
|
|
|
|
|
use Makefile::Parallel::Scheduler::PBS; |
77
|
|
|
|
|
|
|
$scheduler = Makefile::Parallel::Scheduler::PBS->new(); |
78
|
|
|
|
|
|
|
$scheduler->{mail} = $options->{mail} if $options->{mail}; |
79
|
|
|
|
|
|
|
} else { |
80
|
|
|
|
|
|
|
use Makefile::Parallel::Scheduler::Local; |
81
|
|
|
|
|
|
|
$scheduler = Makefile::Parallel::Scheduler::Local->new({ max => $options->{local} }); |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# Debug settings |
85
|
|
|
|
|
|
|
if($options->{debug}) { |
86
|
|
|
|
|
|
|
# Clean logs... ## FIXME - do not rely on OS. |
87
|
|
|
|
|
|
|
`rm -rf log/`; mkdir "log"; |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
my $conf = q( |
90
|
|
|
|
|
|
|
log4perl.category.PMake = DEBUG, Logfile, Screen |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
log4perl.appender.Logfile = Log::Log4perl::Appender::File |
93
|
|
|
|
|
|
|
log4perl.appender.Logfile.filename = log/makefile.log |
94
|
|
|
|
|
|
|
log4perl.appender.Logfile.layout = Log::Log4perl::Layout::PatternLayout |
95
|
|
|
|
|
|
|
log4perl.appender.Logfile.layout.ConversionPattern = [%d] [%p] %F(%L) %m%n |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
log4perl.appender.Screen = Log::Log4perl::Appender::Screen |
98
|
|
|
|
|
|
|
log4perl.appender.Screen.stderr = 0 |
99
|
|
|
|
|
|
|
log4perl.appender.Screen.layout = Log::Log4perl::Layout::PatternLayout |
100
|
|
|
|
|
|
|
log4perl.appender.Screen.layout.ConversionPattern = [%d] %m%n |
101
|
|
|
|
|
|
|
); |
102
|
|
|
|
|
|
|
Log::Log4perl::init(\$conf); |
103
|
|
|
|
|
|
|
$debug = 1; |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
else { |
106
|
|
|
|
|
|
|
my $conf = q( |
107
|
|
|
|
|
|
|
log4perl.category.PMake = INFO, Screen |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
log4perl.appender.Screen = Log::Log4perl::Appender::Screen |
110
|
|
|
|
|
|
|
log4perl.appender.Screen.stderr = 0 |
111
|
|
|
|
|
|
|
log4perl.appender.Screen.layout = Log::Log4perl::Layout::PatternLayout |
112
|
|
|
|
|
|
|
log4perl.appender.Screen.layout.ConversionPattern = [%d] %m%n |
113
|
|
|
|
|
|
|
); |
114
|
|
|
|
|
|
|
Log::Log4perl::init(\$conf); |
115
|
|
|
|
|
|
|
$debug = 0; |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
$logger = Log::Log4perl::get_logger("PMake"); |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
# Parse the file |
120
|
|
|
|
|
|
|
$logger->info("Trying to parse \"$file\""); |
121
|
|
|
|
|
|
|
$queue = Makefile::Parallel::Grammar->parseFile($file); |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
if($queue) { $logger->info("Parse ok.. proceeding to plan the scheduling"); } |
124
|
|
|
|
|
|
|
else { $logger->error("Parse failed, aborting..."); return } |
125
|
|
|
|
|
|
|
$filename = $file; |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# Copy perl routines to perl actions |
128
|
|
|
|
|
|
|
if(defined $queue->[-1]{perl}) { |
129
|
|
|
|
|
|
|
for my $job (@{$queue}) { |
130
|
|
|
|
|
|
|
if(defined $job->{action}[0]{perl}) { |
131
|
|
|
|
|
|
|
$job->{perl} = $queue->[-1]{perl}; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
delete $queue->[-1]; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# Dump if the user want it |
138
|
|
|
|
|
|
|
die Dumper $queue if($options->{dump}); |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# Clean the temporary files if we are PBS |
141
|
|
|
|
|
|
|
clean() if($options->{clean}); |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# Recover the journal if the user wants to continue |
144
|
|
|
|
|
|
|
journal_recover() if ($options->{continue}); |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# Enter the loop |
147
|
|
|
|
|
|
|
while(1) { |
148
|
|
|
|
|
|
|
# $logger->debug("New loop starting"); |
149
|
|
|
|
|
|
|
loop(); |
150
|
|
|
|
|
|
|
# $logger->debug("Loop processed, sleeping"); |
151
|
|
|
|
|
|
|
sleep $options->{clock}; |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=head1 journal_recover |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
Tries to recover the journal of the last makefile run. |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=cut |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
sub journal_recover { |
162
|
|
|
|
|
|
|
my $journal = do "$filename.journal" or die "Can't open $filename.journal: $!"; |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
my $md5 = calc_makefile_md5(); |
165
|
|
|
|
|
|
|
if($journal->{md5} ne $md5) { |
166
|
|
|
|
|
|
|
$logger->warn("MD5 Check Failed... The original Makefile was changed!! CONTINUE AT YOUR OWN RISK!"); |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# Restore the finnished list |
170
|
|
|
|
|
|
|
$finnished = $journal->{finnished}; |
171
|
|
|
|
|
|
|
$counter = $journal->{counter}; |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# Ignore jobs already concluded |
174
|
|
|
|
|
|
|
# 1a passagem - cálculo das variáveis |
175
|
|
|
|
|
|
|
for my $job (@{$queue}) { |
176
|
|
|
|
|
|
|
next unless $job; |
177
|
|
|
|
|
|
|
if(is_finnished($job->{rule}{id})) { |
178
|
|
|
|
|
|
|
# If we got asShell to run, run it! |
179
|
|
|
|
|
|
|
find_and_run_asShell($job->{rule}{id}); |
180
|
|
|
|
|
|
|
# If we got asPerl to run, run it! |
181
|
|
|
|
|
|
|
find_and_run_asPerl($job->{rule}{id}); |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
# 2a passagem - remoção dos já executados |
186
|
|
|
|
|
|
|
my $new_queue = []; |
187
|
|
|
|
|
|
|
for my $job (@{$queue}) { |
188
|
|
|
|
|
|
|
next unless $job; |
189
|
|
|
|
|
|
|
push @{$new_queue}, $job unless is_finnished($job->{rule}{id}); |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
$queue = $new_queue; |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
$logger->warn("Journal recovered.. Cross your fingers now..."); |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=head1 clean |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
This function is responsible to clean all the temporary files |
199
|
|
|
|
|
|
|
created by the PBS system. It should be used only on the PBS scheduler |
200
|
|
|
|
|
|
|
method. |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=cut |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
sub clean { |
205
|
|
|
|
|
|
|
$scheduler->clean($queue); |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
$logger->info("Temporary files cleaned"); |
208
|
|
|
|
|
|
|
exit(0); |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=head1 loop |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
Loop it baby :D |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=cut |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
sub loop { |
218
|
|
|
|
|
|
|
reap_dead_bodies(); |
219
|
|
|
|
|
|
|
dispatch(); |
220
|
|
|
|
|
|
|
write_journal(); |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=head1 reap_dead_bodies |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
This function is responsible of reaping the jobs that are |
226
|
|
|
|
|
|
|
finnished. If the job needs to run something at the end |
227
|
|
|
|
|
|
|
(example, find i <- grep | awk...) it is executed and the job |
228
|
|
|
|
|
|
|
queue is expanded. |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=cut |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
sub reap_dead_bodies { |
233
|
|
|
|
|
|
|
# Search all running procs for someone who died |
234
|
|
|
|
|
|
|
for my $runid (keys %{$running}) { |
235
|
|
|
|
|
|
|
if($scheduler->poll($running->{$runid}, $logger)) { |
236
|
|
|
|
|
|
|
# Still running |
237
|
|
|
|
|
|
|
} else { |
238
|
|
|
|
|
|
|
# No running anymore, remove from running and save |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
# Save time stats |
241
|
|
|
|
|
|
|
my $t1 = [gettimeofday]; |
242
|
|
|
|
|
|
|
my $elapsed = tv_interval($running->{$runid}->{starttime}, $t1); |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
$running->{$runid}->{stoptime} = $t1; |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
$elapsed = parseInterval(seconds => int($elapsed), Small => 1); |
247
|
|
|
|
|
|
|
$running->{$runid}->{elapsed} = $elapsed; |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
# Give user some feedback |
250
|
|
|
|
|
|
|
$logger->info("Process " . $scheduler->get_id($running->{$runid}) |
251
|
|
|
|
|
|
|
. " (" . $running->{$runid}->{rule}->{id} |
252
|
|
|
|
|
|
|
. ") has terminated [$elapsed]"); |
253
|
|
|
|
|
|
|
$finnished->{$runid} = $running->{$runid}; |
254
|
|
|
|
|
|
|
delete $running->{$runid}; |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
# Don't do nothing more if it was interrupted |
257
|
|
|
|
|
|
|
next if($finnished->{$runid}{interrupted}); |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
# Verify the exit status |
260
|
|
|
|
|
|
|
$scheduler->get_dead_job_info($finnished->{$runid}); |
261
|
|
|
|
|
|
|
if($finnished->{$runid}{exitstatus} && !$finnished->{$runid}{interrupted}) { |
262
|
|
|
|
|
|
|
# Pumm!! Cancelar tudo! |
263
|
|
|
|
|
|
|
$logger->fatal("Process " . $scheduler->get_id($finnished->{$runid}) . " exited |
264
|
|
|
|
|
|
|
with exit status " . $finnished->{$runid}{exitstatus} . "! Aborting |
265
|
|
|
|
|
|
|
all queue..."); |
266
|
|
|
|
|
|
|
process_interrupt(1); # Forced; |
267
|
|
|
|
|
|
|
$finnished->{$runid}{fatal} = 1; # To graphviz later... |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
# If we got asShell to run, run it! |
271
|
|
|
|
|
|
|
find_and_run_asShell($runid); |
272
|
|
|
|
|
|
|
# If we got asPerl to run, run it! |
273
|
|
|
|
|
|
|
find_and_run_asPerl($runid); |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=head1 find_and_run_asShell |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
This function goes through the finnished job |
281
|
|
|
|
|
|
|
and tries to find asShell commands to run, doing |
282
|
|
|
|
|
|
|
all the expands necessary |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
=cut |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
sub find_and_run_asShell { |
287
|
|
|
|
|
|
|
my ($runid) = @_; |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
for my $action (@{$finnished->{$runid}->{action}}) { |
290
|
|
|
|
|
|
|
if($action->{asShell} && !(defined $finnished->{__var__}->{$action->{def}})) { |
291
|
|
|
|
|
|
|
$logger->info("Running shell action $action->{asShell}"); |
292
|
|
|
|
|
|
|
$finnished->{__var__}->{$action->{def}} = []; |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
open P, "$action->{asShell} |"; |
295
|
|
|
|
|
|
|
while( ) { |
296
|
|
|
|
|
|
|
chomp; |
297
|
|
|
|
|
|
|
$logger->warn("Return value from the shell action is not a integer") unless /^\d+$/; |
298
|
|
|
|
|
|
|
push @{$finnished->{__var__}->{$action->{def}}}, $_; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
close P; |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# Now expand the queue |
303
|
|
|
|
|
|
|
expand_forks($action->{def}); |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=head1 find_and_run_asPerl |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
This function goes through the finnished job |
311
|
|
|
|
|
|
|
and tries to find asPerl commands to run, doing |
312
|
|
|
|
|
|
|
all the expands necessary |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
=cut |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
sub find_and_run_asPerl { |
317
|
|
|
|
|
|
|
my ($runid) = @_; |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
for my $action (@{$finnished->{$runid}->{action}}) { |
320
|
|
|
|
|
|
|
if($action->{asPerl} && !(defined $finnished->{__var__}->{$action->{def}})) { |
321
|
|
|
|
|
|
|
$logger->info("Running perl action $action->{asPerl}"); |
322
|
|
|
|
|
|
|
$finnished->{__var__}->{$action->{def}} = []; |
323
|
|
|
|
|
|
|
$finnished->{__var__}{$action->{def}} = paction_list($action->{asPerl}); |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
# Now expand the queue |
326
|
|
|
|
|
|
|
expand_forks($action->{def}); |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
=head1 paction_list |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
this function evaluates a perl action and retruns a list of strings. |
334
|
|
|
|
|
|
|
the action can: |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
.return a ARRAY reference, |
337
|
|
|
|
|
|
|
.print a list of lines to STDOUT (to be splited end chomped) |
338
|
|
|
|
|
|
|
.or return a string (to be splited and chomped) |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
=cut |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
sub paction_list{ |
343
|
|
|
|
|
|
|
my $act=shift; |
344
|
|
|
|
|
|
|
my $var=""; |
345
|
|
|
|
|
|
|
my $final=[]; |
346
|
|
|
|
|
|
|
open(A,'>', \$var); |
347
|
|
|
|
|
|
|
my $old= select A; |
348
|
|
|
|
|
|
|
my $res = eval( "package main; no strict; " . $act ); |
349
|
|
|
|
|
|
|
die $@ if $@; |
350
|
|
|
|
|
|
|
close A; |
351
|
|
|
|
|
|
|
select $old; |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
if (ref($res) eq "ARRAY"){ |
354
|
|
|
|
|
|
|
$final = $res; } |
355
|
|
|
|
|
|
|
elsif($var =~ /\S/) { |
356
|
|
|
|
|
|
|
for(split("\n",$var)){ push (@$final, $_) if /\S/; } } |
357
|
|
|
|
|
|
|
else{ |
358
|
|
|
|
|
|
|
for(split("\n",$res)){ push (@$final, $_) if /\S/; } } |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
$final; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=head1 expand_forks |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
This function is responsible of expanding all the jobs |
366
|
|
|
|
|
|
|
when a variable is evaluated. It expands both forks and |
367
|
|
|
|
|
|
|
joins. |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=cut |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
sub expand_forks { |
372
|
|
|
|
|
|
|
my ($var) = @_; |
373
|
|
|
|
|
|
|
my $values = $finnished->{__var__}->{$var}; |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
# For all queue items that has a $var, expand |
376
|
|
|
|
|
|
|
my $index = -1; |
377
|
|
|
|
|
|
|
for my $job (@{$queue}) { |
378
|
|
|
|
|
|
|
$index++; |
379
|
|
|
|
|
|
|
next unless $job; |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
if($job->{rule}{vars} && (grep { $_ eq "\$$var" } @{$job->{rule}{vars}} )) { |
382
|
|
|
|
|
|
|
$logger->info("Found a fork on $job->{rule}->{id}. Expanding..."); |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
# Expand, expand, expand |
385
|
|
|
|
|
|
|
$job->{rule}{vars} = [ grep { $_ ne "\$$var" } @{$job->{rule}{vars} }]; |
386
|
|
|
|
|
|
|
delete $job->{rule}{vars} unless scalar @{$job->{rule}{vars}}; |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
delete $queue->[$index]; |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
my $count = 0; |
391
|
|
|
|
|
|
|
my @added_jobs = (); |
392
|
|
|
|
|
|
|
for my $index (@{$values}) { |
393
|
|
|
|
|
|
|
my $newjob = clone($job); |
394
|
|
|
|
|
|
|
$count++; |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
# Actualiazr o id |
397
|
|
|
|
|
|
|
$newjob->{rule}{id} .= $index; |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
# Actualizar a linha a executar |
400
|
|
|
|
|
|
|
for my $act (@{$newjob->{action}}) { |
401
|
|
|
|
|
|
|
if($act->{shell}){ |
402
|
|
|
|
|
|
|
$act->{shell} =~ s/\$$var\b/$index/g; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
elsif($act->{perl}){ |
405
|
|
|
|
|
|
|
$act->{perl} =~ s/\$$var\b/$index/g; |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
# Expand pipelines |
410
|
|
|
|
|
|
|
for my $dep (@{$newjob->{depend_on}}) { |
411
|
|
|
|
|
|
|
if ($dep->{vars} && (grep { $_ eq "\$$var"} @{$dep->{vars}} )) { |
412
|
|
|
|
|
|
|
# Expand the dependencie |
413
|
|
|
|
|
|
|
$dep->{vars} = [ grep { $_ ne "\$$var" } @{$dep->{vars}} ]; |
414
|
|
|
|
|
|
|
delete $dep->{vars} unless scalar @{$dep->{vars}}; |
415
|
|
|
|
|
|
|
$dep->{id} .= $index; |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
push @{$queue}, $newjob; |
419
|
|
|
|
|
|
|
push @added_jobs, $newjob->{rule}{id}; |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
$logger->info("Expanded.. Created new $count jobs: @added_jobs"); |
422
|
|
|
|
|
|
|
} |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
# Find joiners |
425
|
|
|
|
|
|
|
my $pos = 0; |
426
|
|
|
|
|
|
|
for my $dep (@{$job->{depend_on}}) { |
427
|
|
|
|
|
|
|
if ($dep->{vars} && (grep { $_ eq "\$$var" } @{$dep->{vars}} )) { |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
$dep->{vars} = [ grep { $_ ne "\$$var" } @{$dep->{vars}}]; |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
# Expand the dependencies |
432
|
|
|
|
|
|
|
delete $job->{depend_on}->[$pos]; |
433
|
|
|
|
|
|
|
for my $index (@{$values}) { |
434
|
|
|
|
|
|
|
my @vars = (scalar @{$dep->{vars}})?(vars => $dep->{vars}):(); |
435
|
|
|
|
|
|
|
push @{$job->{depend_on}}, { @vars, |
436
|
|
|
|
|
|
|
id => $dep->{id} . $index }; |
437
|
|
|
|
|
|
|
} |
438
|
|
|
|
|
|
|
} |
439
|
|
|
|
|
|
|
$pos++; |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
# Now find constructors like @var |
444
|
|
|
|
|
|
|
for my $job (@{$queue}) { |
445
|
|
|
|
|
|
|
next unless $job; |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
# Search on actions |
448
|
|
|
|
|
|
|
for my $action (@{$job->{action}}) { |
449
|
|
|
|
|
|
|
if($action->{shell} && $action->{shell} =~ /\@$var\b/) { |
450
|
|
|
|
|
|
|
my $string = ''; |
451
|
|
|
|
|
|
|
map { $string .= "$_ " } @{$values}; |
452
|
|
|
|
|
|
|
$action->{shell} =~ s/\@$var\b/$string/g; |
453
|
|
|
|
|
|
|
$logger->info("The job $job->{rule}->{id} has been action expanded with $string"); |
454
|
|
|
|
|
|
|
} |
455
|
|
|
|
|
|
|
elsif($action->{perl} && $action->{perl} =~ /\@$var\b/) { |
456
|
|
|
|
|
|
|
my $string = join(",", map { "q{$_}" } @{$values}); |
457
|
|
|
|
|
|
|
$action->{perl} =~ s/\@$var\b/($string)/g; |
458
|
|
|
|
|
|
|
$logger->info("The job $job->{rule}->{id} has been action expanded with ($string)"); |
459
|
|
|
|
|
|
|
} |
460
|
|
|
|
|
|
|
} |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
# Search on asShell |
463
|
|
|
|
|
|
|
for my $action (@{$job->{action}}) { |
464
|
|
|
|
|
|
|
if($action->{asShell} && $action->{asShell} =~ /\@$var\b/) { |
465
|
|
|
|
|
|
|
my $string = ''; |
466
|
|
|
|
|
|
|
map { $string .= "$_ " } @{$values}; |
467
|
|
|
|
|
|
|
$action->{asShell} =~ s/\@$var\b/$string/g; |
468
|
|
|
|
|
|
|
$logger->info("The job $job->{rule}->{id} has been shell expanded with $string"); |
469
|
|
|
|
|
|
|
} |
470
|
|
|
|
|
|
|
} |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
# Search on asPerl |
473
|
|
|
|
|
|
|
for my $action (@{$job->{action}}) { |
474
|
|
|
|
|
|
|
if($action->{asPerl} && $action->{asPerl} =~ /\@$var\b/) { |
475
|
|
|
|
|
|
|
my $string = 'qw/'; |
476
|
|
|
|
|
|
|
map { $string .= "$_ " } @{$values}; |
477
|
|
|
|
|
|
|
$string .= "/"; |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
$action->{asPerl} =~ s/\@$var\b/$string/g; |
480
|
|
|
|
|
|
|
$logger->info("The job $job->{rule}->{id} has been Perl expanded with $string"); |
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
} |
484
|
|
|
|
|
|
|
} |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
=head1 report |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
Print a pretty report bla bla bla |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
=cut |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
sub report { |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
$logger->info("Creating HTML report"); |
495
|
|
|
|
|
|
|
open REPORT, ">$filename.html" or die "Can't create $filename.html"; |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
print REPORT "\n";
498
|
|
|
|
|
|
|
print REPORT " | ID | Start Time | End Time | Elapsed | \n";
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
my ($id,$start,$stop,$interval); |
501
|
|
|
|
|
|
|
for my $job (sort sortcallback keys %{$finnished}) { |
502
|
|
|
|
|
|
|
next unless $finnished->{$job}{rule}; |
503
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
$id = $finnished->{$job}{rule}{id}; |
505
|
|
|
|
|
|
|
$start = (localtime($finnished->{$job}{starttime}[0]))->iso; |
506
|
|
|
|
|
|
|
$stop = (localtime($finnished->{$job}{stoptime}[0]))->iso; |
507
|
|
|
|
|
|
|
$interval = $finnished->{$job}{realtime} || $finnished->{$job}{elapsed}; |
508
|
|
|
|
|
|
|
print REPORT " | $id | $start | $stop | $interval | \n";
509
|
|
|
|
|
|
|
} |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
print REPORT " | \n"; |
512
|
|
|
|
|
|
|
close REPORT; |
513
|
|
|
|
|
|
|
} |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
sub sortcallback { |
516
|
|
|
|
|
|
|
my $foo = $finnished->{$a}; |
517
|
|
|
|
|
|
|
my $bar = $finnished->{$b}; |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
return 0 if(!$foo->{order} && !$bar->{order}); |
520
|
|
|
|
|
|
|
return -1 unless $foo->{order}; |
521
|
|
|
|
|
|
|
return 1 unless $bar->{order}; |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
return $foo->{order} <=> $bar->{order}; |
524
|
|
|
|
|
|
|
} |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
=head1 dispatch |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
This function is responsible for dispatching the jobs that can run. |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
=cut |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
sub dispatch { |
533
|
|
|
|
|
|
|
my $new_queue = []; |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
# If we aren't running nothing and ($interrupted || $queue empty) exit |
536
|
|
|
|
|
|
|
if((scalar keys %{$running}) == 0 && ($interrupted || (scalar @{$queue} == 0))) { |
537
|
|
|
|
|
|
|
$logger->info("Terminating the pipeline"); |
538
|
|
|
|
|
|
|
at_exit(); |
539
|
|
|
|
|
|
|
} |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
# We don't wanna dispatch NOTHING if we have interrupted |
542
|
|
|
|
|
|
|
return if $interrupted; |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
for my $job (@{$queue}) { |
545
|
|
|
|
|
|
|
next unless $job; |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
# Find if the job dependencies are finnished |
548
|
|
|
|
|
|
|
if(can_run_job($job->{rule}->{id}, $job->{depend_on})) { |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
$logger->info(Dumper($job)) unless $job->{rule}{id}; |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
$logger->info("The job \"" . $job->{rule}->{id} . "\" is ready to run. Launching"); |
553
|
|
|
|
|
|
|
launch($job); |
554
|
|
|
|
|
|
|
$job->{starttime} = [gettimeofday]; |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
# Jump to the next job in queue |
557
|
|
|
|
|
|
|
next; |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
# This job can't run yet.. add it to the new queue |
561
|
|
|
|
|
|
|
push @{$new_queue}, $job; |
562
|
|
|
|
|
|
|
} |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
# Return the new queue, the jobs that can't be dispatched yet |
565
|
|
|
|
|
|
|
$queue = $new_queue; |
566
|
|
|
|
|
|
|
} |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
=head1 is_finnished |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
This function checks if the specified job is already done in |
571
|
|
|
|
|
|
|
the finnished list. |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
=cut |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
sub is_finnished { |
576
|
|
|
|
|
|
|
my ($jobid) = @_; |
577
|
|
|
|
|
|
|
for my $job (keys %{$finnished}) { |
578
|
|
|
|
|
|
|
next unless $finnished->{$job}{rule}; |
579
|
|
|
|
|
|
|
return 1 if($finnished->{$job}{rule}{id} eq $jobid); |
580
|
|
|
|
|
|
|
} |
581
|
|
|
|
|
|
|
return 0; |
582
|
|
|
|
|
|
|
} |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
=head1 at_exit |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
This sub is called at the program exit |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
=cut |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
sub at_exit { |
591
|
|
|
|
|
|
|
graphviz(); |
592
|
|
|
|
|
|
|
report(); |
593
|
|
|
|
|
|
|
write_journal(); |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
exit(0); |
596
|
|
|
|
|
|
|
} |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
=head1 write_journal |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
Saves the scheduler state to disk. |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
=cut |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
sub write_journal { |
605
|
|
|
|
|
|
|
my $journal = {}; |
606
|
|
|
|
|
|
|
$journal->{md5} = calc_makefile_md5(); |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
# Pass all interrupted and failled processes back to queue |
609
|
|
|
|
|
|
|
my $acabados = clone($finnished); |
610
|
|
|
|
|
|
|
for my $job (keys %{$acabados}) { |
611
|
|
|
|
|
|
|
next unless $acabados->{$job}{rule}; |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
if($acabados->{$job}{fatal} || $acabados->{$job}{interrupted}) { |
614
|
|
|
|
|
|
|
delete $acabados->{$job}; |
615
|
|
|
|
|
|
|
} |
616
|
|
|
|
|
|
|
} |
617
|
|
|
|
|
|
|
delete $acabados->{__var__}; |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
$journal->{finnished} = $acabados; |
620
|
|
|
|
|
|
|
$journal->{counter} = $counter; |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
open F, ">$filename.journal"; |
623
|
|
|
|
|
|
|
print F (Dumper $journal); |
624
|
|
|
|
|
|
|
close F; |
625
|
|
|
|
|
|
|
} |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
=head1 calc_makefile_md5 |
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
Calculates the MD5 of the current makefile |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
=cut |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
sub calc_makefile_md5 { |
634
|
|
|
|
|
|
|
open F, "<$filename"; |
635
|
|
|
|
|
|
|
my $ctx = Digest::MD5->new; |
636
|
|
|
|
|
|
|
$ctx->addfile(*F); |
637
|
|
|
|
|
|
|
close F; |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
return $ctx->b64digest; |
640
|
|
|
|
|
|
|
} |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
=head1 can_run_jub |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
This one finds out if a job can run (all the dependencies are met). |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
=cut |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
sub can_run_job { |
649
|
|
|
|
|
|
|
my ($id, $deps) = @_; |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
return 0 unless $scheduler->can_run(); |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
for my $dep (@{$deps}) { |
654
|
|
|
|
|
|
|
next unless $dep; |
655
|
|
|
|
|
|
|
next unless $dep->{id}; |
656
|
|
|
|
|
|
|
return 0 unless defined $finnished->{$dep->{id}} |
657
|
|
|
|
|
|
|
} |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
return 1; |
660
|
|
|
|
|
|
|
} |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
=head1 launch |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
Launch a process (really??) |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
=cut |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
sub launch { |
669
|
|
|
|
|
|
|
my ($job) = @_; |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
# Launch the process |
672
|
|
|
|
|
|
|
$scheduler->launch($job, $debug); |
673
|
|
|
|
|
|
|
$job->{order} = $counter++; |
674
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
# Save in the running list |
676
|
|
|
|
|
|
|
$running->{$job->{rule}->{id}} = $job; |
677
|
|
|
|
|
|
|
$logger->info("Launched \"" . $job->{rule}->{id} . "\" (" . $scheduler->get_id($job) . ")"); |
678
|
|
|
|
|
|
|
} |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
=head1 graphviz |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
Builds a preety graphviz file after the execution of the makefile |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
=cut |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
sub graphviz { |
687
|
|
|
|
|
|
|
my $time_for = {}; # Holds the walltime for the job id |
688
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
my $g = GraphViz->new(rankdir => 1); |
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
$logger->info("Creating GraphViz nodes"); |
692
|
|
|
|
|
|
|
# Create all nodes |
693
|
|
|
|
|
|
|
for my $job (keys %{$finnished}) { |
694
|
|
|
|
|
|
|
next unless $finnished->{$job}{rule}; |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
my $id = $finnished->{$job}{rule}{id}; |
697
|
|
|
|
|
|
|
$time_for->{$id} = $finnished->{$job}{realtime} || $finnished->{$job}{elapsed}; |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
my $color = 'black'; |
700
|
|
|
|
|
|
|
$color = 'red' if $finnished->{$job}{fatal}; |
701
|
|
|
|
|
|
|
$color = 'yellow' if $finnished->{$job}{interrupted}; |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
$g->add_node($id, label => "$id\n$time_for->{$id}" |
704
|
|
|
|
|
|
|
, shape => 'box', color => $color); |
705
|
|
|
|
|
|
|
} |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
$logger->info("Creating GraphViz edges"); |
708
|
|
|
|
|
|
|
# Create edges |
709
|
|
|
|
|
|
|
for my $job (keys %{$finnished}) { |
710
|
|
|
|
|
|
|
next unless $finnished->{$job}{rule}; |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
for my $dep (@{$finnished->{$job}{depend_on}}) { |
713
|
|
|
|
|
|
|
next unless $dep; |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
$g->add_edge($dep->{id}, $finnished->{$job}{rule}{id}); |
716
|
|
|
|
|
|
|
} |
717
|
|
|
|
|
|
|
} |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
open F, ">$filename.ps"; |
720
|
|
|
|
|
|
|
print F $g->as_ps; |
721
|
|
|
|
|
|
|
close F; |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
open F, ">$filename.dot"; |
724
|
|
|
|
|
|
|
print F $g->as_text; |
725
|
|
|
|
|
|
|
close F; |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
$logger->info("GraphViz file created on $filename.ps"); |
728
|
|
|
|
|
|
|
} |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
=head1 process_interrupt |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
This function is called everytime the user send a SIGINT to this process. |
733
|
|
|
|
|
|
|
The objective is to kill all the running processes and wait for them to die. |
734
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
=cut |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
sub process_interrupt { |
738
|
|
|
|
|
|
|
my $forced = shift; |
739
|
|
|
|
|
|
|
$forced = 0 if $forced eq "INT"; # Hack O:-) |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
if(!$interrupted || $forced) { |
742
|
|
|
|
|
|
|
if(!$forced) { |
743
|
|
|
|
|
|
|
$logger->warn("Interrupt pressed, enter QUIT to quit, other thing to continue"); |
744
|
|
|
|
|
|
|
my $linha = ; |
745
|
|
|
|
|
|
|
chomp($linha); |
746
|
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
if($linha ne 'QUIT') { |
748
|
|
|
|
|
|
|
$logger->info("Interrupt canceled... Keeping the loop"); |
749
|
|
|
|
|
|
|
return; |
750
|
|
|
|
|
|
|
} |
751
|
|
|
|
|
|
|
} |
752
|
|
|
|
|
|
|
|
753
|
|
|
|
|
|
|
$interrupted = 1; |
754
|
|
|
|
|
|
|
$logger->info("Interrupt pressed, cleaning all the running processes"); |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
for my $runid (keys %{$running}) { |
757
|
|
|
|
|
|
|
$logger->info("Terminating job " . $scheduler->get_id($running->{$runid})); |
758
|
|
|
|
|
|
|
$running->{$runid}{interrupted} = 1; |
759
|
|
|
|
|
|
|
$scheduler->interrupt($running->{$runid}); |
760
|
|
|
|
|
|
|
} |
761
|
|
|
|
|
|
|
} else { |
762
|
|
|
|
|
|
|
$logger->warn("Interrupt already called, please wait while cleaning"); |
763
|
|
|
|
|
|
|
} |
764
|
|
|
|
|
|
|
} |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
=head1 AUTHOR |
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
Ruben Fonseca, C<< >> |
770
|
|
|
|
|
|
|
|
771
|
|
|
|
|
|
|
Alberto Simões C<< >> |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
José João Almeida C<< >> |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
=head1 BUGS |
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
Please report any bugs or feature requests to |
778
|
|
|
|
|
|
|
C, or through the web interface at |
779
|
|
|
|
|
|
|
L. |
780
|
|
|
|
|
|
|
I will be notified, and then you'll automatically be notified of progress on |
781
|
|
|
|
|
|
|
your bug as I make changes. |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
Copyright 2006-2011 Ruben Fonseca, et al, all rights reserved. |
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
788
|
|
|
|
|
|
|
under the same terms as Perl itself. |
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
=cut |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
1; # End of Makefile::Parallel |