2017-04-27 640 views
0

当使用iperf2工具测量Windows PC和基于Zynq的设备之间的UDP吞吐量时,我通过专用1Gb以太网链路获得约950 Mb/s的吞吐量。但是,在PC上使用我自己的UDP应用程序时,我只能获得大约50 Mb/s的吞吐量,这比iperf测得的吞吐量大大降低。当然,在我的UDP应用程序中,我没有任何处理,只有在我调用sendto函数的循环中,使用大小为1470字节的UDP数据包。 Zynq设备上的应用程序由XAPP1026提供,所以它不是我的。我正在查看iperf代码,试图弄清楚他们做了什么不同,但基本上,我找不到任何套接字或udp选项或类似的工具,以最大化UDP吞吐量。与iperf UDP性能相比,UDP吞吐量较低

这里是main函数的代码(MAXUDP定义为1470):

int main(int argc, char** argv) 
{ 
int sockfd; 
struct sockaddr_in servaddr; 
char sendline[MAXUDP]; 
int i; 
int j; 
const int tr_size = (200 * MB); 
const int npackets = (tr_size/MAXUDP); 
const int neval = 2; 
DWORD start; 
DWORD end; 
int optval; 

WSADATA wsaData; 
if(WSAStartup(MAKEWORD(2, 1), &wsaData) != 0) 
{ 
    printf("Err: %d\n", WSAGetLastError()); 
    exit(1); 
} 

bzero(&servaddr, sizeof(servaddr)); 
servaddr.sin_family = AF_INET; 
servaddr.sin_port = htons(SERV_PORT); 
servaddr.sin_addr.s_addr = inet_addr("172.16.0.215"); 

sockfd = Socket(AF_INET, SOCK_DGRAM, 0); 
Connect(sockfd, (const SA*) &servaddr, sizeof(servaddr)); 

optval = 208*KB; 
Setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char*) &optval, sizeof optval); 

prep_data(sendline, MAXUDP); 

for (i = 1; i <= neval; i++) 
{ 
    start = GetTickCount(); 
    for (j = 0; j < npackets/neval; j++) 
     sendto(sockfd, sendline, MAXUDP, 0, NULL, NULL); 
    end = GetTickCount() - start; 

    printf("Time elapsed: %d sec.\n", end/1000); 
    printf("Throughput: %d.%3d MB/s\n", (tr_size/neval)/end/1000, (tr_size/neval)/end - (tr_size/neval)/end/1000); 
} 
return 0; 
} 

所以,我的主要问题是如何最大限度地发挥UDP的吞吐量以同样的方式iperf的不是吗?

更新: 我切换到Ubuntu PC。结果是不同的,但仍然有一些随机的东西发生。 我所做的第一件事情是为eth0(ifconfig eth0 172.16.0.200 netmask 255.255.255.0)和网关地址(route add default gw 172.16.0.1)设置IP地址。当我用iperf -c 172.16.0.215 -i 5 -t 25 -u -b 1000m运行iperf时)我正在接近800 Mbits/sec。然而,在以相同的方式运行几次Iperf之后,我突然间只能获得大约15 Mbits/sec甚至更少的速度。我发现我需要再次设置IP,网络掩码和网关地址才能获得800 Mbits/sec。另外,我的UDP应用程序的行为方式也是一样的。我在运行设置IP地址的命令后测量了957 Mbits/sec(其中MAXUDP设置为1470)。但经过几次迭代后,它会减慢到11 Mbits/sec左右。然后我再次设置IP地址,并且行为重复。因此,正如Kariem在他的回答中所述,问题不在于代码本身,而在于某些操作系统,netif配置相关的东西。但是,我必须在Windows上运行我的UDP应用程序,所以我需要弄清楚发生了什么。如果您对Windows中可能发生的情况有任何想法,请立即告诉我。

+0

请张贴您的代码。我会帮你的。 – Kariem

+0

你是说你用一个1470字节*有效载荷*发送UDP数据报,或者你的数据包是*总体* 1470字节大小? (注意:如果您提供[mcve],那么这是一个我们不需要提出的问题的例子,正如我们通常的预期那样)。 –

+0

我已经添加了代码,所以现在情况会更加清晰。另外,当我把MAXUDP设置为1470而不是14700(而且我只是试验)时,我刚刚发现,我正在达到550 Mb/s。混乱也在增加。 – Irie

回答

0

您在计算吞吐量方面存在错误。你的大小是以字节为单位设置的,所以你在计算你的吞吐量(以字节为单位),而iperf以比特为单位。

变化

printf("Throughput: %d.%3d MB/s\n", (tr_size/neval)/end/1000, (tr_size/neval)/end - (tr_size/neval)/end/1000); 

这个

printf("Throughput: %d.%3d MB/s\n", ((tr_size/neval)/end/1000)*8, (tr_size/neval)/end - ((tr_size/neval)/end/1000)*8); 

我在我的机器上跑了一个版本的代码和我得到1GB的吞吐量。这里是

#include <netinet/in.h> 
#include <string.h> 
#include <sys/time.h> 
#include <cstdio> 
#include <arpa/inet.h> 
#include <fcntl.h> 

#define MAXUDP 1470 
#define SERV_PORT 5001 
static inline long int getCurTimeInMs() 
{ 
    struct timeval tp; 
    gettimeofday(&tp, NULL); 
    return tp.tv_sec * 1000 + tp.tv_usec/1000; 

} 


int main(int argc, char** argv) 
{ 
    int sockfd; 
    struct sockaddr_in servaddr; 
    char sendline[MAXUDP]; 
    int i; 
    int j; 
    const int tr_size = (10000 * 1024*1024); 
    const int npackets = (tr_size/MAXUDP); 
    const int neval = 2; 

    int optval; 

    bzero(&servaddr, sizeof(servaddr)); 
    servaddr.sin_family = AF_INET; 
    servaddr.sin_port = htons(SERV_PORT); 

     servaddr.sin_addr.s_addr = inet_addr("10.0.1.2"); 

    sockfd = socket(AF_INET, SOCK_DGRAM, 0); 


    connect(sockfd, (const sockaddr*) &servaddr, sizeof(servaddr)); 


    optval = 208*1024; 
    setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char*) &optval, sizeof optval); 
    long int start = 0, end = 0; 
    for (i = 1; i <= neval; i++) 
    { 
     start = getCurTimeInMs(); 
     for (j = 0; j < npackets/neval; j++) 
      sendto(sockfd, sendline, MAXUDP, 0, NULL, NULL); 
     end = getCurTimeInMs() - start; 

     printf("Time elapsed: %d sec.\n", end/1000); 
     printf("Throughput: %d.%3d MB/s\n", (tr_size/neval)/end/1000 * 8, (tr_size/neval)/end - (tr_size/neval)/end/1000); 

    } 
    return 0; 
} 
+0

我不会说有一个错误。例如,当我总共传输100 MB时,我花费了大约15秒的时间,吞吐量大约为6.6 MB/s,这非常合理。而且,当在Wireshark中查看统计信息时,我需要大约16秒来传输71250个UDP数据包,每个数据包的大小为1514字节(71250 * 1514 = 107872500(〜100MB))。 71250 * 1514/16约为6.7 MB/s。 – Irie

+0

是的,如果你计算每秒的字节数,那么数字是正确的,但这不是iperf所做的。 iperf以每秒位数计算吞吐量,因此它将是计算吞吐量的8倍。 MBPS代表每秒兆位。 – Kariem

+0

是的,所以这意味着我在这个例子中得到6.6 * 1024 * 1024 * 8 Mb/s,这是55 Mb/s。这就是我在原帖中所说的。这个结果与iperf正在测量的950 Mb/s相差甚远。 – Irie

0

你为什么要定义MAXUDP 1470?尝试将其设置为65535,再次测量并在此处报告。

您不应该将以太网帧大小(1500字节)与UDP数据报大小混淆。不同的东西。让IP栈执行必要的碎片而不是应用程序。这可能更有效率。

+0

更改Linux的优先级,我也是这样做的。在Windows上,我在这种情况下达到了695 Mbits/sec。但是,Windows上的iperf正在发送1470字节的数据报,速度超过900 Mbits/sec。我不知道该如何解释。 – Irie

+0

在Ubuntu上运行我的应用程序时,即使将'MAXUDP'设置为1470,我也获得了955 Mbits/sec。 – Irie

+0

还有一件事。代码中用于测量流逝时间的部分(for循环中包含sendto())仅衡量应用程序将数据交给套接字/ IP堆栈的速度。在使用UDP时,没有来自“另一方”的反馈。你也可以断开电缆。 – Sokre