7 use Getopt::Long qw(:config posix_default no_ignore_case gnu_compat);
8 use Parallel::ForkManager;
10 use Time::HiRes qw(sleep gettimeofday);
12 usage() if (@ARGV == 0);
15 'h|help' => \ my $help,
16 'i|inputfile=s' => \ my $file,
17 'c|concurrency=i' => \ my $concurrency,
18 'n|loops=i' => \ my $loops,
19 'd|duration=i' => \ my $duration,
20 'w|wait=f' => \ my $wait,
30 my @urls = file2urls($file) if ($file);
33 my $num = scalar @urls;
34 my $l = ($duration) ? "$duration seconds loops" : "$loops loops";
35 warn "$num urls with $concurrency clients, $l\n";
36 warn "Total: ", $num * $concurrency * $loops, " requests\n" if (! $duration);
37 warn "wait for $wait second between requests\n" if ($wait);
39 my $ua = LWP::UserAgent->new(
40 ssl_opts => { verify_hostname => 0 },
43 my $pm = Parallel::ForkManager->new($concurrency);
46 my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $dataref) = @_;
47 if (defined $dataref) {
48 $transfer += $$dataref;
53 my ($startsec, $startmicro) = gettimeofday();
54 for (my $child = 0; $child < $concurrency; $child++) {
58 warn "forks $child/$concurrency child ...\n";
66 last if (time() - $startsec > $duration);
69 last if ($i >= $loops);
72 print STDERR "processing $i/$loops loop\r";
73 foreach my $url (@urls) {
74 my $res = $ua->get($url);
75 if ($res->is_success) {
76 $transfer += length($res->content);
79 print STDERR "\nfail: $url";
86 $pm->finish(0, \$transfer);
89 $pm->wait_all_children;
90 my ($endsec, $endmicro) = gettimeofday();
91 my $elapsed = ($endsec - $startsec) + ($endmicro - $startmicro) / 10**6;
92 my $bytepersec = $transfer / $elapsed;
94 my @units = qw( B/s KiB/s MiB/s GiB/s );
96 while ($bytepersec > 1024) {
100 $bytepersec = sprintf("%.4g", $bytepersec);
102 warn "\n ...done.\n";
103 warn "get $transfer bytes in $elapsed seconds ($bytepersec $units[$unit])\n";
106 warn "$0 -i urls.txt -c concurrency -n loops -w wait_interval\n",
117 open my $fh, '<', $file or die "$file: $!";
120 while ($url = <$fh>) {