0

私は約1000枚の画像を読み取り、その内容の統計要約を作成するプログラムを持っています。各イメージはOpenMPを使用して独自のスレッドで処理され、プロセッサの数に合わせてスレッド制限を設定しています。

約2週間前まで、プログラムは正常に実行されていました。ただし、プログラムを複数回実行すると、システムの速度が低下し、最終的にフリーズします。

トラブルシューティングを行うために、プログラムが実行していることをエミュレートする以下の簡単なコードを作成しました。このコードは、35行目で数個のファイルのみを読み取ろうとした後、元のプログラムと同じようにシステムをフリーズします。

プログラムを実行し、失敗するたびに以前のカーネルに続けて戻しましたが、バージョン3.6.8までのすべての3.6カーネルで失敗することがわかりました。

ただし、カーネル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 }       

Makefile:

  1 a:$
  2     g++ -fopenmp -Wall -o test -g test.cc$
  3     ./test$

私の質問は、このプログラムが失敗する原因となるが、バージョン3.5では失敗しないカーネル3.6の違いは何ですか?

4

2 に答える 2

1

コードを確認せずに、プロセスに制限を設定したい場合は、リソースの使用を制限するためのcgroupを参照してください。

フリーズに関しては、GB単位のデータを一度にディスクに読み書きしようとしています。今日のハード ドライブの速度が ~100MB/秒であることを考えると、カーネルがキャッシュをディスクにフラッシュすることを決定した時点でフリーズが発生することが予想されます。メモリ不足のディスクから (大量のメモリを割り当てたため、キャッシュのスペースは限られています)。

ファイルを試すmmap()か、カーネル I/O スケジューラを変更してください。

于 2012-11-28T16:34:25.107 に答える
0

私はあなたのコードを深く調べていませんが、いくつかの悪い習慣に気づきました(少なくとも、私はそれらがそうであると思います):

  • まず、criticalopenmpループ内のセクション。それは同期のポイントであり、すべての反復にそれを入れることは私にはちょっと問題があるように聞こえます。各スレッドは他のスレッドがそこに入っていないことを確認する必要があるため、おそらく同期によって生じるオーバーヘッドはスレッドの数とともに増加します。

  • 2番目:私はC ++にあまり慣れていませんが、vector<char> a (SZ)実行されるたびにメモリが割り当てられます(そしてブロックの最後で解放されます)。私が間違っていたらすみません。vector<vector<char> >SZの値は事前にわかっているので、並列領域の前にスレッドと同じ数の要素を割り当てた方がよいでしょう。次に、並列領域で、各スレッドにそのスレッドへのアクセスを許可しvector<char>ます。

于 2012-11-29T17:09:30.403 に答える