catchunks: use ndn-cxx's RttEstimator

Refs: #4887
Change-Id: If24bea40a22909bf0fd9e49ec7b18330dbe336f2
diff --git a/tools/chunks/catchunks/main.cpp b/tools/chunks/catchunks/main.cpp
index af345cf..9ec1973 100644
--- a/tools/chunks/catchunks/main.cpp
+++ b/tools/chunks/catchunks/main.cpp
@@ -35,7 +35,6 @@
 #include "pipeline-interests-aimd.hpp"
 #include "pipeline-interests-cubic.hpp"
 #include "pipeline-interests-fixed.hpp"
-#include "rtt-estimator.hpp"
 #include "statistics-collector.hpp"
 #include "core/version.hpp"
 
@@ -207,9 +206,7 @@
 
   try {
     Face face;
-
     auto discover = make_unique<DiscoverVersion>(Name(uri), face, options);
-
     unique_ptr<PipelineInterests> pipeline;
     unique_ptr<StatisticsCollector> statsCollector;
     unique_ptr<RttEstimator> rttEstimator;
@@ -223,20 +220,29 @@
     }
     else if (pipelineType == "aimd" || pipelineType == "cubic") {
       RttEstimator::Options optionsRttEst;
-      optionsRttEst.isVerbose = options.isVerbose;
       optionsRttEst.alpha = rtoAlpha;
       optionsRttEst.beta = rtoBeta;
       optionsRttEst.k = k;
-      optionsRttEst.minRto = Milliseconds(minRto);
-      optionsRttEst.maxRto = Milliseconds(maxRto);
-
+      optionsRttEst.minRto = RttEstimator::MillisecondsDouble(minRto);
+      optionsRttEst.maxRto = RttEstimator::MillisecondsDouble(maxRto);
       rttEstimator = make_unique<RttEstimator>(optionsRttEst);
 
+      if (options.isVerbose) {
+        std::cerr << "RTT estimator parameters:\n"
+                  << "\tAlpha = " << optionsRttEst.alpha << "\n"
+                  << "\tBeta = " << optionsRttEst.beta << "\n"
+                  << "\tK = " << optionsRttEst.k << "\n"
+                  << "\tInitial RTO = " << optionsRttEst.initialRto << "\n"
+                  << "\tMin RTO = " << optionsRttEst.minRto << "\n"
+                  << "\tMax RTO = " << optionsRttEst.maxRto << "\n"
+                  << "\tBackoff multiplier = " << optionsRttEst.rtoBackoffMultiplier << "\n";
+      }
+
       PipelineInterestsAdaptive::Options optionsPipeline(options);
       optionsPipeline.disableCwa = disableCwa;
       optionsPipeline.resetCwndToInit = resetCwndToInit;
-      optionsPipeline.initCwnd = static_cast<double>(initCwnd);
-      optionsPipeline.initSsthresh = static_cast<double>(initSsthresh);
+      optionsPipeline.initCwnd = initCwnd;
+      optionsPipeline.initSsthresh = initSsthresh;
       optionsPipeline.aiStep = aiStep;
       optionsPipeline.mdCoef = aimdBeta;
       optionsPipeline.ignoreCongMarks = ignoreCongMarks;
diff --git a/tools/chunks/catchunks/pipeline-interests-adaptive.cpp b/tools/chunks/catchunks/pipeline-interests-adaptive.cpp
index 93cd30d..fd28829 100644
--- a/tools/chunks/catchunks/pipeline-interests-adaptive.cpp
+++ b/tools/chunks/catchunks/pipeline-interests-adaptive.cpp
@@ -101,8 +101,8 @@
   for (auto& entry : m_segmentInfo) {
     SegmentInfo& segInfo = entry.second;
     if (segInfo.state != SegmentState::InRetxQueue) { // skip segments already in the retx queue
-      Milliseconds timeElapsed = time::steady_clock::now() - segInfo.timeSent;
-      if (timeElapsed.count() > segInfo.rto.count()) { // timer expired?
+      auto timeElapsed = time::steady_clock::now() - segInfo.timeSent;
+      if (timeElapsed > segInfo.rto) { // timer expired?
         m_nTimeouts++;
         hasTimeout = true;
         enqueueForRetransmission(entry.first);
@@ -235,7 +235,7 @@
   }
 
   SegmentInfo& segInfo = segIt->second;
-  Milliseconds rtt = time::steady_clock::now() - segInfo.timeSent;
+  RttEstimator::MillisecondsDouble rtt = time::steady_clock::now() - segInfo.timeSent;
   if (m_options.isVerbose) {
     std::cerr << "Received segment #" << recvSegNo
               << ", rtt=" << rtt.count() << "ms"
@@ -285,7 +285,7 @@
       m_retxCount.count(recvSegNo) == 0) {
     auto nExpectedSamples = std::max<int64_t>((m_nInFlight + 1) >> 1, 1);
     BOOST_ASSERT(nExpectedSamples > 0);
-    m_rttEstimator.addMeasurement(recvSegNo, rtt, static_cast<size_t>(nExpectedSamples));
+    m_rttEstimator.addMeasurement(rtt, static_cast<size_t>(nExpectedSamples), recvSegNo);
   }
 
   // remove the entry associated with the received segment
@@ -422,15 +422,15 @@
             << ", skipped: " << m_nSkippedRetx << "\n"
             << "RTT ";
 
-  if (m_rttEstimator.getMinRtt() == std::numeric_limits<double>::max() ||
-      m_rttEstimator.getMaxRtt() == std::numeric_limits<double>::min()) {
-     std::cerr << "stats unavailable\n";
-   }
-   else {
-     std::cerr << "min/avg/max = " << std::fixed << std::setprecision(3)
-                                   << m_rttEstimator.getMinRtt() << "/"
-                                   << m_rttEstimator.getAvgRtt() << "/"
-                                   << m_rttEstimator.getMaxRtt() << " ms\n";
+  if (m_rttEstimator.getMinRtt().count() == std::numeric_limits<double>::max() ||
+      m_rttEstimator.getMaxRtt().count() == std::numeric_limits<double>::min()) {
+    std::cerr << "stats unavailable\n";
+  }
+  else {
+    std::cerr << "min/avg/max = " << std::fixed << std::setprecision(3)
+              << m_rttEstimator.getMinRtt().count() << "/"
+              << m_rttEstimator.getAvgRtt().count() << "/"
+              << m_rttEstimator.getMaxRtt().count() << " ms\n";
   }
 }
 
diff --git a/tools/chunks/catchunks/pipeline-interests-adaptive.hpp b/tools/chunks/catchunks/pipeline-interests-adaptive.hpp
index 0c4f889..8ecc45b 100644
--- a/tools/chunks/catchunks/pipeline-interests-adaptive.hpp
+++ b/tools/chunks/catchunks/pipeline-interests-adaptive.hpp
@@ -30,15 +30,18 @@
 #define NDN_TOOLS_CHUNKS_CATCHUNKS_PIPELINE_INTERESTS_ADAPTIVE_HPP
 
 #include "options.hpp"
-#include "rtt-estimator.hpp"
 #include "pipeline-interests.hpp"
 
+#include <ndn-cxx/util/rtt-estimator.hpp>
+
 #include <queue>
 #include <unordered_map>
 
 namespace ndn {
 namespace chunks {
 
+using util::RttEstimator;
+
 class PipelineInterestsAdaptiveOptions : public Options
 {
 public:
@@ -81,7 +84,7 @@
 {
   ScopedPendingInterestHandle interestHdl;
   time::steady_clock::TimePoint timeSent;
-  Milliseconds rto;
+  RttEstimator::MillisecondsDouble rto;
   SegmentState state;
 };
 
@@ -116,10 +119,10 @@
   /**
    * @brief Signals when the congestion window changes.
    *
-   * The callback function should be: void(Milliseconds age, double cwnd) where age is the
-   * duration since pipeline starts, and cwnd is the new congestion window size (in segments).
+   * The callback function should be: `void(nanoseconds age, double cwnd)`, where `age` is the
+   * time since the pipeline started and `cwnd` is the new congestion window size (in segments).
    */
-  signal::Signal<PipelineInterestsAdaptive, Milliseconds, double> afterCwndChange;
+  signal::Signal<PipelineInterestsAdaptive, time::nanoseconds, double> afterCwndChange;
 
 protected:
   DECLARE_SIGNAL_EMIT(afterCwndChange)
diff --git a/tools/chunks/catchunks/rtt-estimator.cpp b/tools/chunks/catchunks/rtt-estimator.cpp
deleted file mode 100644
index fd3a592..0000000
--- a/tools/chunks/catchunks/rtt-estimator.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2016-2019, Arizona Board of Regents.
- *
- * This file is part of ndn-tools (Named Data Networking Essential Tools).
- * See AUTHORS.md for complete list of ndn-tools authors and contributors.
- *
- * ndn-tools is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * ndn-tools, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
- *
- * @author Shuo Yang
- * @author Weiwei Liu
- * @author Chavoosh Ghasemi
- */
-
-#include "rtt-estimator.hpp"
-
-#include <cmath>
-
-namespace ndn {
-namespace chunks {
-
-RttEstimator::RttEstimator(const Options& options)
-  : m_options(options)
-  , m_sRtt(std::numeric_limits<double>::quiet_NaN())
-  , m_rttVar(std::numeric_limits<double>::quiet_NaN())
-  , m_rto(m_options.initialRto.count())
-  , m_rttMin(std::numeric_limits<double>::max())
-  , m_rttMax(std::numeric_limits<double>::min())
-  , m_rttAvg(0.0)
-  , m_nRttSamples(0)
-{
-  if (m_options.isVerbose) {
-    std::cerr << m_options;
-  }
-}
-
-void
-RttEstimator::addMeasurement(uint64_t segNo, Milliseconds rtt, size_t nExpectedSamples)
-{
-  BOOST_ASSERT(nExpectedSamples > 0);
-
-  if (m_nRttSamples == 0) { // first measurement
-    m_sRtt = rtt;
-    m_rttVar = m_sRtt / 2;
-    m_rto = m_sRtt + m_options.k * m_rttVar;
-  }
-  else {
-    double alpha = m_options.alpha / nExpectedSamples;
-    double beta = m_options.beta / nExpectedSamples;
-    m_rttVar = (1 - beta) * m_rttVar + beta * time::abs(m_sRtt - rtt);
-    m_sRtt = (1 - alpha) * m_sRtt + alpha * rtt;
-    m_rto = m_sRtt + m_options.k * m_rttVar;
-  }
-
-  m_rto = ndn::clamp(m_rto, m_options.minRto, m_options.maxRto);
-  afterRttMeasurement({segNo, rtt, m_sRtt, m_rttVar, m_rto});
-
-  m_rttAvg = (m_nRttSamples * m_rttAvg + rtt.count()) / (m_nRttSamples + 1);
-  m_rttMax = std::max(rtt.count(), m_rttMax);
-  m_rttMin = std::min(rtt.count(), m_rttMin);
-  m_nRttSamples++;
-}
-
-void
-RttEstimator::backoffRto()
-{
-  m_rto = ndn::clamp(m_rto * m_options.rtoBackoffMultiplier,
-                     m_options.minRto, m_options.maxRto);
-}
-
-std::ostream&
-operator<<(std::ostream& os, const RttEstimator::Options& options)
-{
-  os << "RTT estimator parameters:\n"
-     << "\tAlpha = " << options.alpha << "\n"
-     << "\tBeta = " << options.beta << "\n"
-     << "\tK = " << options.k << "\n"
-     << "\tInitial RTO = " << options.initialRto << "\n"
-     << "\tMin RTO = " << options.minRto << "\n"
-     << "\tMax RTO = " << options.maxRto << "\n";
-  return os;
-}
-
-} // namespace chunks
-} // namespace ndn
diff --git a/tools/chunks/catchunks/rtt-estimator.hpp b/tools/chunks/catchunks/rtt-estimator.hpp
deleted file mode 100644
index 47f2ac8..0000000
--- a/tools/chunks/catchunks/rtt-estimator.hpp
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (c) 2016-2019,  Arizona Board of Regents.
- *
- * This file is part of ndn-tools (Named Data Networking Essential Tools).
- * See AUTHORS.md for complete list of ndn-tools authors and contributors.
- *
- * ndn-tools is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * ndn-tools, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
- *
- * @author Shuo Yang
- * @author Weiwei Liu
- * @author Chavoosh Ghasemi
- */
-
-#ifndef NDN_TOOLS_CHUNKS_CATCHUNKS_RTT_ESTIMATOR_HPP
-#define NDN_TOOLS_CHUNKS_CATCHUNKS_RTT_ESTIMATOR_HPP
-
-#include "core/common.hpp"
-
-namespace ndn {
-namespace chunks {
-
-typedef time::duration<double, time::milliseconds::period> Milliseconds;
-
-struct RttRtoSample
-{
-  uint64_t segNo;
-  Milliseconds rtt; ///< measured RTT
-  Milliseconds sRtt; ///< smoothed RTT
-  Milliseconds rttVar; ///< RTT variation
-  Milliseconds rto; ///< retransmission timeout
-};
-
-/**
- * @brief RTT Estimator.
- *
- * This class implements the "Mean-Deviation" RTT estimator, as discussed in RFC 6298,
- * with the modifications to RTO calculation described in RFC 7323 Appendix G.
- */
-class RttEstimator
-{
-public:
-  class Options
-  {
-  public:
-    Options()
-      : isVerbose(false)
-      , alpha(0.125)
-      , beta(0.25)
-      , k(8)
-      , initialRto(1000.0)
-      , minRto(200.0)
-      , maxRto(20000.0)
-      , rtoBackoffMultiplier(2)
-    {
-    }
-
-  public:
-    bool isVerbose;
-    double alpha; ///< parameter for RTT estimation
-    double beta; ///< parameter for RTT variation calculation
-    int k; ///< factor of RTT variation when calculating RTO
-    Milliseconds initialRto; ///< initial RTO value
-    Milliseconds minRto; ///< lower bound of RTO
-    Milliseconds maxRto; ///< upper bound of RTO
-    int rtoBackoffMultiplier;
-  };
-
-  /**
-   * @brief Create a RTT Estimator
-   *
-   * Configures the RTT Estimator with the default parameters if an instance of Options
-   * is not passed to the constructor.
-   */
-  explicit
-  RttEstimator(const Options& options = Options());
-
-  /**
-   * @brief Add a new RTT measurement to the estimator for the given received segment.
-   *
-   * @param segNo the segment number of the received segmented Data
-   * @param rtt the sampled rtt
-   * @param nExpectedSamples number of expected samples, must be greater than 0.
-   *        It should be set to current number of in-flight Interests. Please
-   *        refer to Appendix G of RFC 7323 for details.
-   * @note Don't take RTT measurement for retransmitted segments
-   */
-  void
-  addMeasurement(uint64_t segNo, Milliseconds rtt, size_t nExpectedSamples);
-
-  /**
-   * @brief Returns the estimated RTO value
-   */
-  Milliseconds
-  getEstimatedRto() const
-  {
-    return m_rto;
-  }
-
-  /**
-   * @brief Returns the minimum RTT observed
-   */
-  double
-  getMinRtt() const
-  {
-    return m_rttMin;
-  }
-
-  /**
-   * @brief Returns the maximum RTT observed
-   */
-  double
-  getMaxRtt() const
-  {
-    return m_rttMax;
-  }
-
-  /**
-   * @brief Returns the average RTT
-   */
-  double
-  getAvgRtt() const
-  {
-    return m_rttAvg;
-  }
-
-  /**
-   * @brief Backoff RTO by a factor of Options::rtoBackoffMultiplier
-   */
-  void
-  backoffRto();
-
-  /**
-   * @brief Signals after rtt is measured
-   */
-  signal::Signal<RttEstimator, RttRtoSample> afterRttMeasurement;
-
-PUBLIC_WITH_TESTS_ELSE_PRIVATE:
-  const Options m_options;
-  Milliseconds m_sRtt; ///< smoothed round-trip time
-  Milliseconds m_rttVar; ///< round-trip time variation
-  Milliseconds m_rto; ///< retransmission timeout
-
-  double m_rttMin;
-  double m_rttMax;
-  double m_rttAvg;
-  int64_t m_nRttSamples; ///< number of RTT samples
-};
-
-std::ostream&
-operator<<(std::ostream& os, const RttEstimator::Options& options);
-
-} // namespace chunks
-} // namespace ndn
-
-#endif // NDN_TOOLS_CHUNKS_CATCHUNKS_RTT_ESTIMATOR_HPP
diff --git a/tools/chunks/catchunks/statistics-collector.cpp b/tools/chunks/catchunks/statistics-collector.cpp
index 44c342c..8984e78 100644
--- a/tools/chunks/catchunks/statistics-collector.cpp
+++ b/tools/chunks/catchunks/statistics-collector.cpp
@@ -27,7 +27,8 @@
 namespace ndn {
 namespace chunks {
 
-StatisticsCollector::StatisticsCollector(PipelineInterestsAdaptive& pipeline, RttEstimator& rttEstimator,
+StatisticsCollector::StatisticsCollector(PipelineInterestsAdaptive& pipeline,
+                                         RttEstimator& rttEstimator,
                                          std::ostream& osCwnd, std::ostream& osRtt)
   : m_osCwnd(osCwnd)
   , m_osRtt(osRtt)
@@ -35,18 +36,18 @@
   m_osCwnd << "time\tcwndsize\n";
   m_osRtt  << "segment\trtt\trttvar\tsrtt\trto\n";
   pipeline.afterCwndChange.connect(
-    [this] (Milliseconds timeElapsed, double cwnd) {
-      m_osCwnd << timeElapsed.count() / 1000 << '\t' << cwnd << '\n';
+    [this] (time::nanoseconds timeElapsed, double cwnd) {
+      m_osCwnd << timeElapsed.count() / 1e9 << '\t' << cwnd << '\n';
     });
-  rttEstimator.afterRttMeasurement.connect(
-    [this] (const RttRtoSample& rttSample) {
-      m_osRtt << rttSample.segNo << '\t'
-              << rttSample.rtt.count() << '\t'
-              << rttSample.rttVar.count() << '\t'
-              << rttSample.sRtt.count() << '\t'
-              << rttSample.rto.count() << '\n';
+  rttEstimator.afterMeasurement.connect(
+    [this] (const RttEstimator::Sample& sample) {
+      m_osRtt << *sample.segNum << '\t'
+              << sample.rtt.count() << '\t'
+              << sample.rttVar.count() << '\t'
+              << sample.sRtt.count() << '\t'
+              << sample.rto.count() << '\n';
     });
 }
 
 } // namespace chunks
-} // namespace ndn
\ No newline at end of file
+} // namespace ndn
diff --git a/tools/chunks/catchunks/statistics-collector.hpp b/tools/chunks/catchunks/statistics-collector.hpp
index cd71018..35a0846 100644
--- a/tools/chunks/catchunks/statistics-collector.hpp
+++ b/tools/chunks/catchunks/statistics-collector.hpp
@@ -26,7 +26,6 @@
 #define NDN_TOOLS_CHUNKS_CATCHUNKS_STATISTICS_COLLECTOR_HPP
 
 #include "pipeline-interests-adaptive.hpp"
-#include "rtt-estimator.hpp"
 
 namespace ndn {
 namespace chunks {