2
0
mirror of https://github.com/munin-monitoring/contrib.git synced 2018-11-08 00:59:34 +01:00
contrib-munin/plugins/other/cpu
Gorlow Maxim aka Sheridan 6552dd3fb3 Initial version
2011-12-18 15:10:25 +01:00

893 lines
26 KiB
Perl
Executable File

#!/usr/bin/perl -w
# -*- perl -*-
=head1 NAME
cpu - Plugin to monitor CPU usage and frequencies.
=head1 APPLICABLE SYSTEMS
All Linux systems, but read below section
=head1 CONFIGURATION
The plugin automatically selects which graphics drawing.
Charts related to the frequencies of processors depends on the settings of the kernel:
Power management and ACPI options -> CPU Frequency scaling -> CPU frequency translation statistics -> Advanced statistics
=head2 WARNING AND CRITICAL SETTINGS
You can set warning and critical levels for each of the data
series the plugin reports. The following environment variables are
used as default for all fields:
env.warning
env.critical
But each field (system user nice idle iowait irq softirq steal guest) can be controlled separately:
For example:
env.system_warning 70
env.user_warning 70
env.idle_critical 1
=head1 INTERPRETATION
The plugin shows each cpu usage in percent, shows the CPU frequency,
frequency shift frequencies, the percentage of use of frequencies
=head1 MAGIC MARKERS
#%# family=auto
#%# capabilities=autoconf
=head1 VERSION
1.0
=head1 BUGS
none known
=head1 AUTHOR
Gorlow Maxim aka Sheridan <sheridan@sheridan-home.ru> (email and jabber)
=head1 LICENSE
GPLv2
=cut
use strict;
use warnings;
use Munin::Plugin;
use Data::Dumper;
my @cnames = qw(user nice system idle iowait irq softirq steal guest);
my $stat_file = "/proc/stat";
my $freq_path = "/sys/devices/system/cpu";
my $limits = {};
my $cpuinfo = {}; $cpuinfo->{'cpu_count'} = 0;
my @stat_file_content = ();
my $freq_mul = 1000; # CPU frequency multiplier from kHz to Hz
$limits->{'warning'} = $ENV{warning} || undef;
$limits->{'critical'} = $ENV{critical} || undef;
for my $cname (@cnames)
{
for my $t (qw(warning critical))
{
my $name = sprintf("%s_%s", $cname, $t);
$limits->{$name} = $ENV{$name} || undef;
}
}
my $graphs =
{
'cpu_utilisation' => # multigraph
{
'title' => 'CPU:t: utilisation',
'args' => '--base 1000 -r --lower-limit 0 --upper-limit 100',
'vlabel' => '%',
'scale' => 'no',
'info' => 'This graph shows how CPU:t: time is spent :i:'
},
'cpu_all' => # single
{
'title' => 'All CPU utilisation',
'args' => '--base 1000 -r --lower-limit 0 --upper-limit 100',
'vlabel' => '%',
'scale' => 'no',
'info' => 'This graph shows how CPU time is spent on each processor',
'category' => 'cpu'
},
'cpu_freq_trans' => # multi
{
'title' => 'CPU frequency transitions',
'args' => '--base 1000',
'vlabel' => 'count',
'scale' => 'no',
'info' => 'This graph shows CPU transitions of each processor',
},
'cpu_freq' => # child of cpu_freq_trans
{
'title' => 'CPU:t: frequency',
'args' => '--base 1000 -r --lower-limit 0 --upper-limit 100',
'vlabel' => '%',
'info' => 'This graph shows CPU:t: frequency :i:',
'category' => 'cpu'
},
'cpu_freq_trans_table' => # child of cpu_freq_trans
{
'title' => 'CPU:t: frequency switches',
'args' => '--base 1000 -r --lower-limit 0 --upper-limit 100',
'vlabel' => 'count',
'scale' => 'no',
'info' => 'This graph shows CPU:t: frequency switches :i:',
}
};
my $transparent = 'CC';
my $fields =
{
'user' =>
{
'label' => 'User',
'info' => 'Normal processes executing in user mode',
'type' => 'GAUGE',
'draw' => 'AREASTACK',
'min' => 0,
'max' => 100
},
'nice' =>
{
'label' => 'Nice',
'info' => 'Niced processes executing in user mode',
'type' => 'GAUGE',
'draw' => 'AREASTACK',
'min' => 0,
'max' => 100
},
'system' =>
{
'label' => 'System',
'info' => 'Processes executing in kernel mode',
'type' => 'GAUGE',
'draw' => 'AREASTACK',
'min' => 0,
'max' => 100
},
'idle' =>
{
'label' => 'Idle',
'info' => 'Twiddling thumbs',
'type' => 'GAUGE',
'draw' => 'AREASTACK',
'colour'=> 'FFFFDD'.$transparent,
'min' => 0,
'max' => 100
},
'iowait' =>
{
'label' => 'I/O wait',
'info' => 'Waiting for I/O to complete',
'type' => 'GAUGE',
'draw' => 'AREASTACK',
'min' => 0,
'max' => 100
},
'irq' =>
{
'label' => 'IRQ',
'info' => 'Servicing interrupts',
'type' => 'GAUGE',
'draw' => 'AREASTACK',
'min' => 0,
'max' => 100
},
'softirq' =>
{
'label' => 'Software IRQ',
'info' => 'Servicing software interrupts',
'type' => 'GAUGE',
'draw' => 'AREASTACK',
'min' => 0,
'max' => 100
},
'steal' =>
{
'label' => 'Steal',
'info' => 'Involuntary wait',
'type' => 'GAUGE',
'draw' => 'AREASTACK',
'min' => 0,
'max' => 100
},
'guest' =>
{
'label' => 'Guest',
'info' => 'Running a guest',
'type' => 'GAUGE',
'draw' => 'AREASTACK',
'min' => 0,
'max' => 100
},
'cpu_util' =>
{
'label' => ':t:',
'info' => ':t: utilisation',
'type' => 'GAUGE',
'draw' => 'LINE0.5',
'min' => 0,
'max' => 100
},
'freq_percent' =>
{
'label' => 'CPU:t: frequency',
'info' => 'CPU:t: frequency percent',
'type' => 'GAUGE',
'draw' => 'LINE0.5',
'min' => 0,
'max' => 100
},
'freq_hz' =>
{
'label' => ':t:',
'info' => 'CPU :t: frequency',
'type' => 'GAUGE',
'draw' => 'AREASTACK',
'min' => 0,
'max' => 100
},
'freq_trans' =>
{
'label' => ':t:',
'info' => ':t: frequency transitions',
'type' => 'GAUGE',
'draw' => 'LINE0.5',
'min' => 0
},
'freq_trans_table' =>
{
'label' => ':t:',
'info' => ':t: frequency switch',
'type' => 'GAUGE',
'draw' => 'AREASTACK',
'min' => 0,
'max' => 100
}
};
# ----------------- main ----------------
load_cpuinfo();
need_multigraph();
remove_unavialabled_counters();
if (defined($ARGV[0]) and ($ARGV[0] eq 'autoconf'))
{
printf("%s\n", -e $stat_file ? "yes" : "no (stats not exists)");
exit (0);
}
if (defined($ARGV[0]) and ($ARGV[0] eq 'config'))
{
print_config();
exit (0);
}
print_values();
#print Dumper prepare_graphs_fields();
exit(0);
# ----------------- sub's ----------------
# ----------------------- trim whitespace at begin and end of string ------------
sub trim
{
my($string)=@_;
for ($string) { s/^\s+//; s/\s+$//; }
return $string;
}
my $items_exists = {};
sub check_exists
{
my ($t, $cpu_num) = @_[0..1];
if (defined($cpu_num))
{
unless (exists($items_exists->{$t}{$cpu_num}))
{
if ($t eq 'freq_hz')
{
$items_exists->{$t}{$cpu_num} = ( -e sprintf("%s/cpu%s/cpufreq/scaling_min_freq", $freq_path, $cpu_num) and
-e sprintf("%s/cpu%s/cpufreq/scaling_cur_freq", $freq_path, $cpu_num) and
-e sprintf("%s/cpu%s/cpufreq/scaling_max_freq", $freq_path, $cpu_num) );
}
elsif ($t eq 'freq_trans')
{
$items_exists->{$t}{$cpu_num} = -e sprintf("%s/cpu%s/cpufreq/stats/time_in_state", $freq_path, $cpu_num);
}
elsif ($t eq 'freq_times')
{
$items_exists->{$t}{$cpu_num} = -e sprintf("%s/cpu%s/cpufreq/stats/total_trans", $freq_path, $cpu_num);
}
elsif ($t eq 'freq_ttable')
{
$items_exists->{$t}{$cpu_num} = -e sprintf("%s/cpu%s/cpufreq/stats/trans_table", $freq_path, $cpu_num);
}
}
#print Dumper $items_exists;
return $items_exists->{$t}{$cpu_num};
}
else
{
unless(exists($items_exists->{$t}{'total'}))
{
my $c = 0;
for (my $i=0; $i < $cpuinfo->{'cpu_count'}; $i++)
{
$c++ if (check_exists($t, $i));
}
$items_exists->{$t}{'total'} = $c > 0;
}
return $items_exists->{$t}{'total'};
}
}
# ------------------------- remove unavialable fields from graph --------------------------
sub remove_unavialabled_counters
{
my @cpu = split(/\s+/, (grep(/cpu\s/, get_stat_file_content()))[0]);
my $counters_count = scalar(@cpu) - 3;
@cnames = @cnames[0..$counters_count];
}
# ----------------------- get sysfs file content ----------------
my $fcontents = {};
sub get_sys_file_content
{
my $file = $_[0];
return 'nan' if (-z $file);
unless (exists($fcontents->{$file}))
{
open (FH, '<', $file) or die "$! $file \n";
$fcontents->{$file} = <FH>;
close (FH);
chomp $fcontents->{$file};
}
return $fcontents->{$file};
}
# -------------------------- loading cpu info ---------------------------------
sub load_cpuinfo
{
my $file = "/proc/cpuinfo";
open (FH, '<', $file) or die "$! $file \n";
my $cpu_num = -1;
for my $line (<FH>)
{
chomp $line;
$cpu_num++ if $line =~ m/^processor\s+:/;
$cpuinfo->{$cpu_num}{'name'} = trim((split(/:/,$line))[1]) if $line =~ m/^model name\s+:/;
$cpuinfo->{$cpu_num}{'bogomips'} = trim((split(/:/,$line))[1]) if $line =~ m/^bogomips\s+:/;
if (not exists($cpuinfo->{$cpu_num}{'info'}) and exists($cpuinfo->{$cpu_num}{'name'}) and exists($cpuinfo->{$cpu_num}{'bogomips'}))
{
$cpuinfo->{$cpu_num}{'info'} = sprintf("[%s (%s bogomips)]", $cpuinfo->{$cpu_num}{'name'}, $cpuinfo->{$cpu_num}{'bogomips'}) ;
}
}
close (FH);
$cpuinfo->{'cpu_count'} = $cpu_num+1;
}
# -------------------------- loading stat file lines ---------------------------------
sub get_stat_file_content
{
if(scalar(@stat_file_content) == 0)
{
open (FH, '<', $stat_file) or die "$! $stat_file \n";
for (<FH>)
{
next unless $_ =~ m/cpu/;
chomp $_;
push(@stat_file_content, $_);
}
close (FH);
}
return @stat_file_content;
}
# -------------------------------- replacing strings ------------------------
sub replace_template
{
my ($string, $needle, $replacement) = @_[0..2];
$string =~ s/$needle/$replacement/g;
return $string;
}
sub replace_templates
{
my ($src, $replacement_t, $replacement_i) = @_[0..2];
my $dst = {};
for my $key ( keys %{$src} )
{
$dst->{$key} = $src->{$key};
if($key =~ m/label|info|title/) { $dst->{$key} = replace_template($dst->{$key}, ':t:', $replacement_t); }
if($key =~ m/info|title/) { $dst->{$key} = replace_template($dst->{$key}, ':i:', $replacement_i); }
}
return $dst;
}
sub append_order
{
my ($pg, $graph_name, $field_name) = @_[0..2];
$pg->{$graph_name}{'graph'}{'order'} = exists($pg->{$graph_name}{'graph'}{'order'}) ? sprintf("%s %s", $pg->{$graph_name}{'graph'}{'order'}, $field_name) : $field_name;
}
sub append_field
{
my ($pg, $graph_name, $field_name, $field_src, $replacement_t, $replacement_i) = @_[0..5];
$pg->{$graph_name}{'fields'}{$field_name} = replace_templates($fields->{$field_src}, $replacement_t, $replacement_i);
append_order($pg, $graph_name, $field_name);
}
sub append_graph
{
my ($pg, $graph_name, $category, $graph_src, $replacement_t, $replacement_i) = @_[0..5];
$pg->{$graph_name}{'graph'} = replace_templates($graphs->{$graph_src}, $replacement_t, $replacement_i);
$pg->{$graph_name}{'graph'}{'category'} = $category;
}
# ---------------------------------------- preparing data for graphs ------------------------------------
sub prepare_graphs_fields
{
my $pg = {};
# ------------------ cpu_utilisation -----------------------------------
# ---------- general ----------------------
append_graph($pg, 'cpu_utilisation', 'cpu', 'cpu_utilisation', '', '');
for my $cname (@cnames) { append_field($pg, 'cpu_utilisation', $cname, $cname, '', ''); build_limits($pg, 'cpu_utilisation', $cname); }
if(check_exists('freq_hz')) { for (my $i = 0; $i < $cpuinfo->{'cpu_count'}; $i++) { append_field($pg, 'cpu_utilisation', sprintf("fp_%s", $i), 'freq_percent', $i, ''); } }
# ---------------- childs -------------------
if ($cpuinfo->{'cpu_count'} > 1)
{
for (my $i=0; $i < $cpuinfo->{'cpu_count'}; $i++)
{
my $graph_name = sprintf("cpu_utilisation.cpu%s", $i);
append_graph($pg, $graph_name, sprintf("CPU %s", $i), 'cpu_utilisation', $i, $cpuinfo->{$i}{'info'});
for my $cname (@cnames) { append_field($pg, $graph_name, $cname, $cname, '', ''); build_limits($pg, $graph_name, $cname); }
if(check_exists('freq_hz', $i)) { append_field($pg, $graph_name, 'fp', 'freq_percent', '', ''); }
}
}
# --------------- cpu_frequency --------------------------------------------
if(check_exists('freq_trans'))
{
# ------------ general --------------------
append_graph($pg, 'cpu_frequency', 'cpu', 'cpu_freq_trans', '', '');
for (my $i = 0; $i < $cpuinfo->{'cpu_count'}; $i++) { if (check_exists('freq_trans', $i)) { append_field($pg, 'cpu_frequency', sprintf("cpu_%s", $i), 'freq_trans', sprintf("CPU%s", $i), ''); } }
append_field($pg, 'cpu_frequency', 'total', 'freq_trans', 'Total', '');
# ---------------- childs -------------------
if(check_exists('freq_times'))
{
my $frequences = get_frequency_times();
for (my $i=0; $i < $cpuinfo->{'cpu_count'}; $i++)
{
if(check_exists('freq_times', $i))
{
my $graph_name = sprintf("cpu_frequency.percent_cpu%s", $i);
append_graph($pg, $graph_name, sprintf("CPU %s", $i), 'cpu_freq', $i, $cpuinfo->{$i}{'info'});
for my $freq (@{$frequences->{'names'}{$i}}) { append_field($pg, $graph_name, sprintf("hz_%s", $freq), 'freq_hz', scaleNumber($freq, 'Hz'), ''); }
}
}
}
if(check_exists('freq_ttable'))
{
my $f_table = get_frequency_trans_table() if check_exists('freq_ttable');
for (my $i=0; $i < $cpuinfo->{'cpu_count'}; $i++)
{
if(check_exists('freq_ttable', $i))
{
my $graph_name = sprintf("cpu_frequency.trans_table_cpu%s", $i);
append_graph($pg, $graph_name, sprintf("CPU %s", $i), 'cpu_freq_trans_table', $i, $cpuinfo->{$i}{'info'});
for my $from (sort keys %{$f_table->{'values'}{$i}})
{
for my $to (sort keys %{$f_table->{'values'}{$i}{$from}})
{
next if ($from eq $to);
append_field($pg, $graph_name, sprintf("f_%s_t_%s", $from, $to), 'freq_trans_table', sprintf("%s -> %s", scaleNumber($from, 'Hz'), scaleNumber($to, 'Hz')), '');
}
}
}
}
}
}
# --------------- cpu_all -----------------------------------------
if ($cpuinfo->{'cpu_count'} > 1)
{
append_graph($pg, 'cpu_all', 'cpu', 'cpu_all', '', '');
for (my $i = 0; $i < $cpuinfo->{'cpu_count'}; $i++) { append_field($pg, 'cpu_all', sprintf("cpu_%s", $i), 'cpu_util', sprintf("CPU%s", $i)); }
append_field($pg, 'cpu_all', 'total', 'cpu_util', 'Combined');
}
return $pg;
}
# ------------------------------------ printing limits (for utilisation graphs) ----------------
sub build_limits
{
my ($pg, $graph_name, $cname) = @_[0..2];
for my $t (qw(warning critical))
{
my $e = sprintf("%s_%s", $cname, $t);
my $v = defined($limits->{$e}) ? $limits->{$e} : ( defined($limits->{$t}) ? $limits->{$t} : undef );
if(defined($v)) { $pg->{$graph_name}{'fields'}{$cname}{$t} = $v; }
}
}
# --------------------------------- graph configs ----------------------------
sub print_config
{
my $config = prepare_graphs_fields();
for my $g (sort keys %{$config})
{
printf("multigraph %s\n", $g);
for my $go (sort keys %{$config->{$g}{'graph'}}) { printf("graph_%s %s\n", $go, $config->{$g}{'graph'}{$go}); }
for my $f (sort keys %{$config->{$g}{'fields'}}) { for my $fo (sort keys %{$config->{$g}{'fields'}{$f}}) { printf("%s.%s %s\n", $f, $fo, $config->{$g}{'fields'}{$f}{$fo}); } }
print "\n";
}
}
# ----------------------------------- saving state data using munin --------------------
sub save_state_data
{
my $data = $_[0];
my $d = Data::Dumper->new([$data]);
$d->Indent(0);
save_state($d->Dump);
}
# -------------------------------- loading previous state data using munin -------------------
sub restore_state_data
{
my $VAR1;
my $states = (restore_state())[0];
eval $states if defined $states;
return $VAR1;
}
sub load_stats
{
my $stats = {};
# need to store --------------------
$stats->{'timestamp'} = time();
$stats->{'cpu_util'} = get_cpu_utilisation_stats() ;
$stats->{'f_trans'} = get_frequency_transitions() if check_exists('freq_trans') ;
save_state_data($stats);
# no need to store --------------------
$stats->{'f_minmax'} = get_cpu_curr_max_freqences() if check_exists('freq_hz') ;
$stats->{'f_times'} = get_frequency_times() if check_exists('freq_times') ;
$stats->{'f_ttable'} = get_frequency_trans_table() if check_exists('freq_ttable');
#print Dumper $stats;
return $stats;
}
# ---------------------------------- loading cpu stats from loaded lines ------------------------
sub get_cpu_utilisation_stats
{
my $stats = {};
for (my $i = 0; $i <= $cpuinfo->{'cpu_count'}; $i++)
{
my $rx = $i == $cpuinfo->{'cpu_count'} ? 'cpu' : sprintf ("cpu%s", $i);
my $cn = $i == $cpuinfo->{'cpu_count'} ? 'total' : $i;
my @tmp = split(/\s+/, (grep(/$rx\s/, get_stat_file_content()))[0]);
my $j = 1;
for my $cname (@cnames)
{
$stats->{$cn}{$cname} = $tmp[$j];
$j++;
}
}
return $stats;
}
# ------------------ loading frequency transitions for each cpu ----------------------------
sub get_frequency_transitions
{
my $stats = {};
for (my $i = 0; $i < $cpuinfo->{'cpu_count'}; $i++)
{
next unless (check_exists('freq_trans', $i));
$stats->{$i} = get_sys_file_content(sprintf("%s/cpu%s/cpufreq/stats/total_trans", $freq_path, $i));
}
return $stats;
}
# ------------------ loading frequency times for each cpu ----------------------------
sub get_frequency_times
{
my $stat = {};
for (my $i = 0; $i < $cpuinfo->{'cpu_count'}; $i++)
{
next unless (check_exists('freq_times', $i));
my $total = 0;
my $file = sprintf("%s/cpu%s/cpufreq/stats/time_in_state", $freq_path, $i);
open (FH, '<', $file) or die "$! $file \n";
for my $line (<FH>)
{
chomp $line;
my ($hz, $count) = split(/\s+/, $line);
$hz = $hz*$freq_mul;
$stat->{'values'}{$i}{$hz} = $count;
push(@{$stat->{'names'}{$i}}, $hz);
$total += $count;
}
close (FH);
$stat->{'total'}{$i} = $total;
}
return $stat;
}
# ------------------ loading current and max frequency for each cpu ----------------------------
sub get_cpu_curr_max_freqences
{
my $freq = {};
for (my $i = 0; $i < $cpuinfo->{'cpu_count'}; $i++)
{
next unless (check_exists('freq_hz', $i));
my $cpu_path = sprintf("%s/cpu%s/cpufreq", $freq_path, $i);
$freq->{'cur'}{$i} = get_sys_file_content(sprintf("%s/scaling_cur_freq", $cpu_path))*$freq_mul;
$freq->{'max'}{$i} = get_sys_file_content(sprintf("%s/scaling_max_freq", $cpu_path))*$freq_mul;
$freq->{'min'}{$i} = get_sys_file_content(sprintf("%s/scaling_min_freq", $cpu_path))*$freq_mul;
}
return $freq;
}
sub get_frequency_trans_table
{
my $tbl = {};
for (my $i = 0; $i < $cpuinfo->{'cpu_count'}; $i++)
{
next unless (check_exists('freq_ttable', $i));
my @frequences;
my $fcount = 0;
my $total = 0;
my $file = sprintf("%s/cpu%s/cpufreq/stats/trans_table", $freq_path, $i);
open (FH, '<', $file) or die "$! $file \n";
for my $line (<FH>)
{
chomp $line;
my ($left, $right) = split(/:/, $line);
next if($left =~ m/From/);
if($left =~ m/\d+/)
{
my $frequence = trim($left)*$freq_mul;
my @counters = split(/\s+/, trim($right));
for (my $j = 0; $j<$fcount; $j++)
{
$tbl->{'values'}{$i}{$frequence}{$frequences[$j]*$freq_mul} = $counters[$j];
$total += $counters[$j];
}
}
else
{
@frequences = split(/\s+/, trim($right));
$fcount = scalar(@frequences);
}
}
$tbl->{'total'}{$i} = $total;
close (FH);
}
return $tbl;
}
sub one_second_part
{
my ($curr, $prev, $timediff) = @_[0..2];
#print "$prev, $curr, $timediff\n";
return 'NaN' if ($curr < $prev or $timediff < 0);
return $curr - $prev if $timediff == 0;
return ($curr - $prev)/$timediff;
}
sub divide
{
my ($divider, $divident) = @_[0..1];
return 'NaN' if $divident == 0;
return $divider/$divident;
}
# -------------------------------- calculating fields values ------------------------------
sub calculate
{
my ($pstats, $cstats) = @_[0..1];
my $result = {};
my $timediff = $cstats->{'timestamp'} - $pstats->{'timestamp'};
# --- cpu utilisation ----
for my $cpu (keys %{$cstats->{'cpu_util'}})
{
# ------ calculating 1%
$result->{'cpu_util'}{'1%'}{$cpu} = 0;
for my $cname (@cnames)
{
$result->{'cpu_util'}{'diff'}{$cpu}{$cname} = one_second_part($cstats->{'cpu_util'}{$cpu}{$cname}, $pstats->{'cpu_util'}{$cpu}{$cname}, $timediff);
$result->{'cpu_util'}{'1%'}{$cpu} += $result->{'cpu_util'}{'diff'}{$cpu}{$cname} if $result->{'cpu_util'}{'diff'}{$cpu}{$cname} ne 'NaN';
}
$result->{'cpu_util'}{'1%'}{$cpu} = $result->{'cpu_util'}{'1%'}{$cpu}/100;
# ------ calculating used percents
$result->{'cpu_util'}{'used'}{$cpu} = 0;
for my $cname (@cnames)
{
$result->{'cpu_util'}{'%'}{$cpu}{$cname} = divide($result->{'cpu_util'}{'diff'}{$cpu}{$cname}, $result->{'cpu_util'}{'1%'}{$cpu});
next if $cname eq 'idle';
$result->{'cpu_util'}{'used'}{$cpu} += $result->{'cpu_util'}{'%'}{$cpu}{$cname} if $result->{'cpu_util'}{'%'}{$cpu}{$cname} ne 'NaN';
}
}
# ------ freq min max ----
if (check_exists('freq_hz'))
{
for (my $i = 0; $i < $cpuinfo->{'cpu_count'}; $i++)
{
$result->{'f_minmax'}{'%'}{$i} = divide($cstats->{'f_minmax'}{'cur'}{$i} - $cstats->{'f_minmax'}{'min'}{$i},
(($cstats->{'f_minmax'}{'max'}{$i} - $cstats->{'f_minmax'}{'min'}{$i}) / 100 )) if (check_exists('freq_hz', $i));
}
}
# ---- freq trans ----
if (check_exists('freq_trans'))
{
$result->{'f_trans'}{'total'} = 0;
for (my $i = 0; $i < $cpuinfo->{'cpu_count'}; $i++)
{
if(check_exists('freq_trans', $i))
{
$result->{'f_trans'}{$i} = one_second_part($cstats->{'f_trans'}{$i}, $pstats->{'f_trans'}{$i}, $timediff);
$result->{'f_trans'}{'total'} += $result->{'f_trans'}{$i} if $result->{'f_trans'}{$i} ne 'NaN';
}
}
}
# -- freq times ---
if (check_exists('freq_times'))
{
for (my $i = 0; $i < $cpuinfo->{'cpu_count'}; $i++)
{
if (check_exists('freq_times', $i))
{
my $oneprc = $cstats->{'f_times'}{'total'}{$i}/100;
for my $hz (@{$cstats->{'f_times'}{'names'}{$i}})
{
$result->{'f_times'}{$i}{$hz} = divide($cstats->{'f_times'}{'values'}{$i}{$hz}, $oneprc);
}
}
}
}
# ------- freq trans table ---
if (check_exists('freq_ttable'))
{
for (my $i = 0; $i < $cpuinfo->{'cpu_count'}; $i++)
{
if (check_exists('freq_ttable', $i))
{
my $oneprc = $cstats->{'f_ttable'}{'total'}{$i}/100;
for my $from (keys %{$cstats->{'f_ttable'}{'values'}{$i}})
{
for my $to (keys %{$cstats->{'f_ttable'}{'values'}{$i}{$from}})
{
next if ($from eq $to);
$result->{'f_ttable'}{$i}{$from}{$to} = divide($cstats->{'f_ttable'}{'values'}{$i}{$from}{$to}, $oneprc);
}
}
}
}
}
#print Dumper $result;
return $result;
}
# ---------------------------------------- preparing values ------------------------------------
sub prepare_graphs_values
{
my ($data) = $_[0];
my $pg = {};
# ------------------ cpu_utilisation -----------------------------------
# ---------- general ----------------------
for my $cname (@cnames) { $pg->{'cpu_utilisation'}{$cname} = $data->{'cpu_util'}{'%'}{'total'}{$cname}; }
if(check_exists('freq_hz')) { for (my $i = 0; $i < $cpuinfo->{'cpu_count'}; $i++) { $pg->{'cpu_utilisation'}{sprintf("fp_%s", $i)} = $data->{'f_minmax'}{'%'}{$i}; } }
# ---------------- childs -------------------
if ($cpuinfo->{'cpu_count'} > 1)
{
for (my $i=0; $i < $cpuinfo->{'cpu_count'}; $i++)
{
my $graph_name = sprintf("cpu_utilisation.cpu%s", $i);
for my $cname (@cnames) { $pg->{$graph_name}{$cname} = $data->{'cpu_util'}{'%'}{$i}{$cname}; }
if(check_exists('freq_hz', $i)) { $pg->{$graph_name}{'fp'} = $data->{'f_minmax'}{'%'}{$i}; }
}
}
# --------------- cpu_frequency --------------------------------------------
if(check_exists('freq_trans'))
{
# ------------ general --------------------
for (my $i = 0; $i < $cpuinfo->{'cpu_count'}; $i++) { $pg->{'cpu_frequency'}{sprintf("cpu_%s", $i)} = $data->{'f_trans'}{$i} if (check_exists('freq_trans', $i)); }
$pg->{'cpu_frequency'}{'total'} = $data->{'f_trans'}{'total'};
# ---------------- childs -------------------
if(check_exists('freq_times'))
{
for (my $i=0; $i < $cpuinfo->{'cpu_count'}; $i++)
{
if(check_exists('freq_times', $i))
{
my $graph_name = sprintf("cpu_frequency.percent_cpu%s", $i);
for my $freq (keys %{$data->{'f_times'}{$i}}) { $pg->{$graph_name}{sprintf("hz_%s", $freq)} = $data->{'f_times'}{$i}{$freq}; }
}
}
}
if(check_exists('freq_ttable'))
{
for (my $i=0; $i < $cpuinfo->{'cpu_count'}; $i++)
{
if(check_exists('freq_ttable', $i))
{
my $graph_name = sprintf("cpu_frequency.trans_table_cpu%s", $i);
for my $from (keys %{$data->{'f_ttable'}{$i}})
{
for my $to (keys %{$data->{'f_ttable'}{$i}{$from}})
{
$pg->{$graph_name}{sprintf("f_%s_t_%s", $from, $to)} = $data->{'f_ttable'}{$i}{$from}{$to};
}
}
}
}
}
}
# --------------- cpu_all --------------------------------------------
if ($cpuinfo->{'cpu_count'} > 1)
{
for (my $i = 0; $i < $cpuinfo->{'cpu_count'}; $i++) { $pg->{'cpu_all'}{sprintf("cpu_%s", $i)} = $data->{'cpu_util'}{'used'}{$i}; }
$pg->{'cpu_all'}{'total'} = $data->{'cpu_util'}{'used'}{'total'};
}
return $pg;
}
# -------------------------------- printing values -----------------------------------
sub print_values
{
my $pstats = restore_state_data();
my $cstats = load_stats();
if (exists ($pstats->{'timestamp'}))
{
my $values = prepare_graphs_values(calculate($pstats, $cstats));
#print Dumper $values;
for my $g (sort keys %{$values})
{
printf("multigraph %s\n", $g);
for my $f (sort keys %{$values->{$g}}) { printf("%s.value %s\n", $f, $values->{$g}{$f}); }
print "\n";
}
}
}
__END__
- user: normal processes executing in user mode
- nice: niced processes executing in user mode
- system: processes executing in kernel mode
- idle: twiddling thumbs
- iowait: waiting for I/O to complete
- irq: servicing interrupts
- softirq: servicing softirqs
- steal: involuntary wait
- guest: running a guest