#!/bin/perl -w # # System Data Recorder: cpurec # # netrec - records CPU telemetry # from kstat for global zone under Solaris OE # # USAGE: cpurec [[interval [count]] # eg, # cpurec 60 # print continously every minute # # mpstat telemetry # # COPYRIGHT: Copyright (c) 2008 Stefan Parvu. # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at Docs/cddl1.txt # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # CDDL HEADER END # # VERSION: 0.62 # # HISTORY # 2008-07-09 Perl version, RRD format output - 0.60 sp # 2009-01-28 More accurate reporting for # usr, sys and idle - 0.62 sp use strict; use Getopt::Std; use Time::Local; use Sun::Solaris::Kstat; use POSIX; # # Command line arguments # usage() if defined $ARGV[0] and $ARGV[0] eq "--help"; getopts('hv') or usage(); usage() if defined $main::opt_h; revision() if defined $main::opt_v; # process [[interval [count]] my ($interval, $loop_max); if (defined $ARGV[0]) { $interval = $ARGV[0]; $loop_max = defined $ARGV[1] ? $ARGV[1] : 2**32; usage() if $interval == 0; } else { $interval = 1; $loop_max = 1; } # Variables my $HZ; my $loop = 0; # current loop number $main::opt_h = 0; # help option $main::opt_v = 0; # revision option my $update; # used for deltas my %cpudataOld; # cpu_stats data $| = 1; # autoflush # ######### # # MAIN BODY # # ######### # my $kstat = Sun::Solaris::Kstat->new(); # no need to read HZ every loop, since # changing hires in Solaris requires boot $HZ = POSIX::sysconf(&POSIX::_SC_CLK_TCK); while (1) { # get cpu stats my(@cpudata) = get_cpu(); foreach my $values (@cpudata) { my ($c, $x, $ir, $irt, $cs, $ics, $mi, $sm, $sysc, $u, $s, $i, $time) = split /:/, $values; # old values my ($old_x, $old_ir, $old_irt, $old_cs, $old_ics, $old_mi, $old_sm, $old_sysc, $old_u, $old_s, $old_i, $old_time); if (defined $cpudataOld{$c}) { ($old_x, $old_ir, $old_irt, $old_cs, $old_ics, $old_mi, $old_sm, $old_sysc, $old_u, $old_s, $old_i, $old_time) = split /:/, $cpudataOld{$c}; } else { $old_x = $old_ir = $old_irt = $old_cs = $old_ics = $old_mi = $old_sm = $old_sysc = $old_u = $old_s = $old_i = $old_time = 0; } # get the delta my $tdelta = $time - $old_time; # check mpstat.c for more details # used to report btter numbers for # usr, sys, idle my $ticks = cpu_ticks($old_u, $u); $ticks = $ticks + cpu_ticks($old_s, $s); $ticks = $ticks + cpu_ticks($old_i, $i); my $etime = $ticks / $HZ; if ( $etime == 0 ) { $etime = 1; } my $percent = 100 / $etime / $HZ; my $xcal = ($x - $old_x) / $tdelta; my $intr = ($ir - $old_ir) / $tdelta; my $ithr = ($irt - $old_irt) / $tdelta; my $csw = ($cs - $old_cs) / $tdelta; my $icsw = ($ics - $old_ics) / $tdelta; my $migr = ($mi - $old_mi) / $tdelta; my $smtx = ($sm - $old_sm) / $tdelta; my $syscall = ($sysc - $old_sysc) / $tdelta; my $user = kstat_delta($old_u, $u) * $percent; my $sys = kstat_delta($old_s, $s) * $percent; my $idle = kstat_delta($old_i, $i) * $percent; printf "%d:%d:%.0f:%.0f:%.0f:%.0f:%.0f:%.0f:%.0f:%.0f:%.0f:%.0f:%.0f\n", time,$c,$xcal,$intr,$ithr,$csw,$icsw,$migr,$smtx,$syscall,$user,$sys,$idle; $cpudataOld{$c} = "$x:$ir:$irt:$cs:$ics:$mi:$sm:$sysc:$u:$s:$i:$time"; } # for end ### Check for end last if ++$loop == $loop_max; ### Interval sleep $interval; } sub cpu_ticks { my ($old, $new) = @_; my $lticks = 0; my $d = kstat_delta($old, $new); $lticks += $d; return $lticks; } sub kstat_delta { my ($old, $new) = @_; return $new - $old; } sub get_cpu { # vars my ($lx, $lintr, $lithr, $lcsw, $licsw, $lmigr, $lsmtx, $lsy, $lu, $ls, $li, $lt); my @cpu_data = (); # get the kstat updates $kstat->update(); ### Loop over all CPUs my $Modules = $kstat->{cpu_stat}; foreach my $instance (keys(%$Modules)) { my $Instances = $Modules->{$instance}; foreach my $name (keys(%$Instances)) { my $Names = $Instances->{$name}; # xcalls if (defined $$Names{xcalls}) { $lx = $$Names{xcalls}; } # intr if (defined $$Names{intr}) { $lintr = $$Names{intr}; } # ithr if (defined $$Names{intrthread}) { $lithr = $$Names{intrthread}; } # csw if (defined $$Names{pswitch}) { $lcsw = $$Names{pswitch}; } # icsw if (defined $$Names{inv_swtch}) { $licsw = $$Names{inv_swtch}; } # migr if (defined $$Names{cpumigrate}) { $lmigr = $$Names{cpumigrate}; } # smtx if (defined $$Names{mutex_adenters}) { $lsmtx = $$Names{mutex_adenters}; } # syscl if (defined $$Names{syscall}) { $lsy = $$Names{syscall}; } if (defined $$Names{kernel}) { $ls = $$Names{kernel}; } if (defined $$Names{user}) { $lu = $$Names{user}; } if (defined $$Names{idle}) { $li = $$Names{idle}; } # use last time seen $lt = $$Names{snaptime}; push @cpu_data, "$instance:$lx:$lintr:$lithr:$lcsw: $licsw:$lmigr:$lsmtx:$lsy:$lu:$ls:$li:$lt"; } } # return return @cpu_data; } # # usage - print usage and exit. # sub usage { print STDERR <