chunks: include RTT stats in final summary

Change-Id: I9cc7cba4c8fe1f7d7a2d68c96a7db2c04774bc19
Refs: #4406
diff --git a/AUTHORS.md b/AUTHORS.md
index 85fac62..e35c9ad 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -23,3 +23,4 @@
 * Weiwei Liu            <https://www.linkedin.com/in/weiweiliu10>
 * Zipeng Wang
 * Qianshan Yu
+* Chavoosh Ghasemi
diff --git a/tests/chunks/aimd-rtt-estimator.t.cpp b/tests/chunks/aimd-rtt-estimator.t.cpp
index 38db749..9241fee 100644
--- a/tests/chunks/aimd-rtt-estimator.t.cpp
+++ b/tests/chunks/aimd-rtt-estimator.t.cpp
@@ -1,8 +1,8 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2016,  Regents of the University of California,
- *                      Colorado State University,
- *                      University Pierre & Marie Curie, Sorbonne University.
+/*
+ * Copyright (c) 2016-2018,  Regents of the University of California,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University.
  *
  * This file is part of ndn-tools (Named Data Networking Essential Tools).
  * See AUTHORS.md for complete list of ndn-tools authors and contributors.
@@ -21,12 +21,15 @@
  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
  *
  * @author Weiwei Liu
+ * @author Chavoosh Ghasemi
  */
 
 #include "tools/chunks/catchunks/aimd-rtt-estimator.hpp"
 
 #include "tests/test-common.hpp"
 
+#include <limits>
+
 namespace ndn {
 namespace chunks {
 namespace aimd {
@@ -62,6 +65,39 @@
 BOOST_AUTO_TEST_SUITE(Chunks)
 BOOST_FIXTURE_TEST_SUITE(TestAimdRttEstimator, RttEstimatorFixture)
 
+BOOST_AUTO_TEST_CASE(MinAvgMaxRtt)
+{
+  // check initial values
+  BOOST_CHECK_CLOSE(rttEstimator.m_rttMin, std::numeric_limits<double>::max(), 0.1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_rttAvg, 0.0, 0.1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_rttMax, std::numeric_limits<double>::min(), 0.1);
+  BOOST_CHECK_EQUAL(rttEstimator.m_nRttSamples, 0);
+
+  // start with three samples
+  rttEstimator.addMeasurement(1, Milliseconds(100), 1);
+  rttEstimator.addMeasurement(2, Milliseconds(400), 1);
+  rttEstimator.addMeasurement(3, Milliseconds(250), 1);
+
+  BOOST_CHECK_CLOSE(rttEstimator.m_rttMin, 100, 0.1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_rttAvg, 250, 0.1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_rttMax, 400, 0.1);
+  BOOST_CHECK_EQUAL(rttEstimator.m_nRttSamples, 3);
+
+  // add another sample (new minimum)
+  rttEstimator.addMeasurement(4, Milliseconds(50), 2);
+  BOOST_CHECK_CLOSE(rttEstimator.m_rttMin, 50, 0.1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_rttAvg, 200, 0.1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_rttMax, 400, 0.1);
+  BOOST_CHECK_EQUAL(rttEstimator.m_nRttSamples, 4);
+
+  // add another sample (new maximum)
+  rttEstimator.addMeasurement(5, Milliseconds(700), 1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_rttMin, 50, 0.1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_rttAvg, 300, 0.1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_rttMax, 700, 0.1);
+  BOOST_CHECK_EQUAL(rttEstimator.m_nRttSamples, 5);
+}
+
 BOOST_AUTO_TEST_CASE(MeasureRtt)
 {
   BOOST_REQUIRE(std::isnan(rttEstimator.m_sRtt.count()));
@@ -71,9 +107,9 @@
   // first measurement
   rttEstimator.addMeasurement(1, Milliseconds(100), 1);
 
-  BOOST_CHECK_CLOSE(rttEstimator.m_sRtt.count(), 100, 1);
-  BOOST_CHECK_CLOSE(rttEstimator.m_rttVar.count(), 50, 1);
-  BOOST_CHECK_CLOSE(rttEstimator.m_rto.count(), 300, 1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_sRtt.count(), 100, 0.1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_rttVar.count(), 50, 0.1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_rto.count(), 300, 0.1);
 
   rttEstimator.m_sRtt = Milliseconds(500.0);
   rttEstimator.m_rttVar = Milliseconds(100.0);
@@ -82,16 +118,16 @@
   size_t nExpectedSamples = 1;
   rttEstimator.addMeasurement(1, Milliseconds(100), nExpectedSamples);
 
-  BOOST_CHECK_CLOSE(rttEstimator.m_sRtt.count(), 450, 1);
-  BOOST_CHECK_CLOSE(rttEstimator.m_rttVar.count(), 175, 1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_sRtt.count(), 450, 0.1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_rttVar.count(), 175, 0.1);
   BOOST_CHECK_CLOSE(rttEstimator.m_rto.count(), 1150, 0.1);
 
-  // expected Samples larger than 1
+  // expected samples larger than 1
   nExpectedSamples = 5;
   rttEstimator.addMeasurement(1, Milliseconds(100), nExpectedSamples);
 
-  BOOST_CHECK_CLOSE(rttEstimator.m_sRtt.count(), 441.25, 1);
-  BOOST_CHECK_CLOSE(rttEstimator.m_rttVar.count(), 183.75, 1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_sRtt.count(), 441.25, 0.1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_rttVar.count(), 183.75, 0.1);
   BOOST_CHECK_CLOSE(rttEstimator.m_rto.count(), 1176.25, 0.1);
 
   rttEstimator.m_sRtt = Milliseconds(100.0);
@@ -102,9 +138,9 @@
   nExpectedSamples = 1;
   rttEstimator.addMeasurement(1, Milliseconds(100), nExpectedSamples);
 
-  BOOST_CHECK_CLOSE(rttEstimator.m_sRtt.count(), 100, 1);
-  BOOST_CHECK_CLOSE(rttEstimator.m_rttVar.count(), 22.5, 1);
-  BOOST_CHECK_CLOSE(rttEstimator.m_rto.count(), 200, 1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_sRtt.count(), 100, 0.1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_rttVar.count(), 22.5, 0.1);
+  BOOST_CHECK_CLOSE(rttEstimator.m_rto.count(), 200, 0.1);
 
   rttEstimator.m_sRtt = Milliseconds(2000.0);
   rttEstimator.m_rttVar = Milliseconds(400.0);
diff --git a/tools/chunks/catchunks/aimd-rtt-estimator.cpp b/tools/chunks/catchunks/aimd-rtt-estimator.cpp
index faa9d83..5e88f7c 100644
--- a/tools/chunks/catchunks/aimd-rtt-estimator.cpp
+++ b/tools/chunks/catchunks/aimd-rtt-estimator.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2016-2017, Arizona Board of Regents.
+ * Copyright (c) 2016-2018, 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.
@@ -20,10 +20,13 @@
  *
  * @author Shuo Yang
  * @author Weiwei Liu
+ * @author Chavoosh Ghasemi
  */
 
 #include "aimd-rtt-estimator.hpp"
+
 #include <cmath>
+#include <limits>
 
 namespace ndn {
 namespace chunks {
@@ -34,6 +37,10 @@
   , 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;
@@ -45,7 +52,7 @@
 {
   BOOST_ASSERT(nExpectedSamples > 0);
 
-  if (std::isnan(m_sRtt.count())) { // first measurement
+  if (m_nRttSamples == 0) { // first measurement
     m_sRtt = rtt;
     m_rttVar = m_sRtt / 2;
     m_rto = m_sRtt + m_options.k * m_rttVar;
@@ -59,8 +66,12 @@
   }
 
   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
diff --git a/tools/chunks/catchunks/aimd-rtt-estimator.hpp b/tools/chunks/catchunks/aimd-rtt-estimator.hpp
index 292395a..d7d1aca 100644
--- a/tools/chunks/catchunks/aimd-rtt-estimator.hpp
+++ b/tools/chunks/catchunks/aimd-rtt-estimator.hpp
@@ -1,5 +1,5 @@
-/**
- * Copyright (c) 2016,  Arizona Board of Regents.
+/*
+ * Copyright (c) 2016-2018,  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.
@@ -19,6 +19,7 @@
  *
  * @author Shuo Yang
  * @author Weiwei Liu
+ * @author Chavoosh Ghasemi
  */
 
 #ifndef NDN_TOOLS_CHUNKS_CATCHUNKS_AIMD_RTT_ESTIMATOR_HPP
@@ -44,7 +45,7 @@
 /**
  * @brief RTT Estimator.
  *
- * This class implements the "Mean--Deviation" RTT estimator, as discussed in RFC6298,
+ * 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
@@ -77,7 +78,7 @@
   };
 
   /**
-   * @brief create a RTT Estimator
+   * @brief Create a RTT Estimator
    *
    * Configures the RTT Estimator with the default parameters if an instance of Options
    * is not passed to the constructor.
@@ -88,24 +89,54 @@
   /**
    * @brief Add a new RTT measurement to the estimator for the given received segment.
    *
-   * @note Don't take RTT measurement for retransmitted segments
    * @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);
 
   /**
-   * @return estimated RTO
+   * @brief Returns the estimated RTO value
    */
   Milliseconds
-  getEstimatedRto() const;
+  getEstimatedRto() const
+  {
+    return m_rto;
+  }
 
   /**
-   * @brief backoff RTO by the factor of RttEstimatorOptions::rtoBackoffMultiplier
+   * @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();
@@ -120,16 +151,12 @@
   Milliseconds m_sRtt; ///< smoothed round-trip time
   Milliseconds m_rttVar; ///< round-trip time variation
   Milliseconds m_rto; ///< retransmission timeout
-};
 
-/**
- * @brief returns the estimated RTO value
- */
-inline Milliseconds
-RttEstimator::getEstimatedRto() const
-{
-  return m_rto;
-}
+  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);
@@ -138,4 +165,4 @@
 } // namespace chunks
 } // namespace ndn
 
-#endif // NDN_TOOLS_CHUNKS_CATCHUNKS_RTT_ESTIMATOR_HPP
+#endif // NDN_TOOLS_CHUNKS_CATCHUNKS_AIMD_RTT_ESTIMATOR_HPP
diff --git a/tools/chunks/catchunks/pipeline-interests-aimd.cpp b/tools/chunks/catchunks/pipeline-interests-aimd.cpp
index a63c9de..fceb90b 100644
--- a/tools/chunks/catchunks/pipeline-interests-aimd.cpp
+++ b/tools/chunks/catchunks/pipeline-interests-aimd.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2016-2017, Regents of the University of California,
+ * Copyright (c) 2016-2018, Regents of the University of California,
  *                          Colorado State University,
  *                          University Pierre & Marie Curie, Sorbonne University.
  *
@@ -29,6 +29,7 @@
 #include "data-fetcher.hpp"
 
 #include <cmath>
+#include <iomanip>
 
 namespace ndn {
 namespace chunks {
@@ -440,7 +441,11 @@
             << "Packet loss rate: "
             << static_cast<double>(m_nLossEvents) / static_cast<double>(m_nReceived) << "\n"
             << "Total # of retransmitted segments: " << m_nRetransmitted << "\n"
-            << "Total # of received congestion marks: " << m_nCongMarks << "\n";
+            << "Total # of received congestion marks: " << m_nCongMarks << "\n"
+            << "RTT min/avg/max = " << std::fixed << std::setprecision(3)
+                                    << m_rttEstimator.getMinRtt() << "/"
+                                    << m_rttEstimator.getAvgRtt() << "/"
+                                    << m_rttEstimator.getMaxRtt() << " ms\n";
 }
 
 std::ostream&