#!/usr/perl5/bin/perl -w # ## Originally by benr@cuddletech.com ## Converted to HTML output by James Dickens ## ## zfs_arc_web.pl v0.3 use strict; use Sun::Solaris::Kstat; use POSIX; my $Kstat = Sun::Solaris::Kstat->new(); ## html subroutines sub http_headers($) { my($content_type) = @_; print <<"EOF"; Content-Type: $content_type Refresh: 60 Pragma: no-cache EOF # Expires header calculation stolen from CGI.pm print strftime("Expires: %a, %d %b %Y %H:%M:%S GMT\n\n", gmtime(time+60*5)); } sub print_style() { print <<'EOF'; EOF } sub start_of_page() { print <<'EOF' ZFS ARC Summary

ZFS ARC Summary

EOF } sub setup_table($) { my($header) = @_; print <<"EOF"; EOF } sub table_header($) { my($header) = @_; print "" } sub start_row() { print "
$header
$header
"; } sub end_table() { print "

\n\n\n"; } ### System Memory ### my $phys_pages = ${Kstat}->{unix}->{0}->{system_pages}->{physmem}; my $free_pages = ${Kstat}->{unix}->{0}->{system_pages}->{freemem}; my $lotsfree_pages = ${Kstat}->{unix}->{0}->{system_pages}->{lotsfree}; my $pagesize = `pagesize`; my $phys_memory = ($phys_pages * $pagesize); my $free_memory = ($free_pages * $pagesize); my $lotsfree_memory = ($lotsfree_pages * $pagesize); ### print headers ### http_headers('text/html'); start_of_page(); print_style(); setup_table("System Memory"); start_row(); printf("Physical RAM%d MB\n", $phys_memory / 1024 / 1024); start_row(); printf("Free Memory%d MB\n", $free_memory / 1024 / 1024); start_row(); printf("LotsFree%d MB\n", $lotsfree_memory / 1024 / 1024); end_table(); ########################## #### Tunables ##################### # #my @tunables = `grep zfs /etc/system`; #print "

ZFS Tunables (/etc/system):

\n"; #foreach(@tunables) { # chomp($_); # print "\t $_
\n"; #} #### ARC Sizing ############### my $mru_size = ${Kstat}->{zfs}->{0}->{arcstats}->{p}; my $target_size = ${Kstat}->{zfs}->{0}->{arcstats}->{c}; my $arc_min_size = ${Kstat}->{zfs}->{0}->{arcstats}->{c_min}; my $arc_max_size = ${Kstat}->{zfs}->{0}->{arcstats}->{c_max}; my $arc_size = ${Kstat}->{zfs}->{0}->{arcstats}->{size}; my $mfu_size = ${target_size} - $mru_size; my $mru_perc = 100*($mru_size / $target_size); my $mfu_perc = 100*($mfu_size / $target_size); ##print "

ARC Size:

\n"; setup_table("ARC Size"); start_row();printf("Current Size%d MB (arcsize)\n", $arc_size / 1024 / 1024); start_row();printf("Target Size (Adaptive)%d MB (c)\n", $target_size / 1024 / 1024); start_row();printf("Min Size (Hard Limit)%d MB (zfs_arc_min)\n", $arc_min_size / 1024 / 1024); start_row();printf("Max Size (Hard Limit:%d MB (zfs_arc_max)\n", $arc_max_size / 1024 / 1024); end_table(); setup_table("ARC Size Breakdown"); start_row();printf("Most Recently Used Cache Size%2d%%  %d MB (p)\n", $mru_perc, $mru_size / 1024 / 1024); start_row();printf("Most Frequently Used Cache Size%2d%%  %d MB (c-p)\n", $mfu_perc, $mfu_size / 1024 / 1024); end_table(); ################################## #my $arc_size = ${Kstat}->{zfs}->{0}->{arcstats}->{size}; ####### ARC Efficency #########################
my $arc_hits = ${Kstat}->{zfs}->{0}->{arcstats}->{hits}; my $arc_misses = ${Kstat}->{zfs}->{0}->{arcstats}->{misses}; my $arc_accesses_total = ($arc_hits + $arc_misses); my $arc_hit_perc = 100*($arc_hits / $arc_accesses_total); my $arc_miss_perc = 100*($arc_misses / $arc_accesses_total); my $mfu_hits = ${Kstat}->{zfs}->{0}->{arcstats}->{mfu_hits}; my $mru_hits = ${Kstat}->{zfs}->{0}->{arcstats}->{mru_hits}; my $mfu_ghost_hits = ${Kstat}->{zfs}->{0}->{arcstats}->{mfu_ghost_hits}; my $mru_ghost_hits = ${Kstat}->{zfs}->{0}->{arcstats}->{mru_ghost_hits}; my $anon_hits = $arc_hits - ($mfu_hits + $mru_hits + $mfu_ghost_hits + $mru_ghost_hits); my $real_hits = ($mfu_hits + $mru_hits); my $real_hits_perc = 100*($real_hits / $arc_accesses_total); ### These should be based on TOTAL HITS ($arc_hits)
my $anon_hits_perc = 100*($anon_hits / $arc_hits); my $mfu_hits_perc = 100*($mfu_hits / $arc_hits); my $mru_hits_perc = 100*($mru_hits / $arc_hits); my $mfu_ghost_hits_perc = 100*($mfu_ghost_hits / $arc_hits); my $mru_ghost_hits_perc = 100*($mru_ghost_hits / $arc_hits); my $demand_data_hits = ${Kstat}->{zfs}->{0}->{arcstats}->{demand_data_hits}; my $demand_metadata_hits = ${Kstat}->{zfs}->{0}->{arcstats}->{demand_metadata_hits}; my $prefetch_data_hits = ${Kstat}->{zfs}->{0}->{arcstats}->{prefetch_data_hits}; my $prefetch_metadata_hits = ${Kstat}->{zfs}->{0}->{arcstats}->{prefetch_metadata_hits}; my $demand_data_hits_perc = 100*($demand_data_hits / $arc_hits); my $demand_metadata_hits_perc = 100*($demand_metadata_hits / $arc_hits); my $prefetch_data_hits_perc = 100*($prefetch_data_hits / $arc_hits); my $prefetch_metadata_hits_perc = 100*($prefetch_metadata_hits / $arc_hits); my $demand_data_misses = ${Kstat}->{zfs}->{0}->{arcstats}->{demand_data_misses}; my $demand_metadata_misses = ${Kstat}->{zfs}->{0}->{arcstats}->{demand_metadata_misses}; my $prefetch_data_misses = ${Kstat}->{zfs}->{0}->{arcstats}->{prefetch_data_misses}; my $prefetch_metadata_misses = ${Kstat}->{zfs}->{0}->{arcstats}->{prefetch_metadata_misses}; my $demand_data_misses_perc = 100*($demand_data_misses / $arc_misses); my $demand_metadata_misses_perc = 100*($demand_metadata_misses / $arc_misses); my $prefetch_data_misses_perc = 100*($prefetch_data_misses / $arc_misses); my $prefetch_metadata_misses_perc = 100*($prefetch_metadata_misses / $arc_misses); my $prefetch_data_total = ($prefetch_data_hits + $prefetch_data_misses); my $prefetch_data_perc = "00"; if ($prefetch_data_total > 0 ) { $prefetch_data_perc = 100*($prefetch_data_hits / $prefetch_data_total); } my $demand_data_total = ($demand_data_hits + $demand_data_misses); my $demand_data_perc = 100*($demand_data_hits / $demand_data_total); ##print "

ARC Efficency:

\n"; setup_table("ARC Efficency"); start_row();printf("Cache Access Total%d\n", $arc_accesses_total); start_row();printf("Cache Hit Ratio%2d%   %d [Defined State for buffer]\n", $arc_hit_perc, $arc_hits); start_row();printf("Cache Miss Ratio%2d%%  %d [Undefined State for Buffer]\n", $arc_miss_perc, $arc_misses); start_row();printf("REAL Hit Ratio%2d%%  %d [MRU/MFU Hits Only]\n", $real_hits_perc, $real_hits); start_row();printf("Data Demand Efficiency%2d%%\n", $demand_data_perc); if ($prefetch_data_total == 0){ start_row();printf("Data Prefetch Efficiency DISABLED (zfs_prefetch_disable)\n"); } else { start_row();printf("Data Prefetch Efficiency %2d%%\n", $prefetch_data_perc); } table_header("CACHE HITS BY CACHE LIST"); if ( $anon_hits < 1 ){ start_row();printf("Anon--%%  Counter Rolled.\n"); } else { start_row();printf("Anon:%2d%%  %d [ New Customer, First Cache Hit ]\n", $anon_hits_perc, $anon_hits); } start_row();printf("Most Recently Used%2d%%   %d (mru)  [ Return Customer ]\n", $mru_hits_perc, $mru_hits); start_row();printf("Most Frequently Used%2d%%    %d (mfu   [ Frequent Customer ]\n", $mfu_hits_perc, $mfu_hits); start_row();printf("Most Recently Used Ghost%2d%%    %d (mru_ghost)  [ Return Customer Evicted, Now Back ]\n", $mru_ghost_hits_perc, $mru_ghost_hits); start_row();printf("Most Frequently Used Ghost%2d%%    %d (mfu_ghost)  [ Frequent Customer Evicted, Now Back ]\n", $mfu_ghost_hits_perc, $mfu_ghost_hits); table_header("CACHE HITS BY DATA TYPE"); start_row();printf("Demand Data%2d%%  %d\n", $demand_data_hits_perc, $demand_data_hits); start_row();printf("Prefetch Data%2d%%  %d\n", $prefetch_data_hits_perc, $prefetch_data_hits); start_row();printf("Demand Metadata%2d%%  %d\n", $demand_metadata_hits_perc, $demand_metadata_hits); start_row();printf("Prefetch Metadata%2d%%  %d\n", $prefetch_metadata_hits_perc, $prefetch_metadata_hits); table_header("CACHE MISSES BY DATA TYPE"); start_row();printf("Demand Data%2d%%  %d\n", $demand_data_misses_perc, $demand_data_misses); start_row();printf("Prefetch Data%2d%%  %d\n", $prefetch_data_misses_perc, $prefetch_data_misses); start_row();printf("Demand Metadata%2d%%  %d\n", $demand_metadata_misses_perc, $demand_metadata_misses); start_row();printf("Prefetch Metadata%2d%%  %d\n", $prefetch_metadata_misses_perc, $prefetch_metadata_misses); end_table(); ###############################################