-
Notifications
You must be signed in to change notification settings - Fork 0
/
launch
executable file
·201 lines (138 loc) · 4.13 KB
/
launch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#!perl
use v5.22.0;
use feature qw(signatures);
no warnings qw(experimental::signatures);
use FindBin qw($Bin);
use lib "$Bin/../lib";
use CpuCount;
use Data::Dumper;
use File::Path qw(make_path);
use File::Spec::Functions qw(catfile updir);
use Getopt::Long qw(GetOptions);
use POSIX qw(ceil :sys_wait_h);
=head1 NAME
launch - start a bunch of processes to look for excellent numbers
=head1 SYNOPSIS
% launch
# 20 digit numbers
% launch --length 20
# 20 digit numbers in 10 processes
% launch --length 20 --processes 10
# 20 digit numbers in 10 processes, from numbers starting with
# 32 to numbers starting in 47
% launch --length 20 --processes 10 --start 32 --end 47
=head1 DESCRIPTION
=head2 Options
=over
=item * --processes, -j
The number of processes to use. The default is to use them all.
Default: 2
=item * --length, -l
The number of digits in the numbers to check. This must be an even number.
Default: 10
=item * --start
The start value for I<a>. It will be 0-padded to half the digits of the
length we're testing.
Default: 1
=item * --end
The start value for I<a>. It will be 0-padded to half the digits of the
length we're testing.
Default: 62
=item * --output_dir, -o
The directory for output files.
Default: F<output/>
=item * --command, --cmd
The command to run. It's arguments are the length, the start, and the end.
Default: B<c/excellent-gmp>
=item * --sleep
The time in seconds to delay before checking on processes again.
Default: 300
=back
=head1 TO DO
=head1 SEE ALSO
=head1 SOURCE AVAILABILITY
This source is part of a GitHub project:
https://github.com/briandfoy/excellent_numbers
=head1 AUTHOR
brian d foy, C<< <brian.d.foy@gmail.com> >>
=head1 COPYRIGHT AND LICENSE
Copyright © 2015, brian d foy <brian.d.foy@gmail.com>. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
die "Invalid options or values\n" unless GetOptions( \my %opts,
'processes|j=i',
'start=i',
'end=i',
'length|l=i',
'output_dir|o=s',
'command|cmd=s',
'sleep|s=i',
);
$opts{'processes'} //= CpuCount::get_cpu_count();
$opts{'length'} //= 26;
$opts{'start'} //= 1;
$opts{'end'} //= 62;
$opts{'output_dir'} //= 'output';
$opts{'command'} //= catfile( 'c', 'excellent-gmp' );
$opts{'sleep'} //= 300;
if( $opts{'length'} % 2 ) {
die "length must be an even number (not $opts{'length'})\n";
}
unless( -d $opts{'output_dir'} ) {
make_path( $opts{'output_dir'} ) or
die "Output directory $opts{'output_dir'} does not exist!\n";
}
unless( -e $opts{'command'} ) {
die "Command $opts{'command'} does not exist!\n";
}
unless( -x $opts{'command'} ) {
die "Command $opts{'command'} is not executable!\n";
}
foreach my $key ( qw( start end ) ) {
if( length $opts{$key} < $opts{'length'} / 2 ) {
$opts{$key} .= 0 x ( $opts{'length'} / 2 - length $opts{$key} );
}
}
my $interval = ceil(
( $opts{'end'} - $opts{'start'} + 1 ) / $opts{'processes'}
);
my @output_files = ();
my %children;
for( my $a = $opts{'start'}; $a <= $opts{'end'}; $a += $interval ) {
state $i = 0;
$i++;
my $end = $a + $interval - 1;
$end = $opts{'end'} if $end > $opts{'end'};
my @args = ( $opts{'length'}, $a, $end );
my $output_file = make_filename( $opts{output_dir}, $opts{length}, $a, $end );
push @output_files, $output_file;
if( my $child_pid = fork ) { # parent
say "*** Parent process $$ forked child $child_pid, saving in $output_file";
$children{$child_pid} = {
file => $output_file,
start => $a,
end => $end,
done => 0,
};
}
else { # child
open STDOUT, '>:utf8', $output_file
or die "Could not open $output_file: $!";
exec $opts{command}, @args;
die "Could not exec! $!";
}
}
while(1) {
my $rc = waitpid( -1, WNOHANG );
last if $rc == -1;
say "*** Process $rc ended ($children{$rc}{start} - $children{$rc}{end})" if $rc;
redo if $rc;
sleep $opts{'sleep'};
}
sub make_filename ( $output_dir, $length, $start, $end, $pid=$$, $time=time ) {
return catfile(
$output_dir,
join( '.', $length, $start, $end, $pid, 'txt' )
);
}