基於solarflare的openonload技術以TCPDirect方法加速epoll

【前言】基於solarflare的onload模式加速,官方文檔給出TCPDirect模式能夠實現從300ns到30ns的延遲縮減。咱們須要測試在咱們的交易模型框架中他的延時,有人給出了tcpdirect加速大約會比onload模式快300ns左右,不是倍數關係,是一個數量差。雖未達如此高速交易,但量化交易,分秒必爭。可是tcpdirect有一個缺點就是必須使用它的接口,不像onload只須要安裝好加速環境,使用onload模式就能夠了。TCPDirect須要拿到源碼,並重寫底層。html

  咱們實現一個類epoll-socket,TCPDirect使用了muxer,實現叫作zocket,進行RTT測試。react

1、server端

  對應epoll,咱們使用muxer實現,和epoll接口相似。c++

  一、注意後面要釋放掉建立的zf_muxer_free(muxer);sql

  二、由於咱們使用內核旁路技術,不要使用zf_recv()函數,雖然他有返回接收數據的大小,可是他是基於copy的,使用zf_zc_recv()。mongodb

  三、每次在使用接口有數據交換或者使用硬件時,要使用zf_reactor_perform(stack);,由於咱們的zocket是運行在一個初始化的stack上的,每次都要用此接口來進行「初始化」,文檔這樣寫的,我也不清楚。服務器

  四、其餘的和epoll不一樣之處要悉心,好比無需綁定,用zft_listen()綁定,zf_zc_recv和zf_send的存儲的數據結構也不相同,下面有個人兩種數據的轉換存儲方式,由於在服務器端須要進行一個轉存;數據結構

  五、測試時間的核心程序:框架

ZF_TRY(zf_muxer_add(muxer, zft_to_waitable(zock), &evs[i]));
 //初始化stack           
zf_reactor_perform(stack);
rd1.zcr.iovcnt = 1;
HP_TIMING_NOW(t0);
zft_zc_recv(zock, &rd1.zcr, 0);
if( rd1.zcr.iovcnt == 0 )
    continue;
if( first_recv ) {
    first_recv = 0;
    siov.iov_len = rd1.zcr.iov[0].iov_len;
    memcpy(buf, ((char*)rd1.zcr.iov[0].iov_base),siov.iov_len);
    }            
for( int i = 0 ; i < rd1.zcr.iovcnt; ++i ) {
    len3=zft_send(zock, &siov, 1, 0);
    }
    HP_TIMING_NOW(t1);
     //c++11的元組,編譯時候可能要加上-std=c++11           
    time_v.push_back(std::make_tuple(len3,t1, t0, (t1 - t0)));
    cout<<"服務器發送:"<<len3<<"數據:"<<buf<<endl;
            
    zft_zc_recv_done(zock, &rd1.zcr);

2、客戶端

  一、初始化的stack可能會用完,要加上ZF_TRY(zft_send_space(tcp,&send_size));,send_size是一個傳出參數,返回tcp鏈接的棧剩餘空間,小於目標大小的時候要判斷,而後從新分配,咱們僅是實現測試,足夠我用;nosql

  二、測試結果,就在客戶端。咱們須要發送和其餘模式下一樣的數據,到server,而後返回,client再收到所用的時間。socket

  三、發送和接受和server同樣注意,此處無需裝換;

  四、輸出結果的代碼,使用tuple。mongodb那種nosql能夠用這種數據組織方式存儲。

std::vector<std::tuple<int, u64_t, u64_t, int>>::iterator it;
for (it = time_v.begin(); it != time_v.end(); ++it) {
     cout << "len=" << std::get<0>(*it) << " --- recv time = " << std::get<1>(*it) << ", send time = " << std::get<2>(*it)
           << ", gap = " << std::get<3>(*it) << endl;
   if (it != time_v.begin()) {
          sum += std::get<3>(*it);
          ++num;
        }
    }
#第一個時間是jiffies,要除以本機的cpu主頻

 std::cout << "avg gap = " << (sum / (num*1.0) ) << endl;
 std::cout << "avg gap(ns) = " << (sum / (num*3.4)) << endl;

(關於jiffies和cpu頻率的關係:https://www.cnblogs.com/by-dream/p/5143192.html   相除就是時間)

    使用tcpdirect在char類型511字節數據上,進行RTT測試,循環1000次的平均用時3444納秒(3.5微秒)左右。

  具體和普通socket、使用onload加速的對比:

  固然,這只是個別。我大約測了10次,平均值大約如此。

3、收穫心得

一、學會了初步的gdb- 對於coredump狀況調試方法,學會了一些分析錯誤的思路。

 二、tcpdump抓包分析,wireshark分析。

相關文章
相關標籤/搜索