Added DL and UL RLC performance
authorjnin
Mon, 11 Apr 2011 17:29:52 +0200
changeset 7954 80e46addfeee
parent 7950 4a4009fdd6b8
child 7955 9808ee664831
Added DL and UL RLC performance Added new output data as described in Requirements Documents
src/lte/examples/lena-rlc-calculator.cc
src/lte/helper/rlc-stats-calculator.cc
src/lte/helper/rlc-stats-calculator.h
src/lte/model/lte-ue-net-device.cc
src/lte/model/lte-ue-rrc.cc
--- a/src/lte/examples/lena-rlc-calculator.cc	Wed Apr 06 14:50:49 2011 +0200
+++ b/src/lte/examples/lena-rlc-calculator.cc	Mon Apr 11 17:29:52 2011 +0200
@@ -26,20 +26,32 @@
 #include "ns3/rlc-stats-calculator.h"
 
 
-//#include "ns3/gtk-config-store.h"
+#include "ns3/gtk-config-store.h"
 
 using namespace ns3;
 
-void TxPduCallback(Ptr<RlcStatsCalculator> rlcStats, std::string path,
+void UlTxPduCallback(Ptr<RlcStatsCalculator> rlcStats, std::string path,
                    uint16_t rnti, uint8_t lcid, uint32_t packetSize)
 {
-  rlcStats->TxPdu(rnti, lcid, packetSize);
+  rlcStats->UlTxPdu(rnti, lcid, packetSize);
+}
+
+void UlRxPduCallback(Ptr<RlcStatsCalculator> rlcStats, std::string path,
+                   uint16_t rnti, uint8_t lcid, uint32_t packetSize, uint64_t delay)
+{
+  rlcStats->UlRxPdu(rnti, lcid, packetSize, delay);
 }
 
-void RxPduCallback(Ptr<RlcStatsCalculator> rlcStats, std::string path,
+void DlTxPduCallback(Ptr<RlcStatsCalculator> rlcStats, std::string path,
+                   uint16_t rnti, uint8_t lcid, uint32_t packetSize)
+{
+  rlcStats->DlTxPdu(rnti, lcid, packetSize);
+}
+
+void DlRxPduCallback(Ptr<RlcStatsCalculator> rlcStats, std::string path,
                    uint16_t rnti, uint8_t lcid, uint32_t packetSize, uint64_t delay)
 {
-  rlcStats->RxPdu(rnti, lcid, packetSize, delay);
+  rlcStats->DlRxPdu(rnti, lcid, packetSize, delay);
 }
 
 int main (int argc, char *argv[])
@@ -51,7 +63,7 @@
   cmd.Parse (argc, argv);
 
   // Enable LTE log components
-  lena.EnableLogComponents ();
+  //lena.EnableLogComponents ();
 
   // Create Nodes: eNodeB and UE
   NodeContainer enbNodes;
@@ -80,20 +92,25 @@
   EpsBearer bearer (q);
   lena.ActivateEpsBearer (ueDevs, bearer);
 
-  Simulator::Stop (Seconds (0.1));
+  Simulator::Stop (Seconds (4));
 
   // Insert RLC Performance Calculator
   Ptr<RlcStatsCalculator> rlcStats = CreateObject<RlcStatsCalculator> ();
   Config::Connect("/NodeList/0/DeviceList/0/LteEnbRrc/UeMap/*/RadioBearerMap/*/LteRlc/TxPDU",
-                   MakeBoundCallback(&TxPduCallback, rlcStats));
+                   MakeBoundCallback(&DlTxPduCallback, rlcStats));
+  Config::Connect("/NodeList/*/DeviceList/0/LteUeRrc/RlcMap/*/RxPDU",
+                   MakeBoundCallback(&DlRxPduCallback, rlcStats));
+
+  Config::Connect("/NodeList/*/DeviceList/0/LteUeRrc/RlcMap/*/TxPDU",
+                   MakeBoundCallback(&UlTxPduCallback, rlcStats));
   Config::Connect ("/NodeList/0/DeviceList/0/LteEnbRrc/UeMap/*/RadioBearerMap/*/LteRlc/RxPDU",
-                   MakeBoundCallback(&RxPduCallback, rlcStats));
+                   MakeBoundCallback(&UlRxPduCallback, rlcStats));
 
   Simulator::Run ();
 
   // Uncomment to show available paths
-  //GtkConfigStore config;
-  //config.ConfigureAttributes ();
+  /*GtkConfigStore config;
+  config.ConfigureAttributes ();*/
 
   Simulator::Destroy ();
 
--- a/src/lte/helper/rlc-stats-calculator.cc	Wed Apr 06 14:50:49 2011 +0200
+++ b/src/lte/helper/rlc-stats-calculator.cc	Mon Apr 11 17:29:52 2011 +0200
@@ -32,7 +32,8 @@
 NS_OBJECT_ENSURE_REGISTERED (RlcStatsCalculator);
 
 RlcStatsCalculator::RlcStatsCalculator() :
-    m_outputFilename (""),
+    m_dlOutputFilename (""),
+    m_ulOutputFilename (""),
     m_firstWrite(true)
 {
   NS_LOG_FUNCTION (this);
@@ -51,10 +52,15 @@
   static TypeId tid = TypeId ("ns3::RlcStatsCalculator")
     .SetParent<Object> ()
     .AddConstructor<RlcStatsCalculator> ()
-    .AddAttribute ("OutputFilename",
-                   "Name of the file where the output will be saved.",
-                   StringValue ("RlcStats.csv"),
-                   MakeStringAccessor (&RlcStatsCalculator::SetOutputFilename),
+    .AddAttribute ("DlOutputFilename",
+                   "Name of the file where the downlink results will be saved.",
+                   StringValue ("DlRlcStats.csv"),
+                   MakeStringAccessor (&RlcStatsCalculator::SetDlOutputFilename),
+                   MakeStringChecker ())
+    .AddAttribute ("UlOutputFilename",
+                   "Name of the file where the uplink results will be saved.",
+                   StringValue ("UlRlcStats.csv"),
+                   MakeStringAccessor (&RlcStatsCalculator::SetUlOutputFilename),
                    MakeStringChecker ())
     .AddAttribute ("StartTime",
                    "Start time of the on going epoch.",
@@ -70,40 +76,81 @@
 }
 
 void
-RlcStatsCalculator::SetOutputFilename (std::string outputFilename)
+RlcStatsCalculator::SetUlOutputFilename (std::string outputFilename)
 {
-  m_outputFilename = outputFilename;
+  m_ulOutputFilename = outputFilename;
+}
+
+void
+RlcStatsCalculator::SetDlOutputFilename (std::string outputFilename)
+{
+  m_dlOutputFilename = outputFilename;
 }
 
 void
-RlcStatsCalculator::TxPdu (uint16_t rnti, uint8_t lcid, uint32_t packetSize)
+RlcStatsCalculator::UlTxPdu (uint16_t rnti, uint8_t lcid, uint32_t packetSize)
 {
-  NS_LOG_FUNCTION (this << "TxPDU" << rnti << (uint32_t) lcid << packetSize);
+  NS_LOG_FUNCTION (this << "UlTxPDU" << rnti << (uint32_t) lcid << packetSize);
   if (Simulator::Now () > m_startTime )
     {
       lteFlowId_t pair (rnti, lcid);
-      m_txPackets[pair]++;
+      m_ulTxPackets[pair]++;
+    }
+  CheckEpoch ();
+}
+
+void
+RlcStatsCalculator::DlTxPdu (uint16_t rnti, uint8_t lcid, uint32_t packetSize)
+{
+  NS_LOG_FUNCTION (this << "DlTxPDU" << rnti << (uint32_t) lcid << packetSize);
+  if (Simulator::Now () > m_startTime )
+    {
+      lteFlowId_t pair (rnti, lcid);
+      m_dlTxPackets[pair]++;
     }
   CheckEpoch ();
 }
 
 void
-RlcStatsCalculator::RxPdu (uint16_t rnti, uint8_t lcid, uint32_t packetSize, uint64_t delay)
+RlcStatsCalculator::UlRxPdu (uint16_t rnti, uint8_t lcid, uint32_t packetSize, uint64_t delay)
 {
-  NS_LOG_FUNCTION (this << "RxPDU" << rnti << (uint32_t) lcid << packetSize << delay);
+  NS_LOG_FUNCTION (this << "UlRxPDU" << rnti << (uint32_t) lcid << packetSize << delay);
   if (Simulator::Now () > m_startTime )
     {
       lteFlowId_t pair(rnti, lcid);
-      m_rxPackets[pair]++;
-      m_rxData[pair] += packetSize;
-      m_throughput[pair] = 8 * m_rxData[pair] / 1.0e9 * (Simulator::Now().GetNanoSeconds() - m_startTime.GetNanoSeconds());
+      m_ulRxPackets[pair]++;
+      m_ulRxData[pair] += packetSize;
+
+      uint64StatsMap::iterator it = m_ulDelay.find(pair);
+      if (it == m_ulDelay.end())
+        {
+          m_ulDelay[pair] = CreateObject<MinMaxAvgTotalCalculator<uint64_t> > ();
+          m_ulPduSize[pair] = CreateObject<MinMaxAvgTotalCalculator<uint32_t> > ();
+        }
+      m_ulDelay[pair]->Update (delay);
+      m_ulPduSize[pair]->Update (packetSize);
+    }
+  CheckEpoch ();
+}
 
-      uint64StatsMap::iterator it = m_delay.find(pair);
-      if (it == m_delay.end())
+void
+RlcStatsCalculator::DlRxPdu (uint16_t rnti, uint8_t lcid, uint32_t packetSize, uint64_t delay)
+{
+  NS_LOG_FUNCTION (this << "UlRxPDU" << rnti << (uint32_t) lcid << packetSize << delay);
+  if (Simulator::Now () > m_startTime )
+    {
+      lteFlowId_t pair(rnti, lcid);
+      m_dlRxPackets[pair]++;
+      m_dlRxData[pair] += packetSize;
+
+      uint64StatsMap::iterator it = m_dlDelay.find(pair);
+      if (it == m_dlDelay.end())
         {
-          m_delay[pair] = CreateObject<MinMaxAvgTotalCalculator<uint64_t> > ();
-          }
-      m_delay[pair]->Update(delay);
+          m_dlDelay[pair] = CreateObject<MinMaxAvgTotalCalculator<uint64_t> > ();
+          m_dlPduSize[pair] = CreateObject<MinMaxAvgTotalCalculator<uint32_t> > ();
+        }
+      m_dlDelay[pair]->Update(delay);
+      m_dlPduSize[pair]->Update (packetSize);
     }
   CheckEpoch ();
 }
@@ -111,39 +158,69 @@
 void
 RlcStatsCalculator::ShowResults (void)
 {
-  uint32Map::iterator it;
-
 
-  NS_LOG_FUNCTION (this <<  m_outputFilename.c_str ());
-  NS_LOG_INFO ("Write Rlc Stats in: " << m_outputFilename.c_str ());
+  NS_LOG_FUNCTION (this <<  m_ulOutputFilename.c_str () << m_dlOutputFilename.c_str () );
+  NS_LOG_INFO ("Write Rlc Stats in " << m_ulOutputFilename.c_str () <<
+               " and in " << m_dlOutputFilename.c_str ());
   
-  std::ofstream m_outFile;
+  std::ofstream ulOutFile;
+  std::ofstream dlOutFile;
+
   if ( m_firstWrite == true )
     {
-      m_outFile.open (m_outputFilename.c_str ());
-      if (! m_outFile.is_open ())
+      ulOutFile.open (m_ulOutputFilename.c_str ());
+      if (! ulOutFile.is_open ())
       {
-        NS_LOG_ERROR ("Can't open file " << m_outputFilename.c_str ());
+        NS_LOG_ERROR ("Can't open file " << m_ulOutputFilename.c_str ());
+        return;
+      }
+
+      dlOutFile.open (m_dlOutputFilename.c_str ());
+      if (! dlOutFile.is_open ())
+      {
+        NS_LOG_ERROR ("Can't open file " << m_dlOutputFilename.c_str ());
         return;
       }
       m_firstWrite = false;
-      m_outFile << "# startTime, endTime, RNTI, LCID, throughput (bps), delay (s), PDU loss ratio (%)" << std::endl;
+      ulOutFile << "# startTime, endTime, RNTI, LCID, nTxPDUs, TxBytes, nRxPDUs, RxBytes, ";
+      ulOutFile << "delay mean, delay std dev, delay min, delay max, ";
+      ulOutFile << "PDU size mean, PDU size std dev, PDU size min, PDU size max, ";
+      ulOutFile << std::endl;
+      dlOutFile << "# startTime, endTime, RNTI, LCID, nTxPDUs, TxBytes, nRxPDUs, RxBytes, ";
+      dlOutFile << "delay mean, delay std dev, delay min, delay max, ";
+      dlOutFile << "PDU size mean, PDU size std dev, PDU size min, PDU size max, ";
+      dlOutFile << std::endl;
     }
   else
     {
-      m_outFile.open (m_outputFilename.c_str (),  std::ios_base::app);
-      if (! m_outFile.is_open ())
+      ulOutFile.open (m_ulOutputFilename.c_str (),  std::ios_base::app);
+      if (! ulOutFile.is_open ())
       {
-        NS_LOG_ERROR ("Can't open file " << m_outputFilename.c_str ());
+        NS_LOG_ERROR ("Can't open file " << m_ulOutputFilename.c_str ());
+        return;
+      }
+
+      dlOutFile.open (m_dlOutputFilename.c_str (),  std::ios_base::app);
+      if (! dlOutFile.is_open ())
+      {
+        NS_LOG_ERROR ("Can't open file " << m_dlOutputFilename.c_str ());
         return;
       }
     }
 
+  WriteUlResults(ulOutFile);
+  WriteDlResults(dlOutFile);
 
+}
+
+void
+RlcStatsCalculator::WriteUlResults (std::ofstream& outFile)
+{
+  uint32Map::iterator it;
 
   // Get all the unique lteFlowIds in the calculator
   std::vector<lteFlowId_t> lteFlowIds;
-  for ( it = m_txPackets.begin(); it != m_txPackets.end(); ++it)
+  for ( it = m_ulTxPackets.begin(); it != m_ulTxPackets.end(); ++it)
     {
       if (find (lteFlowIds.begin (), lteFlowIds.end (),  (*it).first ) == lteFlowIds.end () )
         {
@@ -155,21 +232,84 @@
   Time endTime = m_startTime + m_epochDuration;
   for ( itFlow = lteFlowIds.begin(); itFlow != lteFlowIds.end(); ++itFlow)
     {
-      m_outFile << m_startTime.GetNanoSeconds () / 1.0e9  << " " << endTime.GetNanoSeconds() / 1.0e9;
-      m_outFile << " " << (*itFlow).m_rnti << " " << (uint32_t) (*itFlow).m_lcId << " " << GetThroughput (*itFlow);
-      m_outFile << " " << GetDelay(*itFlow) << " " << GetPacketLossProbability (*itFlow) << std::endl;
+      outFile << m_startTime.GetNanoSeconds () / 1.0e9  << " ";
+      outFile << endTime.GetNanoSeconds() / 1.0e9       << " ";
+      outFile << (*itFlow).m_rnti                       << " ";
+      outFile << (uint32_t) (*itFlow).m_lcId            << " ";
+      outFile << GetUlTxPackets (*itFlow)               << " ";
+      outFile << GetUlTxData (*itFlow)                  << " ";
+      outFile << GetUlRxPackets (*itFlow)               << " ";
+      outFile << GetUlRxData (*itFlow)                  << " ";
+      std::vector<double> stats = GetUlDelayStats (*itFlow);
+      for( std::vector<double>::iterator it = stats.begin (); it != stats.end (); ++it )
+        {
+          outFile << (*it) * 1e-9 << " ";
+        }
+      stats = GetUlPduSizeStats (*itFlow);
+      for( std::vector<double>::iterator it = stats.begin (); it != stats.end (); ++it )
+        {
+          outFile << (*it) << " ";
+        }
+      outFile << std::endl;
     }
-  m_outFile.close ();
+
+  outFile.close ();
+}
+
+void
+RlcStatsCalculator::WriteDlResults (std::ofstream& outFile)
+{
+  uint32Map::iterator it;
+
+  // Get all the unique lteFlowIds in the calculator
+  std::vector<lteFlowId_t> lteFlowIds;
+  for ( it = m_dlTxPackets.begin(); it != m_dlTxPackets.end(); ++it)
+    {
+      if (find (lteFlowIds.begin (), lteFlowIds.end (),  (*it).first ) == lteFlowIds.end () )
+        {
+          lteFlowIds.push_back ((*it).first);
+        }
+    }
+
+  std::vector<lteFlowId_t>::iterator itFlow;
+  Time endTime = m_startTime + m_epochDuration;
+  for ( itFlow = lteFlowIds.begin(); itFlow != lteFlowIds.end(); ++itFlow)
+    {
+      outFile << m_startTime.GetNanoSeconds () / 1.0e9  << " ";
+      outFile << endTime.GetNanoSeconds() / 1.0e9       << " ";
+      outFile << (*itFlow).m_rnti                       << " ";
+      outFile << (uint32_t) (*itFlow).m_lcId            << " ";
+      outFile << GetDlTxPackets (*itFlow)               << " ";
+      outFile << GetDlTxData (*itFlow)                  << " ";
+      outFile << GetDlRxPackets (*itFlow)               << " ";
+      outFile << GetDlRxData (*itFlow)                  << " ";
+      std::vector<double> stats = GetDlDelayStats (*itFlow);
+      for( std::vector<double>::iterator it = stats.begin (); it != stats.end (); ++it )
+        {
+          outFile << (*it) * 1e-9 << " ";
+        }
+      stats = GetDlPduSizeStats (*itFlow);
+      for( std::vector<double>::iterator it = stats.begin (); it != stats.end (); ++it )
+        {
+          outFile << (*it) << " ";
+        }
+      outFile << std::endl;
+    }
+  outFile.close ();
 }
 
 void
 RlcStatsCalculator::ResetResults (void)
 {
-   m_txPackets.erase (m_txPackets.begin (), m_txPackets.end () );
-   m_rxPackets.erase (m_rxPackets.begin (), m_rxPackets.end () );
-   m_rxData.erase (m_rxData.begin (), m_rxData.end () );
-   m_throughput.erase (m_throughput.begin (), m_throughput.end () );
-   m_delay.erase (m_delay.begin (), m_delay.end () );
+   m_ulTxPackets.erase (m_ulTxPackets.begin (), m_ulTxPackets.end () );
+   m_ulRxPackets.erase (m_ulRxPackets.begin (), m_ulRxPackets.end () );
+   m_ulRxData.erase (m_ulRxData.begin (), m_ulRxData.end () );
+   m_ulDelay.erase (m_ulDelay.begin (), m_ulDelay.end () );
+
+   m_dlTxPackets.erase (m_dlTxPackets.begin (), m_dlTxPackets.end () );
+   m_dlRxPackets.erase (m_dlRxPackets.begin (), m_dlRxPackets.end () );
+   m_dlRxData.erase (m_dlRxData.begin (), m_dlRxData.end () );
+   m_dlDelay.erase (m_dlDelay.begin (), m_dlDelay.end () );
 }
 
 void
@@ -191,86 +331,255 @@
 }
 
 uint32_t
-RlcStatsCalculator::GetTxPackets (lteFlowId_t p)
+RlcStatsCalculator::GetUlTxPackets (lteFlowId_t p)
 {
-  return m_txPackets[p];
+  return m_ulTxPackets[p];
 }
 
 uint32_t
-RlcStatsCalculator::GetRxPackets (lteFlowId_t p)
+RlcStatsCalculator::GetUlRxPackets (lteFlowId_t p)
 {
-  return m_rxPackets[p];
+  return m_ulRxPackets[p];
 }
 
 uint64_t
-RlcStatsCalculator::GetRxData (lteFlowId_t p)
+RlcStatsCalculator::GetUlTxData (lteFlowId_t p)
 {
-  return m_rxData[p];
+  return m_ulTxData[p];
 }
 
 uint64_t
-RlcStatsCalculator::GetDelay (lteFlowId_t p)
+RlcStatsCalculator::GetUlRxData (lteFlowId_t p)
 {
-  uint64StatsMap::iterator it = m_delay.find (p);
-  if ( it == m_delay.end () )
-    {
-      return 0;
-    }
-  return m_delay[p]->getMean ();
+  return m_ulRxData[p];
 }
 
 double
-RlcStatsCalculator::GetThroughput (lteFlowId_t p)
+RlcStatsCalculator::GetUlDelay (lteFlowId_t p)
 {
-  return m_throughput[p];
+  uint64StatsMap::iterator it = m_ulDelay.find (p);
+  if ( it == m_ulDelay.end () )
+    {
+      NS_LOG_ERROR("UL delay for " << p.m_rnti << ", " <<
+                   (uint32_t) p.m_lcId << " not found");
+      return 0;
+
+    }
+  return m_ulDelay[p]->getMean ();
 }
 
-double
-RlcStatsCalculator::GetPacketLossProbability (lteFlowId_t p)
+std::vector<double>
+RlcStatsCalculator::GetUlDelayStats (lteFlowId_t p)
 {
-   return (GetTxPackets (p) - GetRxPackets (p)) / (double) GetTxPackets (p);
+  std::vector<double> stats;
+  uint64StatsMap::iterator it = m_ulDelay.find (p);
+  if ( it == m_ulDelay.end () )
+    {
+      NS_LOG_ERROR("UL delay for " << p.m_rnti << ", " <<
+                   (uint32_t) p.m_lcId << " not found");
+      return stats;
+
+    }
+  stats.push_back(m_ulDelay[p]->getMean ());
+  stats.push_back(m_ulDelay[p]->getStddev ());
+  stats.push_back(m_ulDelay[p]->getMin ());
+  stats.push_back(m_ulDelay[p]->getMax ());
+  return stats;
+}
+
+std::vector<double>
+RlcStatsCalculator::GetUlPduSizeStats (lteFlowId_t p)
+{
+  std::vector<double> stats;
+  uint32StatsMap::iterator it = m_ulPduSize.find (p);
+  if ( it == m_ulPduSize.end () )
+    {
+      NS_LOG_ERROR("UL PDU Size for " << p.m_rnti << ", " <<
+                   (uint32_t) p.m_lcId << " not found");
+      return stats;
+
+    }
+  stats.push_back (m_ulPduSize[p]->getMean ());
+  stats.push_back (m_ulPduSize[p]->getStddev ());
+  stats.push_back (m_ulPduSize[p]->getMin ());
+  stats.push_back (m_ulPduSize[p]->getMax ());
+  return stats;
+}
+
+uint32_t
+RlcStatsCalculator::GetDlTxPackets (lteFlowId_t p)
+{
+  return m_dlTxPackets[p];
 }
 
 uint32_t
-RlcStatsCalculator::GetTxPackets (uint16_t rnti, uint8_t lcid)
+RlcStatsCalculator::GetDlRxPackets (lteFlowId_t p)
+{
+  return m_dlRxPackets[p];
+}
+
+uint64_t
+RlcStatsCalculator::GetDlTxData (lteFlowId_t p)
+{
+  return m_dlTxData[p];
+}
+
+uint64_t
+RlcStatsCalculator::GetDlRxData (lteFlowId_t p)
+{
+  return m_dlRxData[p];
+}
+
+double
+RlcStatsCalculator::GetDlDelay (lteFlowId_t p)
+{
+  uint64StatsMap::iterator it = m_dlDelay.find (p);
+  if ( it == m_dlDelay.end () )
+    {
+      NS_LOG_ERROR("DL delay for " << p.m_rnti << ", " <<
+                   (uint32_t) p.m_lcId << " not found");
+      return 0;
+    }
+  return m_dlDelay[p]->getMean ();
+}
+
+std::vector<double>
+RlcStatsCalculator::GetDlDelayStats (lteFlowId_t p)
 {
-  lteFlowId_t p (rnti, lcid);
-  return GetTxPackets (p);
+  std::vector<double> stats;
+  uint64StatsMap::iterator it = m_dlDelay.find (p);
+  if ( it == m_dlDelay.end () )
+    {
+
+      NS_LOG_ERROR("DL delay for " << p.m_rnti << ", " <<
+                   (uint32_t) p.m_lcId << " not found");
+      return stats;
+
+    }
+  stats.push_back(m_dlDelay[p]->getMean ());
+  stats.push_back(m_dlDelay[p]->getStddev ());
+  stats.push_back(m_dlDelay[p]->getMin ());
+  stats.push_back(m_dlDelay[p]->getMax ());
+  return stats;
+}
+
+std::vector<double>
+RlcStatsCalculator::GetDlPduSizeStats (lteFlowId_t p)
+{
+  std::vector<double> stats;
+  uint32StatsMap::iterator it = m_dlPduSize.find (p);
+  if ( it == m_dlPduSize.end () )
+    {
+
+      NS_LOG_ERROR("DL delay for " << p.m_rnti << ", " <<
+                   (uint32_t) p.m_lcId << " not found");
+      return stats;
+
+    }
+  stats.push_back(m_dlPduSize[p]->getMean ());
+  stats.push_back(m_dlPduSize[p]->getStddev ());
+  stats.push_back(m_dlPduSize[p]->getMin ());
+  stats.push_back(m_dlPduSize[p]->getMax ());
+  return stats;
 }
 
 uint32_t
-RlcStatsCalculator::GetRxPackets (uint16_t rnti, uint8_t lcid)
+RlcStatsCalculator::GetUlTxPackets (uint16_t rnti, uint8_t lcid)
 {
   lteFlowId_t p (rnti, lcid);
-  return GetRxPackets (p);
+  return GetUlTxPackets (p);
 }
 
-uint64_t
-RlcStatsCalculator::GetRxData (uint16_t rnti, uint8_t lcid)
+uint32_t
+RlcStatsCalculator::GetUlRxPackets (uint16_t rnti, uint8_t lcid)
 {
   lteFlowId_t p (rnti, lcid);
-  return GetRxData (p);
+  return GetUlRxPackets (p);
 }
 
 uint64_t
-RlcStatsCalculator::GetDelay (uint16_t rnti, uint8_t lcid)
+RlcStatsCalculator::GetUlTxData (uint16_t rnti, uint8_t lcid)
 {
   lteFlowId_t p (rnti, lcid);
-  return GetDelay (p);
+  return GetUlTxData (p);
+}
+
+uint64_t
+RlcStatsCalculator::GetUlRxData (uint16_t rnti, uint8_t lcid)
+{
+  lteFlowId_t p (rnti, lcid);
+  return GetUlRxData (p);
 }
 
 double
-RlcStatsCalculator::GetThroughput (uint16_t rnti, uint8_t lcid)
+RlcStatsCalculator::GetUlDelay (uint16_t rnti, uint8_t lcid)
+{
+  lteFlowId_t p (rnti, lcid);
+  return GetUlDelay (p);
+}
+
+std::vector<double>
+RlcStatsCalculator::GetUlDelayStats (uint16_t rnti, uint8_t lcid)
+{
+  lteFlowId_t p (rnti, lcid);
+  return GetUlDelayStats (p);
+}
+
+std::vector<double>
+RlcStatsCalculator::GetUlPduSizeStats (uint16_t rnti, uint8_t lcid)
 {
   lteFlowId_t p (rnti, lcid);
-  return GetThroughput (p);
+  return GetUlPduSizeStats (p);
+}
+
+
+uint32_t
+RlcStatsCalculator::GetDlTxPackets (uint16_t rnti, uint8_t lcid)
+{
+  lteFlowId_t p (rnti, lcid);
+  return GetDlTxPackets (p);
+}
+
+uint32_t
+RlcStatsCalculator::GetDlRxPackets (uint16_t rnti, uint8_t lcid)
+{
+  lteFlowId_t p (rnti, lcid);
+  return GetDlRxPackets (p);
+}
+
+uint64_t
+RlcStatsCalculator::GetDlTxData (uint16_t rnti, uint8_t lcid)
+{
+  lteFlowId_t p (rnti, lcid);
+  return GetDlTxData (p);
+}
+
+uint64_t
+RlcStatsCalculator::GetDlRxData (uint16_t rnti, uint8_t lcid)
+{
+  lteFlowId_t p (rnti, lcid);
+  return GetDlRxData (p);
 }
 
 double
-RlcStatsCalculator::GetPacketLossProbability (uint16_t rnti, uint8_t lcid)
+RlcStatsCalculator::GetDlDelay (uint16_t rnti, uint8_t lcid)
 {
   lteFlowId_t p (rnti, lcid);
-  return GetPacketLossProbability (p);
+  return GetDlDelay (p);
+}
+
+std::vector<double>
+RlcStatsCalculator::GetDlDelayStats (uint16_t rnti, uint8_t lcid)
+{
+  lteFlowId_t p (rnti, lcid);
+  return GetDlDelayStats (p);
+}
+
+std::vector<double>
+RlcStatsCalculator::GetDlPduSizeStats (uint16_t rnti, uint8_t lcid)
+{
+  lteFlowId_t p (rnti, lcid);
+  return GetDlPduSizeStats (p);
 }
 
 } // namespace ns3
--- a/src/lte/helper/rlc-stats-calculator.h	Wed Apr 06 14:50:49 2011 +0200
+++ b/src/lte/helper/rlc-stats-calculator.h	Mon Apr 11 17:29:52 2011 +0200
@@ -34,6 +34,7 @@
 
 typedef std::map<lteFlowId_t, uint32_t> uint32Map;
 typedef std::map<lteFlowId_t, uint64_t> uint64Map;
+typedef std::map<lteFlowId_t, Ptr<MinMaxAvgTotalCalculator<uint32_t> > > uint32StatsMap;
 typedef std::map<lteFlowId_t, Ptr<MinMaxAvgTotalCalculator<uint64_t> > > uint64StatsMap;
 typedef std::map<lteFlowId_t, double> doubleMap;
 
@@ -46,39 +47,72 @@
   ~RlcStatsCalculator();
   static TypeId GetTypeId (void);
 
-  void SetOutputFilename (std::string outputFilename);
+  void SetUlOutputFilename (std::string outputFilename);
+  void SetDlOutputFilename (std::string outputFilename);
+
+  void UlTxPdu (uint16_t rnti, uint8_t lcid, uint32_t packetSize);
+  void UlRxPdu (uint16_t rnti, uint8_t lcid, uint32_t packetSize, uint64_t delay);
 
-  void TxPdu (uint16_t rnti, uint8_t lcid, uint32_t packetSize);
-  void RxPdu (uint16_t rnti, uint8_t lcid, uint32_t packetSize, uint64_t delay);
+  void DlTxPdu (uint16_t rnti, uint8_t lcid, uint32_t packetSize);
+  void DlRxPdu (uint16_t rnti, uint8_t lcid, uint32_t packetSize, uint64_t delay);
+
+  uint32_t GetUlTxPackets (lteFlowId_t p);
+  uint32_t GetUlRxPackets (lteFlowId_t p);
+  uint64_t GetUlTxData (lteFlowId_t p);
+  uint64_t GetUlRxData (lteFlowId_t p);
+  double   GetUlDelay (lteFlowId_t p);
+  std::vector<double> GetUlDelayStats (lteFlowId_t p);
+  std::vector<double> GetUlPduSizeStats (lteFlowId_t p);
 
-  uint32_t GetTxPackets (lteFlowId_t p);
-  uint32_t GetRxPackets (lteFlowId_t p);
-  uint64_t GetRxData (lteFlowId_t p);
-  uint64_t GetDelay (lteFlowId_t p);
-  double   GetThroughput (lteFlowId_t p);
-  double   GetPacketLossProbability (lteFlowId_t p);
+  uint32_t GetUlTxPackets (uint16_t rnti, uint8_t lcid);
+  uint32_t GetUlRxPackets (uint16_t rnti, uint8_t lcid);
+  uint64_t GetUlTxData (uint16_t rnti, uint8_t lcid);
+  uint64_t GetUlRxData (uint16_t rnti, uint8_t lcid);
+  double   GetUlDelay (uint16_t rnti, uint8_t lcid);
+  std::vector<double> GetUlDelayStats (uint16_t rnti, uint8_t lcid);
+  std::vector<double> GetUlPduSizeStats (uint16_t rnti, uint8_t lcid);
+
 
-  uint32_t GetTxPackets (uint16_t rnti, uint8_t lcid);
-  uint32_t GetRxPackets (uint16_t rnti, uint8_t lcid);
-  uint64_t GetRxData (uint16_t rnti, uint8_t lcid);
-  uint64_t GetDelay (uint16_t rnti, uint8_t lcid);
-  double   GetThroughput (uint16_t rnti, uint8_t lcid);
-  double   GetPacketLossProbability (uint16_t rnti, uint8_t lcid);
+  uint32_t GetDlTxPackets (lteFlowId_t p);
+  uint32_t GetDlRxPackets (lteFlowId_t p);
+  uint64_t GetDlTxData (lteFlowId_t p);
+  uint64_t GetDlRxData (lteFlowId_t p);
+  double   GetDlDelay (lteFlowId_t p);
+  std::vector<double> GetDlDelayStats (lteFlowId_t p);
+  std::vector<double> GetDlPduSizeStats (lteFlowId_t p);
+
+  uint32_t GetDlTxPackets (uint16_t rnti, uint8_t lcid);
+  uint32_t GetDlRxPackets (uint16_t rnti, uint8_t lcid);
+  uint64_t GetDlTxData (uint16_t rnti, uint8_t lcid);
+  uint64_t GetDlRxData (uint16_t rnti, uint8_t lcid);
+  double   GetDlDelay (uint16_t rnti, uint8_t lcid);
+  std::vector<double> GetDlDelayStats (uint16_t rnti, uint8_t lcid);
+  std::vector<double> GetDlPduSizeStats (uint16_t rnti, uint8_t lcid);
 
 private:
   void ShowResults (void);
+  void WriteUlResults (std::ofstream& outFile);
+  void WriteDlResults (std::ofstream& outFile);
   void ResetResults (void);
 
   void StartEpoch (void);
   void CheckEpoch (void);
 
-  std::string m_outputFilename;
-  std::ofstream m_outFile;
-  uint32Map m_txPackets;
-  uint32Map m_rxPackets;
-  uint64Map m_rxData;
-  doubleMap m_throughput;
-  uint64StatsMap m_delay;
+  std::string m_dlOutputFilename;
+  uint32Map m_dlTxPackets;
+  uint32Map m_dlRxPackets;
+  uint64Map m_dlTxData;
+  uint64Map m_dlRxData;
+  uint64StatsMap m_dlDelay;
+  uint32StatsMap m_dlPduSize;
+
+  std::string m_ulOutputFilename;
+  uint32Map m_ulTxPackets;
+  uint32Map m_ulRxPackets;
+  uint64Map m_ulTxData;
+  uint64Map m_ulRxData;
+  uint64StatsMap m_ulDelay;
+  uint32StatsMap m_ulPduSize;
 
   /**
    * Start time of the on going epoch
--- a/src/lte/model/lte-ue-net-device.cc	Wed Apr 06 14:50:49 2011 +0200
+++ b/src/lte/model/lte-ue-net-device.cc	Mon Apr 11 17:29:52 2011 +0200
@@ -53,7 +53,14 @@
   static TypeId
   tid =
     TypeId ("ns3::LteUeNetDevice")
-    .SetParent<LteNetDevice> ();
+    .SetParent<LteNetDevice> ()
+    .AddAttribute ("LteUeRrc",
+                   "The RRC associated to this UeNetDevice",
+                   PointerValue (),
+                   MakePointerAccessor (&LteUeNetDevice::m_rrc),
+                   MakePointerChecker <LteUeRrc> ())
+    ;
+
   return tid;
 }
 
--- a/src/lte/model/lte-ue-rrc.cc	Wed Apr 06 14:50:49 2011 +0200
+++ b/src/lte/model/lte-ue-rrc.cc	Mon Apr 11 17:29:52 2011 +0200
@@ -20,6 +20,7 @@
 
 #include <ns3/fatal-error.h>
 #include <ns3/log.h>
+#include "ns3/object-map.h"
 
 #include "lte-ue-rrc.h"
 #include "lte-rlc.h"
@@ -96,7 +97,12 @@
 {
   static TypeId tid = TypeId ("ns3::LteUeRrc")
     .SetParent<Object> ()
-    .AddConstructor<LteUeRrc> ();
+    .AddConstructor<LteUeRrc> ()
+    .AddAttribute ("RlcMap", "List of UE RadioBearerInfo by LCID.",
+                   ObjectMapValue (),
+                   MakeObjectMapAccessor (&LteUeRrc::m_rlcMap),
+                   MakeObjectMapChecker<LteRlc> ())
+    ;
   return tid;
 }
 
@@ -139,7 +145,7 @@
   // create RLC instance
   // for now we support RLC SM only
 
-  Ptr<LteRlc> rlc = Create<LteRlcSm> ();
+  Ptr<LteRlc> rlc = CreateObject<LteRlcSm> ();
   rlc->SetLteMacSapProvider (m_macSapProvider);
   rlc->SetRnti (rnti);
   rlc->SetLcId (lcid);