[转] 网路模拟软体NS2来做网路效能分析需看的文章(二) 转载

接下来,笔者先简单介绍awk,然后如何使用awk去分析trace file,以得到Throughput、Delay、Jitter、和Loss Rate。

[awk]

A.简介

         awk是一种程式语言。它具有一般程式语言常见的功能。因awk语言具有某些特点,如:使用直译器(Interpreter)不需先行编译;变数无型别之分(Typeless),可使用文字当阵列的注标(Associative Array)等特色。因此,使用awk撰写程式比起使用其它语言更简洁便利且节省时间。awk还具有一些内建功能,使得awk擅于处理具资料列(Record),栏位(Field)型态的资料;此外, awk内建有pipe的功能,可将处理中的资料传送给外部的 Shell命令加以处理, 再将Shell命令处理后的资料传回awk程式,这个特点也使得awk程式很容易使用系统资源。

B. awk是如何运作的

        为便于解释awk程式架构,以及相关的术语,笔者就以上面trace file为例,来加以介绍。

a.名词定义:

1.      资料列:awk从资料档上读取的基本单位,以trace file为例,awk读入的

第一笔资料列为 ”+ 0.1 1 2 cbr 1000 ------- 2 1.0 3.1 0 0”

第二笔资料列为 “- 0.1 1 2 cbr 1000 ------- 2 1.0 3.1 0 0”

一般而言,一笔资料列相当于资料档上的一行资料。

 

2.      栏位(Field):为资料列上被分隔开的子字串。

以资料列”+ 0.1 1 2 cbr 1000 ------- 2 1.0 3.1 0 0”为例,

十一

十二

0.1

1

2

cbr

1000

-------

2

1.0

3.1

0

0

一般而言是以空白字元来分隔相邻的栏位。

 

当awk读入资料列后,会把每个栏位的值存入栏位变数。

欄位變數

意義

$0

為一字串, 其內容為目前awk所讀入的資料列.

$1

代表 $0 上第一個欄位的資料.

$2

代表 $0 上第二欄個位的資料.

……

……

b.程式主要节构:

        Pattern1           { Actions1 }

        Pattern2           { Actions2 }

        ………………

        Pattern3           { Actions3 }

 

一般常用”关係判断式”来当成Pattern。例如:

x > 3 用来判断变数x是否大于3

x == 5 用来判断变数x是否等于5

awk提供c语言常见的关係运算元,如:>、<、>=、<=、==、!=等等

 

Actions是由许多awk指令所构成,而awk的指令与c语言中的指令非常类似。

IO指令:print 、 printf( ) 、getline ......

流程控制指令 : if ( ...) {...} else {…}、 while(…){…} ……

 

在awk程式的流程为先判断Pattern的结果,若为真True则执行相对应的Actions,若为假False则不执行相对的Actions。若是处理的过程中没有Pattern,awk会无条件的去执行Actions。

 

c.工作流程: 执行awk时, 它会反複进行下列四步骤。

1. 自动从指定的资料档中读取一笔资料列。

2. 自动更新(Update)相关的内建变数之值。

3. 逐次执行程式中 所有 的 Pattern { Actions } 指令。

4. 当执行完程式中所有 Pattern { Actions }时,若资料档中还有未读取的料,则反覆执行步骤1到步骤4。

 

awk会自动重覆进行上述的四个步骤,所以使用者不须在程式中写这个迴圈。

 

[End-to-End Delay]

笔者把量测CBR封包端点到端点间延迟时间的awk程式,写在档桉measure-delay.awk档桉中,读者可以参考此范例,修改成符合读者需求的程式。


BEGIN {
#程式初始化,设定一变数以记录目前最高处理封包的ID。
     highest_packet_id = 0;
}
{
   action = $1;
   time = $2;
   node_1 = $3;
   node_2 = $4;
   type = $5;
   flow_id = $8;
   node_1_address = $9;
   node_2_address = $10;
   seq_no = $11;
   packet_id = $12;

#记录目前最高的packet ID
   if ( packet_id > highest_packet_id )
                highest_packet_id = packet_id;

#记录封包的传送时间
   if ( start_time[packet_id] == 0 )
               start_time[packet_id] = time;

#记录CBR (flow_id=2) 的接收时间
   if ( flow_id == 2 && action != "d" ) {
      if ( action == "r" ) {
         end_time[packet_id] = time;
      }
   } else {
#把不是flow_id=2的封包或者是flow_id=2但此封包被drop的时间设为-1
      end_time[packet_id] = -1;
   }
}                                                                                                          
END {
#当资料列全部读取完后,开始计算有效封包的端点到端点延迟时间
    for ( packet_id = 0; packet_id <= highest_packet_id; packet_id++ ) {
       start = start_time[packet_id];
       end = end_time[packet_id];
       packet_duration = end - start;

#只把接收时间大于传送时间的记录列出来
       if ( start < end ) printf("%f %f\n", start, packet_duration);
   }
}

执行方法: ($为shell的提示符号)
$awk -f measure-delay.awk out.tr

若是要把结果存到档桉,可使用导向的方式。(把结果存到cbr_delay档桉中)
$awk -f measure-delay.awk out.tr > cbr_delay

执行结果:
0.100000 0.038706
0.108000 0.038706
0.116000 0.038706
0.124000 0.038706
0.132000 0.038706
………………………

[Jitter]

Jitter 就是延迟时间变化量delay variance,由于网路的状态随时都在变化,有时候流量大,有时候流量小,当流量大的时候,许多封包就必需在节点的伫列中等待被传送,因此每个封包从传送端到目的地端的时间不一定会相同,而这个不同的差异就是所谓的Jitter。Jitter越大,则表示网路越不稳定。笔者把量测CBR flow的Jitter的awk写在档桉measure-jitter.awk内。

 

BEGIN {

#程式初始化

   old_time=0;

   old_seq_no=0;

   i=0;

}

{

   action = $1;

   time = $2;

   node_1 = $3;

   node_2 = $4;

   type = $5;

   flow_id = $8;

   node_1_address = $9;

   node_2_address = $10;

   seq_no = $11;

   packet_id = $12;

 

#判断是否为n2传送到n3,且封包型态为cbr,动作为接受封包

   if(node_1==2 && node_2==3 && type=="cbr" && action=="r") {

#求出目前封包的序号和上次成功接收的序号差值

               dif=seq_no-old_seq_no;

 

#处理第一个接收封包

        if(dif==0)

          dif=1;

 

#求出jitter

         jitter[i]=(time-old_time)/dif;

         seq[i]=seq_no;

                               i=i+1;

         old_seq_no=seq_no;

         old_time=time;

   }    

}

END {

   for (j=1; j <i ;j++)

    printf("%d\t%f\n",seq[j],jitter[j]);

}

 

执行方法: ($为shell的提示符号)
$awk -f measure-jitter.awk out.tr

若是要把结果存到档桉,可使用导向的方式。(把结果存到cbr_jitter档桉中)
$awk -f measure-jitter.awk out.tr > cbr_jitter

执行结果:
1             0.008000
2             0.008000
3             0.008000
4             0.008000
……………………

[另一种计算Jitter的方法---更精确的方式]

# ================================================================================

# NormalJitter.awk

# Version now: 0.1

# Last Modified Date: 2004-10-23,19:39:54

# == Usage ==

# awk -f NormalJitter.awk out.tr

# == Programed By ==

# 查辉(ZHA HUI), Wuhan, China, Email: zhahui AT gmail.com

# == Description ==

# 本awk程式给出了另外一种jitter的计算方法,这种方法中jitter的计算是基于以下公式:

# jitter =((recvtime(j)-sendtime(j))-(recvtime(i)-sendtime(i)))/(j-i), 其中 j>i 。

# == Attention ==

# NormalJitter.awk中关于jitter的计算完全基于柯志亨博士的measure-delay.awk程式中delay的

# 计算。而measure-delay.awk在柯博士网页中的ns2类比例子中是正确的,但是对于不同的例子需要根

# 据情况进行一定的修改,并可能需要加入某些鲁棒性处理代码(例如对于第一个包的处理,对于丢包的处

# 理等)。

# == Reference ==

# http://140.116.72.80/~smallko/ns2/ns2.htm

# == Feedback ==

# 如有任何关于本程式jitter计算的问题,请致信

# 柯志亨(ChihHeng, Ke)博士 smallko2001 AT pchome.com.tw 或者与本人联繫。

# == Acknowledgements ==

# Dr. ChihHeng, Ke provided valuable documents and awk files upon my requests.

# ================================================================================

 

BEGIN {

#程式初始化,设定一变数以记录目前最高处理封包的ID。

     highest_packet_id = 0;

}

{

   action = $1;

   time = $2;

   node_1 = $3;

   node_2 = $4;

   type = $5;

   flow_id = $8;

   node_1_address = $9;

   node_2_address = $10;

   seq_no = $11;

   packet_id = $12;

 

#记录目前最高的packet ID

   if ( packet_id > highest_packet_id ) {

           highest_packet_id = packet_id;

        }

 

#记录封包的传送时间

   if ( start_time[packet_id] == 0 ) {

           # 记录下包的seq_no -- ZHA

           pkt_seqno[packet_id] = seq_no;

           start_time[packet_id] = time;

   }

 

#记录CBR (flow_id=2) 的接收时间

   if ( flow_id == 2 && action != "d" ) {

      if ( action == "r" ) {

         end_time[packet_id] = time;

      }

   } else {

#把不是flow_id=2的封包或者是flow_id=2但此封包被drop的时间设为-1

      end_time[packet_id] = -1;

   }

}                                                       

END {

        # 初始化jitter计算所需变量 -- ZHA

        last_seqno = 0;

        last_delay = 0;

        seqno_diff = 0;

#当资料列全部读取完后,开始计算有效封包的端点到端点延迟时间

    for ( packet_id = 0; packet_id <= highest_packet_id; packet_id++ ) {

       start = start_time[packet_id];

       end = end_time[packet_id];

       packet_duration = end - start;

 

#只把接收时间大于传送时间的记录列出来

       if ( start < end ) {

               # 得到了delay值(packet_duration)后计算jitter -- ZHA

               seqno_diff = pkt_seqno[packet_id] - last_seqno;

               delay_diff = packet_duration - last_delay;

               if (seqno_diff == 0) {

                       jitter =0;

               } else {

                       jitter = delay_diff/seqno_diff;

               }

               printf("%f %f\n", start, jitter);

               last_seqno = pkt_seqno[packet_id];

               last_delay = packet_duration;

       }

    }

}

posted on 2012-06-29 09:50  haivey  阅读(319)  评论(0)    收藏  举报

导航