TCP/UDPの通信速度を向上させたい

弊社TCP/IPプロトコルスタック「μNet3」に関するご質問
返信する
アバター
eForce技術担当
記事: 193
登録日時: 2014年4月24日(木) 14:18

TCP/UDPの通信速度を向上させたい

投稿記事 by eForce技術担当 » 2016年7月26日(火) 19:32

以下の手順を実施する事でネットワーク通信性能を向上させる事が出来ます。
但し、基本的に通信性能向上とメモリ使用量はトレードオフとなる為、
最終的なコンフィグレーション設定値は、アプリケーションの設計に適した値を検討した上でカスタマイズしてください。

注意:評価版ではコンフィグレーション制限がある為、この手順を実施する事は出来ません。

1.通信速度を計測するテストプログラムヘッダ(sample_throughput.h)を作成

コード: 全て選択

#ifndef SAMPLE_THROUGHPUT_H_
#define SAMPLE_THROUGHPUT_H_

extern UW total_byte;
extern UW pps;

typedef ER (*FP_SNDRCV)(SID sid, VP data, UH len);

typedef struct t_task_param
{
    UB proto;          // 生成するソケットのプロトコル(IP_PROTO_TCP or IP_PROTO_UDP)
    UH data_size;      // 送受信サイズ(1-32768)
    UB con_flg;        // 接続モード(0 or SOC_SER or SOC_CLI)
    FP_SNDRCV api;     // 使用する関数ポインタ(&snd_soc or &rcv_soc)
} T_TASK_PARAM, *PT_TASK_PARAM;

void ThroughputTask(VP_INT exinf);

#endif
2.通信速度を計測するテストプログラムソース(sample_throughput.c)を作成

コード: 全て選択

#include "kernel.h"
#include "net_hdr.h"
#include "net_strlib.h"
#include "sample_throughput.h"

static char buf[32768];

UW total_byte = 0UL;
UW pps = 0UL;

void ThroughputTask(VP_INT exinf)
{
    PT_TASK_PARAM pParam;
    SID sid;
    T_NODE host;
    T_NODE remote;
    ER ercd;

    sid = 0U;
    pParam = (PT_TASK_PARAM)exinf;

    /* ソケット生成 */
    host.num  = 1;
    host.ver  = IP_VER4;
    host.ipa  = INADDR_ANY;
    host.port = 12345;
    ercd = cre_soc( pParam->proto, &host );
    if ( ercd <= 0 ) {
    	goto TASK_END;
    }
    sid = (SID)ercd;

    /* TCPクライアント接続 */
    remote.ver = IP_VER4;
    remote.num = 1;     /* ネットワークデバイス番号 */
    remote.ipa = ip_aton( "172.16.0.1" );
    remote.port = 10000;
    ercd = con_soc( sid, &remote, pParam->con_flg );
    if ( ercd != E_OK ) {
    	goto TASK_END;
    }

    /* スループット計測 */
    for ( ; ; ) {
        ercd = (pParam->api)( sid, &buf[0], pParam->data_size );
        if ( ercd <= 0 ) {
        	break;
        }

        total_byte += (UW)ercd;
        pps++;
    }

TASK_END:
    /* 後始末 */
    if ( sid != 0U ) {
        cls_soc( sid, 0 );
        del_soc( sid );
        sid = 0U;
    }
    ext_tsk();
}
3.テストプログラムを起動するロジックを実装
  ※このトピックの例では、HELIO.NETサンプルプログラムのmain.c内にあるMainTaskをベースに実装しました
throughput2.png
throughput2.png (8.97 KiB) 閲覧された回数 20509 回
throughput1.png
コピーペースト用テンプレート

コード: 全て選択

#define TCP_THROUGHPUT_ENABLE

T_CTSK ctsk_throughput = { TA_HLNG | TA_ACT | TA_FPU, (VP_INT)0, (FP)ThroughputTask, 5, 0x400, 0, "ThroughputTask" };


void MainTask(VP_INT exinf)
{
    T_TASK_PARAM param = { 0 };
    VB msg[32];
    ER ercd;

    ini_com(ID_UART, &uart_ini);
    ctr_com(ID_UART, STA_COM, 0);

    ctr_com(ID_UART, SND_BRK, 100);
    puts_com_opt((VB *)demo_str);

    /* Initialize Network */
    ercd = net_setup();
    if (ercd != E_OK) {
        return;
    }

    /* スループット計測タスク生成 */
#ifdef TCP_THROUGHPUT_ENABLE
#if 1
    param.proto = IP_PROTO_TCP;
    param.data_size = 32768;
    param.con_flg = SOC_CLI;
    param.api = &snd_soc;
#else
    param.proto = IP_PROTO_TCP;
    param.data_size = 32768;
    param.con_flg = SOC_SER;
    param.api = &rcv_soc;
#endif
#else
#if 1
    param.proto = IP_PROTO_UDP;
    param.data_size = 1472;
    param.con_flg = 0;
    param.api = &snd_soc;
#else
    param.proto = IP_PROTO_UDP;
    param.data_size = 1472;
    param.con_flg = 0;
    param.api = &rcv_soc;
#endif
#endif
    ctsk_throughput.exinf = (VP_INT)&param;
    acre_tsk( (T_CTSK *)&ctsk_throughput );

    for ( ; ; ) {
        tslp_tsk( 1000 );

        sprintf( &msg[0], "%dMbps, pps = %d\r\n", (total_byte * 8) / 1000 / 1000, pps );
        puts_com_opt( &msg[0] );

        total_byte = 0UL;
        pps = 0UL;
    }

#if 0
    /* Start UART console */
    net_sta_console();
#endif

    return;
}
4.これで性能計測する準備が出来ました。まず、デフォルトのコンフィグレーション内容で速度計測してみます。
■TCP送信性能
計測コマンド:「iperf -s -p 10000 -i 10」
throughput3.png
■TCP受信性能
以下を変更してリビルドし実行
throughput4.png
throughput4.png (15.19 KiB) 閲覧された回数 20509 回
計測コマンド:「iperf -c 172.16.0.95 -p 12345 -i 10 -w 64000 -t 200」
throughput5.png
■UDP送信性能
以下を変更してリビルドし実行
throughput6.png
throughput6.png (5.35 KiB) 閲覧された回数 20509 回
計測コマンド:「iperf -s -u -p 10000 -i 10 -l 1472」
throughput7.png
■UDP受信性能
以下を変更してリビルドし実行
throughput8.png
throughput8.png (9.67 KiB) 閲覧された回数 20509 回
計測コマンド:「iperf -u -c 172.16.0.95 -p 12345 -l 1472 -i 10 -b 810M -t 200」
throughput9.png
■デフォルト設定のスループット性能
TCP送信性能:55Kbps
TCP受信性能:90Mbps
UDP送信性能:495Mbps
UDP受信性能:500Mbps

5.次に通信性能に関わるコンフィグレーションのカスタマイズを行います。
■net_cfg.h
throughput10.png
■DDR_CYCLONEV_ETH_cfg.h(ドライバによって名称が異なります)
throughput11.png
CFG_TCP_SND_WNDの値をデフォルト1024から16384に変更(TCPの送信性能に影響します)
CFG_TCP_RCV_WNDの値をデフォルト1024から32768に変更(TCPの受信性能に影響します)
CFG_PKT_RCV_QUEの値をデフォルト1から255に変更(UDPの受信性能に影響します。また、UDPパケット取りこぼしにも影響します)
ETH1_RXDESC_CNTの値をデフォルト4から18に変更(Ethernetドライバのパケット受信性能に影響します)

■TCP送信性能
計測コマンド:「iperf -s -p 10000 -i 10」
throughput12.png
■TCP受信性能
計測コマンド:「iperf -c 172.16.0.95 -p 12345 -i 10 -w 64000 -t 200」
throughput13.png
■UDP送信性能
計測コマンド:「iperf -s -u -p 10000 -i 10 -l 1472」
throughput14.png
■UDP受信性能
計測コマンド:「iperf -u -c 172.16.0.95 -p 12345 -l 1472 -i 10 -b 810M -t 200」
throughput15.png
1472バイトを超えるUDPパケットの送受信が失敗してしまう
上記トピックにてIPフラグメントの受信を行える形にした上で受信処理を行うとUDP受信性能の向上が確認出来ます。
送信処理はIPフラグメントを行わない方が性能が出るみたいです。

トピック対応を行い、UDP送受信バイト数の設定を変更
throughput18.png
トピック対応を行い、スループット計測を行う処理を一部変更
throughput19.png
■UDP送信性能(IPフラグメント)
計測コマンド:「iperf -s -u -p 10000 -i 10 -l 5888」
throughput17.png
■UDP受信性能(IPフラグメント)
計測コマンド:「iperf -u -c 172.16.0.95 -p 12345 -l 5888 -i 10 -b 960M -t 200」
throughput16.png
■カスタマイズ設定後のスループット性能
TCP送信性能:434Mbps
TCP受信性能:948Mbps
UDP送信性能:518Mbps(IPフラグメント無しの場合) → 376Mbps(IPフラグメント有りの場合)
UDP受信性能:813Mbps(IPフラグメント無しの場合) → 960Mbps(IPフラグメント有りの場合)

■コンフィグレーション内容まとめ(※1)
Ethernetドライバの送受信タスクの優先度 = 4(※2)
スループット計測タスク(ThroughputTask)の優先度 = 5(※2)
TCP送信バッファサイズ(CFG_TCP_SND_WND) = 16384
TCP受信ウィンドウサイズ(CFG_TCP_RCV_WND) = 32768
UDP受信キュー数(CFG_PKT_RCV_QUE) = 255
Ethernetドライバ送信ディスクリプタ数 = 4
Ethernetドライバ受信ディスクリプタ数 = 18

※1:色々試した結果、上記の設定で一番性能を出す事が出来ました。
   ただ、環境によって適切な値があると思うので参考値としてください。
※2:性能的にはEthernetドライバ > アプリケーションタスクの優先度の方が良い結果が出ます

■その他・補足
本サンプルはuC3/Standardをベースでのサンプルとなっています。
uC3/Compactで同様の事をやる場合は以下の点に注意してカスタマイズしてください。

1.CompactではコンフィグレータでTCPソケットの送信バッファや受信ウィンドウサイズをカスタマイズする機能があります。
  従って、送信バッファや受信ウィンドウサイズを変更する場合はコンフィグレータから変更してください。
  ※ソケット生成の仕組みがStandardとは異なる為、net_cfg.hのCFG_TCP_SND_WNDやCFG_TCP_RCV_WNDの値を直接変更したとしても設定値として反映されないので注意が必要です。
2.CompactとStandardでは、del_soc()などいくつかサポートされていないAPIが存在します。
  従って、Compactに本サンプルを適用する場合はサポートされていないAPIの処理は削除してください。

返信する