如何用boost :: iostreams更改缓冲区大小?
我的程序并行读取数十个非常大的文件,每次只读一行。看起来主要的性能瓶颈是硬盘从文件到文件的寻道时间(尽管我不完全确定如何验证这一点),所以我认为如果我可以缓冲输入,速度会更快。如何用boost :: iostreams更改缓冲区大小?
我使用C++这样的代码,通过升压来阅读我的文件:: iostreams的“流过滤”:
input = new filtering_istream;
input->push(gzip_decompressor());
file_source in (fname);
input->push(in);
按照documentation,file_source
没有任何办法来设置缓冲区的大小,但filtering_stream ::推似乎:
void push(const T& t,
std::streamsize buffer_size,
std::streamsize pback_size);
所以,我想input->push(in, 1E9)
其实我心里想程序的内存使用量飙升,但速度一点都没有改变。
我只是错了,读缓冲会提高性能?或者我做错了吗?我可以直接缓冲一个file_source,还是我需要创建一个filtering_streambuf?如果后者,这是如何工作的?该文档并不完全是例子。
你也应该剖析它,看看瓶颈在哪里。
也许它在内核中,也许你的硬件的限制。直到你分析它,发现你在黑暗中磕磕绊绊。
编辑:
好,更完整的答案这一次,然后。根据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。
如果你认为这是错误的,你可以:
- 敦促加速开发人员能够将这样的功能,使用邮件列表或TRAC。
- 构建您自己的
filebuf
包装,它确实暴露了缓冲区大小。本教程中有一个section,它解释了编写自定义源可能是一个很好的起点。 - 根据任何内容编写自定义源代码,完成所有您喜欢的缓存。
请记住,您的硬盘驱动器以及内核已经对文件读取进行了缓存和缓冲,我认为您不会从缓存中获得更多性能提升。
而最后,关于剖析的一个词。有很多功能强大的分析工具可用于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限制。如果你需要更强大的功能,我相信谷歌可以帮助你。
请记住,在热或冷高速缓存上进行基准测试会极大地影响结果。
也许这是另一个帖子的问题,但我将如何描述它?我知道如何使用gprof,但它只告诉我CPU时间,在这里我很确定瓶颈是磁盘I/O。 或者如果有人能告诉我如何正确设置缓冲区大小,我可以试试看看是否有帮助。 – user387250 2010-07-10 02:07:19
@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
@Staffan:好的,我试过callgrind + KCachegrind,我对Profiler印象深刻,但我仍然不知道自己在找什么。结果看起来很像gprof's。称为T.3577的东西有很高的“包含”。但低“自我”;大部分时间似乎都花在std :: basic_ios上。也许这就是磁盘I/O? 我仍然想回答我如何设置缓冲区大小的原始问题。如果这很容易,那么我可以尝试一下,看看它是否有帮助,但无论如何它都是有用的。 – user387250 2010-07-12 21:41:50