in reply to LWP slow downloads on windows

This probably won't go down well with some, but mod:;//LWP seems to be badly broken on Win32. The following code downloads the same file from CPAN using 3 different methods; LWP::Simple::get(), LWP::UserAgent::get(), and Win32::Internet::FetchURL():

#! perl -slw use strict; use Time::HiRes qw[ time ]; use LWP; use LWP::Simple; use Win32::Internet; $|++; my $url = 'http://www.mirrorservice.org/sites/ftp.funet.fi/pub/languag +es/perl/CPAN/authors/id/J/JD/JDB/Win32-Internet-0.084.tar.gz'; my $start1 = time; my $file1 = get( $url ); printf "\nLWP::Simple took %7.3f seconds\n", my $time1 = time() - $sta +rt1; print "Size: ", length $file1; printf "Transfer rate: %5.2f bytes/sec\n", length( $file1 ) / $time1; my $inet = new Win32::Internet; my $start2 = time; my $file2 = $inet->FetchURL( $url ); printf "\nWin32::I took %7.3f seconds\n", my $time2 = time() - $start2 +; print "Size: ", length $file2; printf "Transfer rate: %5.2f bytes/sec\n", length( $file2 ) / $time2; my $ua = LWP::UserAgent->new; my $start3 = time; my $resp = $ua->get( $url ); printf "\nLWP::UA took %7.3f seconds\n", my $time3 = time() - $start3; + ## Corrected [Mr Mischief]++ my $file3 = $resp->content; print "Size: ", length $file3; printf "Transfer rate: %5.2f bytes/sec\n", length( $file3 ) / $time3;

The upshot is that LWP::Simple::get() was twice as fast and LWP::UserAgent::get(). But the native API wrapper is 25 times faster than LWP::Simple & LWP::UserAgent!

I could not believe the difference using the native API made--it HAD to be an error! Didn't it?-- but I've run this a dozen times now. I tried altering the ordering of the downloads to check that there was no caching involved; I re-booted and killed every process except those required to allow the system to run. And the following figures are pretty average for the results I've seen:

Uodated: figures for corrected benchmark. Mr Mischief++

C:\test>Win32Itest.pl LWP::Simple took 14.703 seconds Size: 64230 Transfer rate: 4368.46 bytes/sec Win32::I took 0.639 seconds Size: 64230 Transfer rate: 100515.50 bytes/sec LWP::UA took 14.796 seconds Size: 64230 Transfer rate: 4340.89 bytes/sec

Can anyone out there confirm these figures? Someone with a decent speed internet connection?

So, I tried wget:

C:\test>wget http://www.mirrorservice.org/sites/ftp.funet.fi/pub/langu +ages/perl/CPAN/authors/id/J/JD/JDB/Win32-Internet-0.084.tar.gz --02:17:39-- http://www.mirrorservice.org/sites/ftp.funet.fi/pub/lang +uages/perl/CPAN/authors/id/J/JD/JDB/Win32-Internet-0.084.tar.gz => `Win32-Internet-0.084.tar.gz' Resolving www.mirrorservice.org... 212.219.56.138, 212.219.56.139, 212 +.219.56.153, ... Connecting to www.mirrorservice.org|212.219.56.138|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 64,230 (63K) [application/x-gzip] 100%[==============...==============>] 64,230 4.51K/s ETA 0 +0:00 02:17:54 (4.60 KB/s) - `Win32-Internet-0.084.tar.gz' saved [64230/6423 +0]

Conclusion: if you use win32, and regularly download large files, seriously consider using the Win32::Internet module, because unless someone can explain my mistake, it really is remarkably quick.


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re^2: LWP slow downloads on windows (50 times faster?)
by Anonymous Monk on Dec 04, 2008 at 03:10 UTC
    your example returns
    LWP::Simple took 1.594 seconds Size: 64230 Transfer rate: 40303.76 bytes/sec Win32::I took 4.489 seconds Size: 64230 Transfer rate: 14308.64 bytes/sec LWP::UA took 15.613 seconds Size: 64230 Transfer rate: 4113.83 bytes/sec
    with perl 5.8.8.822 at win2k3 server

      Thank you Anonymonk.

      You at least confirmed the potential for wild variation--even if it didn't quite match my empirical evidence.

      There is something going on here that greatly (order of magnitude greatly) affects the performance of sockets, and LWP::UserAgent seems to be the loser.

      (I realise that 2 out of 2 is hardly a significant sample, but still, the trend is promising for my premise :)


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        Here is my output:

        LWP::Simple took 1.406 seconds Size: 64230 Transfer rate: 45675.25 bytes/sec Win32::I took 0.618 seconds Size: 64230 Transfer rate: 103852.38 bytes/sec LWP::UA took 2.353 seconds Size: 64230 Transfer rate: 27299.07 bytes/sec
        I have tried several times and Win32::Internet always fastest.
Re^2: LWP slow downloads on windows (50 times faster?)
by Anonymous Monk on Dec 04, 2008 at 07:42 UTC
    Callbacks are one reason UA is slower, winxp home, perl v5.8.7, LWP 5.819 (libwww-perl-5.821), GNU Wget 1.11.4
    D:\>perl lwp-bench.pl LWP::Simple took 2.376 seconds Size: 64230 Transfer rate: 27036.45 bytes/sec Win32::I took 1.358 seconds Size: 64230 Transfer rate: 47312.34 bytes/sec LWP::UA took 2.717 seconds Size: 64230 Transfer rate: 23640.49 bytes/sec D:\>perl lwp-bench.pl LWP::Simple took 1.327 seconds Size: 64230 Transfer rate: 48385.75 bytes/sec Win32::I took 0.396 seconds Size: 64230 Transfer rate: 162095.51 bytes/sec LWP::UA took 1.878 seconds Size: 64230 Transfer rate: 34205.63 bytes/sec D:\>perl lwp-bench.pl LWP::Simple took 1.457 seconds Size: 64230 Transfer rate: 44091.30 bytes/sec Win32::I took 0.535 seconds Size: 64230 Transfer rate: 120084.79 bytes/sec LWP::UA took 2.035 seconds Size: 64230 Transfer rate: 31564.64 bytes/sec D:\> D:\>wget -c http://www.mirrorservice.org/sites/ftp.funet.fi/pub/langua +ges/perl/CPAN/authors/id/J/JD/JDB/Win32-In ternet-0.084.tar.gz --2008-12-03 23:29:27-- http://www.mirrorservice.org/sites/ftp.funet. +fi/pub/languages/perl/CPAN/authors/id/J/JD/JDB/Win 32-Internet-0.084.tar.gz Resolving www.mirrorservice.org... 212.219.56.135, 212.219.56.138, 212 +.219.56.139, ... Connecting to www.mirrorservice.org|212.219.56.135|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 64230 (63K) [application/x-gzip] Saving to: `Win32-Internet-0.084.tar.gz' 100%[================================================================= +=============>] 64,230 68.5K/s in 0.9s 2008-12-03 23:29:29 (68.5 KB/s) - `Win32-Internet-0.084.tar.gz' saved +[64230/64230] D:\>rm Win32-Internet-0.084.tar.gz D:\>wget -c http://www.mirrorservice.org/sites/ftp.funet.fi/pub/langua +ges/perl/CPAN/authors/id/J/JD/JDB/Win32-In ternet-0.084.tar.gz --2008-12-03 23:29:38-- http://www.mirrorservice.org/sites/ftp.funet. +fi/pub/languages/perl/CPAN/authors/id/J/JD/JDB/Win 32-Internet-0.084.tar.gz Resolving www.mirrorservice.org... 212.219.56.135, 212.219.56.138, 212 +.219.56.139, ... Connecting to www.mirrorservice.org|212.219.56.135|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 64230 (63K) [application/x-gzip] Saving to: `Win32-Internet-0.084.tar.gz' 100%[================================================================= +=============>] 64,230 59.2K/s in 1.1s 2008-12-03 23:29:39 (59.2 KB/s) - `Win32-Internet-0.084.tar.gz' saved +[64230/64230] D:\>rm Win32-Internet-0.084.tar.gz D:\>
    maybe you can try LWP::Curl next?
Re^2: LWP slow downloads on windows (50 times faster?)
by robobunny (Friar) on Dec 04, 2008 at 16:54 UTC
    I saw roughly the same speed differences as everyone else, both using the external URL in your script and using the internal file that I started with. After running a profiler on LWP, it looks like most of the time is spent appending the new chunk it just downloaded to the existing buffer (HTTP::Message, add_content method, line 142 in version 5.814):
    $self->{_content} .= $$chunkref;
    add_content is called in a loop by the collect method of LWP::Protocol. I was able to reduce the download time for a 12MB file from 36 seconds to 5 seconds by changing the collect method to use an array for the buffer and then stick everything together at the end, instead of calling add_content repeatedly:
    my @total_content; if (!defined($arg) || !$response->is_success) { # scalar while ($content = &$collector, length $$content) { if ($parser) { $parser->parse($$content) or undef($parser); } LWP::Debug::debug("read " . length($$content) . " bytes"); push(@total_content, $$content); $content_size += length($$content); $ua->progress(($length ? ($content_size / $length) : "tick"), +$response); if (defined($max_size) && $content_size > $max_size) { LWP::Debug::debug("Aborting because size limit exceeded"); $response->push_header("Client-Aborted", "max_size"); last; } } $response->add_content(join('', @total_content));
    Anybody know any reason that would be a problem?
      Your changes indeed speed things up on my testing system so long as they don't cause additional swapping. I see only one issue. It does seem to use more memory than the stock LWP::Protocol.

      Yours hit more heavily into my swap file for a large file (703MB on a system with only 512 MB of RAM) than the stock version. The map in BrowserUk's version put my poor antiquated testing server right out of physical RAM and swap completely.

      My conclusion is that I really do need more RAM in this machine. It's something to consider if you're under similar constraints or if you're submitting a patch to the module's maintainers, though. As always, paging to swap can erase any gains you'd get otherwise and then cause even much slower execution. Sometimes optimizing for speed at the expense of memory fails, and sometimes optimizing for memory use is actually a performance win.

      This helped greatly speeding up zip downloads when I added this fix to the collect method in LWP::Protocal under perl 5.825. Before the fix it took ~3.5h to download 28 zip files and after adding this LWP::Protocal fix it took only ~1.5h :-)

      However, now I have perl 5.8.9 (with latest libwww-perl 5.825 2009-02-16) installed *and* the zip downloads are back to taking ~3.5 hours.

      I diffed the Protocal.pm files but they are redical different (between libwww-perl 5.825 2009 and Protocol.pm,v 1.41 2003/10/23 19:11:32) and I don't see any hooks for a similar quick fix.

      Can anyone suggest a fix for speeding up downloads using libwww-perl (5.825 2009-02-16)...?

Re^2: LWP slow downloads on windows (50 times faster?)
by mr_mischief (Monsignor) on Dec 05, 2008 at 17:23 UTC
    Your benchmark is charging the time for both Win32::Internet and LWP::UserAgent to the latter:

    printf "\nLWP::UA took %7.3f seconds\n", my $time3 = time() - $start2;

    should be:

    printf "\nLWP::UA took %7.3f seconds\n", my $time3 = time() - $start3;

        LWP::Simple took 1.063 seconds Size: 64230 Transfer rate: 60451.76 bytes/sec Win32::I took 0.370 seconds Size: 64230 Transfer rate: 173628.77 bytes/sec LWP::UA took 1.126 seconds Size: 64230 Transfer rate: 57055.80 bytes/sec wget 2008-12-06 05:24:53 (84.8 KB/s) 84.8K/s in 0.7s ----------- LWP::Simple took 1.977 seconds Size: 64230 Transfer rate: 32487.30 bytes/sec Win32::I took 0.399 seconds Size: 64230 Transfer rate: 160821.89 bytes/sec LWP::UA took 1.423 seconds Size: 64230 Transfer rate: 45124.67 bytes/sec wget 2008-12-06 05:27:44 (69.5 KB/s) 69.5K/s in 0.9s ----------- LWP::Simple took 1.409 seconds Size: 64230 Transfer rate: 45600.76 bytes/sec Win32::I took 0.374 seconds Size: 64230 Transfer rate: 171676.43 bytes/sec LWP::UA took 1.620 seconds Size: 64230 Transfer rate: 39641.76 bytes/sec wget 2008-12-06 05:27:49 (60.1 KB/s) 60.1K/s in 1.0s ----------- LWP::Simple took 1.287 seconds Size: 64230 Transfer rate: 49899.63 bytes/sec Win32::I took 0.368 seconds Size: 64230 Transfer rate: 174528.19 bytes/sec LWP::UA took 1.751 seconds Size: 64230 Transfer rate: 36673.87 bytes/sec wget 2008-12-06 05:27:54 (67.8 KB/s) 67.8K/s in 0.9s