#!/usr/bin/perl # # gnome-spyware.pl : Monitor system usage # # Copyright (C) 2006 by Callum McKenzie # # Time-stamp: <2006-12-19 20:30:51 callum> # =head1 NAME gnome-spyware - Monitor your system's resource use =head1 SYNOPSIS gnome-spyware [B<-f> I] =head1 DESCRIPTION GNOME Spyware is a program that periodically examines the resources use in your system. It operates completely in the background with the results written to a file (by default this is F<~/.gnome-spyware-log>, see the B<-f> option for how to change this). =head1 OPTIONS =over 4 =item B<-f> I Specify the name of the log file. Without this option commands are written to F<~/.gnome-spyware-log>. Data is I to this file. =back =head1 FILES =over 4 =item ~/.gnome-spyware-log The default file to which logging data is appended. =back =head1 COPYRIGHT AND LICENSE Copyright 2006 by Callum McKenzie This program is free software; you may redistribute it and/or modify it under the terms of the GNU General Public License. =cut $version = "0.2"; use POSIX qw(strftime); use IO::Handle; use Getopt::Std; $logfile = "$ENV{HOME}/.gnome-spyware-log"; %options = (); getopt ("f", \%options); $logfile = $options{f} if defined $options{f}; open (LOGFILE, ">>" . $logfile) or die "Could not open the log file: $!"; output ("### GNOME Spyware log. Version $version"); $starttime = time; sub output ($) { my $message = @_[0]; print LOGFILE $message, "\n"; # print $message, "\n"; } sub parse_total_memory { my $buffers, $cached, $memtotal, $memfree, $swaptotal, $swapfree; open (MEMINFO, ") { if (/^Buffers:\D*(\d+)\D*$/) { $buffers = $1; } if (/^Cached:\D*(\d+)\D*$/) { $cached = $1; } if (/^MemTotal:\D*(\d+)\D*$/) { $memtotal = $1; } if (/^MemFree:\D*(\d+)\D*$/) { $memfree = $1; } if (/^SwapTotal:\D*(\d+)\D*$/) { $swaptotal = $1; } if (/^SwapFree:\D*(\d+)\D*$/) { $swapfree = $1; } } output (">>> Physical memory used: " . ($memtotal - $memfree) . " kB"); output (">>> Memory mapped for processes (excluding mmapped files): " . ($memtotal - $memfree - $cached - $buffers) . " kB"); output (">>> Swap used: " . ($swaptotal - $swapfree) . " kB"); close MEMINFO; } sub scan_processes { opendir PROCDIR, "/proc" or return; @proclist = grep /^\d+$/, readdir (PROCDIR); closedir PROCDIR; output (">>> Number of processes: " . $#proclist); my %rsses = {}; my %names = {}; my %shared_dirties = {}; my %private_dirties = {}; my %shared_cleans = {}; my %private_cleans = {}; foreach (@proclist) { my $pid = $_; my $basename = "/proc/" . $pid . "/"; my $rss = 0; my $private_dirty = 0; my $private_clean = 0; my $shared_dirty = 0; my $shared_clean = 0; open STATUS, "<" . $basename . "status" or next; while () { if (/^Name:\s*(.+)$/) { $procname = $1; } } close STATUS; open SMAPS, "<" . $basename . "smaps" or next; while () { if (/^Rss:\D*(\d+)\D*$/) { $rss += $1; } if (/^Private_Clean:\D*(\d+)\D*$/) { $private_clean += $1; } if (/^Private_Dirty:\D*(\d+)\D*$/) { $private_dirty += $1; } if (/^Shared_Clean:\D*(\d+)\D*$/) { $shared_clean += $1; } if (/^Shared_Dirty:\D*(\d+)\D*$/) { $shared_dirty += $1; } } $names{$pid} = $procname; $rsses{$pid} = $rss; $shared_dirties{$pid} = $shared_dirty; $private_dirties{$pid} = $private_dirty; $shared_cleans{$pid} = $shared_clean; $private_cleans{$pid} = $private_clean; } output (">>> Top 10 processes (sorted by private dirty memory)"); @proclist = sort { $private_dirties{$b} <=> $private_dirties{$a} } keys %private_dirties; $i = 1; foreach $pid (@proclist[0..9]) { output (">>> " . $i . ": (" . $pid . ") " . $names{$pid} . "\tSC/SD/PC/PD =\t$shared_cleans{$pid}/$shared_dirties{$pid}/$private_cleans{$pid}/$private_dirties{$pid} kB\t RSS: $rsses{$pid} kB"); $i++; } } sub collect_data { # Write out the current time. output ( ">>> Time: " . (time - $starttime)); parse_total_memory (); scan_processes (); LOGFILE->flush(); } while (1) { collect_data (); sleep (30); }