Add TCP test case logging, scripts default tip
authorJosh Pelkey <jpelkey@gatech.edu>
Tue, 01 Feb 2011 14:31:54 -0500
changeset 6781 36929d9236ad
parent 6780 61b82ca887f5
Add TCP test case logging, scripts
src/test/ns3tcp/ns3tcp-loss-test-suite.cc
src/test/ns3tcp/ns3tcp-state-test-suite.cc
src/test/ns3tcp/plot.gp
src/test/ns3tcp/trTidy.pl
--- a/src/test/ns3tcp/ns3tcp-loss-test-suite.cc	Thu Jan 20 14:39:10 2011 -0500
+++ b/src/test/ns3tcp/ns3tcp-loss-test-suite.cc	Tue Feb 01 14:31:54 2011 -0500
@@ -16,6 +16,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <iomanip>
+
 #include "ns3/log.h"
 #include "ns3/abort.h"
 #include "ns3/test.h"
@@ -42,6 +44,7 @@
 NS_LOG_COMPONENT_DEFINE ("Ns3TcpLossTest");
 
 const bool WRITE_VECTORS = false;           // set to true to write response vectors
+const bool WRITE_LOGGING = false;            // set to true to write logging
 const uint32_t PCAP_LINK_TYPE = 1187373557; // Some large random number -- we use to verify data was written by this program
 const uint32_t PCAP_SNAPLEN   = 64;         // Don't bother to save much data
 
@@ -62,6 +65,7 @@
   virtual void DoRun (void);
   virtual void DoTeardown (void);
 
+  Ptr<OutputStreamWrapper> m_osw;
   std::string m_pcapFilename;
   PcapFile m_pcapFile;
   uint32_t m_testCase;
@@ -69,10 +73,12 @@
   uint32_t m_currentTxBytes;
   bool m_writeVectors;
   bool m_writeResults;
+  bool m_writeLogging;
   bool m_needToClose;
   std::string m_tcpModel;
 
   void Ipv4L3Tx (std::string context, Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface);
+  void CwndTracer (uint32_t oldval, uint32_t newval);
   void WriteUntilBufferFull (Ptr<Socket> localSocket, uint32_t txSpace);
   void StartFlow (Ptr<Socket> localSocket, 
                   Ipv4Address servAddress, 
@@ -87,6 +93,7 @@
     m_currentTxBytes (0),
     m_writeVectors (WRITE_VECTORS),
     m_writeResults (false),
+    m_writeLogging (WRITE_LOGGING),
     m_needToClose (true),
     m_tcpModel ("ns3::TcpTahoe")
 {
@@ -99,6 +106,7 @@
     m_currentTxBytes (0),
     m_writeVectors (WRITE_VECTORS),
     m_writeResults (false),
+    m_writeLogging (WRITE_LOGGING),
     m_needToClose (true),
     m_tcpModel (tcpModel)
 {
@@ -194,6 +202,17 @@
     }
 }
 
+void
+Ns3TcpLossTestCase::CwndTracer (uint32_t oldval, uint32_t newval)
+{
+  if (m_writeLogging)
+    {
+      *(m_osw->GetStream ()) << "Moving cwnd from " << oldval << " to " << newval 
+        << " at time " << Simulator::Now ().GetSeconds () 
+        << " seconds" << std::endl;
+    }
+}
+
 ////////////////////////////////////////////////////////////////////
 // Implementing an "application" to send bytes over a TCP connection
 void 
@@ -211,14 +230,22 @@
         {
           return;
         };
-      NS_LOG_LOGIC ("Submitting " << toWrite << " bytes to TCP socket");
+      if (m_writeLogging)
+        {
+          std::clog << "Submitting " << toWrite 
+            << " bytes to TCP socket" << std::endl;
+        }
       int amountSent = localSocket->Send (0, toWrite, 0);
       NS_ASSERT (amountSent > 0);  // Given GetTxAvailable() non-zero, amountSent should not be zero
       m_currentTxBytes += amountSent;
     }
   if (m_needToClose)
     {
-      NS_LOG_LOGIC ("Close socket at " <<  Simulator::Now ().GetSeconds ());
+      if (m_writeLogging)
+        {
+          std::clog << "Close socket at " 
+            <<  Simulator::Now ().GetSeconds () << std::endl;
+        }
       localSocket->Close ();
       m_needToClose = false;
     }
@@ -229,7 +256,11 @@
                                 Ipv4Address servAddress,
                                 uint16_t servPort)
 {
-  NS_LOG_LOGIC ("Starting flow at time " <<  Simulator::Now ().GetSeconds ());
+  if (m_writeLogging)
+    {
+      std::clog << "Starting flow at time " 
+        <<  Simulator::Now ().GetSeconds () << std::endl;
+    }
   localSocket->Connect (InetSocketAddress (servAddress, servPort)); // connect
 
   // tell the tcp implementation to call WriteUntilBufferFull again
@@ -249,7 +280,7 @@
   //       s1-----------------r1-----------------k1
   //
   // Example corresponding to simulations in the paper "Simulation-based
-  // Comparisons of Tahoe, Reno, and SACK TCP"
+  // Comparisons of Tahoe, Reno, and SACK TCP 
 
   std::ostringstream tcpModel;
   tcpModel << "ns3::Tcp" << m_tcpModel;
@@ -258,6 +289,18 @@
   Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (1000));
   Config::SetDefault ("ns3::TcpSocket::DelAckCount", UintegerValue (1));
 
+  if (m_writeLogging)
+    {
+      LogComponentEnableAll (LOG_PREFIX_FUNC);
+      LogComponentEnable ("TcpLossResponse", LOG_LEVEL_ALL);
+      LogComponentEnable ("ErrorModel", LOG_LEVEL_DEBUG);
+      LogComponentEnable ("TcpLossResponse", LOG_LEVEL_ALL);
+      LogComponentEnable ("TcpNewReno", LOG_LEVEL_INFO);
+      LogComponentEnable ("TcpReno", LOG_LEVEL_INFO);
+      LogComponentEnable ("TcpTahoe", LOG_LEVEL_INFO);
+      LogComponentEnable ("TcpSocketBase", LOG_LEVEL_INFO);
+    }
+
   ////////////////////////////////////////////////////////
   // Topology construction
   //
@@ -319,6 +362,10 @@
   Config::Connect ("/NodeList/0/$ns3::Ipv4L3Protocol/Tx",
                    MakeCallback (&Ns3TcpLossTestCase::Ipv4L3Tx, this));
 
+  Config::ConnectWithoutContext
+    ("/NodeList/0/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",
+     MakeCallback (&Ns3TcpLossTestCase::CwndTracer, this));
+
   ////////////////////////////////////////////////////////
   // Set up loss model at node k1
   //
@@ -368,6 +415,16 @@
       p2p.EnablePcapAll (oss.str ());
       p2p.EnableAsciiAll (oss.str ());
     }
+
+  std::ostringstream oss2;
+  oss2 << "src/test/ns3tcp/Tcp" << m_tcpModel << "." << m_testCase << ".log";
+  AsciiTraceHelper ascii;
+  if (m_writeLogging)
+    {
+      m_osw = ascii.CreateFileStream (oss2.str ());
+      *(m_osw->GetStream ()) << std::setprecision (9) << std::fixed;
+      p2p.EnableAsciiAll (m_osw);
+    }
   
   // Finally, set up the simulator to run.  The 1000 second hard limit is a
   // failsafe in case some change above causes the simulation to never end
--- a/src/test/ns3tcp/ns3tcp-state-test-suite.cc	Thu Jan 20 14:39:10 2011 -0500
+++ b/src/test/ns3tcp/ns3tcp-state-test-suite.cc	Tue Feb 01 14:31:54 2011 -0500
@@ -16,6 +16,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <iomanip>
+
 #include "ns3/log.h"
 #include "ns3/abort.h"
 #include "ns3/test.h"
@@ -42,6 +44,7 @@
 NS_LOG_COMPONENT_DEFINE ("Ns3TcpStateTest");
 
 const bool WRITE_VECTORS = false;           // set to true to write response vectors
+const bool WRITE_LOGGING = false;           // set to true to write logging
 const uint32_t PCAP_LINK_TYPE = 1187373554; // Some large random number -- we use to verify data was written by this program
 const uint32_t PCAP_SNAPLEN   = 64;         // Don't bother to save much data
 
@@ -69,6 +72,7 @@
   uint32_t m_currentTxBytes;
   bool m_writeVectors;
   bool m_writeResults;
+  bool m_writeLogging;
   bool m_needToClose;
 
   void Ipv4L3Tx (std::string context, Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface);
@@ -86,6 +90,7 @@
     m_currentTxBytes (0),
     m_writeVectors (WRITE_VECTORS),
     m_writeResults (false),
+    m_writeLogging (WRITE_LOGGING),
     m_needToClose (true)
 {
 }
@@ -97,6 +102,7 @@
     m_currentTxBytes (0),
     m_writeVectors (WRITE_VECTORS),
     m_writeResults (false),
+    m_writeLogging (WRITE_LOGGING),
     m_needToClose (true)
 {
 }
@@ -208,14 +214,23 @@
         {
           return;
         };
-      NS_LOG_LOGIC ("Submitting " << toWrite << " bytes to TCP socket");
+      if (m_writeLogging)
+        {
+          std::clog << "Submitting " 
+            << toWrite << " bytes to TCP socket" << std::endl;
+        }
       int amountSent = localSocket->Send (0, toWrite, 0);
       NS_ASSERT (amountSent > 0);  // Given GetTxAvailable() non-zero, amountSent should not be zero
       m_currentTxBytes += amountSent;
     }
   if (m_needToClose)
     {
-      NS_LOG_LOGIC ("Close socket at " <<  Simulator::Now ().GetSeconds ());
+      if (m_writeLogging)
+        {
+          std::clog << "Close socket at " 
+            <<  Simulator::Now ().GetSeconds () 
+            << std::endl;
+        }
       localSocket->Close ();
       m_needToClose = false;
     }
@@ -226,7 +241,13 @@
                                 Ipv4Address servAddress,
                                 uint16_t servPort)
 {
-  NS_LOG_LOGIC ("Starting flow at time " <<  Simulator::Now ().GetSeconds ());
+  if (m_writeLogging)
+    {
+      std::clog << "Starting flow at time " 
+        <<  Simulator::Now ().GetSeconds () 
+        << std::endl;
+    }
+
   localSocket->Connect (InetSocketAddress (servAddress, servPort)); // connect
 
   // tell the tcp implementation to call WriteUntilBufferFull again
@@ -252,6 +273,18 @@
   Config::SetDefault ("ns3::TcpSocket::DelAckCount", UintegerValue (1));
   Config::SetDefault ("ns3::DropTailQueue::MaxPackets", UintegerValue (20));
 
+  if (m_writeLogging)
+    {
+      LogComponentEnableAll (LOG_PREFIX_FUNC);
+      LogComponentEnable ("TcpTestCases", LOG_LEVEL_ALL);
+      LogComponentEnable ("ErrorModel", LOG_LEVEL_DEBUG);
+      LogComponentEnable ("TcpTestCases", LOG_LEVEL_ALL);
+      LogComponentEnable ("TcpNewReno", LOG_LEVEL_INFO);
+      LogComponentEnable ("TcpReno", LOG_LEVEL_INFO);
+      LogComponentEnable ("TcpTahoe", LOG_LEVEL_INFO);
+      LogComponentEnable ("TcpSocketBase", LOG_LEVEL_INFO);
+    }
+
   ////////////////////////////////////////////////////////
   // Topology construction
   //
@@ -314,44 +347,54 @@
 
   std::list<uint32_t> dropListN0;
   std::list<uint32_t> dropListN1;
+  std::string caseDescription;
   switch (m_testCase)
     {
-    case 0: // Verify connection establishment
+    case 0:
       m_totalTxBytes = 1000;
+      caseDescription = "Verify connection establishment";
       break;
-    case 1: // Verify a bigger (100 pkts) transfer: Sliding window operation, etc.
+    case 1:
       m_totalTxBytes = 100*1000;
+      caseDescription = "Verify a bigger (100 pkts) transfer: Sliding window operation, etc.";
       break;
-    case 2: // Survive a SYN lost
+    case 2:
       m_totalTxBytes = 1000;
+      caseDescription = "Survive a SYN lost";
       dropListN0.push_back (0);
       break;
-    case 3: // Survive a SYN+ACK lost
+    case 3:
       m_totalTxBytes = 2000;
+      caseDescription = "Survive a SYN+ACK lost";
       dropListN1.push_back (0);
       break;
-    case 4: // Survive a ACK (last packet in 3-way handshake) lost
+    case 4:
       m_totalTxBytes = 2000;
+      caseDescription = "Survive a ACK (last packet in 3-way handshake) lost";
       dropListN0.push_back (1);
       break;
-    case 5: // Immediate FIN upon SYN_RCVD
+    case 5:
       m_totalTxBytes = 0;
+      caseDescription = "Immediate FIN upon SYN_RCVD";
       m_needToClose = false;
       dropListN0.push_back (1); // Hide the ACK in 3WHS
       Simulator::Schedule (Seconds(0.002), &Socket::Close, localSocket);
       break;
-    case 6: // Simulated simultaneous close
+    case 6:
       m_totalTxBytes = 5000;
+      caseDescription = "Simulated simultaneous close";
       dropListN1.push_back (5); // Hide the ACK-to-FIN from n2
       break;
-    case 7: // FIN check 1: Lost of initiator's FIN. Shall wait until application close.
+    case 7:
       m_totalTxBytes = 5000;
+      caseDescription = "FIN check 1: Loss of initiator's FIN. Wait until app close";
       m_needToClose = false;
       dropListN0.push_back (7); // Hide the FIN from n0
       Simulator::Schedule (Seconds(0.04), &Socket::Close, localSocket);
       break;
-    case 8: // FIN check 2: Lost of responder's FIN. The FIN will resent after last ack timeout
+    case 8:
       m_totalTxBytes = 5000;
+      caseDescription = "FIN check 2: Loss responder's FIN. FIN will be resent after last ack timeout";
       dropListN1.push_back (6); // Hide the FIN from n2
       break;
     default:
@@ -376,6 +419,16 @@
       p2p.EnableAsciiAll (oss.str ());
     }
 
+  if (m_writeLogging)
+    {
+      Ptr<OutputStreamWrapper> osw = Create<OutputStreamWrapper> (&std::clog);
+      *(osw->GetStream ()) << std::setprecision (9) << std::fixed;
+      p2p.EnableAsciiAll (osw);
+
+      std::clog << std::endl << "Running TCP test-case " << m_testCase << ": "
+        << caseDescription << std::endl;
+    }
+
   // Finally, set up the simulator to run.  The 1000 second hard limit is a
   // failsafe in case some change above causes the simulation to never end
   Simulator::Stop (Seconds (1000));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/ns3tcp/plot.gp	Tue Feb 01 14:31:54 2011 -0500
@@ -0,0 +1,119 @@
+###
+# *
+# * Copyright (c) 2010 Adrian Sai-wah Tam
+# *
+# * This program is free software; you can redistribute it and/or modify
+# * it under the terms of the GNU General Public License version 2 as
+# * published by the Free Software Foundation;
+# *
+# * This program 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 this program; if not, write to the Free Software
+# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# * 02111-1307  USA
+# *
+# * This gnuplot file is used to plot a number of graphs from the 
+# * Ns3TcpLossTestCases. In order to run this properly, the 
+# * logging output from Ns3TcpLossTest case must first be enabled 
+# * by manually editing ns3-tcp-loss-test-suite.cc and setting 
+# * WRITE_LOGGING to true. Then, the test suite should be re-run 
+# * with ./waf --run "test-runner --suite='ns3-tcp-loss'"
+# * This will generate a number of log files which are parsed 
+# * below for eventual plotting to .eps format using gnuplot.
+# * To run this file in gnuplot, simply: gnuplot plot.gp
+### 
+
+set key left
+set terminal postscript eps enhanced color
+set yrange [0:100000]
+set xrange [0:3.5]
+set xtics 0.5
+set mxtics 2
+set mytics 2
+set grid mxtics xtics ytics mytics
+set output "TcpNewReno.0.eps"
+plot \
+  "< grep ^r TcpNewReno.0.log | perl trTidy.pl | grep N0 | perl -ne 's/^..//;s/\t.*Ack=/ /;s/ Win.*$//;split;print $_[0].q{ }.($_[1]%100000).q{\n}'" using 1:2 w p pt 2 lc rgb "#00FF00" title "ack", \
+  "< grep cwnd TcpNewReno.0.log | grep seconds | perl -pe 's/^.*to //;s/ at time / /;s/ seconds//'" using 2:1 w p pt 1 lc rgb "#FF0000" title "cwnd"
+ 
+set output "TcpReno.0.eps"
+plot \
+  "< grep ^r TcpReno.0.log | perl trTidy.pl | grep N0 | perl -ne 's/^..//;s/\t.*Ack=/ /;s/ Win.*$//;split;print $_[0].q{ }.($_[1]%100000).q{\n}'" using 1:2 w p pt 2 lc rgb "#00FF00" title "ack", \
+  "< grep cwnd TcpReno.0.log | grep seconds | perl -pe 's/^.*to //;s/ at time / /;s/ seconds//'" using 2:1 w p pt 1 lc rgb "#FF0000" title "cwnd"
+ 
+set output "TcpTahoe.0.eps"
+plot \
+  "< grep ^r TcpTahoe.0.log | perl trTidy.pl | grep N0 | perl -ne 's/^..//;s/\t.*Ack=/ /;s/ Win.*$//;split;print $_[0].q{ }.($_[1]%100000).q{\n}'" using 1:2 w p pt 2 lc rgb "#00FF00" title "ack", \
+  "< grep cwnd TcpTahoe.0.log | grep seconds | perl -pe 's/^.*to //;s/ at time / /;s/ seconds//'" using 2:1 w p pt 1 lc rgb "#FF0000" title "cwnd"
+ 
+set yrange [0:25000]
+set xrange [0:5.5]
+set output "TcpNewReno.1.eps"
+plot \
+  "< grep ^r TcpNewReno.1.log | perl trTidy.pl | grep N0 | perl -ne 's/^..//;s/\t.*Ack=/ /;s/ Win.*$//;split;print $_[0].q{ }.($_[1]%25000).q{\n}'" using 1:2 w p pt 2 lc rgb "#00FF00" title "ack", \
+  "< grep cwnd TcpNewReno.1.log | grep seconds | perl -pe 's/^.*to //;s/ at time / /;s/ seconds//'" using 2:1 w p pt 1 lc rgb "#FF0000" title "cwnd"
+ 
+set output "TcpReno.1.eps"
+plot \
+  "< grep ^r TcpReno.1.log | perl trTidy.pl | grep N0 | perl -ne 's/^..//;s/\t.*Ack=/ /;s/ Win.*$//;split;print $_[0].q{ }.($_[1]%25000).q{\n}'" using 1:2 w p pt 2 lc rgb "#00FF00" title "ack", \
+  "< grep cwnd TcpReno.1.log | grep seconds | perl -pe 's/^.*to //;s/ at time / /;s/ seconds//'" using 2:1 w p pt 1 lc rgb "#FF0000" title "cwnd"
+
+set output "TcpTahoe.1.eps"
+plot \
+  "< grep ^r TcpTahoe.1.log | perl trTidy.pl | grep N0 | perl -ne 's/^..//;s/\t.*Ack=/ /;s/ Win.*$//;split;print $_[0].q{ }.($_[1]%25000).q{\n}'" using 1:2 w p pt 2 lc rgb "#00FF00" title "ack", \
+  "< grep cwnd TcpTahoe.1.log | grep seconds | perl -pe 's/^.*to //;s/ at time / /;s/ seconds//'" using 2:1 w p pt 1 lc rgb "#FF0000" title "cwnd"
+
+set yrange [0:30000]
+set output "TcpNewReno.2.eps"
+plot \
+  "< grep ^r TcpNewReno.2.log | perl trTidy.pl | grep N0 | perl -ne 's/^..//;s/\t.*Ack=/ /;s/ Win.*$//;split;print $_[0].q{ }.($_[1]%30000).q{\n}'" using 1:2 w p pt 2 lc rgb "#00FF00" title "ack", \
+  "< grep cwnd TcpNewReno.2.log | grep seconds | perl -pe 's/^.*to //;s/ at time / /;s/ seconds//'" using 2:1 w p pt 1 lc rgb "#FF0000" title "cwnd"
+
+set output "TcpReno.2.eps"
+plot \
+  "< grep ^r TcpReno.2.log | perl trTidy.pl | grep N0 | perl -ne 's/^..//;s/\t.*Ack=/ /;s/ Win.*$//;split;print $_[0].q{ }.($_[1]%30000).q{\n}'" using 1:2 w p pt 2 lc rgb "#00FF00" title "ack", \
+  "< grep cwnd TcpReno.2.log | grep seconds | perl -pe 's/^.*to //;s/ at time / /;s/ seconds//'" using 2:1 w p pt 1 lc rgb "#FF0000" title "cwnd"
+
+set output "TcpTahoe.2.eps"
+plot \
+  "< grep ^r TcpTahoe.2.log | perl trTidy.pl | grep N0 | perl -ne 's/^..//;s/\t.*Ack=/ /;s/ Win.*$//;split;print $_[0].q{ }.($_[1]%30000).q{\n}'" using 1:2 w p pt 2 lc rgb "#00FF00" title "ack", \
+  "< grep cwnd TcpTahoe.2.log | grep seconds | perl -pe 's/^.*to //;s/ at time / /;s/ seconds//'" using 2:1 w p pt 1 lc rgb "#FF0000" title "cwnd"
+
+set yrange [0:35000]
+set xrange [0:6.0]
+set output "TcpNewReno.3.eps"
+plot \
+  "< grep ^r TcpNewReno.3.log | perl trTidy.pl | grep N0 | perl -ne 's/^..//;s/\t.*Ack=/ /;s/ Win.*$//;split;print $_[0].q{ }.($_[1]%35000).q{\n}'" using 1:2 w p pt 2 lc rgb "#00FF00" title "ack", \
+  "< grep cwnd TcpNewReno.3.log | grep seconds | perl -pe 's/^.*to //;s/ at time / /;s/ seconds//'" using 2:1 w p pt 1 lc rgb "#FF0000" title "cwnd"
+
+set output "TcpReno.3.eps"
+plot \
+  "< grep ^r TcpReno.3.log | perl trTidy.pl | grep N0 | perl -ne 's/^..//;s/\t.*Ack=/ /;s/ Win.*$//;split;print $_[0].q{ }.($_[1]%35000).q{\n}'" using 1:2 w p pt 2 lc rgb "#00FF00" title "ack", \
+  "< grep cwnd TcpReno.3.log | grep seconds | perl -pe 's/^.*to //;s/ at time / /;s/ seconds//'" using 2:1 w p pt 1 lc rgb "#FF0000" title "cwnd"
+
+set output "TcpTahoe.3.eps"
+plot \
+  "< grep ^r TcpTahoe.3.log | perl trTidy.pl | grep N0 | perl -ne 's/^..//;s/\t.*Ack=/ /;s/ Win.*$//;split;print $_[0].q{ }.($_[1]%35000).q{\n}'" using 1:2 w p pt 2 lc rgb "#00FF00" title "ack", \
+  "< grep cwnd TcpTahoe.3.log | grep seconds | perl -pe 's/^.*to //;s/ at time / /;s/ seconds//'" using 2:1 w p pt 1 lc rgb "#FF0000" title "cwnd"
+
+set yrange [0:40000]
+set xrange [0:6.5]
+set output "TcpNewReno.4.eps"
+plot \
+  "< grep ^r TcpNewReno.4.log | perl trTidy.pl | grep N0 | perl -ne 's/^..//;s/\t.*Ack=/ /;s/ Win.*$//;split;print $_[0].q{ }.($_[1]%40000).q{\n}'" using 1:2 w p pt 2 lc rgb "#00FF00" title "ack", \
+  "< grep cwnd TcpNewReno.4.log | grep seconds | perl -pe 's/^.*to //;s/ at time / /;s/ seconds//'" using 2:1 w p pt 1 lc rgb "#FF0000" title "cwnd"
+
+set output "TcpReno.4.eps"
+plot \
+  "< grep ^r TcpReno.4.log | perl trTidy.pl | grep N0 | perl -ne 's/^..//;s/\t.*Ack=/ /;s/ Win.*$//;split;print $_[0].q{ }.($_[1]%40000).q{\n}'" using 1:2 w p pt 2 lc rgb "#00FF00" title "ack", \
+  "< grep cwnd TcpReno.4.log | grep seconds | perl -pe 's/^.*to //;s/ at time / /;s/ seconds//'" using 2:1 w p pt 1 lc rgb "#FF0000" title "cwnd"
+
+set output "TcpTahoe.4.eps"
+plot \
+  "< grep ^r TcpTahoe.4.log | perl trTidy.pl | grep N0 | perl -ne 's/^..//;s/\t.*Ack=/ /;s/ Win.*$//;split;print $_[0].q{ }.($_[1]%40000).q{\n}'" using 1:2 w p pt 2 lc rgb "#00FF00" title "ack", \
+  "< grep cwnd TcpTahoe.4.log | grep seconds | perl -pe 's/^.*to //;s/ at time / /;s/ seconds//'" using 2:1 w p pt 1 lc rgb "#FF0000" title "cwnd"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/test/ns3tcp/trTidy.pl	Tue Feb 01 14:31:54 2011 -0500
@@ -0,0 +1,47 @@
+###
+# *
+# * Copyright (c) 2010 Adrian Sai-wah Tam
+# *
+# * This program is free software; you can redistribute it and/or modify
+# * it under the terms of the GNU General Public License version 2 as
+# * published by the Free Software Foundation;
+# *
+# * This program 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 this program; if not, write to the Free Software
+# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# * 02111-1307  USA
+# *
+# * This perl script is used within plot.gp, a gnuplot file also
+# * in this directory, for parsing the Ns3TcpLossTest logging output.
+# * It can also be used, stand-alone, to tidy up the logging output 
+# * from Ns3TcpStateTestCases, if logging is enabled in these tests.
+### 
+
+  while(<>) {
+    s|ns3::PppHeader \(Point-to-Point Protocol: IP \(0x0021\)\) ||;
+    s|/TxQueue||;
+    s|/TxQ/|Q|;
+    s|NodeList/|N|;
+    s|/DeviceList/|D|;
+    s|/MacRx||;
+    s|/Enqueue||;
+    s|/Dequeue||;
+    s|/\$ns3::QbbNetDevice||;
+    s|/\$ns3::PointToPointNetDevice||;
+    s| /|\t|;
+    s| ns3::|\t|g;
+    s|tos 0x0 ||;
+    s|protocol 6 ||;
+    s|offset 0 ||;
+    s|flags \[none\] ||;
+    s|length:|len|;
+    s|Header||g;
+    s|/PhyRxDrop||;
+    print;
+ };