报文处理中的主动和被动轮询

时间:2023-02-15 15:09:45

如果你希望避免浪费CPU循环,当你没有事情做时(例如,没有报文等待处理),你应该调用pfring_poll()进行轮询,当有报文需要处理时要求系统唤醒程序。如果你创建一个主动轮询循环时,你可能希望做一些事情,就像下面:

while(<no packet available>) {usleep(1); }

 减少CPU循环花费(理论上)一小会(1ms)时间,最佳的实践是usleep()指定的持续时间(或者你希望使用nanosleep()替代usleep())。不幸的是,这并非如此。这些函数使用系统调用来实现sleep。一个简单的系统调用的开销相当低(例如,你能使用时间系统调用的测试程序测试它),每个调用通常会小于100ns,比我们希望的1us休眠更少。现在让我们测量下usleep()和nanosleep()的精度,使用简单的程序(sleep.c)。

#include <string.h>

#include <sys/time.h>

#include <stdio.h>

 

double delta_time_usec(struct timeval *now,struct timeval *before) {

 time_t delta_seconds;

 time_t delta_microseconds;

 

 delta_seconds      =now->tv_sec  - before->tv_sec;

 

 if(now->tv_usec > before->tv_usec)

    delta_microseconds = now->tv_usec - before->tv_usec;

 else

   delta_microseconds = now->tv_usec - before->tv_usec +1000000;  /* 1e6 */

 

 return((double)(delta_seconds * 1000000) + (double)delta_microseconds);

}

 

int main(int argc, char* argv[]) {

  inti, n = argc > 1 ? atoi(argv[1]) : 100000;

 static struct timeval start, end;

 struct timespec req, rem;

  inthow_many = 1;

 

 gettimeofday(&start, NULL);

  for(i = 0; i < n; i++)

   usleep(how_many);

 gettimeofday(&end, NULL);

 

 printf("usleep(1) took %f usecs\n", delta_time_usec(&end,&start) / n);

 

 gettimeofday(&start, NULL);

  for(i = 0; i < n; i++) {

   req.tv_sec = 0, req.tv_nsec = how_many;

   nanosleep(&req, &rem);

  }

 gettimeofday(&end, NULL);

 

 printf("nanosleep(1) took %f usecs\n",delta_time_usec(&end, &start) / n);

}

结果是不同的机器稍有变化,但是他们大约都在60usec左右。

# ./sleep

usleep(1) took 56.248760 usecs

nanosleep(1) took 65.165280 usecs

       这意味着使用usleep和nanosleep休眠1ms时,实际上它们休眠了大约60ms。该结果不是很惊讶,其它人早就发现了这个问题。

       在实际中这意味着什么呢?我们知道在10G线速下,67ns要接收一个报文,休眠60usec意味着在这段时间中你可接收大约895个报文,你必须有更多的缓冲处理这种情况,否则会出现丢包的情况。它也表示你不能做任何轮询,除了在紧急情况下使用纯粹的主动轮询(例如:在主动报文轮询中不进行任何的usleep/nanosleep),例如:当你从两个网络适配器上对报文进行时间合并时。

       总结:主动轮询不是很优雅,但是在高速下处理报文可能是强制性的,为了达到高速和精确的要求。PF_RING应用支持主动和被动轮询。例如你使用的pfcount使用-a标识强制使用主动报文轮询,因此(有些情况下)增加报文捕获性能,代价是导致你的CPU核利用率100%(例如:当你使用主动轮询时确保你也绑定你的应用到一个核上,在pfcount中你可以使用-g来完成)。

参考文档

[1] PF_RING ZC(零拷贝)简介

http://www.ntop.org/pf_ring/introducing-pf_ring-zc-zero-copy/

[2] 不是所有服务器都一样(DNA)三部分

http://www.ntop.org/pf_ring/not-all-servers-are-alike-with-dna/

http://www.ntop.org/pf_ring/not-all-servers-are-alike-with-pf_ring-zcdna-part-2/

http://www.ntop.org/pf_ring/not-all-servers-are-alike-with-pf_ring-zcdna-part-3/

[3] 应用之间如何使用PF_RING平衡流量

http://www.ntop.org/pf_ring/how-to-balance-mobile-traffic-across-applications-using-pf_ring/

[4] 使用n2disk和PF_RING构建一个廉价的2*10Gbit(继续)报文记录器

http://www.ntop.org/n2disk/building-a-cheap-2x10-gbit-continuous-packet-recorder-using-n2disk-and-pf_ring/