Improving mod_perl Driven Site's Performance -- Part III: Code Profiling and Memory Measurement Techniques Page 5

By Jeremy Reed (Send Email)
Posted Jan 1, 2001


Configure /perl-status if you haven't already:

  <Location /perl-status>
    SetHandler perl-script
    PerlHandler Apache::Status
    order deny,allow
    #deny from all
    #allow from ...
  </Location>

  • Add to httpd.conf
      PerlSetVar StatusOptionsAll On
      PerlSetVar StatusTerse On
      PerlSetVar StatusTerseSize On
      PerlSetVar StatusTerseSizeMainSummary On
    
      PerlModule B::TerseSize

  • Start the server (best in httpd -X mode)

  • From your favorite browser fetch http://localhost/perl-status

  • Click on 'Loaded Modules' or 'Compiled Registry Scripts'

  • Click on the module or script of your choice (you might need to run some script/handler before you will see it here unless it was preloaded)

  • Click on 'Memory Usage' at the bottom

  • You should see all the subroutines and their respective sizes.

    Now you can start to optimize your code. Or test which of the several implementations is of the least size.

    For example, let's compare CGI.pm's OO vs. procedural interfaces:

    As you will see below the first OO script uses about 2k bytes while the second script (procedural interface) uses about 5k.

    Here are the code examples and the numbers:


    1.   cgi_oo.pl
        ---------
        use CGI ();
        my  = CGI->new;
        print ->header;
        print ->b("Hello");
    2.   cgi_mtd.pl
        ---------
        use CGI qw(header b);
        print header();
        print b("Hello");

    After executing each script in single server mode (-X) the results are:

    1.   Totals: 1966 bytes | 27 OPs
      
        handler 1514 bytes | 27 OPs
        exit     116 bytes |  0 OPs
    2.   Totals: 4710 bytes | 19 OPs
      
        handler  1117 bytes | 19 OPs
        basefont  120 bytes |  0 OPs
        frameset  120 bytes |  0 OPs
        caption   119 bytes |  0 OPs
        applet    118 bytes |  0 OPs
        script    118 bytes |  0 OPs
        ilayer    118 bytes |  0 OPs
        header    118 bytes |  0 OPs
        strike    118 bytes |  0 OPs
        layer     117 bytes |  0 OPs
        table     117 bytes |  0 OPs
        frame     117 bytes |  0 OPs
        style     117 bytes |  0 OPs
        Param     117 bytes |  0 OPs
        small     117 bytes |  0 OPs
        embed     117 bytes |  0 OPs
        font      116 bytes |  0 OPs
        span      116 bytes |  0 OPs
        exit      116 bytes |  0 OPs
        big       115 bytes |  0 OPs
        div       115 bytes |  0 OPs
        sup       115 bytes |  0 OPs
        Sub       115 bytes |  0 OPs
        TR        114 bytes |  0 OPs
        td        114 bytes |  0 OPs
        Tr        114 bytes |  0 OPs
        th        114 bytes |  0 OPs
        b         113 bytes |  0 OPs

    Note, that the above is correct if you didn't precompile all CGI.pm's methods at server startup. Since if you did, the procedural interface in the second test will take up to 18k and not 5k as we saw. That's because the whole of CGI.pm's namespace is inherited and it already has all its methods compiled, so it doesn't really matter whether you attempt to import only the symbols that you need. So if you have:

      use CGI  qw(-compile :all);

    in the server startup script. Having:

      use CGI qw(header);

    or

      use CGI qw(:all);

    is essentially the same. You will have all the symbols precompiled at startup imported even if you ask for only one symbol. It seems to me like a bug, but probably that's how CGI.pm works.

    BTW, you can check the number of opcodes in the code by a simple command line run. For example, comparing 'my %hash' vs. 'my %hash = ()'.




  • Comment and Contribute

    Your name/nickname

    Your email

    (Maximum characters: 1200). You have characters left.