You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@perl.apache.org by Joshua Chamas <jo...@chamas.com> on 2001/02/03 02:51:52 UTC

Apache::SizeLimit MAX UNSHARED patch

Hey,

Per Perrin Harkin's advice, and my client's consent, I hacked 
up Apache::SizeLimit to support MAX_PROCESS_UNSHARED_SIZE config, 
where instead of limiting by the apparent process size, one limits 
by the amount of unshared memory being used.  Unshared memory is the 
effective process size, in terms of how much of your machine's RAM 
its eating.   It rewards you for pre-loading modules and pre-compiling
scripts in your parent httpd.

The patch is below, and only supports this config on linux.
My development was on a linux 2.2 kernel, a relies on the format
in /proc/self/statm staying the same.

As Perrin's tells it in a previous thread, this is apparently
a better method of limiting your processes, than 
Apache::GTopLimit's MIN_PROCESS_SHARED_SIZE, and further
does not require installation of libgtop.

Please mail me for the full file, if this diff is too unwieldy.

--Josh


--- SizeLimit.pm~	Fri Feb  2 11:36:43 2001
+++ SizeLimit.pm	Fri Feb  2 13:52:39 2001
@@ -14,6 +14,9 @@
     use Apache::SizeLimit;
     $Apache::SizeLimit::MAX_PROCESS_SIZE = 10000; # in KB, so this is 10MB
 
+    # in KB, so this is 10MB, only supported under linux currently
+    $Apache::SizeLimit::MAX_PROCESS_UNSHARED_SIZE = 10000; 
+
     # in your httpd.conf:
     PerlFixupHandler Apache::SizeLimit
     # you can set this up as any Perl*Handler that handles part of the
@@ -26,6 +29,7 @@
     # in your CGI:
     use Apache::SizeLimit;
     &Apache::SizeLimit::setmax(10000);	# Max Process Size in KB
+    &Apache::SizeLimit::setmax_unshared(10000); # Max Unshared RAM 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
@@ -83,6 +87,9 @@
 (with the C<setmax> function), and see if the CHECK_EVERY_N_REQUESTS
 option is of benefit.
 
+Currently, linux is the only platform that supports the 
+MAX_PROCESS_UNSHARED_SIZE and setmax_unshared() settings.
+
 =item solaris 2.6
 
 For solaris we simply retrieve the size of /proc/self/as, which
@@ -120,12 +127,14 @@
 use Apache::Constants qw(:common);
 use Config;
 use strict;
-use vars qw($VERSION $HOW_BIG_IS_IT $MAX_PROCESS_SIZE
-	    $REQUEST_COUNT $CHECK_EVERY_N_REQUESTS);
+use vars qw($VERSION $HOW_BIG_IS_IT $HOW_UNSHARED_IS_IT 
+	    $MAX_PROCESS_SIZE $MAX_PROCESS_UNSHARED_SIZE
+	    $REQUEST_COUNT $CHECK_EVERY_N_REQUESTS $CHECK_TOTAL);
 
-$VERSION = '0.03';
+$VERSION = '0.05';
 $CHECK_EVERY_N_REQUESTS = 1;
 $REQUEST_COUNT = 1;
+$CHECK_TOTAL = 0;
 
 BEGIN {
     # decide at compile time how to check for a process' memory size.
@@ -134,6 +143,7 @@
 	$HOW_BIG_IS_IT = \&solaris_2_6_size_check;
     } elsif ($Config{'osname'} eq 'linux') {
 	$HOW_BIG_IS_IT = \&linux_size_check;
+	$HOW_UNSHARED_IS_IT = \&linux_unshared_size_check;
     } elsif ($Config{'osname'} =~ /(bsd|aix)/i) {
 	# will getrusage work on all BSDs?  I should hope so.
 	if (eval("require BSD::Resource;")) {
@@ -159,6 +169,24 @@
     return($size);
 }
 
+sub linux_unshared_size_check {
+    my $unshared_size = 0;
+    local(*FH);
+    if (open(FH, "</proc/self/statm")) {
+	my $data = <FH>;
+	close(FH);
+	my($size, $resident, $shared) = split(/\s+/, $data);
+	if($resident && $shared) {
+	    $unshared_size = 4 * ($resident - $shared); # 4KB pages listed
+	} else {
+	    &error_log("Fatal Error: /proc/self/statm not right format, got: $data");
+	}
+    } else {
+	&error_log("Fatal Error: couldn't access /proc/self/statm: $!");
+    }
+    return($unshared_size);
+}
+
 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");
@@ -171,6 +199,7 @@
 }
 
 sub exit_if_too_big {
+    $CHECK_TOTAL++;
     return if ($REQUEST_COUNT++ < $CHECK_EVERY_N_REQUESTS);
     $REQUEST_COUNT = 1;
     if (defined($MAX_PROCESS_SIZE)) {
@@ -184,8 +213,25 @@
 		&error_log("main process too big, SIZE=$size KB");
 	    }
 	}
+    } elsif (defined($MAX_PROCESS_UNSHARED_SIZE)) {
+	if($HOW_UNSHARED_IS_IT) {
+	    my $size = &$HOW_UNSHARED_IS_IT();
+	    if($size > $MAX_PROCESS_UNSHARED_SIZE) {
+		if(getppid > 1) { # this is a child httpd
+		    &error_log("httpd process too unshared, exiting at UNSHARED SIZE=$size KB, after $CHECK_TOTAL checks");
+		    &Apache::exit(-2);
+		} else {
+		    # don't do anything for main httpd
+		}
+	    } else {
+		# don't do anything
+	    }
+	} else {
+	    &error_log("no MAX_PROCESS_UNSHARED_SIZE handler for this platform $^O, ".
+		       "currently only linux supported");
+	}
     } else {
-	&error_log("you didn't set \$Apache::SizeLimit::MAX_PROCESS_SIZE");
+	&error_log("you didn't set \$Apache::SizeLimit::MAX_PROCESS_SIZE or MAX_PROCESS_UNSHARED_SIZE");
     }
 }
 
@@ -194,6 +240,11 @@
 sub setmax {
     $MAX_PROCESS_SIZE = shift;
     Apache->request->post_connection(\&exit_if_too_big);
+}
+
+sub setmax_unshared {
+    $MAX_PROCESS_UNSHARED_SIZE = shift;
+    Apache->request->post_cleanup(\&exit_if_too_big);
 }
 
 sub handler {

Re: Apache::SizeLimit MAX UNSHARED patch

Posted by Perrin Harkins <pe...@primenet.com>.
Joshua Chamas wrote:
> 
> Hey,
> 
> Per Perrin Harkin's advice, and my client's consent, I hacked
> up Apache::SizeLimit to support MAX_PROCESS_UNSHARED_SIZE config,
> where instead of limiting by the apparent process size, one limits
> by the amount of unshared memory being used.

I actually did submit our patch for this a couple of weeks ago.  I sent
it to the guy who's name was in the module, and he told me sent it along
to the proper authorities.  I'll send it to you if you'd like, and then
you could see if there are any extras in it that would help your patch. 
I did patch all the documentation in our version to include the new
option, so that might be a useful addition to yours.

- Perrin

Re: Apache::SizeLimit MAX UNSHARED patch

Posted by Perrin Harkins <pe...@primenet.com>.
Joshua Chamas wrote:
> 
> Hey,
> 
> Per Perrin Harkin's advice, and my client's consent, I hacked
> up Apache::SizeLimit to support MAX_PROCESS_UNSHARED_SIZE config,
> where instead of limiting by the apparent process size, one limits
> by the amount of unshared memory being used.

I actually did submit our patch for this a couple of weeks ago.  I sent
it to the guy who's name was in the module, and he told me sent it along
to the proper authorities.  I'll send it to you if you'd like, and then
you could see if there are any extras in it that would help your patch. 
I did patch all the documentation in our version to include the new
option, so that might be a useful addition to yours.

- Perrin