in reply to Re^8: appending to html at beginning (don't use CGI.pm)
in thread appending to html at beginning

A factor of 6 sounds like a broken benchmark. A plack wrapper is not doing so much that much that it makes sense it would be 600% slower. Though perhaps there is something wonky/unexpected in the CGI handler. Do you have your benchmark on github or someplace to share?

  • Comment on Re^9: appending to html at beginning (don't use CGI.pm)

Replies are listed 'Best First'.
Re^10: appending to html at beginning (don't use CGI.pm)
by hippo (Archbishop) on Mar 02, 2017 at 23:55 UTC

    I couldn't find the original scripts (it was a good while ago and the point was proven then) so I've knocked up these scripts today which follow the same principle. If you can point out the errors in what I've done that would be most helpful.

    Firstly, here's the trivial non-plack CGI:

    #!/usr/bin/perl use strict; use warnings; use CGI::Lite; my $cgi = CGI::Lite->new; $cgi->parse_form_data; print "Content-Type: text/plain\n\n"; $cgi->print_data; exit;

    Here's the equivalent PSGI:

    use strict; use warnings; use Plack::Request; my $app = sub { my $env = shift; my $req = Plack::Request->new($env); my %params = %{$req->parameters}; my $body = ''; while (my ($k, $v) = each %params) { $body .= "$k = $v\n"; } my $res = $req->new_response; $res->status (200); $res->headers ({ 'Content-Type' => 'text/plain' }); $res->body ($body); $res->finalize; }

    And finally the wrapper to turn the PSGI into a CGI:

    #!/usr/bin/perl use strict; use warnings; use Plack::Loader; my $app = Plack::Util::load_psgi("light.psgi"); Plack::Loader->auto->run($app);

    To turn this into a "real" test I've run these through Apache with both client and server on the same host (ie. no network issues). The 2 cgi scripts were called with a single key-value pair in the query string (foo=bar, since you ask) and produced the same content as a result. Each script was called 11 times (1 as PoC and then another 10)

    The timings come from the apache log (with %D) and are as follows (all values are microseconds).

    Normal CGICGI through Plack
    Maximum2137193761
    Minimum1249480521
    Mean1499986481

    So, looking at the mean request time the plack version is 5.77 times slower than the plain CGI.

    Now, these are small samples and are wallclock times so YMMV and I encourage you to re-run the tests on your own platforms to see how they compare but this crude example reflects pretty closely what I originally saw and is enough of a penalty to be avoided (for me).

      Thanks for following up. I should point out this is the opposite of what I was talking about in the other thread when I said that CGI should use PSGI as its interface layer. This is, or flavors of it, is what I meant–

      use strictures; use Plack::App::WrapCGI; Plack::App::WrapCGI->new(script => "./my.cgi")->to_app;

      There is zero functional/feature/middleware benefit to going the other way: PSGI->CGI.

      You’re timing webserver responses… it’s hard to guess what’s up there. It’s also hard to measure such a trivial use meaningfully (it is like benchmarking “hello world”). I just sank about 45 minutes into trying to do a pure backend/perl benchmark but I’m having trouble getting part of it to act right and I’m outta gas and IQ.

        You’re timing webserver responses… it’s hard to guess what’s up there.

        Actually, my interpretation is pretty simple - using Plack in this way is necessarily more burdensome than not. The webserver response times everything from receiving the request to sending the response, ie: compilation, arg processing, handing the output back to Apache, etc. all of which might be faster or slower with one method or the other. The only surprise to me back then was the scale of the difference. I'd hoped for maybe just a factor of 2.

        It’s also hard to measure such a trivial use meaningfully (it is like benchmarking “hello world”).

        That's exactly why I did it this way (as alluded to above). With such a trivially simple script the differences in the runtimes should be as near as possible to the entire difference of using Plack versus not with no other complications. Obviously the percentage increase with Plack will reduce for scripts which do more but one can expect the mean penalty on my test rig to be about 70ms.

        The advantage of quoting a percentage difference for a trivial script is that the percentage should be in the same area for anyone performing this test regardless of CPU speed, disk speed, etc. If I just said "it's 70ms slower" that would differ wildly from what others see.

        Thanks very much for pointing out the possible use of Plack::App::WrapCGI. Unfortunately, if I run your sample script using the vanilla CGI script from my benchmark as the script argument to Plack::App::WrapCGI->new I get no output at all - not even any headers. I think this might be running it as a PSGI application which would then need further Plackage around it to turn it back into CGI? More reading required at this end, I fear.

      And how many workers does apache have? I think thats what you're seeing

      This is what I tried, can't get simpler/faster than this, cgi-bin/printenv.pl

      This one does more (loads modules) so it should be slower , dumpenv.psgi started with  plackup -l 127.6.6.6:80 dumpenv.psgi  2>2 1>1

      Then see whats faster

      for ( 1 .. 10 ) { cmpthese( 1000, { 'psgi' => q{ # LWP::Simple::get('http://127.0.0.1:5000/'); LWP::Simple::get('http://127.6.6.6:80/'); qw//; }, 'apache2cgi' => q{ LWP::Simple::get('http://localhost/cgi-bin/printenv.pl'); qw//; }, } ); }

      I tried it a bunch of times, and psgi is faster "half" the time (ok 4/10 or 3/10)

      So is apache "cgi" or psgi faster?

      My Apache is configured with ThreadsPerChild 4 -- not sure how many actual workers that is on my machine, but I see two apache processes ... one has 1 thread the other has 6, so 6 or 7 workers?

      And psgi still wins 3/10 times? How does that make apache faster?

      But yeah maybe the LWP is skewing the benchmark or .... something I dont understand

        Thanks, but I think you and I are doing completely different comparisons (correct me if I'm wrong).

        My intention here is to compare a very simple CGI script with precisely the same thing running with PSGI as a CGI ie. not in any sort of persistent backend. My (admittedly limited) understanding is that when you run plackup -l 127.6.6.6:80 dumpenv.psgi  2>2 1>1 you are creating a persistent plack server which is going to service the requests as opposed to what I am hoping to measure which is an on-demand set up and tear down single run of a script.

        Your post talks about ThreadsPerChild which is only a concern if there are concurrent requests. Again, I'm not bothered about that for the purposes of this test. I want to know about the single script run in isolation.

        If a persistent backend is used (whichever one is chosen) that ought to be much faster after instantiation than any standalone CGI - that's not in doubt. However, the great big selling point of the Plack middleware is AIUI that the developer can seamlessly switch between various backends including none at all and not have to worry about the protocol intricacies. I'm challenging this selling point when it comes to the none-at-all scenario where we want to run the application as non-persistent CGIs. In that situation my findings are that the use of the middleware imposes what can be a significant performance penalty.