如何监控程序的IO

How to monitor IO of a program

这个用 c++ 编写的开源科学应用程序往往会在短时间内生成大量小写入(使用 ofstream)。我正在修改代码,这样IO就不会那么频繁了。

它真的只是 opens/writes 一两个文件。程序为 运行 时监控 IO 频率的最佳方法是什么?或者监控某些文件的写入频率?

编辑: 在我将所有 "endl" 更改为“\n”之后,strace 显示程序正在使用原始代码执行大量 "writev" 而不是 "write"。这是strace输出比较。

之前:

write(4, "+\n", 2)                      = 2
write(4, ">>=@ABCEDBCFBEACDDCDDCBBCCDDCFAC"..., 77) = 77
write(3, "@C3A7DACXX140502:1:1314:6663:801"..., 37) = 37
write(3, "CATCAAACAAGATATGGATGTAGAACGCTCAG"..., 77) = 77
write(3, "+\n", 2)                      = 2
write(3, "?@>CCCDEDDFBDBCECCCEBAECCD@DDEDE"..., 77) = 77
write(4, "@C3A7DACXX140502:1:1314:6663:801"..., 37) = 37
write(4, "TTAGACAATGTAGTGAAATAGTTACTTTGGGG"..., 77) = 77
write(4, "+\n", 2)                      = 2
write(4, "==:BABBCDFBCEBECABBBE@B?DCDBDDCC"..., 77) = 77
write(3, "@C3A7DACXX140502:1:1314:6664:692"..., 36) = 36
write(3, "CAAAGACAGGTATGGAGACAGGAGAAGGGAGC"..., 77) = 77
write(3, "+\n", 2)                      = 2
write(3, ";=;3=6.?A'7*:;@AA=@@?C>.++68>),)"..., 77) = 77
write(4, "@C3A7DACXX140502:1:1314:6664:692"..., 36) = 36
write(4, "ACAAGATGTCTTCGGAGTTTCCGGGATAGCCA"..., 77) = 77

之后:

writev(3, [{"\n@C3A7DACXX140502:3:1209:20544:1"..., 8186}, {"ACCTCCTCCTGCTTTCACCTATCCCGCTTCAC"..., 76}], 2) = 8262
writev(4, [{"\n@C3A7DACXX140502:3:1209:20544:1"..., 8186}, {"GATCCTCGTCAGTCCTGAAGGAGTGTCAGCTT"..., 76}], 2) = 8262
writev(3, [{"\n+\nBA@CDEEEDEFEDBBDCDBDBCDCB@DDB"..., 8148}, {"??>ABEEECADDBBABBDCEBDCDCBECDBC@"..., 76}], 2) = 8224
writev(4, [{"\n+\n>>;ABCD@BEDFCDCDECCECCE?DADCE"..., 8148}, {">>;ABABBDDECEDECECCCECBBECCDDDFD"..., 76}], 2) = 8224
writev(3, [{"\n@C3A7DACXX140502:3:1209:20618:6"..., 8184}, {"TTGGAAGGCCAGGTCCAGTAACCGGCCCCATT"..., 76}], 2) = 8260
writev(4, [{"\n@C3A7DACXX140502:3:1209:20618:6"..., 8184}, {"ATTAGTAATTTCAGTGCCTCCTCCATCTTTAG"..., 76}], 2) = 8260
writev(3, [{"\n+\n?@>CCDFEEDDDCBDBDEBBCDB@CDBBB"..., 8148}, {"B@<DDDDFCEDEBBDDBDBDC@EBBECDDCEC"..., 76}], 2) = 8224
writev(4, [{"\n+\n>=;?C@?CBCCEDEAEDCDDBDDBDCDEB"..., 8148}, {">><A@BED@DDBDECBCBECCECDBDCDBEED"..., 76}], 2) = 8224
writev(3, [{"\n@C3A7DACXX140502:3:1209:20684:3"..., 8180}, {"ACCCAAATGAGATCTGTGTGCCAATGTCAGTG"..., 76}], 2) = 8256
writev(4, [{"\n@C3A7DACXX140502:3:1209:20684:3"..., 8180}, {"TCATCTGTGAACTCCACCAAGTTTTGTGCCTC"..., 76}], 2) = 8256

这是否意味着它正在写入缓冲区而不是刷新文件?

IO 调整和性能改进既困难又耗时 - 您必须找出应用程序的 IO 模式并将代码和硬件与之匹配。甚至可能调整您的文件系统,您甚至可能首先根据您的 IO 要求 select 文件系统。这有点像为了获得最佳性能而进行阻抗匹配的电气元件 - 当您想要在设计极限下驱动系统时,从应用程序代码到磁盘磁头本身的一切都很重要。

并且您不能在系统设计限制下驱动系统,同时由于 C++ IO 层等软件抽象而忽略设计...

  1. 分析您的应用程序以确定 IO 性能是否是瓶颈。如果 IO 没有瓶颈,提高 IO 对应用程序性能的帮助不大。

  2. 运行 strace 下的应用程序,看看幕后发生了什么。应用程序是否执行了大量 seek()/lseek() 系统调用?这些会使 C++ 运行时库完成的任何缓冲无效,这将需要改进的 IO 方法。

  3. 如果您确实发现您的应用程序需要提高其 IO 性能,您可能需要在不使用 C++ IO 例程的情况下重做 IO - 它们并不快。看这里:std::fstream buffering vs manual buffering (why 10x gain with manual buffering)?.

  4. 如果你只是 reading/writing 大数据流而根本不寻找并且在数据从缓存中刷新之前不重新读取数据,那么内核页面缓存只是让你慢下来。使用较低级别的基于 C 的 IO 例程,使用页面对齐内存 read/write 您的数据,并在打开时使用 O_DIRECT 标志以执行直接 IO 并绕过内核页面缓存。