dd-b has asked for the wisdom of the Perl Monks concerning the following question:

I've been unhappy with my local picture display page routine recently. I just got through revising it considerably, and now I don't like the performance.

The first item of confusion is that I get somewhat different performance numbers depending on how I measure it. (I should mention, since I'm new here, that I've been developing software commercially for 35 years now, and don't think I'm making the really most basic stupid benchmarking mistakes; for example I'm pretty aware of what else is running on the server at the same time).

Using ab (Apache benchmark program) shows it taking about 3.5 seconds to cough up the image page (not including sending the actual image). Running the script standalone (providing environment variables manually to simulate the CGI environment) claims it takes a bit less than 2 seconds (Unix time command). And using Time::HiRes and some embedded code (also running standalone) gives numbers around 3 seconds. This last also gives me a bit of profiling.

First question: I did something "clever" in my Time::HiRes profiling, is it valid?

[snip] BEGIN {$prevtime = time();}; [snip] sub marktime ($) { my $label = shift; my $newtime = time(); my $diff = $newtime - $prevtime; print "Mark $label time $newtime diff $diff\n"; $prevtime = $newtime; } marktime ("Executing");

And then, throughout the later code, put in marktime calls at each point I think might be interesting.

I believe that by putting my first time capture in a BEGIN, I'm capturing all the time spent loading modules (which are all "used" after that BEGIN). I won't get the actual initialization time of the perl executable, though. Is this right?

And when I use the Unix time command and run the script on the command line, what does that measure? That mode gives me the smallest measured time value (elapsed time) of anything I've tried.

Okay, so here are the times measured:

PATH_INFO="/time/galpage" PATH_TRANSLATED="/home/httpd/html/test/galpa +ge" QUERY_STRING="id=Ep850-20011002-036" SCRIPT_NAME="foobar" time t. +cgi Mark Executing time 1074046822.13994 diff 2.13994002342224 Mark YAML read time 1074046822.71538 diff 0.57544207572937 Mark fiddling time 1074046822.71724 diff 0.00185680389404297 Mark order time 1074046822.7257 diff 0.00846314430236816 Mark Comment time 1074046822.72987 diff 0.0041649341583252 Mark stats time 1074046822.73372 diff 0.00384807586669922 [CGI output here] Mark end time 1074046822.73533 diff 0.00161886215209961 1.04user 0.08system 0:01.84elapsed 60%CPU (0avgtext+0avgdata 0maxresid +ent)k 0inputs+0outputs (372major+543minor)pagefaults 0swaps

As you can see, my internal timing reports considerably more time being spent than the Unix time command does. This has me wondering seriously about methodology.

So my figures may be invalid. But if they're valid, then they show that the only thing that takes much time is loading the modules I use. There's measurable time spent loading the info file for the directory (via YAML), and everything else is by comparison trivial. This leaves me few options for improving performance -- except to note in passing that Gallery 1.4, written in PHP, serves up a photo in about half the time.

But I'm not giving up yet. I want to be sure I understand correctly where the time is going, and then I can think about FastCGI, mod_perl, and stuff I guess. I've played with both, but never stuck with either for anything I use regularly.

Pointers, philosophical discussion, corrections to stupid mistakes, and so forth welcomed!

Replies are listed 'Best First'.
Re: Startup cost, CGI performance
by BrowserUk (Patriarch) on Jan 14, 2004 at 04:04 UTC

    You may like to take a look at Benchmark::Timer. It comes with the standard distribution. It has a really simple interface for measuring elapsed times in as many categories as you want, and also allows you to accumulate and average individual timings across many iterations. Finally, it outputs a nicely formatted, brief report.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    Timing (and a little luck) are everything!

      Although I do agree that Benchmark::Timer is really nice for easy benchmarking, I do have to note (for the record) that it is not included with Perl (by default), AFAIK. Benchmark is, but you do have to install Benchmark::Timer yourself.

      --
      b10m

        I sit corrected :)

        I've had it so long, I've reached the point that I assumed it was a consituent part of Benchmark.


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "Think for yourself!" - Abigail
        Timing (and a little luck) are everything!

Re: Startup cost, CGI performance
by perrin (Chancellor) on Jan 14, 2004 at 05:09 UTC
    The discrepancy in times could be due to the fact that ab also measures the time to transfer all the data in your web page. If the page is big, that could take some time.

    To find out where your time is going, use Devel::DProf. It will tell you exactly where the time is being spent. If it really is mostly compiling modules, switching to mod_perl will remove the issue completely. It's faster than PHP too.

      ab should be able to separate transfer time from execution time. If ab is used on the same machine, it will take a huge image to make for circa 1 second of additional transfer time. If there's a suspect anyway that's transfer time being taken, it should be trivial to hack the script so that the image is created but not output and then try to benchmark this case (but it's not worth much, after you discover that - say - it's Apache taking the additional second for its buffers or something like that).

      Sounds to me like this will just give me a fourth number, presumably different from the other three, though, rather than tell me which one is right :-). And does it deal with module load time and perl interpreter startup time?

        It will not give you a fourth number; it will give you a detailed list of how long your program is spending in each chunk of code. That's what you need, if you're looking to speed things up.
Re: Startup cost, CGI performance
by l3nz (Friar) on Jan 14, 2004 at 09:34 UTC
    As a matter of fact, as your original question is "how much time does it take for my script to get the image", I'd believe what ab says. Then we have to understand why it takes 3.5 seconds, but as no caching is being done it is the actual time it takes to serve your request (by the way, how many concurrent sessions do you use on ab and how many hits do you make? the number of concurrent sessions can place a good strain on performance).

    From your profile, it seems that everything you do is comparatively small after you pay 2.1 seconds of startup time. I'd try mod_perl first, then FastCGI, and then maybe I'd play with YAML. The rest of the code is not worth optimizing at this stage. And use ab to benchmark it all, so you have consistent and actual execution results within the web server.

      I'm running only one concurrent session in the benchmark, because of course if I do more they compete with each other and run up the numbers. The system has 512MB of memory and is lightly loaded; no swapping was going on as the benchmark ran. I believe I ran 50 retrievals; enough to avoid the warning about the sample being too small to be meaningful from ab, anyway.

      I was about to go optimize a section of my code that turns out to have almost zero contribution to the total; another example of why one really does need to profile first!

Re: Startup cost, CGI performance
by dws (Chancellor) on Jan 14, 2004 at 09:55 UTC
    I've been unhappy with my local picture display page routine recently. I just got through revising it considerably, and now I don't like the performance.

    Discussing whether or not your profiling technique is valid doesn't help explain why your script it taking so long. Can you show us code?

      Happy to show the code, but never uploaded code to Perlmonks before (just joined this week). Is there something better than just putting it in an ordinary message? And do I have to go through and escape lots of special characters when I do that?

      Actually, I think the profiling demonstrates that the main problem is the loading of modules. So I have to either find some way to use fewer or smaller modules, or to get greater persistance of the process (mod_perl or fastcgi). Using something other than YAML for communicating the config from the front-end program to the picture display program might conceivably help -- but that config is also user-editable, so a binary format would cost me a lot of work elsewhere.

        Is there something better than just putting it in an ordinary message? And do I have to go through and escape lots of special characters when I do that?

        Putting code fragments in messages is standard practice here. Surround the code with a <code> .. </code> tag pair, and HTML entities with the code will be handled automagically.

        Just post the code in a reply, between <code> tags.

        -- zigdon

Re: Startup cost, CGI performance
by bugsbunny (Scribe) on Jan 14, 2004 at 13:35 UTC
    u could also try this one :
    http://people.ee.ethz.ch/~oetiker/webtools/smokeping/
    then look for SpeedyCGI link... sorry i can give it to u, for some reason the page don't load for me...
    excerpt from the page :
    .... The CGI script uses SpeedyCGI to achieve mod_perl like performanc +e without the need to deploy mod_perl on your web server....