Usage

(perl script)

Enter at your own risk :)

#!/usr/local/bin/perl
#
# generate user-based machine usage visualization
#

# print usage line and exit if wrong number of args
if ($#ARGV != 1) {
    print "usage: machineUsage numPrevDays hours\n";
    exit;
}

$numPrevDays = $ARGV[0];  # graph the last N days activity
$hours = $ARGV[1];        # check for usage every N hours

# collect all usage data
$online = true;  # if true, collect data from machines, otherwise look in file
if($online) {
    $machines = `systems sgi`;      # get names of all sgis
    chop($machines);                # get rid of the return at the end
    @sgis = split(/ /, $machines);  # split the big string into an array of machine names
    
    $lastData = "";                         # look on each machine and put all results
    foreach $machine (@sgis) {              # in one great big string called $lastData
	$tmp = `rsh $machine last`;         # ask $machine who was on recently
	$lastData .= "\n$tmp";              # append answer to $lastData string
    }
    @lastData = split(/\n/, $lastData);     # split all usage lines into an array
}

else {
    # just read the data from a file, prob written by a daemon
    open(FILE, "lastData.txt");
    @lastData = <FILE>;
    close(FILE);
}
@lastData = reverse(@lastData);  # put data in chron order

# make an assoc array of unique usernames
$numUsers = 0;
foreach $line (@lastData) {
    $user = &getUserName($line);

    # filter out staff, etc (since left logged in) and root processes
    if(($user ne "phil") && ($user ne "mlewis") && ($user ne "tcp") &&
       ($user ne "smay") && ($user ne "root") && ($user ne "pete") && 
       ($user ne "spencer") && ($user ne "midori") && ($user ne "wtmp") &&
       ($user ne "reboot") && ($user ne "csuri") && ($user ne "susskind"))
    {
	if($users{$user} == undef) { 
	    $users{$user} = $numUsers++; 
	}
    }
}

# for each timeperiod find out usage for all users
$totalTime = $numPrevDays * 24 * 3600;
$time = time;
$timeRez = $hours * 3600;  # check usage every N seconds
$timeSteps = 0;
for($t = $time-$totalTime; $t < $time; $t += $timeRez) {
    $start = $t;
    $finish = $t + $timeRez - 1;
    
    # calc usage for each user for the period of time from $start to $finish
    %usage = computeUsage($start, $finish);

    # fill in one row in 2D array: i=user, j=$start time, val=cpuUsage
    @results = &newArray($numUsers);
    foreach $user (keys %usage) {
	$hours = int($usage{$user} * 100) / 100;
	$results[$users{$user}] = $hours;
    }
    $data[$timeSteps++] = [ @results ];
}

# print out usage for each user
#foreach $user (keys %usage) {
#    print "$user: ";
#    for($i=0; $i<$timeSteps; $i++) {
#	print "$data[$i][$users{$user}] ";
#    }
#    print "\n";
#}

# compute total usage for each user
$maxUsage = 0;
foreach $user (keys %usage) {
    $userNum = $users{$user};
    $totalUsage[$userNum] = 0;
    for($i=0; $i<$timeSteps; $i++) {
	$usage = $data[$i][$userNum];
	$totalUsage[$userNum] += $usage;
	if($usage > $maxUsage) { $maxUsage = $usage; }
    }
}

# sort users by total usage into new array
@sortedKeys = sort by_usage keys(%usage);
#foreach $key (@sortedKeys) {
#    $userNum = $users{$key};
#    print "$key: $totalUsage[$userNum]\n";
#}

# make a heightfield from sorted usage data
# just use top 20 users

print <<EOF
#VRML V2.0 utf8

Group {
  children [
    DEF TOUCH TouchSensor {}
    Shape {
      appearance Appearance { material Material {} }
      geometry DEF GRID ElevationGrid {
  	height [
EOF
;

$names = "";
$colors = "";
$maxHeight = $maxUsage/2;
foreach $key (@sortedKeys) {
  $names .= "\"$key\" ";
  for($x=0; $x<$timeSteps; $x++) {
	$userNum = $users{$key};
        $height = $data[$x][$userNum]/2;
        print $height . " ";
	$red = $height/$maxHeight;
	$colors .= $red." ".(1-$red)." 0 ";
    }
    print "\n";
}

$numKeys = @sortedKeys;
$xs = $numKeys / $timeSteps;
$zs = 1;	     

print <<EOF
          ]
          color Color { color [ $colors ] }
	  xDimension $timeSteps
  	  zDimension $numKeys
	  xSpacing $xs
	  zSpacing $zs
	  solid FALSE
      }
    }
  ]
}

DEF SCRIPT Script {
  eventIn SFVec3f touched
  eventOut MFString who
  field MFString names [ $names ]
  url "vrmlscript:

function touched(val) {
  who[0] = names[Math.round(val.z)];
}

"
}

ROUTE TOUCH.hitPoint_changed TO SCRIPT.touched

DEF NEAR ProximitySensor { size 1000 1000 1000 }

DEF TT Transform {
   children Transform {
      translation -.125 .1 -.3
      scale .02 .02 .02
      children Shape {
	 appearance Appearance {
	    material Material { diffuseColor .5 .5 0 }
 	 }
         geometry DEF TEXT Text { }
      }
   }
}

ROUTE NEAR.position_changed TO TT.translation
ROUTE NEAR.orientation_changed TO TT.rotation
ROUTE SCRIPT.who TO TEXT.string

NavigationInfo { type "EXAMINE" }
EOF
;

# add text label in HUD 
# use it on network for real (leave old code commented, can have daemon drive)

exit;

sub newArray() {
    local $n;
    local $i;
    local @tmp;

    $n = $_[0];
    for($i=0; $i<$n; $i++) { $tmp[$i] = 0; }
    return @tmp;
}

sub computeUsage {
    local $fromTime;
    local $toTime;
    local $user;
    local $cnt;
    local $line;
    local $startTime;
    local $stopTime;
    local %usage;
    local $duration;

    $fromTime = $_[0];
    $toTime = $_[1];

    # examine all usage lines, collect all relevent data
    $cnt = 0;
    foreach $line (@lastData) {
	if(!($line =~ /^\w+ ftp/)) {
	    $startTime = &computeStartTime($line);
	    $stopTime = &computeStopTime($line);
	    if(($stopTime > $fromTime) && ($startTime < $toTime)) {
		$releventData[$cnt++] = $line;
	    }
	}
    }

    # step through all lines and collect total login times
    $prevStopTime = -1;
    $prevUser = "";
    foreach $line (@releventData) {
	# determine start and stop times for this line
	$startTime = &computeStartTime($line);
	$stopTime = &computeStopTime($line);
	$user = &getUserName($line);

	if(($user ne "phil") && ($user ne "mlewis") && ($user ne "tcp") &&
	   ($user ne "smay") && ($user ne "root") && ($user ne "pete") && 
	   ($user ne "spencer") && ($user ne "midori") && ($user ne "wtmp") &&
	   ($user ne "reboot") && ($user ne "csuri") && ($user ne "susskind"))
	{
	    $startTime = &clamp($startTime, $fromTime, $toTime);
	    $stopTime = &clamp($stopTime, $fromTime, $toTime);
	    
	    # determine whether any new info in this line by comparing to info from prev line
	    if(($user ne $prevUser) || ($startTime > $prevStopTime)) {
		
		# determine duration of login according to this line
		$duration = $stopTime - $startTime;

		# add duration to user's total: store in association list, key is user
		if($usage{$user} == undef) { $usage{$user} = $duration / 3600; }
		else { $usage{$user} += $duration / 3600; }
		
		# store user, start and stop times to compare to next line
		$prevUser = $user;
		$prevStopTime = $stopTime;
	    }
	}
    }

    # return findings
    return %usage;
}
    
sub getUserName {
    $thisLine = $_[0];
    
    if($thisLine =~ /^(\w+)/) {
	return $1;
    }
    else { return ""; }
}

sub clamp {
    local $v;  local $hi;  local $low;
    $v = $_[0];
    $low = $_[1];
    $hi = $_[2];
    if($v < $low) { return $low; }
    elsif($v > $hi) { return $hi; }
    else { return $v; }
}

use Time::Local;
sub computeStartTime {
    $thisLine = $_[0];
    
    if($thisLine =~ /(\w+)\s+(\d+) (\d+)\:(\d+)\s+still logged in\s*$/) { 
	$monStr = $1;
	$mon = calcMonth($monStr);
	$mday = $2;
	$startHr = $3;
	$startMin = $4;
	$timeOfLine = timelocal(0, $startMin, $startHr, $mday, $mon, 98);
	return $timeOfLine;
    }
    elsif($thisLine =~ /(\w+)\s+(\d+) (\d+)\:(\d+) - (\d+)\:(\d+)\s+\((\d+)\:(\d+)\)\s*$/) {
	$monStr = $1;
	$mon = calcMonth($monStr);
	$mday = $2;
	$startHr = $3;
	$startMin = $4;
	$stopHr = $5;
	$stopMin = $6;
	$durHr = $7;
	$durMin = $8;
	
	$timeOfLine = timelocal(0, $startMin, $startHr, $mday, $mon, 98);
	return $timeOfLine;
    }
    else { return -1; }
}

sub computeStopTime {
    $thisLine = $_[0];
    
    if($line =~ /still logged in$/) { 
	return time;
    }
    elsif($thisLine =~ /(\w+)\s+(\d+) (\d+)\:(\d+) - (\d+)\:(\d+)\s+\((\d+)\:(\d+)\)\s*$/) {
	$monStr = $1;
	$mon = calcMonth($monStr);
	$mday = $2;
	$startHr = $3;
	$startMin = $4;
	$stopHr = $5;
	$stopMin = $6;
	$durHr = $7;
	$durMin = $8;

	$timeOfLine = timelocal(0, $stopMin, $stopHr, $mday, $mon, 98);

	# if worked past midnight, add one day (in seconds)
	if($stopHr < $startHr) { $timeOfLine += 3600 * 24; }

	return $timeOfLine;
    }
    else { return -1; }
}

sub calcMonth {
    $monStr = $_[0];
    if($monStr eq "Jan") { $mon = 0; } elsif($monStr eq "Feb") { $mon = 1; }
    elsif($monStr eq "Mar") { $mon = 2; } elsif($monStr eq "Apr") { $mon = 3; }
    elsif($monStr eq "May") { $mon = 4; } elsif($monStr eq "Jun") { $mon = 5; }
    elsif($monStr eq "Jul") { $mon = 6; } elsif($monStr eq "Aug") { $mon = 7; }
    elsif($monStr eq "Sep") { $mon = 8; } elsif($monStr eq "Oct") { $mon = 9; }
    elsif($monStr eq "Nov") { $mon = 10; } elsif($monStr eq "Dec") { $mon = 11; }
    return $mon;
}

sub by_usage {
    $userNum1 = $users{$a};
    $userNum2 = $users{$b};
    $totalUsage[$userNum1] <=> $totalUsage[$userNum2];
}


mrl