2 # Batch EXecutor 2.0 -- Parallel Execution Using Screen
3 # (c) 2011 Martin Mares <mj@ucw.cz>
14 my $screen_session = 'BEX';
18 "q|queue=s" => \$queue_name,
19 "session=s" => \$screen_session,
20 "text!" => \$text_mode,
22 Usage: bprun [<options>] [[!]<machine-or-class> ...]
25 -q, --queue=<name> Run jobs in the given queue
26 --session=<name> Job windows should be opened within the given screen
27 session (default: BEX)
28 --text Use textual user interface instead of curses
31 system 'screen', '-S', $screen_session, '-X', 'select', '.';
32 !$? or die "Screen session $screen_session not found\n";
34 my @machines = BEX::Config::parse_machine_list(@ARGV ? @ARGV : '*');
35 my $queue = BEX::Queue->new($queue_name);
37 my $fifo_name = $queue->{'Name'} . '/status-fifo';
39 mkfifo $fifo_name, 0700 or die "Cannot create $fifo_name: $!";
40 open FIFO, '+<', $fifo_name or die "Cannot open $fifo_name: $!";
42 my $ui = ($text_mode ? BEX::bprun::text->new : BEX::bprun::curses->new);
45 my $max = $BEX::Config::max_parallel_jobs;
47 while (keys %running || @machines) {
48 if (@machines && keys %running < $max) {
49 my $mach = shift @machines;
50 my @jobs = $queue->scan($mach);
52 $ui->update($mach, undef, 'START');
53 my @scr = ('screen', '-t', $mach);
54 push @scr, '-S', $screen_session if defined $screen_session;
55 push @scr, '-X', 'screen', './brun', "--status-fifo=$fifo_name", $mach;
57 !$? or $ui->update($mach, undef, 'INTERR');
58 $running{$mach} = 'START';
63 my ($mach, $jid, $stat) = /^! (\S+) (\S+) (\S+)$/;
65 $ui->err("Received invalid status message <$_>");
68 if (!defined $running{$mach}) {
69 $ui->err("Received status message <$_> for a machine which does not run");
72 $running{$mach} = $stat;
73 $ui->update($mach, ($jid eq '-' ? undef : $jid), $stat);
74 if ($stat eq 'DONE') {
75 delete $running{$mach};
83 package BEX::bprun::text;
93 my ($ui, $mach, $jid, $stat) = @_;
94 print +($mach // '-'), (defined($jid) ? ":$jid" : ""), " $stat\n";
99 print STDERR "ERROR: $msg\n";
102 package BEX::bprun::curses;
115 has_colors && COLORS >= 8 && COLOR_PAIRS >= 8 or die "Your terminal is too dumb for me\n";
121 init_pair(1, COLOR_YELLOW, COLOR_BLUE);
122 $nrows = $C->getmaxy - 2;
123 if ($BEX::Config::max_parallel_jobs > $nrows) {
124 $BEX::Config::max_parallel_jobs = $nrows;
137 if (defined ($s = $by_host{$mach})) {
141 for my $i (0..$nrows-1) {
147 } elsif ($r->{'Gone'} && (!$best || $best->{'Gone'} > $r->{'Gone'})) {
153 delete $by_host{$best->{'Host'}};
155 $s->{'Host'} = $mach;
156 $s->{'Row'} = $besti;
157 $by_host{$mach} = $s;
158 $by_row[$besti] = $s;
163 my $gone_counter = 1;
166 $s->{'Gone'} = $gone_counter++;
171 my $mach = $s->{'Host'};
172 my $stat = $s->{'Status'} // "?";
173 my $jid = $s->{'Job'} // "";
174 my $jname = ($jid eq "" ? "" : $queue->job_name($jid));
175 my $text = sprintf("%-20s %-10s %s", $mach, $stat, $jname);
176 if ($stat eq 'DONE') {
179 $C->bkgdset(COLOR_PAIR(1) | A_BOLD);
181 $C->addnstr($s->{'Row'}, 0, $text, $C->getmaxx);
187 my ($ui, $mach, $jid, $stat) = @_;
188 my $s = get_slot($mach);
190 $s->{'Status'} = $stat;
192 if ($stat eq 'DONE') { delete_slot($s); }