我有一个程序可以读取大约1000张图像并创建其内容的统计摘要。每个图像都使用OpenMP在自己的线程中处理,并且我设置的线程限制与我的处理器数量相匹配。
直到大约两周前,该计划运行良好。但是,现在,如果我不止一次运行程序,我的系统会慢下来并最终冻结。
为了排除故障,我编写了下面列出的简单代码,它模拟了我的程序正在做的事情。在尝试仅读取第35行的几个文件后,此代码将冻结我的系统,就像我的原始程序一样。
我运行程序,在每次失败后连续恢复到早期的内核,并发现它在所有3.6内核到3.6.8版本时都失败了。
然而,当我回到内核3.5.6时,它可以工作。
test.cc:
1 #include <cstdio>
2 #include <iostream>
3 #include <vector>
4 #include <unistd.h>
5
6 using namespace std;
7
8 int main ()
9 {
10 // number of files
11 const size_t N = 1000;
12 // total system memory
13 const size_t MEM = sysconf (_SC_PHYS_PAGES) * sysconf (_SC_PAGE_SIZE);
14 // file size
15 const size_t SZ = MEM/N;
16
17 // create temp filenames
18 vector<string> fn (N);
19 for (size_t i = 0; i < fn.size (); ++i)
20 fn[i] = string (tmpnam (NULL));
21
22 // write a bunch of files to disk
23 for (size_t i = 0; i < fn.size (); ++i)
24 {
25 vector<char> a (SZ);
26 FILE *fp = fopen (fn[i].c_str (), "wb");
27 fwrite (&a[0], a.size (), 1, fp);
28 clog << fn[i] << " written" << endl;
29 }
30
31 // read a bunch of files from disk
32 #pragma omp parallel for
33 for (size_t i = 0; i < fn.size (); ++i)
34 {
35 vector<char> a (SZ);
36 FILE *fp = fopen (fn[i].c_str (), "rb");
37 fread (&a[0], a.size (), 1, fp);
38 clog << fn[i] << " read" << endl;
39 }
40
41 return 0;
42 }
生成文件:
1 a:$
2 g++ -fopenmp -Wall -o test -g test.cc$
3 ./test$
我的问题是:内核3.6有什么不同会导致此程序失败,但不会导致它在3.5版中失败?
答案 0 :(得分:1)
如果您不想查看代码,如果您想为流程设置一些限制,请查看cgroups以限制资源使用。
至于冻结 - 你试图立即读取/写入数据的GB数据。鉴于当今硬盘的速度约为100MB / s,我预计在内核决定将缓存刷新到磁盘时会出现冻结 - 这可能会在您尝试读取相当大小的数据块时发生从内存压力下的磁盘(因为你分配了大量内存,缓存空间有限)。
您可以尝试mmap()
文件或更改内核I / O调度程序。
答案 1 :(得分:0)
我没有深入研究你的代码,但我意识到了一些不好的做法(至少,我认为他们是这样):
首先,openmp循环中的critical
部分。这是一个同步点,并且在每次迭代中将它放在我身上听起来有点问题。由于每个线程必须确保没有其他人进入那里,因此同步引入的开销可能会增加线程数。
第二:我不习惯C ++,但我想每次vector<char> a (SZ)
执行时都会分配内存(并在块结束时释放)。如果我错了,请原谅。既然您事先知道了SZ的值,那么最好在并行区域之前分配一个vector<vector<char> >
元素和线程一样多的元素。然后,在并行区域中,您将使每个线程访问其vector<char>
。