openmp DLLの不具合 | 並列化フォーラム | フォーラム

iSUS に投稿されている記事の内容や、IA プラットフォーム上でのソフトウェア開発に関するトピックを開発者同士でディスカッションできる場としてフォーラムを公開しています。

運営ルールはフォーラムの利用案内をご覧ください。
フォーラムの使い方はこちら

 
フォーラムに投稿するにはログインが必要ですログイン

openmp DLLの不具合

メンバー投稿

9:52 PM
2012年4月3日


yoshihingis

投稿数 54

1

投稿は 9:53 PM – 2012年4月3日 に yoshihingis さんにより更新されました


 最近、遭遇した問題で、openmpを使用したコードのDLLのメモリーリークという問題があります。
 VC2010で最初はマイクロソフトコンパイラでビルドしたところ、openmpを使用したDLLをLOADして、処理終了後、FreeLibraryを行うと「例外ハンドル」のエラーが出てプログラムが停止。
 マイクロソフトコンパイラのopenmp用DLL Vcomp100.dllの仕様の様です。
 VC2005で同じコードをビルドすると、「例外ハンドル」ですぐには落ちませんが、パフォーマンスモニターで、Private Byteで並列化した処理を見るとメモリーリークでどんどん使用メモリが増えて行き、LOAd,FreeLibraryを1000回も行うと確実に落ちます。
 インテルコンパイラのcomposer XE UPDATE8のlibomp5md.dllはメモリーリークは無かったのですが、UPDATE9のlibopmp5md.dllはマイクロソフトと同様のメモリーリークが生じます。
 現在、サポートの方を通じてインテル様にお問い合わせ中です。

 マイクロソフトのメモリーリークはpragmaでスレッド数を1にして、等価的にopenmpをDLLの最後で切れば、「例外ハンドル」やメモリーリークは発生しません。

並列化処理はこれから避けて通れませんし、openmpを使用したコードをDLLにして呼び出すなど、これから、当たり前の事になりますので、マイクロソフトさんにもインテルさんにも早く改善して欲しい仕様です。

 どなたか試されて違う結果や良い解決方法が有りましたらご教授ください。

6:19 PM
2012年4月4日


iSUS編集部 – 菅原

投稿数 206

2

投稿は 6:23 PM – 2012年4月4日 に iSUS編集部 – 菅原 さんにより更新されました


yoshihingisさん

レポートありがとうございます。

この問題に関するサンプルコードを作ってみました。以下のDLLを/Qopenmp オプションでコンパイルし、メインルーチンから呼び出して実行すると、ランタイムでメモリーエラーになります。

いろいろ試してみたところ、メインルーチンではOpenMPを使用していませんが /Qopenmp オプションでコンパイルすると、エラーは発生しなくなりました。

シリアルのランタイムと、OpenMPランタイムの移行でリークが発生している可能性があります。yoshihingisさんも、メインルーチンにOpenMPオプションを付けて試してみてください。

以下ソースです。

::::::::::::::::: OpenMP DLL::::::::::::::::::::::
#include "windows.h"

BOOL WINAPI DllMain( HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
{
return TRUE;
}

double __stdcall pi(int num)
{
double pi, sum = 0.0, step;

step = 1./(double)num;
#pragma omp parallel for reduction(+:sum)
for(int i=0; i<num; i++){
double x = ( i + 0.5) * step;
sum = sum + 4.0 / (1.0 + x * x);
}
pi = sum * step;
return (pi);
}

:::::::::::::::: Main ::::::::::::::::
#include "windows.h"
#include "iostream"
#include "time.h"

HINSTANCE hDll;
double ( __stdcall *PI)(int);

void main(void)
{
double start, end;
int loop=0;

LOOP:
hDll = ::LoadLibraryEx("OpenMP_dll.dll",NULL,0);
if( ! hDll ){
std::cout << "dll open error";
return;
}

PI = (double(__stdcall*)(int)) ::GetProcAddress( hDll,"pi");
if( ! PI ){
::FreeLibrary( hDll );
std::cout << "dll read error";
return;
}

start = clock();
double pi = PI(1000000);
end = clock();

::FreeLibrary( hDll );

// std::cout << "Pi = " << pi << std::endl;
// std::cout << "Time = " << (end-start)/CLOCKS_PER_SEC << std::endl;
if(loop++ < 1000){
std::cout << loop << " " ;
goto LOOP;
}
}

8:41 PM
2012年4月4日


yoshihingis

投稿数 54

3

菅原様、貴重なご助言ありがとうございます。
 早速、試してみたいと思います。が、実は、呼び出し側はかなり昔にコードが書かれておりVisual Studio2003で書かれたコードなので、openmp非対応なのです。
 このコードをもちろんVS2005以降で通るようにすればいいのですが、VS2003->2005の時に、C++の文法など一部厳密になり、現在のコードをVS2010などでビルドするとErrorとWarningが大量に出まして、みんなリファクタリングとVs2010対応へのアップデートが必要と思いつつ、手つかず状態なのです。
 ある製品に搭載されているコードで、非常に多機能なコードなので、VS2010対応に修正すると、修正後の製品の検証も膨大な工数となるため、なかなか難しい状態です。
 Microsoftのopenmp DLLは、この不具合はすでに「仕様」と開き直っているようですので、後はIntelさんのopen MP DLLが修正されることを祈るばかりです。
 今後はCilk plusの製品搭載も視野に入れてますので、Cilkでも同様の現象が起こらないよう祈るばかりです。

1:56 PM
2012年4月5日


yoshihingis

投稿数 54

4

マイクロソフトのopenmpのDLLでの同じ不具合は以下のサイトに記述されています。
http://connect.microsoft.com/V…..ses-openmp

2010/07/21のMicrosoftからの投稿にはこの回避策らしいものが2つ記述されています。
(1)
A workaround, if you need one, is to wait for 1 second prior to calling FreeLibrary(), which gives the openmp threads a chance to sleep forever (via WaitForSingleObject). The threads will die when the application closes.

これは、FreeLibraryを実行する前に1sec待てということでしょうが、数10msecを高速化するためにopenmpを使用する場合もあるのに、1sec待てというのは解決策になってない気がします。

(2)
Another potential workaround is to use the DLL CRT & openmp runtime as opposed to statically linking the CRT & openmp. The thread pool should be allocated in the system-wide vcomp100.dll instead of in OmpTestLib.dll.

これがちょっと知識不足もあり理解できてない解決策です。DLL CRT & openmpを使用せよ!ということだと思いますが、具体的にビルドの仕方をどのように変更したらよのでしょうか?もし、この記事を御覧になり、この回避策の具体的なビルド方法が分かる方がおりましたら、ご教授いただければ幸いです。

 なお、これはあくまでマイクロソフトのopenmp DLLに関する問題の解決策なので、インテルのopenmp DLLで同じ手法で問題を回避可能かは分かりません。
 今後、実験してみる予定ではりますが・・・。

2:55 PM
2012年4月5日


iSUS編集部 – 安

5

こんにちは、Input します。

おそらく、DLL のビルドには、/MD コンパイラーオプションと動的 OpenMP ライブラリー(vcomp100.dll)をご使用ください、ということだと思います。そうすれば、Thead Pool が OmpTestLib.dll に属することなく、べつ DLL(vcomp100.dll)に属することになるのでこの問題が回避できるのではないか、ということなのかもしれません。しかし、あくまでも "Potential Workaround" であるようです。

3:21 PM
2012年4月5日


iSUS編集部 – 菅原

投稿数 206

6

いろいろワークアラウンドはあるようですが、先におすすめした方法が確実です。
ソースの全体のリコンパイルが不可能であれば以下の手順を検討ください。

1)Winmainもしくはmainルーチンを別ファイルに切り出す。
2)切り出したメインをICLで /Qopenmp /c オプションで obj を作成
3)VS2003環境に上記Objをインポート(この際libiomp5md、libmmt、libirc、libdecimal、svml_dispmtがリンクで要求されるので、ICLのlibへパスを通しておく)、VS2003プロジェクトはVCでコンパイルしてもOK。
4)DLLはICLでビルドする

ICLは/OpenMPオプションでメインがコンパイルされると、OpenMP実行環境の初期化ルーチンが呼び出されます(VCではない)、その際プロセス内のスタック等がDLLでOpenMPが利用されても整合性が取れるようになります。

ちなみに前述のサンプルコードを10000回以上 load, Free しても大丈夫でした。

4:17 PM
2012年4月5日


yoshihingis

投稿数 54

7

安様、菅原様、貴重なご助言ありがとうございました。
 菅原様のご提案が、現在、もっとも確実な方法だと思いますので、今後はその方法を用いたいと思います。

 解決方法を一応、ご教授頂き、安心しました。
 
 一点、気掛かりなのは、IPPやMKLなどのライブラリーも中身はOPENMPを使用していると聞いております。したがって、IPPやMKLを使用したDLLを作成した場合、菅原様のご提案の対応策を打たないとメモリーリークを起こして、落ちる可能性があるという考えでよろしいのでしょうか?

 IPPでもマルチスレッド化対応のライブラリと非対応のライブラリがありますが、マルチスレッド対応のライブラリを使用してDLLを作成した場合には、メモリーリーク対策を打っておいた方が安全なのでしょうかね?

4:32 PM
2012年4月5日


iSUS編集部 – 安

8

こんにちはー。またインプットさせていただきます。

同じ現象になる可能性はあるかと思いますが、IPP、MKL でマルチスレッドバージョンのライブラリーをリンクした場合は、libiomp5md.dll は、MKL、IPP のコアー DLL に属するかと思いますので、もしかしたらこのケースの限りではないのかもしれません。でも、いづれにしてもテストは必要かと思います。
ちょっと話はずれますが、今回は Load_DLL 側から明示的に DLL をコールしていますが、これを暗黙的コールした場合は、そもそもこの問題は発生しないものなのでしょうか・・・?ちょっと疑問に思った次第です。

4:58 PM
2012年4月5日


yoshihingis

投稿数 54

9

マイクロソフトの場合だけしかまだ実験しておりませんが

親exe(暗黙的コール)-子DLL(openmp使用DLL)の場合は問題は生じません。

ただし

親exe(明示的コール)-子DLL(暗黙的コール)-孫DLL(openmp使用DLL)だと親でFreeLibraryを使用したところで、メモリーリークが発生します。

ということで、すべて暗黙的コールでDLLを呼び出さないとメモリリークは発生します。インテルの場合はまだ試していませんので、今後、確認が必要と思っています。

5:29 AM
2012年4月6日


iSUS編集部 – 菅原

投稿数 206

10

実はIPPやMKLで作ったDLLも同様の問題があるようです。

12:27 PM
2012年4月6日


yoshihingis

投稿数 54

11

IPPやMKLで作成したDLLでもメモリーリークの不具合が発生するようですが、スレッド数を1に設定しておけば問題ありませんでしょうか?
 JPEG Losslessなどはアルゴリズム自体が本質的に並列処理に向かないIPPのライブラリでは、最初からスレッドを1にして使用する場合もあります。
 スレッド数1の設定で、IPPやMKLのライブラリが問題なければ安心なのですが・・・。

8:54 AM
2012年4月10日


yoshihingis

投稿数 54

12

菅原様 今回のopenmpのDLL libomp5md.dllのメモリーリークは、UPDATE8のlibomp5md.dllでは発生しませんが、Ipp,MKLでもバージョンが古いと発生しないのでしょうか?
 もしバージョン依存が有り、問題を起こすバージョンと問題が起きないバージョンが有り、バージョンによっての症状をご存知ならお教えいただければ幸いです。

 Ipp,MKLでもDLL化して、明示的なリンクでLOAD,FreeLibraryを行うとメモリーリークを発生するのでしょうか?

 その辺の情報をご存知の方がいましたら、是非、情報共有していただければ助かります。

 

3:25 AM
2012年4月11日


iSUS編集部 – 菅原

投稿数 206

13

yoshihingis 様

Update9に含まれるIPPとMKLでマルチスレッドが有効なDLLを作成すると同様の問題が発生します。これは、APIや環境変数でスレッド数を1に設定しても解決できません。(呼び出し側のメインルーチンを含むソースを/Qopenmp オプションでコンパイルすると動作します)

マルチスレッド処理を行うIPPやMKLでは、OpenMPランタイムを利用するため、問い合わせいただいたDLL版と同様の動作になります。古い環境ではまだ未確認ですが、コンパイラーに含まれるランタイムの動作と同様と考えられます。

サポートにお問合わせ中とのことですが、最終回答はそちらの返答をお待ちください。

9:10 AM
2012年4月11日


yoshihingis

投稿数 54

14

菅原様、ご助言ありがとうございます。
 今後、インテルコンパイラでopenmpを使用する場合、MKL,IPPを使用する場合の注意点とさせていただきます。

 マイクロソフトの方は、Visual Studio11 β版で試してみましたが、openmp用のDLL vcomp110.dllはVS2010のvcomp100.dllと同じ挙動で、メモリーリークが起こることを確認しました。マイクロソフトのopenmpは将来的にこの不具合が修正されることはないようと推測しております。

8:40 AM
2012年7月6日


yoshihingis

投稿数 54

15

 Intel Compser UPdate9,10では、OPenMP DLL libiopm5md.dllを使用した
DLLで、DLLの呼び出し側でOpenMPを使用しないと、メモリリークが発生したり、プログラムがすぐ落ちるといった症状が発生したことを以前、報告させていただきましたが、最新版のComposer UPDATE11のlibiomp5md.dllではこの不具合は改善されたようです。
 
 特にDllの呼び出し側をOpenMP ONにしなくても、Load,FreeLibraryを1万回繰り返しても、メモリリークや、例外ハンドルでプログラムが落ちるといった症状は出ませんでした。
 libiompm5md.dllをUPDATE10の物に換えるとすぐプログラムが落ちることも確認しましたので、UPDATE11で不具合が修正されていることは、間違いないようですので、ご報告させて頂きました。

10:40 AM
2012年7月6日


iSUS編集部 – 菅原

投稿数 206

16

いただいた事象をインテルの開発チームにインプットしていましたが、直ってよかったです。エンジニアからはなぜ直ったか、まだ理由が説明されていないのですが、OpenMPランタイムで解決したようですね。

ご報告ありがとうございます。