dougm 01/07/06 06:44:41
Modified: . Changes
lib/Apache SizeLimit.pm
Log:
Apache::SizeLimit enhancements [Perrin Harkins <[EMAIL PROTECTED]>]:
- Added support for minimum shared memory and maximum unshared memory
settings.
- Added extra diagnostics to tell how many requests a process served,
how long it lived, and how much shared memory it was using when
SizeLimit killed it.
Revision Changes Path
1.602 +7 -0 modperl/Changes
Index: Changes
===================================================================
RCS file: /home/cvs/modperl/Changes,v
retrieving revision 1.601
retrieving revision 1.602
diff -u -r1.601 -r1.602
--- Changes 2001/06/21 16:11:40 1.601
+++ Changes 2001/07/06 13:44:34 1.602
@@ -10,6 +10,13 @@
=item 1.25_01-dev
+Apache::SizeLimit enhancements [Perrin Harkins <[EMAIL PROTECTED]>]:
+- Added support for minimum shared memory and maximum unshared memory
+settings.
+- Added extra diagnostics to tell how many requests a process served,
+how long it lived, and how much shared memory it was using when
+SizeLimit killed it.
+
win32 enhancement: APACHE_SRC can be either the build or install tree
[Randy Kobes <[EMAIL PROTECTED]>]
1.8 +81 -24 modperl/lib/Apache/SizeLimit.pm
Index: SizeLimit.pm
===================================================================
RCS file: /home/cvs/modperl/lib/Apache/SizeLimit.pm,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- SizeLimit.pm 2000/12/20 18:51:56 1.7
+++ SizeLimit.pm 2001/07/06 13:44:39 1.8
@@ -12,7 +12,10 @@
# in your startup.pl:
use Apache::SizeLimit;
- $Apache::SizeLimit::MAX_PROCESS_SIZE = 10000; # in KB, so this is 10MB
+ # sizes are in KB
+ $Apache::SizeLimit::MAX_PROCESS_SIZE = 10000; # 10MB
+ $Apache::SizeLimit::MIN_SHARE_SIZE = 1000; # 1MB
+ $Apache::SizeLimit::MAX_UNSHARED_SIZE = 12000; # 12MB
# in your httpd.conf:
PerlFixupHandler Apache::SizeLimit
@@ -25,7 +28,9 @@
# in your CGI:
use Apache::SizeLimit;
- &Apache::SizeLimit::setmax(10000); # Max Process Size in KB
+ &Apache::SizeLimit::setmax(10000); # Max size in KB
+ &Apache::SizeLimit::setmin(1000); # Min share in KB
+ &Apache::SizeLimit::setmax_unshared(12000); # Max unshared size in KB
Since checking the process size can take a few system calls on some
platforms (e.g. linux), you may want to only check the process size every
@@ -66,10 +71,29 @@
technique shown in this module and set my MaxRequestsPerChild value to
6000.
+=head1 SHARED MEMORY OPTIONS
+
+In addition to simply checking the total size of a process, this
+module can factor in how much of the memory used by the process is
+actually being shared by copy-on-write. If you don't understand how
+memory is shared in this way, take a look at the mod_perl Guide at
+http://perl.apache.org/guide/.
+
+You can take advantage of the shared memory information by setting a
+minimum shared size and/or a maximum unshared size. Experience on one
+heavily trafficked mod_perl site showed that setting maximum unshared
+size and leaving the others unset is the most effective policy. This
+is because it only kills off processes that are truly using too much
+physical RAM, allowing most processes to live longer and reducing the
+process churn rate.
+
=head1 CAVEATS
This module is platform dependent, since finding the size of a process
-is pretty different from OS to OS, and some platforms may not be supported.
+is pretty different from OS to OS, and some platforms may not be
+supported. In particular, the limits on minimum shared memory and
+maximum shared memory are currently only supported on Linux and BSD.
+If you can contribute support for another OS, please do.
Currently supported OSes:
@@ -87,6 +111,7 @@
For solaris we simply retrieve the size of /proc/self/as, which
contains the address-space image of the process, and convert to KB.
+Shared memory calculations are not supported.
NOTE: This is only known to work for solaris 2.6 and above. Evidently
the /proc filesystem has changed between 2.5.1 and 2.6. Can anyone
@@ -99,7 +124,8 @@
=item AIX?
-Uses BSD::Resource::getrusage() to determine process size.
+Uses BSD::Resource::getrusage() to determine process size. Not sure if the
+shared memory calculations will work or not. AIX users?
=back
@@ -121,12 +147,17 @@
use Config;
use strict;
use vars qw($VERSION $HOW_BIG_IS_IT $MAX_PROCESS_SIZE
- $REQUEST_COUNT $CHECK_EVERY_N_REQUESTS);
+ $REQUEST_COUNT $CHECK_EVERY_N_REQUESTS
+ $MIN_SHARE_SIZE $MAX_UNSHARED_SIZE $START_TIME);
$VERSION = '0.03';
$CHECK_EVERY_N_REQUESTS = 1;
$REQUEST_COUNT = 1;
+$MAX_PROCESS_SIZE = 0;
+$MIN_SHARE_SIZE = 0;
+$MAX_UNSHARED_SIZE = 0;
+
BEGIN {
# decide at compile time how to check for a process' memory size.
if (($Config{'osname'} eq 'solaris') &&
@@ -148,45 +179,58 @@
# return process size (in KB)
sub linux_size_check {
- my $size = 0;
+ my ($size, $resident, $share) = (0,0,0);
local(*FH);
- if (open(FH, "</proc/self/status")) {
- while (<FH>) { last if (($size) = (/^VmRSS:\s+(\d+)/)) }
+ if (open(FH, "</proc/self/statm")) {
+ ($size, $resident, $share) = split(/\s/, scalar <FH>);
close(FH);
} else {
&error_log("Fatal Error: couldn't access /proc/self/status");
}
- return($size);
+ # linux on intel x86 has 4KB page size...
+ return($size*4, $share*4);
}
sub solaris_2_6_size_check {
my $size = -s "/proc/self/as" or
&error_log("Fatal Error: /proc/self/as doesn't exist or is empty");
$size = int($size/1024); # to get it into kb
- return($size);
+ return($size, 0); # return 0 for share, to avoid undef warnings
}
sub bsd_size_check {
- return( (&BSD::Resource::getrusage())[2] );
+ return (&BSD::Resource::getrusage())[2,3];
}
sub exit_if_too_big {
my $r = shift;
- return DECLINED if ($REQUEST_COUNT++ < $CHECK_EVERY_N_REQUESTS);
- $REQUEST_COUNT = 1;
- if ($MAX_PROCESS_SIZE) {
- my $size = &$HOW_BIG_IS_IT();
- if ($size > $MAX_PROCESS_SIZE) {
- # I have no idea if this will work on anything but UNIX
- if (getppid > 1) { # this is a child httpd
- error_log("httpd process too big, exiting at SIZE=$size KB");
+ return DECLINED if ($CHECK_EVERY_N_REQUESTS &&
+ ($REQUEST_COUNT++ % $CHECK_EVERY_N_REQUESTS));
+
+ $START_TIME ||= time;
+
+ my($size, $share) = &$HOW_BIG_IS_IT();
+
+ if (($MAX_PROCESS_SIZE && $size > $MAX_PROCESS_SIZE)
+ ||
+ ($MIN_SHARE_SIZE && $share < $MIN_SHARE_SIZE)
+ ||
+ ($MAX_UNSHARED_SIZE && ($size - $share) > $MAX_UNSHARED_SIZE)) {
+
+ # wake up! time to die.
+ if (getppid > 1) { # this is a child httpd
+ my $e = time - $START_TIME;
+ my $msg = "httpd process too big, exiting at SIZE=$size KB ";
+ $msg .= " SHARE=$share KB " if ($share);
+ $msg .= " REQUESTS=$REQUEST_COUNT LIFETIME=$e seconds";
+ error_log($msg);
$r->child_terminate;
- } else { # this is the main httpd
- error_log("main process too big, SIZE=$size KB");
+
+ } else { # this is the main httpd, whose parent is init?
+ my $msg = "main process too big, exiting at SIZE=$size KB ";
+ $msg .= " SHARE=$share KB" if ($share);
+ error_log($msg);
}
- }
- } else {
- error_log("you didn't set \$Apache::SizeLimit::MAX_PROCESS_SIZE");
}
return OK;
}
@@ -198,6 +242,16 @@
Apache->request->post_connection(\&exit_if_too_big);
}
+sub setmin {
+ $MIN_SHARE_SIZE = shift;
+ Apache->request->post_connection(\&exit_if_too_big);
+}
+
+sub setmax_unshared {
+ $MAX_UNSHARED_SIZE = shift;
+ Apache->request->post_connection(\&exit_if_too_big);
+}
+
sub handler {
my $r = shift || Apache->request;
$r->post_connection(\&exit_if_too_big)
@@ -216,5 +270,8 @@
Doug Bagley <[EMAIL PROTECTED]>, channeling Procrustes.
Brian Moseley <[EMAIL PROTECTED]>: Solaris 2.6 support
+
+Doug Steinwand and Perrin Harkins <[EMAIL PROTECTED]>: added support
+ for shared memory and additional diagnostic info
=cut