#!/usr/bin/perl -w
###############################################################################
# Webmin Sysstats - cpu.pl
#
# Webmin Sysstats Module
# Copyright (C) 2002 by Eric Gerbier
# Bug reports to: gerbier@users.sourceforge.net
# $Id$
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
###############################################################################
use strict;
use warnings;
no warnings 'redefine';
use RRDs;
use English '-no_match_vars';
use FindBin;
# to be used alone or from sysstat.pl without warning
# because require verify the path
if ( !exists $ENV{'WEBMINSTAT_TEMP'} ) {
use lib "$FindBin::Bin/../..";
## no critic (RequireBarewordIncludes)
require 'sysstats-aquisition-lib.pl';
## use critic
}
my $module_name;
my $info = '/proc/stat';
###############################################################################
# compute pourcentage
sub calc($$$) {
my $tps1 = shift @_; # first time tick
my $tps2 = shift @_; # last time tick
my $tps = shift @_; # total time tick
my $res;
if ( $tps2 > $tps1 ) {
$res = pourcent( $tps2 - $tps1, $tps );
}
else {
$res = 0;
}
return $res;
}
###############################################################################
# doc : /usr/share/doc/kernel-doc/Documentation/filesystems/proc.txt
# extract info from /proc/stats :
# cpu 1255564 33135 202816 16988836 198613 7090 45314 0
# cpu0 1255564 33135 202816 16988836 198613 7090 45314 0
### user nice system idle iowait irq softirq steal
# intr 208830507 187342182 110711 0 0 0 0 0 0 3 0 0 0 2535966 0 1765887 1684705 14185588 0 0 0 1205024 0 0 441 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
# ctxt 64914733
# btime 1200295551
# processes 441136
# procs_running 1
# procs_blocked 0
#
sub cpuinfo_from_proc() {
my @raw_info = ();
my $r_tab = read_full_file($info);
@raw_info = grep /^cpu/, @{$r_tab};
if ( !@raw_info ) {
warning("no data from $info");
}
return @raw_info;
}
###############################################################################
# extract cpu info
sub ext_cpu($@) {
my $motif = shift @_; # cpu + number
my @raw_info = @_; # info from /proc
foreach my $ligne (@raw_info) {
return $ligne if ( $ligne =~ m/$motif/ );
}
return;
}
###############################################################################
# main routine
###############################################################################
# read module config
my %config;
read_file_cached( 'config', \%config );
$module_name = $config{'name'};
debug( "run $module_name version " . $config{'version'} );
my %codes = action_load( \%config );
my $pre = $config{'pre'};
# get new state
my @raw_info_new = cpuinfo_from_proc();
if ( !@raw_info_new ) {
warning('problem on new state (cpuinfo_from_proc)');
goto FIN;
}
# get previous state
my @raw_info_old = read_state($module_name);
if ( !@raw_info_old ) {
#first call : save current state and quit
write_state( $module_name, @raw_info_new );
goto FIN;
}
# loop on cpu processors
my $cpu_num = 1;
while ( exists $config{ $pre . $cpu_num } ) {
# in /proc cpu num begin at 0
my $proc_cpu_num = $cpu_num - 1;
my $motif = 'cpu' . $proc_cpu_num;
# test for 2.2 kernel
my $info_old = ext_cpu( $motif, @raw_info_old );
if ( !defined $info_old ) {
# no cpu0 in /proc/stat : seems to be 2.2 kernel,
# so change the filter to cpu
$motif = 'cpu';
$info_old = ext_cpu( $motif, @raw_info_old );
}
my $info_new = ext_cpu( $motif, @raw_info_new );
my @info_old = split_awk($info_old);
my @info_new = split_awk($info_new);
# sum all tics
my $sp1 = $info_old[1] + $info_old[2] + $info_old[3] + $info_old[4];
my $sp2 = $info_new[1] + $info_new[2] + $info_new[3] + $info_new[4];
# total time between 2 calls
my $tps = $sp2 - $sp1;
my $user = calc( $info_old[1], $info_new[1], $tps );
my $nice = calc( $info_old[2], $info_new[2], $tps );
my $syst = calc( $info_old[3], $info_new[3], $tps );
my $idle = calc( $info_old[4], $info_new[4], $tps );
debug(
"$module_name $cpu_num : user=$user syst=$syst nice=$nice idle=$idle");
action_param( 'user', $user, \%codes );
action_param( 'syst', $syst, \%codes );
action_param( 'nice', $nice, \%codes );
action_param( 'idle', $idle, \%codes );
my $rrdbase = 'cpu' . $cpu_num . '.rrd';
RRDs::update( $rrdbase, "N:$user:$syst:$nice:$idle" );
my $ERR = RRDs::error();
warning("ERROR while updating $rrdbase database : $ERR")
if $ERR;
if ( ( scalar @info_new ) > 5 ) {
my $iowait = calc( $info_old[5], $info_new[5], $tps );
my $irq = calc( $info_old[6], $info_new[6], $tps );
my $softirq = calc( $info_old[7], $info_new[7], $tps );
debug(
"$module_name $cpu_num : iowait=$iowait irq=$irq softirq=$softirq");
action_param( 'iowait', $iowait, \%codes );
action_param( 'irq', $irq, \%codes );
action_param( 'softirq', $softirq, \%codes );
$rrdbase = 'extra' . $cpu_num . '.rrd';
RRDs::update( $rrdbase, "N:$iowait:$irq:$softirq" );
$ERR = RRDs::error();
warning("ERROR while updating $rrdbase database : $ERR")
if $ERR;
}
$cpu_num++;
} # while
# translate state for next call
write_state( $module_name, @raw_info_new );
# a label to quit
#I can not use return when executing this script standalone,
# so I had to use goto
FIN: