ljr/local/htdocs/admin/memcache.bml

172 lines
5.3 KiB
Plaintext
Executable File

<?_code
{
#line 3
use strict;
no strict 'refs';
use vars qw(%GET);
use Data::Dumper;
use Time::HiRes ();
my $u = LJ::get_remote();
return "You must be logged in to view this tool." unless $u;
return "You don't have 'finduser' priv." unless LJ::check_priv($u, "finduser");
# return "You don't have 'siteadmin' priv." unless LJ::check_priv($u, "siteadmin");
my $prev_hits = $u ? LJ::MemCache::get([$u->{'userid'},"mcrate:$u->{'userid'}"]) : undef;
my $ret;
my $mode = $GET{'mode'};
if ($GET{'host'}) {
$mode ||= "host";
}
$mode ||= "overview";
$ret .= "<div class='topbar'>[<a href='memcache.bml'>Overview</a>]\n";
if ($mode eq "overview") {
$ret .= <<"END_TOP";
</div>
<h1>Memory Cache Overview</h1>
<table border='1' cellpadding='5'>
<tr><th>Host</th><th>Hit Rate</th><th>Curr/Max Size</th><th><span title='Utilization'>Utlz %</span></th><th>Uptime</th><th>Version</th></tr>
END_TOP
}
my %now_hits;
if ($prev_hits) { %now_hits = %$prev_hits; }
my ($tot_hits, $tot_misses) = ();
foreach my $entry (@LJ::MEMCACHE_SERVERS) {
my $host = ref $entry ? $entry->[0] : $entry;
next if $mode eq "host" && $host ne $GET{'host'};
LJ::MemCache::forget_dead_hosts();
my $sock = Cache::Memcached::sock_to_host($host);
my $t1 = Time::HiRes::time();
my $log;
my %stat;
my @cmds = ("", "malloc", "items", "slabs");
my $cmd;
if ($sock) {
while (defined($cmd = shift @cmds)) {
my $realcmd = "stats" . ($cmd ? " $cmd" : "");
$log .= "<b>$realcmd</b>\n";
foreach (LJ::MemCache::run_command($sock, "$realcmd\r\n")) {
last if $_ eq "END\r\n";
$log .= $_;
next if $cmd eq "maps";
if (/^STAT (\S+) (\S+)/) {
$stat{$cmd}{$1} = $2;
}
}
}
}
my $t2 = Time::HiRes::time();
my $cpu = 0;
foreach my $key (qw(rusage_user rusage_system)) {
my $sec = $stat{''}{$key};
$sec =~ s/:/\./;
$cpu += $sec;
#$ret .= "Host $host was $stat{''}{$key} = $sec, cpu = $cpu<br />\n";
}
$now_hits{$host} = [ $stat{''}{'get_hits'}, $stat{''}{'get_misses'}, $cpu ];
my $hit_rate = sprintf("%0.02f%%", $stat{''}{'get_hits'}/($stat{''}{'get_hits'}+$stat{''}{'get_misses'}||1)*100);
if ($mode eq "overview") {
$ret .= "<tr><td><a href='memcache.bml?host=$host'>$host</a></td>\n";
$ret .= "<td>$hit_rate";
if ($prev_hits && $prev_hits->{$host}) {
my $nh = $now_hits{$host};
my $ph = $prev_hits->{$host};
my $new_hits = $now_hits{$host}[0] - $prev_hits->{$host}[0];
my $new_misses = $now_hits{$host}[1] - $prev_hits->{$host}[1];
$tot_hits += $new_hits;
$tot_misses += $new_misses;
my $new_whatev = $new_hits + $new_misses;
my $new_rate = $new_hits / ($new_whatev || 1);
my $cpu = sprintf("%0.6f", $nh->[2] - $ph->[2]);
$ret .= sprintf(" [%0.02f%% {$new_whatev} $cpu]", $new_rate * 100);
}
$ret .= sprintf(" %0.02f", $t2-$t1);
$ret .= "</td>";
my $gb_used = ($stat{'malloc'}{'mmapped_space'} + $stat{'malloc'}{'arena_size'}) / (1024*1024*1024);
my $gb_max = $stat{''}{'limit_maxbytes'} / (1024*1024*1024);
if ($gb_used >= $gb_max) {
$ret .= sprintf("<td align='center'>%0.01fG</td>", $gb_max);
} else {
$ret .= sprintf("<td>%0.02f/%0.01fG (%0.02f%%)</td>", $gb_used, $gb_max, $gb_used*100/($gb_max||1));
}
my $utiliz = $stat{''}{'bytes'} /
(($stat{'malloc'}{'mmapped_space'} + $stat{'malloc'}{'arena_size'}) || 1);
$ret .= sprintf("<td>%0.02f%%</td>", $utiliz*100);
my $up = $stat{''}{'uptime'};
my $upstring;
foreach my $u ([86400,"d"],[3600,"h"],[60,"m"],[1,"s"]) {
if ($up / $u->[0] > 1) {
my $v = int($up / $u->[0]);
$upstring .= "${v}$u->[1] ";
$up -= $v * $u->[0];
}
}
$ret .= "<td>$upstring</td>";
$ret .= "<td>$stat{''}{'version'}</td>";
$ret .= "</tr>";
}
if ($mode eq "host" && $host eq $GET{'host'}) {
$ret .= "[<a href='memcache.bml?host=$host&amp;mode=raw'>Raw Data</a>]</div>";
$ret .= "<h1>Details for $host</h1>";
$ret .= "<h2>Slab classes</h2>";
$ret .= "<table border='1' cellpadding='2'>";
$ret .= "<tr><th>class</th><th>size</th><th>used</th><th>total</th><th colspan='2'>free</th><th>pages</th><th>max age</th></tr>\n";
foreach my $cls (0..60) {
my $size = $stat{'slabs'}{"$cls:chunk_size"};
next unless $size;
$ret .= "<tr><td>$cls</td>"
. join('', map { "<td>" . $stat{'slabs'}{"$cls:$_"} . "</td>" }
qw(chunk_size used_chunks total_chunks free_chunks free_chunks_end total_pages));
my $age = $stat{'items'}{"items:$cls:age"};
$ret .= "<td>$age</td>";
$ret .= "</tr>";
}
$ret .= "</table>\n";
}
if ($mode eq "raw" && $host eq $GET{'host'}) {
$ret .= "[<a href='memcache.bml?host=$host'>Host Stats</a>]</div>";
$ret .= "<h1>Raw data for $host</h1>";
$ret .= "<pre>$log</pre>";
}
}
LJ::MemCache::set([$u->{'userid'},"mcrate:$u->{'userid'}"], \%now_hits)
if $u;
if ($mode eq "overview") {
$ret .= "</table>\n";
my $new_whatev = $tot_hits + $tot_misses;
my $new_rate = $tot_hits / ($new_whatev || 1);
$ret .= sprintf("Global [%0.02f%% {$new_whatev}]", $new_rate * 100);
}
return $ret;
}
_code?>