2017-04-27 637 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