2010-08-03 50 views
0

我的程序正在经历一个令人讨厌的性能下降。它基本上是一对嵌套for循环,它执行一对数据集的操作,然后写入结果。问题在于,300,000对中的约500对在0.07秒/对到5秒/对之间变慢,并且CPU使用率从接近100%下降到〜4%。所有使用的内存都在嵌套循环之前分配,并在循环之后释放。与C程序剧烈CPU下降

这里是伪代码,这样你就可以有希望的想法:

for (i=0; i<759; i++) { 
    read_binary_data(data_file_1, data_1); 
    read_binary_header(header_file_1, header_1); 
    for (j=i+1; j<760;j++) { 
     read_binary_data(data_file_2, data_2); 
     read_binary_header(header_file_2, header_2); 

     do_operation(data_1, data_2, out_data); 
     update_header_data(header_1, header_2, out_header); 

     write_binary_data_and_header(out_data, out_header); 
    } 
} 

我已经把时序标志的开头和第二个for循环看到上面引述的时机结束,但我想知道如果可能有更好的调试选项来显示操作速度减慢的原因。到目前为止我唯一的想法是文件系统阻塞,但是我只在每次运行时打开5-6个文件,每个文件在其子程序结束时都关闭。

下午10点15分更新太平洋时间:
经过各种测试,我发现罪魁祸首似乎是在read_binary_data部分。许多文件可能需要3秒以上。我将尝试将所有二进制数据打包到一个文件中并一次读取,因此我只需要读取一个。我敢打赌我会用完内存,但它值得一试,如果发生这种情况,我就不那么雄心勃勃,并且尝试每次少于760 * 2 * 31 * 43201浮点数组我想这应该在16 GB左右?)。

+0

“但我只在每次运行时打开5-6个文件,每个文件在子程序结束时都关闭” - 这怎么证明它不是文件系统阻塞? – nos 2010-08-03 21:45:14

+0

我想它并不能证明它,但我认为我尝试打开文件的次数越少,阻止文件系统的可能性就越小。 – robporritt 2010-08-03 21:48:54

回答

5

你是否释放了你持有数据的缓冲区?这听起来像是你已经耗尽内存,并在500个文件后切换到交换。你的内存使用情况如何?

+0

我没有释放任何缓冲区,我只是重复使用相同的内存位置并覆盖不再需要的内容。 Top通常显示内存低于1%(最大内存使用量在data_1和data_2中,这是浮点数组,在磁盘上大约为20mb) – robporritt 2010-08-03 21:41:40

+1

您的文件有多大?如果你注释掉do_operation()和write()以便你正在读的所有内容会发生什么呢?同样,如果你注释掉read_data()和do_operation,以至于你只是写了什么呢?你的机器有多少内存? – Amoss 2010-08-03 23:38:29

+0

这些文件都是2 * 31 * 43201浮点阵列,我相信它是一个带有6GB内存的i7。 do_operation()实际上只是main中的一个长序列的简写(坏 - 我知道)。快速评论阅读和快速阅读。 – robporritt 2010-08-04 05:13:12

2

涌现在脑海,尽管你的要求是内存不被分配循环中的第一件事情,是

  • 内存泄漏
  • 内存碎片
  • 缓存饱和

没有关于实际情况的更多细节,比如你正在运行的环境或者你的函数正在调用的其他函数,那么真的不可能推测更多。问题太抽象了。

3

也许你对文件的写作效率低下,随着你的进步,你需要做更多的寻找?

也许会将写入磁盘的两行注释掉,看看是否得到一致的运行。

否则,它可能是您的阅读。很难看到你是如何实际完成文件操作的,但很容易以非常昂贵的方式来完成。

无论哪种方式,如果你的CPU是低,你的内存不足,请您留下了阻塞I/O操作!

0

除非您分配太多内存以致系统开始交换,否则您是I/O绑定的。

2

首先到您的实际问题 - “C”没有调试选项来处理I/O性能或任何其他类型的性能。你的IDE,调试器或操作系统可能,但我恐怕不知道任何细节。

愚蠢的问题 - 所有的循环产生相同数量的输出吗?也许前500名是小的。

可能是500循环是填充磁盘写入缓存需要多长时间(在一个或多个级别 - 进程,操作系统,硬件),并且在此之后程序是I/O绑定的。在不知道涉及的数据量的情况下,无法确定是否可能。

尝试将1GB的数据写入文件并计算时间,以了解持续率是否合理。如果每对0.07秒,乘以每对数据量,计算出的速度比这个速率更快,那么你的初始快速速率是一次性的特别优惠:磁盘迟早要赶上。

除此之外,更多地考虑你的输出是什么,你没有详细说明。用直线书写?来回寻找?将记录插入到磁盘上的有序数组中,以便每个写入必须平均移动目前写入数据的50%?随着时间的推移,不同的访问模式显然会有很大差异。

我假定读取缓存是无用的,所以您的读取速度将始终相当一致,所以我专注于输出而不是输入。事实并非如此,但如果电脑无法预测您的访问模式,那么这是一个相当不错的近似值。

即使如此,300000 * 5秒超过400小时。这是足够的时间让任何一台致命的计算机多次写入整个硬盘。所以你必须做一些非常奇怪的事情,因为原始写入速度是全部存在的。

+0

所有循环产生相同的输出并覆盖相同的数组。输出是一个直线写 - 开二进制文件,输出一个结构,然后将浮点数组写入一个文件中,关闭二进制文件。它在阅读中显得很慢。 – robporritt 2010-08-04 05:14:50

0

你正在做一个线性搜索类的东西。你的数据存储在一个文件中?

如果是,那么您可以一次只读取所有数据,然后将其存储在二进制搜索树中。它会减少程序的时间复杂度。