From 6552dd3fb36fe64707784ef8e8580f9c003c4640 Mon Sep 17 00:00:00 2001 From: Gorlow Maxim aka Sheridan Date: Thu, 15 Jul 2010 22:18:25 +0200 Subject: [PATCH] Initial version --- plugins/other/cpu | 892 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 892 insertions(+) create mode 100755 plugins/other/cpu diff --git a/plugins/other/cpu b/plugins/other/cpu new file mode 100755 index 00000000..184bcc5e --- /dev/null +++ b/plugins/other/cpu @@ -0,0 +1,892 @@ +#!/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 (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} = ; + 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 () + { + 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 () + { + 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 () + { + 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 () + { + 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