2010-07-08 78 views
6

我的程序並行讀取數十個非常大的文件,每次只讀一行。看起來主要的性能瓶頸是硬盤從文件到文件的尋道時間(儘管我不完全確定如何驗證這一點),所以我認爲如果我可以緩衝輸入,速度會更快。如何用boost :: iostreams更改緩衝區大小?

我使用C++這樣的代碼,通過升壓來閱讀我的文件:: iostreams的「流過濾」:

input = new filtering_istream; 
input->push(gzip_decompressor()); 
file_source in (fname); 
input->push(in); 

按照documentationfile_source沒有任何辦法來設置緩衝區的大小,但filtering_stream ::推似乎:

void push(const T& t, 
    std::streamsize buffer_size, 
    std::streamsize pback_size); 

所以,我想input->push(in, 1E9)其實我心裏想程序的內存使用量飆升,但速度一點都沒有改變。

我只是錯了,讀緩衝會提高性能?或者我做錯了嗎?我可以直接緩衝一個file_source,還是我需要創建一個filtering_streambuf?如果後者,這是如何工作的?該文檔並不完全是例子。

回答

2

你也應該剖析它,看看瓶頸在哪裏。

也許它在內核中,也許你的硬件的限制。直到你分析它,發現你在黑暗中磕磕絆絆。

編輯:

好,更完整的答案這一次,然後。根據Boost.Iostreams文檔basic_file_source僅僅是圍繞std::filebuf的封裝,其依次建立在std::streambuf上。引用文檔:

以只讀模式打開的std :: basic_filebuf的CopyConstructible和Assignable包裝器。

streambuf確實提供了一種方法pubsetbuf(不是最好的參考也許,但在第一谷歌翻起),它可以,顯然,用來控制所述緩衝器大小。

例如:

#include <fstream> 

int main() 
{ 
    char buf[4096]; 
    std::ifstream f; 
    f.rdbuf()->pubsetbuf(buf, 4096); 
    f.open("/tmp/large_file", std::ios::binary); 

    while(!f.eof()) 
    { 
     char rbuf[1024]; 
     f.read(rbuf, 1024); 
    } 

    return 0; 
} 

在我的測試(優化過,雖然)事實上,我更糟糕的表現與4096個字節的緩衝區比16個字節的緩衝區,但情況因人而異 - 一個很好的例子,爲什麼你總是應該個人資料首先:)

但是,正如你所說,basic_file_sink不提供任何手段來訪問它,因爲它隱藏其底filebuf在其private part

如果你認爲這是錯誤的,你可以:

  1. 敦促加速開發人員能夠將這樣的功能,使用郵件列表或TRAC。
  2. 構建您自己的filebuf包裝,它確實暴露了緩衝區大小。本教程中有一個section,它解釋了編寫自定義源可能是一個很好的起點。
  3. 根據任何內容編寫自定義源代碼,完成所有您喜歡的緩存。

請記住,您的硬盤驅動器以及內核已經對文件讀取進行了緩存和緩衝,我認爲您不會從緩存中獲得更多性能提升。

而最後,關於剖析的一個詞。有很多功能強大的分析工具可用於Linux,我甚至不知道其名稱中的一半,但例如有iotop,這是一種整潔,因爲它非常簡單易用。它非常像頂級,但是卻顯示了與磁盤相關的指標。例如:

Total DISK READ: 31.23 M/s | Total DISK WRITE: 109.36 K/s 
TID PRIO USER  DISK READ DISK WRITE SWAPIN  IO> COMMAND   
19502 be/4 staffan 31.23 M/s 0.00 B/s 0.00 % 91.93 % ./apa 

告訴我,我的程序花費了超過90%的時間來等待IO,即它的IO限制。如果你需要更強大的功能,我相信谷歌可以幫助你。

請記住,在熱或冷高速緩存上進行基準測試會極大地影響結果。

+0

也許這是另一個帖子的問題,但我將如何描述它?我知道如何使用gprof,但它只告訴我CPU時間,在這裏我很確定瓶頸是磁盤I/O。 或者如果有人能告訴我如何正確設置緩衝區大小,我可以試試看看是否有幫助。 – user387250 2010-07-10 02:07:19

+0

@jwfoley:我喜歡[Valgrind's](http://valgrind.org/)callgrind分析器。就我的經驗而言(讀作:我不能保證任何事情),它也報告了在內核調用中花費的時間,這是我永遠無法獲得gprof所做的事情。例如,我用它來剖析一個使用OpenGL的應用程序,並正確報告在視頻驅動程序代碼中花費的時間。它非常易於使用(valgrind --tool = callgrind ./your-app)。使用[KCachegrind](http://kcachegrind.sourceforge.net/html/Home.html)解釋結果。唯一的問題是你的應用程序在分析時會運行20次左右。 – Staffan 2010-07-10 02:17:35

+0

@Staffan:好的,我試過callgrind + KCachegrind,我對Profiler印象深刻,但我仍然不知道自己在找什麼。結果看起來很像gprof's。稱爲T.3577的東西有很高的「包含」。但低「自我」;大部分時間似乎都花在std :: basic_ios上。也許這就是磁盤I/O? 我仍然想回答我如何設置緩衝區大小的原始問題。如果這很容易,那麼我可以嘗試一下,看看它是否有幫助,但無論如何它都是有用的。 – user387250 2010-07-12 21:41:50