Commit 21f6a3b2 authored by Kirk Webb's avatar Kirk Webb

Add option to return max and average data to idlestats.

Also fix a bug related to start/end times for short-lived experiments.
Note that a side effect of this fix is that the first aggregated data
point returned by idlestats may include data prior to the beginning of
an experiment (when returning data for nodes in an experiment).
parent e0e282bb
......@@ -48,20 +48,22 @@ my $SD_STATSDIR = "$TB/data/slothd_rrd";
my $ALLZEROMAC = "000000000000";
# Globals
my $valtype = "MAX";
my $now = time();
my $end = floor($now/$STEP)*$STEP - $STEP; # Now, normalized to STEP.
my $start = $end - floor($DEFWINDOW/$STEP)*$STEP + 2*$STEP; # Default window, normalized.
my $g_doboth = 0;
my $g_valtype = "MAX";
my $g_now = time();
my $g_end = floor($g_now/$STEP)*$STEP; # Now, normalized to STEP.
my $g_start = $g_end - floor($DEFWINDOW/$STEP)*$STEP + 2*$STEP; # Default window, normalized.
my $experiment;
my @nodelist = ();
sub usage() {
print STDERR
"Return JSON-encoded node activity stastics.\n\n".
"Usage: $0 [-d] [-A] [-S <start_time>] [-E <end_time>] node [node ...]\n" .
" $0 [-d] [-A] [-S <start_time>] [-E <end_time>] -e <pid>,<eid>\n".
"Usage: $0 [-d] [-A|-B] [-S <start_time>] [-E <end_time>] node [node ...]\n" .
" $0 [-d] [-A|-B] [-S <start_time>] [-E <end_time>] -e <pid>,<eid>\n".
"-d: turn on debugging.\n" .
"-A: return averages instead of maximums.\n".
"-B: return both average and maximum data points.\n".
"-e <pid>,<eid>: request data for nodes in an experiment.\n".
"-S <start_time>: bound the start of the returned data.\n".
" Default is beginning of available data for a list of nodes,\n".
......@@ -99,12 +101,16 @@ if ($UID) {
my %opts = ();
if (!getopts("dhAS:E:e:", \%opts) || $opts{'h'}) {
if (!getopts("dhABS:E:e:", \%opts) || $opts{'h'}) {
usage();
}
if ($opts{'A'}) {
$valtype = "AVERAGE";
$g_valtype = "AVERAGE";
}
if ($opts{'B'}) {
$g_doboth = 1;
}
if ($opts{'e'}) {
......@@ -124,10 +130,10 @@ if ($opts{'e'}) {
exit 1;
}
@nodelist = $experiment->NodeList(0,1);
# Bump start time to the beginning of this experiment plus one
# step. Adding one step epoch prevents us from grabbing stastics
# that incorporate data from prior to the start of the experiment.
$start = ceil($experiment->swapin_time()/$STEP)*$STEP + $STEP;
# Bump start time to the beginning of this experiment. Note that the
# first data point may include data from prior to the start of the
# experiment!
$g_start = ceil($experiment->swapin_time()/$STEP)*$STEP;
}
if (@ARGV) {
......@@ -168,11 +174,11 @@ if ($opts{'S'}) {
exit 1;
}
$stime = floor($stime/$STEP)*$STEP;
if ($experiment && $stime < $start) {
if ($experiment && $stime < $g_start) {
warn "Specified start time is prior to start of experiment!\n".
"Truncating to: $start\n";
"Truncating to: $g_start\n";
} else {
$start = $stime;
$g_start = $stime;
}
}
......@@ -187,19 +193,76 @@ if ($opts{'E'}) {
exit 1;
}
$etime = floor($etime/$STEP)*$STEP;
if ($etime > $now) {
warn "End time is in the future! Truncated to: $now\n";
if ($etime > $g_now) {
warn "End time is in the future! Truncated to: $g_now\n";
}
else {
$end = $etime;
$g_end = $etime;
}
}
if ($start > $end) {
if ($g_start > $g_end) {
warn "Start time must be less than or equal to end time!\n";
exit 1;
}
sub get_main_stats($$) {
my ($rrdfile, $dtype) = @_;
my ($rrd_stamp,$rrd_step,$rrd_names,$rrd_data) =
RRDs::fetch($rrdfile, $dtype, "--start=$g_start", "--end=$g_end",
"--resolution=$STEP");
if (RRDs::error) {
warn "Could not get data from $rrdfile: ". RRDs::error ."\n";
next;
}
my $hasvalues = 0;
my @main_tmp = ();
push @main_tmp,
['timestamp', 'tty_active', 'load_1min', 'load_5min', 'load_15min'];
foreach my $rrd_line (@$rrd_data) {
my ($last_tty, $load_1m, $load_5m, $load_15m) = @$rrd_line;
$last_tty = ($last_tty > 0) ? 1 : 0
if defined($last_tty);
$hasvalues = 1
if (defined($last_tty) && defined($load_1m)
&& defined($load_5m) && defined($load_15m));
push @main_tmp,
[$rrd_stamp, $last_tty, $load_1m, $load_5m, $load_15m];
$rrd_stamp += $rrd_step;
}
if ($hasvalues) {
return \@main_tmp;
}
return [];
}
sub get_iface_stats($$) {
my ($rrdfile, $dtype) = @_;
my ($rrd_stamp,$rrd_step,$rrd_names,$rrd_data) =
RRDs::fetch($rrdfile, $dtype, "--start=$g_start", "--end=$g_end",
"--resolution=$STEP");
if (RRDs::error) {
warn "Could not get interface data from $rrdfile: ". RRDs::error ."\n";
next;
}
my $hasvalues = 0; # track whether or not data exists for iface.
my @intf_tmp = (['timestamp', 'ipkt_rate', 'opkt_rate'],);
foreach my $rrd_line (@$rrd_data) {
my ($ipkt_rate, $opkt_rate) = @$rrd_line;
$hasvalues = 1
if (defined($ipkt_rate) && defined($opkt_rate));
push @intf_tmp, [$rrd_stamp, @$rrd_line];
$rrd_stamp += $rrd_step;
}
if ($hasvalues) {
return \@intf_tmp;
}
return [];
}
# Finally do some real work!
my @results = ();
foreach my $node (@nodelist) {
......@@ -216,34 +279,18 @@ foreach my $node (@nodelist) {
my $mainrrd = "$SD_STATSDIR/${node_id}.rrd";
if (!-f $mainrrd) {
warn "Could not find main rrd file ($mainrrd) for $node_id\n";
$nobj->{'main'} = []; # Indicate that no data was found.
} else {
my ($rrd_stamp,$rrd_step,$rrd_names,$rrd_data) =
RRDs::fetch($mainrrd, $valtype, "--start=$start", "--end=$end",
"--resolution=$STEP");
if (RRDs::error) {
warn "Could not get data for $node_id from $mainrrd: ". RRDs::error ."\n";
next;
}
my $hasvalues = 0;
my @main_tmp = ();
push @main_tmp,
['timestamp', 'tty_active', 'load_1min', 'load_5min', 'load_15min'];
foreach my $rrd_line (@$rrd_data) {
my ($last_tty, $load_1m, $load_5m, $load_15m) = @$rrd_line;
$last_tty = ($last_tty > 0) ? 1 : 0
if defined($last_tty);
$hasvalues = 1
if (defined($last_tty) && defined($load_1m)
&& defined($load_5m) && defined($load_15m));
push @main_tmp,
[$rrd_stamp, $last_tty, $load_1m, $load_5m, $load_15m];
$rrd_stamp += $rrd_step;
if ($g_doboth) {
$nobj->{'main'}->{'AVERAGE'} = []; # Indicate no data found.
$nobj->{'main'}->{'MAX'} = []; # Indicate no data found.
} else {
$nobj->{'main'} = []; # Indicate no data found.
}
if ($hasvalues) {
@{$nobj->{'main'}} = @main_tmp;
} else {
if ($g_doboth) {
$nobj->{'main'}->{'AVERAGE'} = get_main_stats($mainrrd, "AVERAGE");
$nobj->{'main'}->{'MAX'} = get_main_stats($mainrrd, "MAX");
} else {
$nobj->{'main'} = []; # Indicate that no data was found.
$nobj->{'main'} = get_main_stats($mainrrd, $g_valtype);
}
}
......@@ -280,35 +327,26 @@ foreach my $node (@nodelist) {
my $mac = uc($1);
next if (!exists($ifmap{$mac})); # skip if iface is not in DB.
$ifmap{$mac}->{'SEEN'} = 1; # mark.
my ($rrd_stamp,$rrd_step,$rrd_names,$rrd_data) =
RRDs::fetch($intfrrd, $valtype, "--start=$start", "--end=$end",
"--resolution=$STEP");
if (RRDs::error) {
warn "Could not get interface data for $node_id from $intfrrd: ". RRDs::error ."\n";
next;
}
my $hasvalues = 0; # track whether or not data exists for iface.
my @intf_tmp = (['timestamp', 'ipkt_rate', 'opkt_rate'],);
foreach my $rrd_line (@$rrd_data) {
my ($ipkt_rate, $opkt_rate) = @$rrd_line;
$hasvalues = 1
if (defined($ipkt_rate) && defined($opkt_rate));
push @intf_tmp, [$rrd_stamp, @$rrd_line];
$rrd_stamp += $rrd_step;
}
if ($hasvalues) {
@{$nobj->{'interfaces'}->{$mac}} = @intf_tmp;
if ($g_doboth) {
$nobj->{'interfaces'}->{$mac}->{"AVERAGE"} =
get_iface_stats($intfrrd, "AVERAGE");
$nobj->{'interfaces'}->{$mac}->{"MAX"} =
get_iface_stats($intfrrd, "MAX");
} else {
# No data found for iface, so return empty array rather than
# a list of undefined data points.
$nobj->{'interfaces'}->{$mac} = [];
$nobj->{'interfaces'}->{$mac} =
get_iface_stats($intfrrd, $g_valtype);
}
}
# Indicate no data found for interfaces where there is no
# RRD stats file.
foreach my $mac (keys %ifmap) {
if (!$ifmap{$mac}->{'SEEN'}) {
$nobj->{'interfaces'}->{$mac} = [];
if ($g_doboth) {
$nobj->{'interfaces'}->{$mac}->{"AVERAGE"} = [];
$nobj->{'interfaces'}->{$mac}->{"MAX"} = [];
} else {
$nobj->{'interfaces'}->{$mac} = [];
}
}
}
......
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