Commit f8e4942f authored by Pramod R Sanaga's avatar Pramod R Sanaga
Browse files

These are all the files required to make the clustering (with Wavelets) approach

to shared-bottleneck detection work on Planetlab.

Note: The delay calculation/traffic generation method used here is *different* from the one used
earlier to calculate equivalence classes ( and Rubenstein's code ) - Hence the
different directory entry.
parent 7f9a4ddb
#include <stdio.h>
#include<iostream>
#include<cstdlib>
#include<vector>
#include<fstream>
#include "dc.hh"
int main(int argc, char **argv)
{
std::ifstream fileHandle;
fileHandle.open(argv[1], std::ios::in);
std::vector<double> delays;
int delayVal;
while(!(fileHandle.eof()))
{
fileHandle >> delayVal;
if((fileHandle.eof()))
break;
delays.push_back(delayVal);
}
fileHandle.close();
delay_correlation(delays, delays.size());
}
g++ Wavelet.cc dc.cc -lm -o MinSikKimProgram
#include <math.h>
#include <algorithm> // reverse_copy()
#include <numeric> // accumulate()
#include "dc.hh"
#include <iostream> // DEBUG
const int MAX_SAMPLE = 1024;
const int TEST_DURATION = 100;
const int FILTER_LENGTH = 12; /* Using 'db6' wavelet */
const int MAX_LEVEL = 4; /* Maximum decomposition level */
const double LOG2 = 0.69314718055994529f; // log(2)
const double _SMALL = 1.0e-15f;
using namespace std;
//vector<double> wavelet_denoising(vector<double> );
//double xcor(vector<double> ,vector<double> );
//vector<double> wdec(vector<double>,int);
//vector<double> wconv(vector<double>, double *);
//vector<double> wrec(vector<double> ,vector<double>,int);
/* Filter coefficients for 'db6' wavelet */
double LD[12]={-0.00107730108500,0.00477725751101,0.00055384220099,-0.03158203931803,
0.02752286553002,0.09750160558708,-0.12976686756710,-0.22626469396517,
0.31525035170924,0.75113390802158,0.49462389039839,0.11154074335008};
double HD[12]={-0.11154074335008,0.49462389039839,-0.75113390802158,0.31525035170924,
0.22626469396517,-0.12976686756710,-0.09750160558708,0.02752286553002,
0.03158203931803,0.00055384220099,-0.00477725751101,-0.00107730108500};
double LR[12]={0.11154074335008,0.49462389039839,0.75113390802158,0.31525035170924,
-0.22626469396517,-0.12976686756710,0.09750160558708,0.02752286553002,
-0.03158203931803,0.00055384220099,0.00477725751101,-0.00107730108500};
double HR[12]={-0.00107730108500,-0.00477725751101,0.00055384220099,0.03158203931803,
0.02752286553002,-0.09750160558708,-0.12976686756710,0.22626469396517,
0.31525035170924,-0.75113390802158,0.49462389039839,-0.11154074335008};
vector<double> wconv(const vector<double> &data, double *filter)
{
int lx = data.size();
int lf = FILTER_LENGTH;
vector<double> result;
int i,j;
double sum = 0;
for(i=1;i<lx+lf;i++)
{
if(i<lf)
{
for(j=0;j<i;j++)
sum=sum+filter[j]*data[i-j-1];
}
else if(i<lx+1)
{
for(j=0;j<lf;j++)
sum=sum+filter[j]*data[i-j-1];
}
else
{
for(j=i-lx;j<lf;j++)
sum=sum+filter[j]*data[i-j-1];
}
result.push_back(sum);
sum=0;
}
return result;
}
vector<double> wdec(vector<double> data,int option)
{
double diff;
int len,i;
vector<double> conv_result;
vector<double> dyaddown;
vector<double> edata;
len=data.size();
/* Symmetric expansion to prevent edge effect */
reverse_copy(data.begin(),(data.begin()+FILTER_LENGTH-1),inserter(edata,edata.begin()));
copy(data.begin(),data.end(),inserter(edata,edata.end()));
reverse_copy((data.end()-FILTER_LENGTH+1),data.end(),inserter(edata,edata.end()));
/* option 1 for detail space, option 2 for approximation space */
if(option == 1)
conv_result=wconv(edata,HD);
else if(option == 2)
conv_result=wconv(edata,LD);
diff = (conv_result.size()-(len+FILTER_LENGTH-1))/2.0f;
conv_result.erase((conv_result.end()-(int)floor(diff)),conv_result.end());
conv_result.erase(conv_result.begin(),(conv_result.begin()+(int)ceil(diff)));
/* Downsampling */
vector<double>::iterator index;
i=1;
for(index=conv_result.begin();index!=conv_result.end();index++)
{
if((i++)%2 ==0)
dyaddown.push_back(*(index));
}
return dyaddown;
}
vector<double> wrec(vector<double> app,vector<double> detail,int length)
{
vector<double> app_up;
vector<double> detail_up;
vector<double> app_conv;
vector<double> detail_conv;
int i,diff;
/* Upsampling */
for(i=1;i<=2*(app.size());i++)
{
if(i%2==1)
{
app_up.push_back(0.0);
detail_up.push_back(0.0);
}
else
{
app_up.push_back(app[(i/2)-1]);
detail_up.push_back(detail[(i/2)-1]);
}
}
app_conv=wconv(app_up,LR);
detail_conv=wconv(detail_up,HR);
/* Adding detail and approximation */
for(i=0;i<app_conv.size();i++)
app_conv[i]=app_conv[i] + detail_conv[i];
app_conv.erase(app_conv.begin(),(app_conv.begin()+FILTER_LENGTH-1));
diff=app_conv.size()-length;
app_conv.erase((app_conv.end()-diff),app_conv.end());
return app_conv;
}
vector<double> wavelet_denoising(const vector<double> &data, int nSamples)
{
double median;
int appr_size,next_size;
int med_position;
vector<double> wcoeffs;
vector<double> detail;
vector<double> appr;
vector<double> abs_det;
// Decide the maximum decomposition level.
int nblev;
nblev=(int)floorf(logf(nSamples)/LOG2 - logf(logf(nSamples))/LOG2);
if(nblev > MAX_LEVEL) nblev = MAX_LEVEL;
/* Deciding threshold value for 'MINIMAXI' scheme */
int no_wcoeffs = nSamples; /* Add the size of approximation */
int detail_size = nSamples;
double thr, thr_lev;
for(int i = 1; i <= nblev; i++) {
detail_size= (int)floorf((detail_size+FILTER_LENGTH-1) / 2.0f);
no_wcoeffs += detail_size;
}
if(no_wcoeffs <= 32) thr = 0;
else thr = 0.3936 + 0.1829 * (logf(no_wcoeffs)/LOG2);
/* Wavelets decomposition & thresholding */
vector<int> wcolen;
wcolen.push_back(nSamples);
copy(data.begin(), data.end(), inserter(appr, appr.begin()));
for(int i = 1; i <= nblev; i++) {
detail = wdec(appr, 1); /* Fine detail space */
appr = wdec(appr, 2); /* Coarse approximation space */
abs_det.clear();
transform(detail.begin(),detail.end(),inserter(abs_det,abs_det.begin()),fabsf);
/* Finding the median to scale threshold */
sort(abs_det.begin(),abs_det.end());
if( (abs_det.size())%2 == 1 )
{
med_position=(int)floor(abs_det.size()/2.0f);
median = abs_det[med_position];
}
else
{
med_position=(int)(abs_det.size()/2);
median =( abs_det[med_position-1] + abs_det[med_position] )/2.0;
}
thr_lev=thr*(median/0.6745);
/* Soft-thresholding */
for(int j=0;j<detail.size();j++)
{
if(detail[j] >= 0)
{
if(detail[j] <= thr_lev)
detail[j]=0;
else
detail[j]=detail[j]-thr_lev;
}
else
{
if(detail[j] >= (-1*thr_lev) )
detail[j]=0;
else
detail[j]=detail[j]+thr_lev;
}
}
copy(detail.begin(),detail.end(),inserter(wcoeffs,wcoeffs.end()));
wcolen.push_back(detail.size());
}
wcolen.push_back(appr.size());
copy(appr.begin(),appr.end(),inserter(wcoeffs,wcoeffs.end()));
/* Wavelets reconstruction */
appr.clear();
detail.clear();
appr_size=wcolen.back();
wcolen.pop_back();
next_size=wcolen.back();
wcolen.pop_back();
copy((wcoeffs.end()-appr_size),wcoeffs.end(),inserter(appr,appr.begin()));
wcoeffs.resize(wcoeffs.size()-appr_size);
for(int i=1;i<=nblev;i++)
{
copy((wcoeffs.end()-next_size),wcoeffs.end(),inserter(detail,detail.begin()));
wcoeffs.resize(wcoeffs.size()-next_size);
next_size=wcolen.back();
wcolen.pop_back();
appr=wrec(appr,detail,next_size);
}
return appr;
}
void delay_correlation(const vector<double> &delay,
int nSamples)
{
/* Wavelets denoising */
vector<double> wd;
wd=wavelet_denoising(delay, nSamples);
for(int i = 0;i < wd.size(); i++)
cout << wd[i] << "\n";
}
/*
Detecting Shared Congestion by wavelets
Header file for shcon.cpp
By Taek H. Kim (thkim@ece.utexas.edu)
Wavelet : Daubechies 12 (db6)
Thresholding : MINIMAXI soft-thresholding
Noise Scaling : Multi-level scaling
Maximum decomposition level : 4
*/
//#include <iostream>
//#include <fstream>
//#include <algo.h>
#include <vector>
void delay_correlation(const std::vector<double> &delay1,
int nSamples);
#!/usr/bin/perl
#
# EMULAB-COPYRIGHT
# Copyright (c) 2006 University of Utah and the Flux Group.
# All rights reserved.
#
my $expName;
my $projName;
my $logsDir;
my $newExpName;
my $newProjName;
%bottleNecks = {};
my %nodeClasses;
my %nodeNameMap = {};
die "Usage: perl sharedBottle.pl proj_name exp_name newProj_name newExp_name initial_conditions.txt(Optional)"
if($#ARGV < 3);
$projName = $ARGV[0];
$expName = $ARGV[1];
$newProjName = $ARGV[2];
$newExpName = $ARGV[3];
$initialConditionsFilename = $ARGV[4];
$logsDir = "/tmp/clusterLogs2";
# Get the initial conditions.
$elabInitScript = "/proj/tbres/duerig/testbed/pelab/init-elabnodes.pl";
$initConditionsCommand = $elabInitScript . " -o /tmp/initial-conditions.txt " . $newProjName . " " . $newExpName;
if($#ARGV == 3)
{
system($initConditionsCommand);
$initialConditionsFilename = "/tmp/initial-conditions.txt";
}
open(CONDITIONS, $initialConditionsFilename);
my @initialConditions = ();
while(<CONDITIONS>)
{
chomp( $_ );
push(@initialConditions, $_);
}
close(CONDITIONS);
my @addressList = ();
my $addrFlag = 0;
my %bwMap = {};
my %delayMap = {};
my %elabMap = {};
# Create & send events.
# Get initial conditions for the paths of interest
# from the database, using init-elabnodes.pl
my $tevc = "/usr/testbed/bin/tevc -e $newProjName/$newExpName now";
#@@@`/usr/testbed/bin/tevc -w -e $newProjName/$newExpName now elabc reset`;
#@@@`$tevc elabc create start`;
# Create a list of the IP addresses.
foreach $conditionLine (@initialConditions)
{
if($conditionLine =~ /(\d*?\.\d*?\.\d*?\.(\d*?))\s(\d*?\.\d*?\.\d*?\.\d*?)\s(\d*?)\s(\d*?)\s[\d\w\-\.]*/)
{
$srcAddress = $1;
$addrFlag = 0;
foreach $addrEntry (@addressList)
{
if($addrEntry eq $srcAddress)
{
$addrFlag = 1;
}
}
if($addrFlag == 0)
{
push(@addressList, $srcAddress);
$elabMap{$srcAddress} = "elabc-elab-" . $2;
print "Mapping $2 TO $elabMap{$srcAddress}\n";
}
# Create a mapping of the initial conditions.
$bwMap{$1}{$3} = $4;
$delayMap{$1}{$3} = $5;
}
}
opendir(logsDirHandle, $logsDir);
my $addrIndex = 0;
my %addrNodeMapping = {};
my %nodeNumberMapping = {};
my $numDests = 0;
foreach $sourceName (readdir(logsDirHandle))
{
# Map the elab IP address in the initial conditions file, with
# the node names in the gather-results logs directory.
if( (-d $logsDir . "/" . $sourceName ) && $sourceName ne "." && $sourceName ne ".." )
{
$addrNodeMapping{$sourceName} = $addressList[$addrIndex];
$nodeNameMapping{$sourceName} = $addrIndex + 1;
$nodeNumberMapping{$addrIndex + 1} = $sourceName;
$addrIndex++;
$numDests++;
}
}
rewinddir(logsDirHandle);
# Descend into all the source directories
foreach $sourceName (readdir(logsDirHandle))
{
if( (-d $logsDir . "/" . $sourceName ) && $sourceName ne "." && $sourceName ne ".." )
{
my @destLists;
# Then search for all possible destinations for
# a particular source.
opendir(sourceDirHandle, $logsDir . "/" . $sourceName);
my @denoisedDelays = ();
# print "Into directory $sourceName\n";
foreach $destOne (readdir(sourceDirHandle))
{
if( (-d $logsDir . "/" . $sourceName . "/" . $destOne) && $destOne ne "." && $destOne ne ".." )
{
# Inside each destination directory, look for
# delay.log file with delay values.
# print "Into directory $sourceName/$destOne\n";
$fullPath = "$logsDir/$sourceName/$destOne/delay.log";
$waveletScript = "./MinSikKim/MinSikKimProgram $fullPath";
my @scriptOutput;
@scriptOutput = `$waveletScript`;
#print "@scriptOutput\n";
# print "Index = $nodeNameMapping{$destOne}\n";
$denoisedDelays[$nodeNameMapping{$destOne}] = [ @scriptOutput ];
#foreach $testIter (@{$denoisedDelays[$nodeNameMapping{$destOne}]})
#{
# print "$testIter";
#}
}
}
closedir(sourceDirHandle);
local @equivClasses = ();
$tmpTreeRecordFile = "/tmp/bw-wavelet-clustering.rcd";
open(RECORDFILE, ">$tmpTreeRecordFile");
print RECORDFILE "128\n";
for($i = 1; $i <= $numDests; $i++)
{
if($i == $nodeNameMapping{$sourceName})
{
next;
}
else
{
my @scriptOutput;
@scriptOutput = @{ $denoisedDelays[$i] };
# Put this destination in a seperate cluster - we
# have zero samples/delay values.
if( ($#scriptOutput == 0) or ($#scriptOutput < 120) )
{
my @newEquivClass = ();
push(@newEquivClass, $i);
push(@equivClasses, [@newEquivClass]);
}
else
{
my $counter = 0;
my $avgValue = 0;
my @delayValueArray = ();
foreach $delayValue (@scriptOutput)
{
chomp($delayValue);
if($counter < 128)
{
$avgValue += $delayValue;
push(@delayValueArray, $delayValue);
$counter++;
}
else
{
last;
}
}
$avgValue = $avgValue/128.0;
my $denominator = 0;
foreach $delayValue (@delayValueArray)
{
$denominator += ($delayValue - $avgValue)*($delayValue - $avgValue);
}
$denominator = sqrt($denominator);
foreach $delayValue (@delayValueArray)
{
$delayValue = ($delayValue - $avgValue)/$denominator;
print RECORDFILE "$delayValue:";
}
#foreach $delayValue (@scriptOutput)
#{
# chomp($delayValue);
#
# if($counter < 128)
# {
# print RECORDFILE "$delayValue:";
# $counter++;
# }
# else
# {
# last;
# }
# }
print RECORDFILE "$i\n";
}
}
}
close(RECORDFILE);
$clusteringProgram = "/tmp/clustering/c++-samples/wvcluster $tmpTreeRecordFile /tmp/tmp.idx";
my @clusteringOutput ;
@clusteringOutput = `$clusteringProgram`;
foreach $clusterLine (@clusteringOutput)
{
@clusterElements = split(/ /, $clusterLine);
my @newEquivClass = ();
foreach $nodeId (@clusterElements)
{
if($nodeId =~ /\d+/)
{
push(@newEquivClass, $nodeId);
}
}
push(@equivClasses, [@newEquivClass]);
}
print "Clusters for $sourceName:\n";
foreach $tmpName (@equivClasses)
{
foreach $tmpName2 (@$tmpName)
{
print "$nodeNumberMapping{$tmpName2} ";
}
print "\n";
}
print "\n";
# Send the events to all the nodes which form an equivalent class.
foreach $tmpName (@equivClasses)
{
my $bwEventCommand = "$tevc $elabMap{$addrNodeMapping{$sourceName}} modify DEST=";
my $firstDestFlag = 0;
my $maxBw = 0;
# Find the maximum available bandwidth in all the paths of this equivalence class.
foreach $tmpName2 (@$tmpName)
{
if($bwMap{$addrNodeMapping{$sourceName}}{$addrNodeMapping{$nodeNumberMapping{$tmpName2}}} > $maxBw)