Commit 57d17923 authored by Gary Wong's avatar Gary Wong

Predict future node pressure (periods of higher than current demand).

parent 8d1ce4c0
......@@ -833,6 +833,117 @@ sub Forecast($$;$) {
return @answer;
}
#
# Find any future periods with smaller predicted availability than the
# present.
sub FuturePressure($$;$) {
my ($class, $typelist, $projlist) = @_;
my @reservations = ();
foreach my $type ( @$typelist ) {
my $typeres = LookupAll( $class, $type );
push( @reservations, @$typeres );
}
my @forecast = ();
my @answer = ();
my $t = time();
my $maxused = 0;
my $under_pressure = 0;
my $period;
IsFeasible( $class, \@reservations, undef, undef, undef, undef,
\@forecast );
foreach my $f ( @forecast ) {
my $unavailable = 0;
my $held = 0;
my $free = $f->{'free'};
foreach my $pid ( keys( %{$f->{'used'}} ) ) {
$unavailable += $f->{'used'}->{$pid};
}
foreach my $pid ( keys( %{$f->{'reserved'}} ) ) {
my $r = $f->{'reserved'}->{$pid};
my $u = $f->{'used'}->{$pid};
if( $r > $u ) {
if( grep( $_ eq $pid, @$projlist ) ) {
$held += $r - $u;
} else {
$unavailable += $r - $u;
}
}
}
if( $f->{'t'} <= $t ) {
$maxused = $unavailable if( $unavailable > $maxused );
} elsif( $under_pressure ) {
if( $unavailable <= $maxused ) {
$under_pressure = 0;
push( @answer, [ $period, $f->{'t'} ] );
}
} else {
if( $unavailable > $maxused ) {
$under_pressure = 1;
$period = $f->{'t'};
}
}
}
return @answer;
}
#
# Find the earliest unfulfilled reservation for any of the specified projects.
# (If a project is using at least as many nodes as it has reserved,
# reservation(s) will be considered fulfilled and ignored as a possible
# result.) Optionally limited to particular node type(s), otherwise
# reservations for any node type are returned.
#
# Returns a timestamp if any unfulfilled reservation exists, otherwise undef.
sub OutstandingReservation($$;$) {
my ($class, $projlist, $typelist ) = @_;
my $earliest = undef;
foreach ( @$projlist ) {
# reject illegal PIDs
return undef unless /^[-\w]+$/;
}
my $query_result = DBQueryFatal( "SELECT DISTINCT(type) FROM " .
"future_reservations WHERE pid IN ('" .
join( "','", @$projlist ) . "')" );
while( my($type) = $query_result->fetchrow_array() ) {
my $reservations = LookupAll( $class, $type );
my @forecast = ();
IsFeasible( $class, $reservations, undef, undef, undef, undef,
\@forecast );
foreach my $f ( @forecast ) {
foreach my $pid ( keys ( %{$f->{'reserved'}} ) ) {
if( grep( $_ eq $pid, @$projlist ) &&
( !exists( $f->{'used'}->{$pid} ) ||
$f->{'used'}->{$pid} < $f->{'reserved'}->{$pid} ) ) {
# Found an unfulfilled reservation.
my $t = $f->{'t'};
$earliest = $t if( !defined( $earliest ) ||
$t < $earliest );
}
}
}
}
return $earliest;
}
sub ExptTypes($) {
my ($exptidx) = @_;
......
......@@ -47,10 +47,14 @@ sub usage()
print STDERR "Usage: predict [-p] [-u] [-t time] type\n";
print STDERR " predict -c type [pid...]\n";
print STDERR " predict -l type [pid...]\n";
print STDERR " predict -P type [pid...]\n";
print STDERR " predict -x pid...\n";
print STDERR " -h This message\n";
print STDERR " -c Give an oversimplified free node count\n";
print STDERR " -l Give a list of node allocation status counts " .
"over time\n";
print STDERR " -P Identify periods of node pressure\n";
print STDERR " -x Show earliest unfulfilled reservation\n";
print STDERR " -p Identify by pid only, not pid/eid\n";
print STDERR " -t Give time/date for prediction (defaults to now)\n";
print STDERR " -u Interpret/display all times in UTC\n";
......@@ -58,12 +62,14 @@ sub usage()
exit( -1 );
}
my $optlist = "cdhlpt:";
my $debug = 0;
my $time = time; # default to now
my $pidonly = 0;
my $countonly = 0;
my $timeseries = 0;
my $optlist = "cdhlpPt:x";
my $debug = 0;
my $time = time; # default to now
my $pidonly = 0;
my $countonly = 0;
my $pressure = 0;
my $timeseries = 0;
my $unfulfilled = 0;
my $type;
sub fatal($)
......@@ -108,6 +114,9 @@ if (defined($options{h})) {
if (defined($options{p})) {
$pidonly = 1;
}
if (defined($options{P})) {
$pressure = 1;
}
if (defined($options{"t"})) {
$time = $options{"t"};
if ($time !~ /^\d+$/) {
......@@ -123,10 +132,16 @@ if (defined($options{"c"})) {
if (defined($options{"l"})) {
$timeseries = 1;
}
usage() if( ( $countonly || $timeseries ) ? @ARGV < 1 : @ARGV != 1 );
$type = shift( @ARGV );
unless( $type =~ /^[-\w]+$/ ) {
fatal( "Invalid node type." );
if (defined($options{"x"})) {
$unfulfilled = 1;
}
usage() if( ( $countonly || $timeseries || $pressure || $unfulfilled ) ?
@ARGV < 1 : @ARGV != 1 );
if( !$unfulfilled ) {
$type = shift( @ARGV );
unless( $type =~ /^[-\w]+$/ ) {
fatal( "Invalid node type." );
}
}
if( $countonly ) {
......@@ -148,6 +163,29 @@ if( $timeseries ) {
exit( 0 );
}
if( $pressure ) {
foreach ( Reservation->FuturePressure( [ $type ], \@ARGV ) ) {
my ( $start, $end ) = @$_;
print strftime( "%Y-%m-%d %H:%M-", localtime( $start ) ) .
strftime( "%Y-%m-%d %H:%M\n", localtime( $end ) );
}
exit( 0 );
}
if( $unfulfilled ) {
my $t = Reservation->OutstandingReservation( \@ARGV );
if( defined( $t ) ) {
print strftime( "%Y-%m-%d %H:%M\n", localtime( $t ) );
} else {
print "No outstanding reservations found.\n";
}
exit( 0 );
}
my $reservations = Reservation->LookupAll( $type );
my @timeline = ();
my $free = 0;
......
......@@ -407,7 +407,8 @@ if ($clear || $clear_idx) {
# For now, auto-approve reservation requests up to 64 node-hours.
# Later we'll probably want this threshold to vary based on the node type,
# how far into the future the reservation starts, the phase of the moon...
# how far into the future the reservation starts, existing approved
# reservations for the same project, the phase of the moon...
# who knows.
if( $count * ( $endtime - $starttime ) / 3600 <= 0x40 ) {
$approve = 1;
......@@ -472,6 +473,9 @@ while( 1 ) {
}
}
exit( $approve ? 0 : 2 ) if( $impotent );
# FIXME if $modify_idx is set, the old reservation was approved,
# and $approve is false, then things get ugly. e-mail the
# admins and leave the database untouched???
next if( !defined( Reservation->BeginTransaction( $version ) ) );
$res->Book( $modify_idx );
Reservation->EndTransaction();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment