TCP throughput and goodput

910 views
Skip to first unread message

Matteo Danieletto

unread,
May 27, 2015, 3:19:49 AM5/27/15
to ns-3-...@googlegroups.com
Hi all,
I am looking for compute the TCP throughput and goodput.

For me when I talk about throughput it is the amount of data receive at TCP layer by the sink.
Instead goodput is the amount of data received at TCP layer without any duplicate packet. 

I think that for throughput I found the solution. Instead for the goodput I have doubt. 

For the throughput purpose a wrote these lines and two functions:

        int idSinkNode = (int)floor((float)n_nodes/2);
uint32_t port = 20;

Address sinkLocalAddressReceiver1(InetSocketAddress (interfaces.GetAddress (idSinkNode), port));
BulkSendHelper sourceFTP ("ns3::TcpSocketFactory",sinkLocalAddressReceiver1);

sourceFTP.SetAttribute ("MaxBytes", UintegerValue (maxBytes));
ApplicationContainer sourceAppsFTP = sourceFTP.Install (nodes.Get (0));       
sourceAppsFTP.Start (Seconds (50.0));
sourceAppsFTP.Stop (Seconds (1000.0));

Address sinkLocalAddress(InetSocketAddress (Ipv4Address::GetAny (), port));
PacketSinkHelper sink ("ns3::TcpSocketFactory", sinkLocalAddress);
ApplicationContainer sinkAppsTraffic = sink.Install (nodes.Get (idSinkNode));
sinkAppsTraffic.Start (Seconds (50.0));
sinkAppsTraffic.Stop (Seconds (1000.0));

std::string receiverNodeConfig = "/NodeList/"+to_string(idSinkNode)+"/ApplicationList/*/$ns3::PacketSink/Rx";
Config::ConnectWithoutContext (receiverNodeConfig, MakeCallback (&SinkRx2));

Simulator::Schedule (Seconds (50.0), &ThroughputPerSecond, sinkAppsTraffic.Get(0),0 ,0 , nodes.Get (idSinkNode));


-and the two function:

static void SinkRx2 (Ptr<const Packet> p, const Address &ad)
{
uint8_t buf[6]; 
  ad.CopyTo (buf); 
Ipv4Address ipv4 = Ipv4Address::Deserialize (buf); 
p->Print(outTest);
uint32_t ipAdd = ipv4.Get() ;
int a = ((ipAdd >> 24)  & 0xff) ;
int b = ((ipAdd >> 16)  & 0xff) ;
int c = ((ipAdd >> 8)  & 0xff); 
int d = ((ipAdd >> 0)  & 0xff);  

std::cout << Simulator::Now().GetSeconds()<< "\t"<< a <<"."<<b<< "."<< c<<"."<< d <<"\t"<< "ID: " << p->GetUid()<<"\t" << p->GetSize()  << "\t"  << std::endl;
}

void
ThroughputPerSecond (Ptr<Application> sink1Apps, int totalPacketsThrough, float prevThroughput ,Ptr<Node> node)
{

  double throughput = 0.0;
  Ptr<PacketSink> sink1 = DynamicCast<PacketSink> (sink1Apps);
  totalPacketsThrough = sink1->GetTotalRx ();
  throughput = (totalPacketsThrough*8/(1000000.0)) - prevThroughput;
  prevThroughput = (totalPacketsThrough*8)/(1000000.0);
  std::cout << (Simulator::Now ()).GetSeconds () << "\t"<< throughput <<std::endl;
  Simulator::Schedule (Seconds (1.0), &ThroughputPerSecond, sink1Apps, totalPacketsThrough, prevThroughput, node);
}

My doubt regards the function SinkRx2. My idea is to extract the TCP sequence number from the packet received by the sink node. Is it good? I also think that GetUid() is not what I am lookinh for, amn't I?

Thank you a lot
Matteo

Konstantinos

unread,
May 27, 2015, 3:57:09 AM5/27/15
to ns-3-...@googlegroups.com, mdani...@eng.ucsd.edu
Hi Matteo,

The code you have used to calculate throughput is actually the code for goodput as it is based on the packets that the application will receive and TCP will not deliver duplicate packets to the application.

Now, to calculate throughput, i.e. the number of segments received at TCP that may contain also duplicates you could use trace sources from TCP such as the SequenceNumber or from IP (e.g. LocalDeliver, this might need some filtering).

Regards,
K.

Nat P

unread,
May 27, 2015, 8:10:54 AM5/27/15
to ns-3-...@googlegroups.com, mdani...@eng.ucsd.edu


Il giorno mercoledì 27 maggio 2015 09:57:09 UTC+2, Konstantinos ha scritto:
Hi Matteo,

The code you have used to calculate throughput is actually the code for goodput as it is based on the packets that the application will receive and TCP will not deliver duplicate packets to the application.

Now, to calculate throughput, i.e. the number of segments received at TCP that may contain also duplicates you could use trace sources from TCP such as the SequenceNumber or from IP (e.g. LocalDeliver, this might need some filtering).

I agree with Konstantinos: you're counting the packets at application layer (PacketSink is an application), so the exact definition is "goodput". Now, since the definition of goodput includes the notion of "application" by default, obtaining a goodput on TCP layer could be misleading.

My suggestion is to focus on the differences you want to show. In particular, can packet duplication happen in the channel you're using? Sometimes I've seen that the metric used is the number of retransmissions: you have on one hand the goodput and in the other hand the throughput at IP level (or H2N level). By comparing these two values, you can see how the retransmission (and the packet duplication) impact on the nodes.

HTH,

Nat

Matteo Danieletto

unread,
May 27, 2015, 1:47:32 PM5/27/15
to ns-3-...@googlegroups.com, mdani...@eng.ucsd.edu
Thank you guys.
Very good, I've thought that was the throughput at transport layer, instead I was already computing the goodput at App layer
Ok, it is perfect to me to know  the goodput at App layer. 
I was following this example:

Do you suggest to trace TCP throughput to use any callbacks at TCP layer or flow monitor? 

Thank you
Matteo

Matteo Danieletto

unread,
May 27, 2015, 9:17:00 PM5/27/15
to ns-3-...@googlegroups.com
I did in this way:
I am reading the packets when are received at sink and I am extracting the seqnumber.
Is it the right way?
Thank you 
Matteo
std::string receiverNode_MAC_ConfigV = "/NodeList/"+to_string(idSinkNode)+"/DeviceList/0/Mac/MacRx";
Config::Connect (receiverNode_MAC_ConfigV, MakeCallback (&DevRxTraceV));

void
DevRxTraceV (std::string context, Ptr<const Packet> p)
{
Ptr<Packet> q = p->Copy();
PacketMetadata::ItemIterator metadataIterator = q->BeginItem();
PacketMetadata::Item item;
while (metadataIterator.HasNext())
{
   item = metadataIterator.Next();
   if(item.tid.GetName() == "ns3::TcpHeader")
   {

     
Callback<ObjectBase *> constr = item.tid.GetConstructor();
NS_ASSERT(!constr.IsNull());

// Ptr<> and DynamicCast<> won't work here as all headers are from ObjectBase, not Object
ObjectBase *instance = constr();
NS_ASSERT(instance != 0);

TcpHeader* tcpHeader = dynamic_cast<TcpHeader*> (instance);
NS_ASSERT(tcpHeader != 0);

tcpHeader->Deserialize(item.current);
SequenceNumber32 seq = tcpHeader->GetSequenceNumber(); 
std::cout<<Simulator::Now().GetSeconds()<<"\t" <<p->GetSize()<<"\t" << seq<<std::endl;  
   break;

Tommaso Pecorella

unread,
May 28, 2015, 2:31:22 AM5/28/15
to ns-3-...@googlegroups.com
Hi,

there's one thing I barely can stand: lack of thinking. You're only excused because you wrote at 3:17 am.

Logic argument.
If we have to name "goodput" (I really hate the term) the amount of bytes per second received at the application layer (i.e., in the L7 / L6 interface), then what is the throughput ?
The amount of bytes per second at the interface between the layers... ?
Answer: there is no real answer. You have to define it every time. The throughput at MAC layer, at PHY layer, at IP layer, etc.

If you don't define what you mean to measure, the trace you hooked to could be right or could be wrong.

Again, logic.

Sleep more.

T.
Reply all
Reply to author
Forward
0 new messages