ljr/livejournal/cgi-bin/Apache/DebateSuicide.pm

97 lines
2.2 KiB
Perl
Executable File

#!/usr/bin/perl
#
package Apache::DebateSuicide;
use strict;
use Apache::Constants qw(:common);
use vars qw($gtop);
our %known_parent;
our $ppid;
# oh btw, this is totally linux-specific. gtop didn't work, so so much for portability.
sub handler
{
my $r = shift;
return OK if $r->main;
return OK unless $LJ::HAVE_GTOP && $LJ::SUICIDE;
my $meminfo;
return OK unless open (MI, "/proc/meminfo");
$meminfo = join('', <MI>);
close MI;
my %meminfo;
while ($meminfo =~ m/(\w+):\s*(\d+)\skB/g) {
$meminfo{$1} = $2;
}
my $memfree = $meminfo{'MemFree'} + $meminfo{'Cached'};
return OK unless $memfree;
my $goodfree = $LJ::SUICIDE_UNDER{$LJ::SERVER_NAME} || $LJ::SUICIDE_UNDER || 150_000;
return OK if $memfree > $goodfree;
unless ($ppid) {
my $self = pid_info($$);
$ppid = $self->[3];
}
my $pids = child_info($ppid);
my @pids = keys %$pids;
$gtop ||= GTop->new;
my %stats;
my $sum_uniq = 0;
foreach my $pid (@pids) {
my $pm = $gtop->proc_mem($pid);
$stats{$pid} = [ $pm->rss - $pm->share, $pm ];
$sum_uniq += $stats{$pid}->[0];
}
@pids = (sort { $stats{$b}->[0] <=> $stats{$a}->[0] } @pids, 0, 0);
my $my_pid = $$;
if (grep { $my_pid == $_ } @pids[0,1]) {
my $my_use_k = $stats{$$}[0] >> 10;
$r->log_error("Suicide [$$]: system memory free = ${memfree}k; i'm big, using ${my_use_k}k") if $LJ::DEBUG{'suicide'};
Apache::LiveJournal::db_logger($r) unless $r->pnotes('did_lj_logging');
$r->child_terminate;
}
return OK;
}
sub pid_info {
my $pid = shift;
open (F, "/proc/$pid/stat") or next;
$_ = <F>;
close(F);
my @f = split;
return \@f;
}
sub child_info {
my $ppid = shift;
opendir(D, "/proc") or return undef;
my @pids = grep { /^\d+$/ } readdir(D);
closedir(D);
my %ret;
foreach my $p (@pids) {
next if (defined $known_parent{$p} &&
$known_parent{$p} != $ppid);
my $ary = pid_info($p);
my $this_ppid = $ary->[3];
$known_parent{$p} = $this_ppid;
next unless $this_ppid == $ppid;
$ret{$p} = $ary;
}
return \%ret;
}
1;