chunks: AIMD congestion control
refs #3636
Change-Id: Ia5e601201219048eb5c745bba9627e4916dac31a
diff --git a/tools/chunks/catchunks/ndncatchunks.cpp b/tools/chunks/catchunks/ndncatchunks.cpp
index 1f5bd0b..e123ade 100644
--- a/tools/chunks/catchunks/ndncatchunks.cpp
+++ b/tools/chunks/catchunks/ndncatchunks.cpp
@@ -33,8 +33,12 @@
#include "discover-version-fixed.hpp"
#include "discover-version-iterative.hpp"
#include "pipeline-interests-fixed-window.hpp"
+#include "pipeline-interests-aimd.hpp"
+#include "aimd-rtt-estimator.hpp"
+#include "aimd-statistics-collector.hpp"
#include <ndn-cxx/security/validator-null.hpp>
+#include <fstream>
namespace ndn {
namespace chunks {
@@ -50,34 +54,87 @@
int maxRetriesAfterVersionFound(1);
std::string uri;
+ // congestion control parameters, CWA refers to conservative window adaptation,
+ // i.e. only reduce window size at most once per RTT
+ bool disableCwa(false), resetCwndToInit(false);
+ double aiStep(1.0), mdCoef(0.5), alpha(0.125), beta(0.25),
+ minRto(200.0), maxRto(4000.0);
+ int initCwnd(1), initSsthresh(std::numeric_limits<int>::max()), k(4);
+ std::string cwndPath, rttPath;
+
namespace po = boost::program_options;
- po::options_description visibleDesc("Options");
- visibleDesc.add_options()
+ po::options_description basicDesc("Basic Options");
+ basicDesc.add_options()
("help,h", "print this help message and exit")
("discover-version,d", po::value<std::string>(&discoverType)->default_value(discoverType),
"version discovery algorithm to use; valid values are: 'fixed', 'iterative'")
+ ("pipeline-type,t", po::value<std::string>(&pipelineType)->default_value(pipelineType),
+ "type of Interest pipeline to use; valid values are: 'fixed', 'aimd'")
("fresh,f", po::bool_switch(&options.mustBeFresh), "only return fresh content")
("lifetime,l", po::value<uint64_t>()->default_value(options.interestLifetime.count()),
"lifetime of expressed Interests, in milliseconds")
- ("pipeline,p", po::value<size_t>(&maxPipelineSize)->default_value(maxPipelineSize),
- "maximum size of the Interest pipeline")
("retries,r", po::value<int>(&options.maxRetriesOnTimeoutOrNack)->default_value(options.maxRetriesOnTimeoutOrNack),
"maximum number of retries in case of Nack or timeout (-1 = no limit)")
- ("retries-iterative,i", po::value<int>(&maxRetriesAfterVersionFound)->default_value(maxRetriesAfterVersionFound),
- "number of timeouts that have to occur in order to confirm a discovered Data "
- "version as the latest one (only applicable to 'iterative' version discovery)")
("verbose,v", po::bool_switch(&options.isVerbose), "turn on verbose output")
("version,V", "print program version and exit")
;
- po::options_description hiddenDesc("Hidden options");
+ po::options_description iterDiscoveryDesc("Iterative version discovery options");
+ iterDiscoveryDesc.add_options()
+ ("retries-iterative,i", po::value<int>(&maxRetriesAfterVersionFound)->default_value(maxRetriesAfterVersionFound),
+ "number of timeouts that have to occur in order to confirm a discovered Data "
+ "version as the latest one")
+ ;
+
+ po::options_description fixedPipeDesc("Fixed pipeline options");
+ fixedPipeDesc.add_options()
+ ("pipeline-size,s", po::value<size_t>(&maxPipelineSize)->default_value(maxPipelineSize),
+ "size of the Interest pipeline")
+ ;
+
+ po::options_description aimdPipeDesc("AIMD pipeline options");
+ aimdPipeDesc.add_options()
+ ("aimd-debug-cwnd", po::value<std::string>(&cwndPath),
+ "log file for AIMD cwnd statistics")
+ ("aimd-debug-rtt", po::value<std::string>(&rttPath),
+ "log file for AIMD rtt statistics")
+ ("aimd-disable-cwa", po::bool_switch(&disableCwa),
+ "disable Conservative Window Adaptation, "
+ "i.e. reduce window on each timeout (instead of at most once per RTT)")
+ ("aimd-reset-cwnd-to-init", po::bool_switch(&resetCwndToInit),
+ "reset cwnd to initial cwnd when loss event occurs, default is "
+ "resetting to ssthresh")
+ ("aimd-initial-cwnd", po::value<int>(&initCwnd)->default_value(initCwnd),
+ "initial cwnd")
+ ("aimd-initial-ssthresh", po::value<int>(&initSsthresh),
+ "initial slow start threshold (defaults to infinity)")
+ ("aimd-aistep", po::value<double>(&aiStep)->default_value(aiStep),
+ "additive-increase step")
+ ("aimd-mdcoef", po::value<double>(&mdCoef)->default_value(mdCoef),
+ "multiplicative-decrease coefficient")
+ ("aimd-rto-alpha", po::value<double>(&alpha)->default_value(alpha),
+ "alpha value for rto calculation")
+ ("aimd-rto-beta", po::value<double>(&beta)->default_value(beta),
+ "beta value for rto calculation")
+ ("aimd-rto-k", po::value<int>(&k)->default_value(k),
+ "k value for rto calculation")
+ ("aimd-rto-min", po::value<double>(&minRto)->default_value(minRto),
+ "min rto value in milliseconds")
+ ("aimd-rto-max", po::value<double>(&maxRto)->default_value(maxRto),
+ "max rto value in milliseconds")
+ ;
+
+ po::options_description visibleDesc;
+ visibleDesc.add(basicDesc).add(iterDiscoveryDesc).add(fixedPipeDesc).add(aimdPipeDesc);
+
+ po::options_description hiddenDesc;
hiddenDesc.add_options()
("ndn-name,n", po::value<std::string>(&uri), "NDN name of the requested content");
po::positional_options_description p;
p.add("ndn-name", -1);
- po::options_description optDesc("Allowed options");
+ po::options_description optDesc;
optDesc.add(visibleDesc).add(hiddenDesc);
po::variables_map vm;
@@ -153,11 +210,59 @@
}
unique_ptr<PipelineInterests> pipeline;
+ unique_ptr<aimd::StatisticsCollector> statsCollector;
+ unique_ptr<aimd::RttEstimator> rttEstimator;
+ std::ofstream statsFileCwnd;
+ std::ofstream statsFileRtt;
+
if (pipelineType == "fixed") {
PipelineInterestsFixedWindow::Options optionsPipeline(options);
optionsPipeline.maxPipelineSize = maxPipelineSize;
pipeline = make_unique<PipelineInterestsFixedWindow>(face, optionsPipeline);
}
+ else if (pipelineType == "aimd") {
+ aimd::RttEstimator::Options optionsRttEst;
+ optionsRttEst.isVerbose = options.isVerbose;
+ optionsRttEst.alpha = alpha;
+ optionsRttEst.beta = beta;
+ optionsRttEst.k = k;
+ optionsRttEst.minRto = aimd::Milliseconds(minRto);
+ optionsRttEst.maxRto = aimd::Milliseconds(maxRto);
+
+ rttEstimator = make_unique<aimd::RttEstimator>(optionsRttEst);
+
+ PipelineInterestsAimd::Options optionsPipeline;
+ optionsPipeline.isVerbose = options.isVerbose;
+ optionsPipeline.disableCwa = disableCwa;
+ optionsPipeline.resetCwndToInit = resetCwndToInit;
+ optionsPipeline.initCwnd = static_cast<double>(initCwnd);
+ optionsPipeline.initSsthresh = static_cast<double>(initSsthresh);
+ optionsPipeline.aiStep = aiStep;
+ optionsPipeline.mdCoef = mdCoef;
+
+ auto aimdPipeline = make_unique<PipelineInterestsAimd>(face, *rttEstimator, optionsPipeline);
+
+ if (!cwndPath.empty() || !rttPath.empty()) {
+ if (!cwndPath.empty()) {
+ statsFileCwnd.open(cwndPath);
+ if (statsFileCwnd.fail()) {
+ std::cerr << "ERROR: failed to open " << cwndPath << std::endl;
+ return 4;
+ }
+ }
+ if (!rttPath.empty()) {
+ statsFileRtt.open(rttPath);
+ if (statsFileRtt.fail()) {
+ std::cerr << "ERROR: failed to open " << rttPath << std::endl;
+ return 4;
+ }
+ }
+ statsCollector = make_unique<aimd::StatisticsCollector>(*aimdPipeline, *rttEstimator,
+ statsFileCwnd, statsFileRtt);
+ }
+
+ pipeline = std::move(aimdPipeline);
+ }
else {
std::cerr << "ERROR: Interest pipeline type not valid" << std::endl;
return 2;