Commit 0763d8ce authored by Kevin Atkinson's avatar Kevin Atkinson
Browse files

Generalize node_usage plots to work on other sits, after some initial

setup, see http://users.emulab.net/trac/emulab/wiki/NodeUsageInstall.
parent b063af94
......@@ -31,7 +31,7 @@ include Makeconf
SUBDIRS = lib db assign www @optional_subdirs@ ipod security sensors \
pxe tbsetup account tmcd utils backend tip capture ipod vis \
sensors os xmlrpc install/newnode_sshkeys mote tools/whol \
tools/svn wiki bugdb collab tools/rmanage protogeni
tools/svn wiki bugdb collab tools/rmanage protogeni node_usage
all: all-subdirs
......@@ -77,6 +77,9 @@ endif
@$(MAKE) -C bugdb post-install
@$(MAKE) -C collab post-install
@$(MAKE) -C utils post-install
ifeq ($(NODE_USAGE_SUPPORT),1)
@$(MAKE) -C node_usage post-install
endif
#
# For installation on the 'ops' or 'users' node (okay, plastic)
......
......@@ -88,3 +88,5 @@ host_cpu = @host_cpu@
HAVE_ULXMLRPCPP = @HAVE_ULXMLRPCPP@
STANDALONE_CLEARINGHOUSE = @STANDALONE_CLEARINGHOUSE@
NODE_USAGE_SUPPORT = @NODE_USAGE_SUPPORT@
......@@ -1458,6 +1458,7 @@ done
#
......@@ -1541,6 +1542,7 @@ PROTOGENI_SUPPORT=0
PROTOGENI_CLEARINGHOUSE=0
PROTOGENI_DOMAIN="unknown"
STANDALONE_CLEARINGHOUSE=0
NODE_USAGE_SUPPORT=0
#
# XXX You really don't want to change these!
......@@ -2143,17 +2145,17 @@ for ac_hdr in ulxmlrpcpp/ulxr_config.h
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:2147: checking for $ac_hdr" >&5
echo "configure:2149: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 2152 "configure"
#line 2154 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:2157: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:2159: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -2192,17 +2194,17 @@ for ac_hdr in linux/videodev.h
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:2196: checking for $ac_hdr" >&5
echo "configure:2198: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 2201 "configure"
#line 2203 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:2206: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:2208: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -2235,7 +2237,7 @@ done
# Extract the first word of "gtk-config", so it can be a program name with args.
set dummy gtk-config; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:2239: checking for $ac_word" >&5
echo "configure:2241: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_GTK_CONFIG'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
......@@ -2292,7 +2294,7 @@ ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftes
cross_compiling=$ac_cv_prog_cxx_cross
echo $ac_n "checking how to run the C++ preprocessor""... $ac_c" 1>&6
echo "configure:2296: checking how to run the C++ preprocessor" >&5
echo "configure:2298: checking how to run the C++ preprocessor" >&5
if test -z "$CXXCPP"; then
if eval "test \"`echo '$''{'ac_cv_prog_CXXCPP'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
......@@ -2305,12 +2307,12 @@ ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftes
cross_compiling=$ac_cv_prog_cxx_cross
CXXCPP="${CXX-g++} -E"
cat > conftest.$ac_ext <<EOF
#line 2309 "configure"
#line 2311 "configure"
#include "confdefs.h"
#include <stdlib.h>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:2314: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:2316: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
:
......@@ -2336,17 +2338,17 @@ echo "$ac_t""$CXXCPP" 1>&6
ac_safe=`echo "xercesc/dom/DOM.hpp" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for xercesc/dom/DOM.hpp""... $ac_c" 1>&6
echo "configure:2340: checking for xercesc/dom/DOM.hpp" >&5
echo "configure:2342: checking for xercesc/dom/DOM.hpp" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 2345 "configure"
#line 2347 "configure"
#include "confdefs.h"
#include <xercesc/dom/DOM.hpp>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:2350: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:2352: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
......@@ -2410,7 +2412,7 @@ fi
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# ./install, which can be erroneously created by make from ./install.sh.
echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
echo "configure:2414: checking for a BSD compatible install" >&5
echo "configure:2416: checking for a BSD compatible install" >&5
if test -z "$INSTALL"; then
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
......@@ -2471,7 +2473,7 @@ esac
# Extract the first word of "rsync", so it can be a program name with args.
set dummy rsync; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:2475: checking for $ac_word" >&5
echo "configure:2477: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_path_RSYNC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
......@@ -2716,7 +2718,13 @@ outfiles="$outfiles Makeconf GNUmakefile \
collab/mailman/mailmanproxy collab/mailman/setmmpasswd \
collab/cvstools/cvs.proxy collab/cvstools/cvs_ctrl \
collab/cvstools/cvsrepo_ctrl.proxy collab/cvstools/cvsrepo_ctrl \
collab/cvstools/webcvsrepo_ctrl "
collab/cvstools/webcvsrepo_ctrl \
node_usage/GNUmakefile node_usage/mk-plots \
node_usage/analy node_usage/publish \
node_usage/analy2 node_usage/refresh \
node_usage/from_ptop node_usage/sanity \
node_usage/gather node_usage/mk-php-pages \
node_usage/get-start-date"
#
# Do this for easy distclean.
......@@ -2994,6 +3002,7 @@ s%@PROTOGENI_CLEARINGHOUSE@%$PROTOGENI_CLEARINGHOUSE%g
s%@PROTOGENI_DOMAIN@%$PROTOGENI_DOMAIN%g
s%@STANDALONE_CLEARINGHOUSE@%$STANDALONE_CLEARINGHOUSE%g
s%@GMAP_API_KEY@%$GMAP_API_KEY%g
s%@NODE_USAGE_SUPPORT@%$NODE_USAGE_SUPPORT%g
s%@TBOPSEMAIL@%$TBOPSEMAIL%g
s%@TBOPSEMAIL_NOSLASH@%$TBOPSEMAIL_NOSLASH%g
s%@TBROBOCOPSEMAIL@%$TBROBOCOPSEMAIL%g
......
......@@ -212,6 +212,7 @@ AC_SUBST(PROTOGENI_CLEARINGHOUSE)
AC_SUBST(PROTOGENI_DOMAIN)
AC_SUBST(STANDALONE_CLEARINGHOUSE)
AC_SUBST(GMAP_API_KEY)
AC_SUBST(NODE_USAGE_SUPPORT)
#
# Offer both versions of the email addresses that have the @ escaped
......@@ -294,6 +295,7 @@ PROTOGENI_SUPPORT=0
PROTOGENI_CLEARINGHOUSE=0
PROTOGENI_DOMAIN="unknown"
STANDALONE_CLEARINGHOUSE=0
NODE_USAGE_SUPPORT=0
#
# XXX You really don't want to change these!
......@@ -998,7 +1000,13 @@ outfiles="$outfiles Makeconf GNUmakefile \
collab/mailman/mailmanproxy collab/mailman/setmmpasswd \
collab/cvstools/cvs.proxy collab/cvstools/cvs_ctrl \
collab/cvstools/cvsrepo_ctrl.proxy collab/cvstools/cvsrepo_ctrl \
collab/cvstools/webcvsrepo_ctrl "
collab/cvstools/webcvsrepo_ctrl \
node_usage/GNUmakefile node_usage/mk-plots \
node_usage/analy node_usage/publish \
node_usage/analy2 node_usage/refresh \
node_usage/from_ptop node_usage/sanity \
node_usage/gather node_usage/mk-php-pages \
node_usage/get-start-date"
#
# Do this for easy distclean.
......
......@@ -12,3 +12,4 @@ TBSTATEDEMAIL=kevina@fast.cs.utah.edu
TBTESTSUITEEMAIL=kevina@fast.cs.utah.edu
WWW=www.emulab.net/dev/kevina
THISHOMEBASE=Kevina.Emulab.Net
NODE_USAGE_SUPPORT=1
\ No newline at end of file
SCRIPTS = analy from_ptop mk-plots refresh analy2 gather publish sanity
all:
node_usage-install:
cp index.php /usr/testbed/www/node_usage/
cp -p $(SCRIPTS) /usr/testbed/data/node_usage/scripts
#
# EMULAB-COPYRIGHT
# Copyright (c) 2009 University of Utah and the Flux Group.
# All rights reserved.
#
SRCDIR = @srcdir@
TESTBED_SRCDIR = @top_srcdir@
OBJDIR = ..
SUBDIR = node_usage
include $(OBJDIR)/Makeconf
LIBEXEC_NODE_USAGE = analy mk-plots refresh analy2 gather publish mk-php-pages get-start-date
#
# These are Utah emulab specific
#
NODE_USAGE_OTHER = from_ptop sanity
#
# Force dependencies on the scripts so that they will be rerun through
# configure if the .in file is changed.
#
all: $(LIBEXEC_NODE_USAGE)
include $(TESTBED_SRCDIR)/GNUmakerules
install: \
$(addprefix $(INSTALL_LIBEXECDIR)/node_usage/, $(LIBEXEC_NODE_USAGE))
post-install:
$(INSTALL_LIBEXECDIR)/node_usage/%: %
@echo "Installing $<"
-mkdir -p @prefix@/data/node_usage
-mkdir -p $(INSTALL_LIBEXECDIR)/node_usage
$(INSTALL) $< $@
clean:
......@@ -4,21 +4,26 @@ use strict;
use warnings;
use POSIX qw(strftime ceil);
chdir "/usr/testbed/data/node_usage/data";
sub any (@) { $_ && return 1 for @_; 0 }
my $TOLERANCE_ALL = 0.05;
my $TOLERANCE_PC3000 = 0.05;
our ($START, @to_plot);
require "@prefix@/etc/node_usage.conf";
chdir "@prefix@/data/node_usage";
my $TOLERANCE = 0.05;
my $TOLERANCE_INTERVAL = 1/3;
my $START = 1125727200;
my $interval = 60*60;
my $interval_name = "hourly";
my $start = ceil($START / $interval) * $interval;
my @idxs = (0 .. $#to_plot);
my $prev_time = 0;
my @prev_data = (0,0);
my @total_so_far = (0,0);
my @prev_data = map {0} @idxs;
my @total_so_far = map {0} @idxs;
my $next_cutoff = $start;
my $error_frac = 0;
......@@ -26,28 +31,40 @@ my $error_frac = 0;
open F, "node_usage.raw";
open O, ">node_usage-$interval_name.dat";
our %d;
sub sum_usage_stats ($) {
my ($n) = @_;
my @res;
foreach my $row (@to_plot) {
my $r = 0;
my $pcs = $row->[1];
foreach (@$pcs) {
$r += $d{$_}[$n] if defined $d{$_}[$n];
}
push @res, $r;
}
return @res;
}
while (<F>) {
chop;
s/^(\d+) (\d+) // or die;
my $time = $2;
my %d;
undef %d;
while (s/^ ([\w\d\-\?]+): (\d+) (\d+) (\d+) //) {
$d{$1} = [$2, $3, $4];
}
no warnings 'uninitialized';
my @num = ($d{pc850}[0] + $d{pc600}[0] + $d{pc2000}[0] + $d{pc3000}[0],
$d{pc3000}[0]);
die unless $time <= $start || $num[0] == 160 + 128 + 40 + 8;
die unless $time <= $start || $num[1] == 160;
my @data = ($d{pc850}[1] + $d{pc600}[1] + $d{pc2000}[1] + $d{pc3000}[1],
$d{pc3000}[1]);
my @error = ($d{pc850}[2] + $d{pc600}[2] + $d{pc2000}[2] + $d{pc3000}[2],
$d{pc3000}[2]);
$data[0] = $data[0] + $error[0]/2;
$data[1] = $data[1] + $error[1]/2;
if ($error[0] > $num[0]*$TOLERANCE_ALL || $error[1] > $num[1]*$TOLERANCE_PC3000) {
my @num = sum_usage_stats(0);
#die unless $time <= $start || $num[0] == 128 + 40;
#die unless $time <= $start || $num[1] == 128;
my @data = sum_usage_stats(1);
my @error = sum_usage_stats(2);
@data = map {$data[$_] + $error[$_]/2} @idxs;
if (any map {$error[$_] > $num[$_]*$TOLERANCE} @idxs) {
#print STDERR "ERROR $time: $error\n";
@data = ('NaN', 'NaN');
@data = map {'NaN'} @idxs;
}
use warnings;
......@@ -57,26 +74,30 @@ while (<F>) {
if ($prev_data[0] != $prev_data[0]) { # ie NaN
$error_frac += $frac;
} else {
$total_so_far[0] += $prev_data[0] * $frac;
$total_so_far[1] += $prev_data[1] * $frac;
}
foreach my $i (@idxs) {
$total_so_far[$i] += $prev_data[$i] * $frac;
}
}
};
while ($time >= $next_cutoff) {
&$combine($next_cutoff);
my @free = @total_so_far;
if ($error_frac > $TOLERANCE_INTERVAL) {
$free[0] = 'NaN';
$free[1] = 'Nan';
foreach my $i (@idxs) {
$free[0] = 'NaN';
}
} else {
$free[0] /= (1 - $error_frac);
$free[1] /= (1 - $error_frac);
foreach my $i (@idxs) {
$free[$i] /= (1 - $error_frac);
}
}
my @alloc = ($num[0] - $free[0], $num[1] - $free[1]);
my @alloc = map {$num[$_] - $free[$_]} @idxs;
my $dtime = $next_cutoff - $interval;
printf O ("%d %.1f %.1f %.1f %.1f\n", $dtime, @free, @alloc) if $dtime >= $start;
print O join(' ', $dtime, map {sprintf("%.1f", $_)} (@free, @alloc)),"\n"
if $dtime >= $start;
$error_frac = 0;
@total_so_far = (0,0);
@total_so_far = map {0} @idxs;
$prev_time = $next_cutoff;
$next_cutoff += $interval;
......@@ -88,3 +109,14 @@ while (<F>) {
}
......@@ -7,10 +7,15 @@ use strict;
use warnings;
no warnings 'uninitialized';
chdir "/usr/testbed/data/node_usage/data";
our (@to_plot);
require "@prefix@/etc/node_usage.conf";
chdir "@prefix@/data/node_usage";
my $TOLERANCE_INTERVAL = 1/3;
my @idxs = (0 .. (@to_plot * 2 - 1));
my %res;
sub tally ($$@) {
......@@ -19,7 +24,7 @@ sub tally ($$@) {
$res{$what}{data}{$str}{invalid}++;
} else {
$res{$what}{data}{$str}{count}++;
foreach my $i (0 .. 3) {
foreach my $i (@idxs) {
$res{$what}{data}{$str}{data}[$i] += $d[$i];
}
}
......@@ -29,7 +34,7 @@ sub tally_mod ($$@) {
my ($bin, $what, @d) = @_;
return if $d[0] != $d[0]; # ie NaN
$res{$what}{data}[$bin]{count}++;
foreach my $i (0 .. 3) {
foreach my $i (@idxs) {
$res{$what}{data}[$bin]{data}[$i] += $d[$i];
}
}
......@@ -84,13 +89,13 @@ foreach my $k (keys %res) {
my $invalid = $d->{invalid};
my $count = $d->{count};
if ($invalid / ($invalid + $count) > $TOLERANCE_INTERVAL) {
@r = ('NaN', 'NaN', 'NaN', 'NaN');
@r = map {'NaN'} @idxs;
} else {
foreach my $j (0 .. 3) {
foreach my $j (@idxs) {
$r[$j] = $d->{data}[$j]/$count;
}
}
printf F ("%s %5.1f %5.1f %5.1f %5.1f\n", $i, @r);
print F join(' ', "$i ", map {sprintf("%5.1f", $_)} @r),"\n"
}
} else {
my $div = $res{$k}{div};
......@@ -99,10 +104,10 @@ foreach my $k (keys %res) {
my @r;
my $d = $res{$k}{data}[$i];
my $count = $d->{count};
foreach my $j (0 .. 3) {
foreach my $j (@idxs) {
$r[$j] = $d->{data}[$j]/$count;
}
printf F ("%6.3f %5.1f %5.1f %5.1f %5.1f\n", $i/$div, @r);
print F join(' ', sprintf("%6.3f ", $i/$div), map {sprintf("%5.1f", $_)} @r),"\n"
}
}
}
......@@ -13,22 +13,17 @@ use Carp;
use strict;
use warnings;
#
# Configure variables
#
my $TB = "/usr/testbed/";
#
# Turn off line buffering on output
#
$| = 1;
# Load the Testbed support stuff.
use lib "/usr/testbed/lib";
use lib "@prefix@/lib";
use libdb;
use libtestbed;
chdir "/usr/testbed/data/node_usage/data";
chdir "@prefix@/data/node_usage";
my $qr = DBQueryFatal("select t.idx,action,t.exptidx,eid,pid,UNIX_TIMESTAMP(start_time), UNIX_TIMESTAMP(end_time) from testbed_stats as t left join experiment_stats as e on t.exptidx = e.exptidx where (t.action='swapin' or t.action='start') and exitcode=0 and start_time >= '2005-09-03' order by t.idx");
......
......@@ -15,21 +15,22 @@ $Data::Dumper::Indent = 1;
use strict;
use warnings;
our $NODE_USAGE_DB;
require "@prefix@/etc/node_usage.conf";
my $prep = 1;
my $results = 1;
my $fresh = 0;
my $TB = "/usr/testbed/";
# Turn off line buffering on output
$| = 1;
# Load the Testbed support stuff.
use lib "/usr/testbed/lib";
use lib "@prefix@/lib";
use libdb;
use libtestbed;
chdir "/usr/testbed/data/node_usage/data";
chdir "@prefix@/data/node_usage";
$fresh = 1 unless -e "gather.state.1" && "gather.state.2";
......@@ -55,11 +56,17 @@ our $last_history_id = -1;
if ($prep) {
DBQueryFatal("insert into node_usage.node_history_copy select * from node_history where history_id > (select max(history_id) from node_usage.node_history_copy)");
if ($fresh) {
DBQueryFatal("create database if not exists $NODE_USAGE_DB");
DBQueryFatal("drop table if exists $NODE_USAGE_DB.node_history_copy");
DBQueryFatal("create table $NODE_USAGE_DB.node_history_copy like node_history");
}
DBQueryFatal("insert into $NODE_USAGE_DB.node_history_copy select * from node_history where history_id > IFNULL((select max(history_id) from $NODE_USAGE_DB.node_history_copy), 0)");
if ($fresh) {
DBQueryFatal("drop table if exists node_usage.node_trans");
DBQueryFatal("create table node_usage.node_trans (".
DBQueryFatal("drop table if exists $NODE_USAGE_DB.node_trans");
DBQueryFatal("create table $NODE_USAGE_DB.node_trans (".
" history_id int unsigned not null primary key,".
" stamp int unsigned not null, ".
" node_id char(8) not null, ".
......@@ -74,7 +81,7 @@ if ($prep) {
do "gather.state.1";
}
$qr = DBQueryFatal("select history_id,node_id,op,stamp from node_usage.node_history_copy where history_id > $last_history_id order by history_id");
$qr = DBQueryFatal("select history_id,node_id,op,stamp from $NODE_USAGE_DB.node_history_copy where history_id > $last_history_id order by history_id");
local $last_history_id;
......@@ -92,9 +99,9 @@ if ($prep) {
}
if ($invalid) {
#print STDERR "WARNING: $history_id ($stamp) $last_trans{$node_id}: $invalid\n";
DBQueryFatal("update node_usage.node_trans set op = 'invalid' where history_id=$last_trans{$node_id}");
DBQueryFatal("update $NODE_USAGE_DB.node_trans set op = 'invalid' where history_id=$last_trans{$node_id}");
} elsif (!defined $prev_state || $prev_state ne $node_state{$node_id}) {
DBQueryFatal("insert into node_usage.node_trans values ($history_id, $stamp, '$node_id', '$node_state{$node_id}')");
DBQueryFatal("insert into $NODE_USAGE_DB.node_trans values ($history_id, $stamp, '$node_id', '$node_state{$node_id}')");
$last_trans{$node_id} = $history_id;
}
$last_history_id = $history_id;
......@@ -121,7 +128,7 @@ if ($results) {
open F, ">>node_usage.raw";
$qr = DBQueryFatal("select history_id,stamp,node_id,op from node_usage.node_trans where history_id > $last_history_id order by history_id");
$qr = DBQueryFatal("select history_id,stamp,node_id,op from $NODE_USAGE_DB.node_trans where history_id > $last_history_id order by history_id");
while (my ($history_id,$stamp,$node_id,$op) = $qr->fetchrow()) {
my $type = $node_type{$node_id};
......@@ -155,3 +162,11 @@ if ($results) {
#!/usr/bin/perl
use strict;
use warnings;
our ($START);
require "@prefix@/etc/node_usage.conf";
chdir "@prefix@/data/node_usage";
open F, "node_usage.raw" or die;
my @hunt_for;
if (@ARGV == 0 || @ARGV % 2 != 0) {
print "Usage: $0 <pc1> <num1> [<pc2> <num2> ...]\n";
exit 1;
}
while (@ARGV) {
push @hunt_for, [shift @ARGV, shift @ARGV];
}
while (<F>) {
chop;
s/^(\d+) (\d+) // or die;
my $time = $2;
my %d;
while (s/^ ([\w\d\-\?]+): (\d+) (\d+) (\d+) //) {
$d{$1} = [$2, $3, $4];
}
my $num_satisfied = 0;
foreach my $e (@hunt_for) {
$num_satisfied++ if defined $d{$e->[0]} && ($d{$e->[0]}[0]) == $e->[1];
}
if ($num_satisfied == @hunt_for) {
print "$time\n";