Commit bbf42391 authored by Leigh B Stoller's avatar Leigh B Stoller

Add code to compute a utilization number for reservations based on

the timeline.
parent ed2dce21
......@@ -29,8 +29,10 @@ package APT_Utility;
use strict;
use English;
use Data::Dumper;
use Date::Parse;
use Carp;
use Exporter;
use POSIX qw(ceil);
use vars qw(@ISA @EXPORT);
@ISA = "Exporter";
......@@ -44,6 +46,7 @@ use Project;
use Group;
use GeniHRN;
use GeniUser;
use emutil;
# Configure variables
my $TB = "@prefix@";
......@@ -126,3 +129,88 @@ sub MapUserURN($)
return undef;
}
#
# Given a reservation details hash, calculate a utilization number
# from the history array.
#
sub ReservationUtilization($$)
{
my ($res, $active) = @_;
my $count = $res->{'nodes'};
my $resstart = str2time($res->{'start'});
my $resend = ($active ? time() :
(str2time(defined($res->{'deleted'}) ?
$res->{'deleted'} : $res->{'end'})));
my $reshours = (($resend - $resstart) / 3600) * $count;
my $usedhours = 0;
my $inuse = 0;
my $laststamp = $resstart;
my $type = $res->{'type'};
my $remote_uid = $res->{'remote_uid'};
my @tmp = @{$res->{'history'}};
# Init for web interface.
$res->{'reshours'} = $reshours;
$res->{'usedhours'} = undef;
$res->{'utilization'} = undef;
#
# Scan past timeline entries that are *before* the start of the
# reservation; these are experiments that were running when the
# reservation started, and provide the number of nodes allocated
# at the time the reservation starts.
#
while (@tmp) {
my $ref = $tmp[0];
my $stamp = $ref->{'t'};
my $allocated = $ref->{'allocated'};
$ref->{'tt'} = TBDateStringGMT($ref->{'t'});
last
if ($stamp >= $resstart);
# Watch for nothing allocated by the user at this time stamp
my $using = 0;
if (exists($allocated->{$remote_uid})) {
$using = $allocated->{$remote_uid}->{$type};
}
$inuse = $using;
$inuse = $count if ($inuse > $count);
shift(@tmp);
}
foreach my $ref (@tmp) {
my $stamp = $ref->{'t'};
my $reserved = $ref->{'reserved'};
my $allocated = $ref->{'allocated'};
$ref->{'tt'} = TBDateStringGMT($ref->{'t'});
# If this stamp is after the reservation, we can stop. The
# last entry will be the current number of nodes used till
# the end of the reservation. This entry is typically for the
# end of an experiment start before the end of the reservation.
last
if ($stamp > $resend);
# Watch for nothing allocated by the user at this time stamp
my $using = 0;
if (exists($allocated->{$remote_uid})) {
$using = $allocated->{$remote_uid}->{$type};
}
$usedhours += (($stamp - $laststamp) / 3600) * $inuse;
$laststamp = $stamp;
$inuse = $using;
$inuse = $count if ($inuse > $count);
}
# And then a final entry for usage until the end of the reservation.
if ($laststamp) {
$usedhours += (($resend - $laststamp) / 3600) * $inuse;
}
$res->{'reshours'} = $reshours;
$res->{'usedhours'} = $usedhours;
$res->{'utilization'} = POSIX::ceil(($usedhours/$reshours) * 100.0);
$res->{'utilization'} = 100 if ($res->{'utilization'} > 100);
return 0;
}
......@@ -2112,19 +2112,24 @@ sub DoMaxExtensionInternal($$)
#
$res->{'cluster'} = $aptagg->urn();
$res->{'cluster_id'} = $aptagg->nickname();
# Backwards compat
if (!exists($res->{'nodes'})) {
$res->{'nodes'} = $res->{'count'};
}
if ($res->{'approved'} eq "") {
# Maps to JSON NULL.
$res->{'approved'} = undef;
}
if (!exists($res->{'cancel'}) || $res->{'cancel'} eq "") {
# Maps to JSON NULL.
$res->{'cancel'} = undef;
# We need numbers.
$res->{'nodes'} = int($res->{'nodes'});
$res->{'using'} = int($res->{'using'});
#
# Hmm, undef/null is a pain with XMLRPC.
#
foreach my $key ("approved", "cancel", "deleted") {
if (!exists($res->{$key}) || $res->{$key} eq "") {
$res->{$key} = undef;
}
}
#
# Lets calculate a utilization numbers, this will update the
# res hash. Flag says not an active reservation.
#
APT_Utility::ReservationUtilization($res, 0);
}
$blob->{'reservations'}->{$aptagg->urn()} = $reslist;
}
......
......@@ -28,7 +28,7 @@ use XML::Simple;
use Data::Dumper;
use CGI;
use POSIX ":sys_wait_h";
use POSIX qw(:signal_h);
use POSIX qw(:signal_h ceil);
use Date::Parse;
#
......@@ -516,6 +516,10 @@ sub DoList()
$details->{'cluster_id'} = $aggregate->nickname();
$details->{'cluster_urn'} = $aggregate->urn();
# We need numbers.
$details->{'nodes'} = int($details->{'nodes'});
$details->{'using'} = int($details->{'using'});
# Backwards compat
if (!exists($details->{'nodes'})) {
$details->{'nodes'} = $details->{'count'};
......@@ -531,6 +535,12 @@ sub DoList()
}
}
#
# Lets calculate a utilization numbers, this will update the
# res hash. Flag says not an active reservation.
#
APT_Utility::ReservationUtilization($details, 1);
#
# If we have the history, then go through and map the
# experiments to local experiments so we can link to them in
......@@ -1136,6 +1146,10 @@ sub DoHistory()
$res->{'cluster_id'} = $aggregate->nickname();
$res->{'cluster_urn'} = $aggregate->urn();
# We need numbers.
$res->{'nodes'} = int($res->{'nodes'});
$res->{'using'} = int($res->{'using'});
# Backwards compat
if (!exists($res->{'nodes'})) {
$res->{'nodes'} = $res->{'count'};
......@@ -1149,14 +1163,11 @@ sub DoHistory()
}
}
if (!exists($res->{'deleted'}) ||
$res->{'deleted'} eq "") {
$res->{'deleted'} = undef;
}
if (!exists($res->{'uuid'}) ||
$res->{'uuid'} eq "") {
$res->{'uuid'} = NewUUID();
}
#
# Lets calculate a utilization numbers, this will update the
# res hash. Flag says not an active reservation.
#
APT_Utility::ReservationUtilization($res, 0);
}
done:
if (defined($webtask)) {
......
......@@ -19,6 +19,7 @@
<% if (showusing) { %>
<th class="sorter-false">Using</td>
<% } %>
<th>Util</th>
<th>Created</th>
<th>Starts</th>
<th>Ends</th>
......@@ -153,6 +154,13 @@
<td><%- value.using %></td>
<% } %>
<% } %>
<td>
<% if (_.has(value, "utilization") && value.utilization) { %>
<%- value.utilization %>%
<% } else { %>
&nbsp;
<% } %>
</td>
<td class="format-date"><%- value.created %></td>
<td>
<% if (new Date().getTime() > new Date(value.start).getTime()) { %>
......@@ -164,8 +172,13 @@
</td>
<td>
<% if (_.has(value, "deleted") && value.deleted) { %>
<span class="format-date"
style="color: red;"><%- value.deleted %></span>
<% if (_.has(value, "canceled") && value.canceled) { %>
<span class="format-date text-danger">
<%- value.deleted %></span>
<% } else { %>
<span class="format-date text-warning">
<%- value.deleted %></span>
<% } %>
<% } else { %>
<span class="format-date"><%- value.end %></span>
<% } %>
......
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