[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [ns] End-to-end performance of a single flow in an ad hocnetwork



>Hi,
>
>I have a simulation of a 50-node ad hoc network with 15 flows using DSDV
>protocol. I would like to compute certain end-to-end performance metrics
>for one particular flow, like end-to-end delay of packets, number of
>packets dropped, etc.
>
>Can someone give me an idea how to do it? I can record the time at the
>sender when the packet is sent by looking at the trace file. But how do I
>further track this same packet to see if it is dropped or what time it has
>arrived at the receiver? When a packet is received at the final
>destination (as seen in the trace file), how do I know which one of the
>packets sent by the sender it is? It just seems to be coming from the
>last-but-one intermediate hop!
>
>Thanks and regards,
>Samarth.


Hi Samarth,

You may cut out & edit the two attached C++ programs, A.cc and B.cc;
just read the following instructions and use a gcc compiler. This is
a slight upgrade from my ns-2 post of 28 July 2000, on extracting the
end-to-end performance data.


1) Suppose you wish to extract the performance data for traffic from, say,
source node s = 26 to sink node t = 87 with a flow id f = 1, from an
all-trace data file out.tr.

Then you type the command sequence:

g++ A.cc
cat out.tr | ./a.out 26 87 1 selected
g++ B.cc
./a.out 26 87 1 selected

(Istead of "selected" you can type any name you please, of course, it just got
to be the same at both places.)

This should yield you the packet loss rate, average delay, and jitter at
the standard output.


2) There is a bit more you can do now with these programs.  Sometimes
the all-trace file out.tr is indeed very large, and if one is stuck with
insufficient disk memory, one might prefer to generate the gzipped verzion
out.tr.gz by the ns program (- say, by placing the lines

set compout [open "|gzip -c > out.tr.gz" w]
$ns trace-all $compout

). If that is the case, my extraction program tandem can be applied directly
to the compressed file out.tr.gz. You simply type:

g++ A.cc
funzip out.tr.gz | ./a.out 26 87 1 selected
g++ B.cc
./a.out 26 87 1 selected

(For this last, I use RH Linux, which does have the command funzip. It
 is a "filter for extracting a ZIP archive in a pipe", as the man page says.)


Regards,

Miroslav


---
Dr. Miroslav I. Klun
Verizon Laboratories Inc., MS-51
Waltham, MA 02451
(781) 466-3830
[email protected]



////////////////////////////////////////////////////////////////////////////////
//// A.cc:
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// The program reads all the lines of the out.tr file, selects those that
// refer to flow f packets that are sent from source node s to sink node t,
// and that either are just entering the queue at node s or are just
// arriving at node t.  The selected lines are placed in a temporary file
// ("selected").
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <iostream.h>
#include <string.h>
#include <fstream.h>
#include <stdlib.h>
#include <iomanip.h>
#include <math.h>

int main(int argc, char *argv[])
{
  // Packet type to be excluded - e.g., ack in case of TCP, etc.:
  char *Type;
  Type = "ack";

  cout << "\n" << "The packet type that will be excluded: " << Type << "\n\n";

  int s = atoi(argv[1]); // Source node.
  int t = atoi(argv[2]); // Sink node.
  int f = atoi(argv[3]);  // Flow id.


  ofstream out_file(argv[4]);

  char line[100];
  char *vector[12];
  char *tokenPtr;
  char buffer[100];


  while (!feof(stdin)&&gets(line)!=0)
  {
    // Each "line" is a row of characters in the original file out.tr.
    // These characters form 12 words separated by 11 blank delimiters.
    // Thus, each character array "line" yields a 12-word array "vector".
    // The following parses ("tokenizes") "line" into "vector":
//  buffer = line;
    strcpy (buffer, line);
    // It is necessary to use a _copy_ of "line", "buffer", instead of "line"
    // itself, since an application of "strtok" function modifies its first
    // argument!
    tokenPtr = strtok(buffer, " ");
    for (int j=0; j < 11; j++) {
      vector[j] = tokenPtr;
      tokenPtr = strtok(NULL, " ");
    }
    vector[11] = tokenPtr;
    // Now we are ready to examine each line of our out.tr file. We first need
    // some labels:
    char *sign;
    sign = vector[0];
    float time_stamp = atof(vector[1]);
    int from_node = atoi(vector[2]);
    int to_node = atoi(vector[3]);
    char *type;
    type = vector[4];
    int flow  = atoi(vector[7]);
    int source_node = atoi(vector[8]);
    int sink_node = atoi(vector[9]);
    int packet_id = atoi(vector[11]);

    // Finally, here is the criterion for finding the desirable lines of the
    // file out.tr and placing them into a new file argv[4].
    if ((((*sign == '+') && (from_node == s) && (flow == f) && (source_node
== s) && (sink_node == t)) || ((*sign == 'r') && (to_node == t) && (flow ==
f) && (source_node == s) && (sink_node == t))) && (strcmp(type,Type)!=0)) {
      out_file << line << "\n";
    }
  }
  out_file.close();

 return 0;
}





//// A.cc
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// The program reads the temporary file ("selected"), and records the delays of
// all the packets belonging to flow f that start from a source at node s and
// are received at a sink at node t. It also records the precentage of the
// packets and the jitter. It prints all the statistics to the standard
// output.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

#include <iostream.h>
#include <string.h>
#include <fstream.h>
#include <stdlib.h>
#include <iomanip.h>
#include <math.h>

int main(int argc, char *argv[])
{
  int s = atoi(argv[1]); // Source node.
  int t = atoi(argv[2]); // Sink node.
  int f = atoi(argv[3]);  // Flow id.

  ifstream in_file(argv[4]);
  int i = 0;
  char buffer[100];
  while (in_file) {
    in_file.getline(buffer, 100);
    i++;
  }
  // From here we get the number M of rows in the input data file
  // (i.e., the size of the character array "data" defined below):
  int M = i-1;
  in_file.close();

  char sign[M][2];
  float time_stamp[M];
  int packet_id[M];

  ifstream inn_file(argv[4]);
  i = 0;
  while (i < M){
    char data[100];
    inn_file.getline(data, 100);
    strcpy(buffer, data);
    char *tokenPtr;
    tokenPtr = strtok(buffer, " ");
    strcpy(sign[i], tokenPtr);
    tokenPtr = strtok(NULL, " ");
    time_stamp[i] = atof(tokenPtr);
    for (int j=1; j < 11; j++) {
      tokenPtr = strtok(NULL, " ");
    }
    packet_id[i] = atoi(tokenPtr);
    i++;
  }
  inn_file.close();

  // The array "delay" shall have plenty of zeros at the tail...
  float delay[M];
  int k = 0;
  int l = 0;
  for (int i=0; i < M; i++) {
    if ((*sign[i] == '+')) {
      k++;
      for (int j=0; j < M; j++) {
	if ((*sign[j] == 'r') && (packet_id[j] == packet_id[i])) {
	  delay[l] = time_stamp[j] - time_stamp[i];
	  l++;
	}
      }
    }
  }

  int T = k; // The number of packets transmitted.
  int R = l; // The number of packets received.
  int L = T - R; // The number of packets lost.
  cout << "\n\n";
  cout << "The number of packets transmitted T = " << T << ".\n";
  cout << "The number of packets received R = " << R << ".\n";
  cout << "The number of packets lost L = " << L << ".\n";

  ///////////////////////////////////////////////////////////////////
  // The following computes the percentage, truncated at two decimals,
  // of the lost packets:
  double loss_ratio = floor(10000*L/T)/100;
  cout << "\n" << loss_ratio << "% of all packets of flow " << f << " sent
from node " << s << " to node " << t << " were lost." << "\n\n";

  ///////////////////////////////////////////////////////////////////////
  // This computes delay sample mean and prints it to the standard output:
  double sigma = 0;
  for (l=0; l < R; l++){
    sigma = sigma + delay[l];
  }
  double delay_mean = sigma/R;
  cout << "Delay mean for flow " << f << " = " << 1000*delay_mean << " ms"
<< "\n\n";

  ///////////////////////////////
  // This computes delay variance:
  double quad = 0;
  for (l=0; l < R; l++){
    quad = quad + pow(delay[l] - delay_mean,2);
  }
  double delay_variance = quad/R;

  /////////////////////////////////////////////////////////////
  // This computes delay sample standard variation and prints it
  // to the standard output:
  double delay_standard_deviation = sqrt(delay_variance);
  cout << "Jitter for flow " << f << " = " << 1000*delay_standard_deviation
<< " ms" << "\n\n";

  return 0;
}

///////////////////////////////////////////////////////////////////////////////