#!/usr/bin/perl use strict; use warnings; use Time::HiRes qw( gettimeofday tv_interval ); # 0. Initialize our $start_time = [gettimeofday()]; my $data = {}; my @accepted_commands = ( 'import.pl', 'HandBrakeCLI', 'hive2_ffmpegsvn', 'mediainfo', 'cp' ); my $accepted_commands_pattern = '(' . join('|', @accepted_commands) . ')'; print '='x80 . "\n"; print '='x30 . ' IOTop Report ' . '='x30 . "\n"; print '='x80 . "\n\n"; # 1. Read in arguments print 'Arguments:' . "\n"; if (!defined $ARGV[0] || !-f $ARGV[0]) { &printError('Missing iotop log file or not a file.'); &printUsage(); &exitProgram(); } my $iotop_file = $ARGV[0]; print "\t" . 'IOTop file: ' . $iotop_file . "\n"; print "\n"; # 2. Loop through iolog file print 'Process:' . "\n"; print "\t" . ' * Reading IOTop log file... '; my $iolog_fh; open($iolog_fh, '<:utf8', $iotop_file); if ($iolog_fh) { my $line = ''; while ($line = <$iolog_fh>) { # Look for lines describing process IO activity if ($line =~ /(\d\d:\d\d:\d\d)\s+(\d+)\s+([^\s]+)\s+([^\s]+)\s+(\d+\.\d+\s[BKMG](?:\/s)?)\s+(\d+\.\d+\s[BKMG](?:\/s)?)\s+(\d+\.\d+)\s\%\s+(\d+\.\d+)\s\%\s+(.*)/) { my $timestamp = $1; my $pid = $2; my $priority = $3; my $user = $4; my $disk_read = $5; my $disk_write = $6; my $swap_in = $7; my $io_percent = $8; my $command = $9; # Shorten command so it is more ueful $command = &parseCommand($command); # If we are not ignoring these commands... if ($command =~ /$accepted_commands_pattern/) { # Store this information for a new record if (!defined $data->{$pid}) { $data->{$pid} = {'command' => $command, 'start_time' => $timestamp, 'end_time' => $timestamp, 'occurances' => 1, 'iopercents' => $io_percent }; } # or update an existing record else { $data->{$pid}->{'end_time'} = $timestamp; $data->{$pid}->{'occurances'}++; $data->{$pid}->{'iopercents'} .= ':' . $io_percent } } } } close($iolog_fh); } else { &printError('Failed to open file for reading: ' . $iotop_file); &exitProgram(); } print 'Done!' . "\n"; # 3. Print report to CSV print "\t" . ' * Writing report... ' . "\n";; my $ioreport_fh; open($ioreport_fh, '>:utf8', 'ioreport.csv'); my $temp_sum = 0; if ($ioreport_fh) { print 'PID, DUR, TIME, IOPCT, COMMAND' . "\n"; foreach my $pid (sort keys %{$data}) { my $start_seconds = &parseEpoc($data->{$pid}->{'start_time'}); my $end_seconds = &parseEpoc($data->{$pid}->{'end_time'}); my $duration = $end_seconds - $start_seconds; my @io_percents = split(/:/, $data->{$pid}->{'iopercents'}); my $io_sum = 0.00; foreach my $io_percent (@io_percents) { if ($io_percent > 0) { $temp_sum += $io_percent; } $io_sum += $io_percent; } my $io_avg = 0.00; if ($io_sum > 0) { $io_avg = $io_sum / $data->{$pid}->{'occurances'}; } print sprintf('%5d, %4d, %4d, %5.2f, "%s"', $pid, $duration, $data->{$pid}->{'occurances'}, $io_avg, $data->{$pid}->{'command'}) . " [" . $data->{$pid}->{'iopercents'} . "]\n"; } close($ioreport_fh); } else { &printError('Failed to open file for writing: ./ioreport.csv'); } print 'Done!' . "\n\n"; print "Sum: " . $temp_sum . "\n"; &exitProgram(); # Should never get here exit; ###### FUNCTIONS ###### ## @function # sub exitProgram { my $end_time = [gettimeofday()]; my $elapsed = tv_interval($start_time, $end_time); print sprintf('%s Complete in %7.3f seconds! %1$s', '='x24, $elapsed) . "\n\n"; exit; } ## exitProgram() ## ## @function # sub parseCommand { my ($full_command) = @_; my $command; # Anything that starts with perl, we extract just the script name if ($full_command =~ /perl.*?([a-z0-9]+\.pl)/) { $command = $1; } elsif ($full_command =~ /^([^\s]+)/) { $command = $1; } # Everything else we shorten to just 12 characters else { $command = substr($full_command, 0, 12); } return $command; } ## parseCommand() ## ## @function # sub parseEpoc { my ($timestamp) = @_; my @parts = split(/:/, $timestamp); my $seconds = $parts[2]; # Seconds $seconds += $parts[1] * 60; # Minutes $seconds += $parts[0] * 60 * 60; # Hours return $seconds; } ## parseEpoc() ## ## @function # sub printError { my ($msg) = @_; print 'Error! ' . $msg . "\n"; } ## printError() ## ## @function # sub printUsage { print 'Usage: iotop_report.pl ' . "\n\n"; } ## printUsage() ##