No | ケース | 相違点 | 原因 | |
1 | 浮動小数点例外 | VEではサブノーマル数に関連する例外は出力されません | VEアーキテクチャはサブノーマル数をサポートしないため | |
2 | スレッドの最小スタックサイズ(PTHREAD_STACK_MIN) | x86アーキテクチャでの最小スタックサイズが16KBですが、VEの最小スタックサイズは4MBです。 | ||
3 | pthread_attr_setstack()によるスレッドスタックの指定 | pthread_attr_setstackでスレッド属性オブジェクトの内部の値を変更した場合、スタックオーバーフローが検出できなくなります。そのため、pthread_attr_setstack()は使用しないでください。スタックサイズを明示的に変更したい場合、pthread_attr_setstacksize()を使用してください。pthread_attr_setstacksize()では上記のような問題は発生しません。 |
Linux
Programmer's Manualには以下の記載があります。 アプリケーションが pthread_attr_setstack() を利用する際には、 スタックの割り当てに責任を持つ必要がある。 pthread_attr_setguardsize(3) を使って設定された guard size の値は無視される。 必要と思われる場合は、アプリケーションが責任を持ってガード領域 (読み書 きが行われないように保護された 1 個かそれ以上のページ) の割り当てを行い、 スタックオーバーフローの可能性に対処するようにする必要がある。 一方、VEOSの振る舞いは異なります。ユーザによってガード領域が与えられたとしても、スタックはスタック領域の限界を超えて伸長し、予期しない結果を招くことがあります。そのため、pthread_attr_setstack()は使用しないでください。 |
|
4 | $ORIGIN変数 | x86/Linux環境ではリンク時オプションのrpath
指定やdlopen()等で"$ORIGIN"を指定した場合、プログラムや共有ライブラリがあるディレクトリに展開されますが、 VEでは環境変数"VE_LD_ORIGIN_PATH"の値が参照されます。 プログラム中で"$ORIGIN"によりプログラムや共有ライブラリがあるディレクトリを指定される場合、あらかじめ対象のパスを環境変数"VE_LD_ORIGIN_PATH"に設定してください。 |
ve_execが引数として"/proc/self/exe"を指定してreadlinkシステムコールをcallした場合、戻り値はve_execのパスとなるため。 | |
5 | "ve_exec"または"execve()"からの"ld-linux-ve.so.1"の直接実行 | x86/Linux環境ではダイナミックリンカ"ld-linux-x86-64.so.2"をコマンドとして直接実行すると引数に指定されたx86バイナリをロードすることができますが、VEではダイナミックリンカをコマンドとして実行することはできません。 | ||
6 | "ldd"コマンド | VE用 "ldd"コマンドは実行バイナリの依存リストのみ表示し、共有ライブラリについては表示しません。対して、x86_64 の "ldd" は両方の依存リストを表示します。 | lddコマンドでは内部でダイナミックリンカを実行していますが、VEではダイナミックリンカの直接実行はサポートされないため。(#5 参照) | |
7 | malloc()によるメモリアロケーションの最適化 | a) x86/Linux環境ではDEFAULT_MMAP_THRESHOLD_MAXマクロの値は32MBに設定されていますが、VEでは1GBに設定されます。 |
malloc()はサイズによってsbrk()またはmmap()を用いてメモリ領域を確保しており、"mmap_threshold"より小さいサイズの領域はsbrk()によって、それ以上のサイズの領域はmmap()によって確保します。 mmap()を使用した場合にはページサイズ単位でメモリが確保されますが、VEのページサイズは2MBまたは64MBと大きいため、x86/Linuxと同じ128kBの"mmap_threshold"ではページサイズに満たない領域に対してもmmap()が使用され、メモリが無駄に消費されてしまうケースが多くなります。 メモリの利用効率を高めるため、VEではDEFAULT_MMAP_THRESHOLDの値を1GBに設定し、1GBより小さい領域に対してはsbrk()を用いてメモリを割り当てるようにしています。 |
|
b) x86/Linux環境ではDEFAULT_MMAP_THRESHOLDマクロの値は128kBに設定されていますが、VEでは1GBに設定されます。 | ||||
c) x86/Linux環境ではmalloc()によって作成されるアリーナの最大数は有効コア数となりますが、VEでは1に設定されます。 | VEではHEAP_MAX_SIZEが2GBに設定されるため、malloc()によって作成されるアリーナのサイズも2GBとなります。 一方、glibc malloc()は通常スレッド毎に独立したヒープ領域を設定します。つまり、マルチスレッドのアプリケーションでは、スレッド内でmalloc()をcallするとそれがどんなに小さい値であったとしても2GBの領域が確保されてしまうこととなり、メモリの利用効率が著しく低下してしまいます。 この問題を避けるため、VEではmalloc()によって作成可能なアリーナの最大数1に設定しています。この結果、VEではアリーナはプロセスに対して1つだけ作成され、全てのスレッドで共用されます。 |
|||
d) x86/Linux環境ではHEAP_MAX_SIZEマクロの値は64MBに設定されていますが、VEでは2GBに設定されます。 | Glibcでは、HEAP_MAX_SIZEは通常DEFAULT_MMAP_THRESHOLD_MAXの2倍の値に設定されるため。 | |||
8 | システム環境変数の名前 | a)
VEでは、mallopt()に関連する環境変数(MALLOC_xxx)に"VE_"プリフィックスが必要です。例) MALLOC_ARENA_TEST変数をVE向けに設定する場合には、VE_MALLOC_ARENA_TESTを設定してください。 "VE_"を付加する対象は以下の環境変数です。 VE_MALLOC_ARENA_MAX VE_MALLOC_ARENA_TEST VE_MALLOC_CHECK_ VE_MALLOC_MMAP_MAX_ VE_MALLOC_MMAP_THRESHOLD_ VE_MALLOC_PERTURB_ VE_MALLOC_TRIM_THRESHOLD_ VE_MALLOC_TOP_PAD_ |
VE向けプロセスとVH(x86)向けプロセスで異なる環境変数の値を設定できるようにするため | |
b)
VEでは、memusageコマンドに関連する環境変数(MEMUSAGE_xxx)に"VE_"プリフィックスが必要です。例)
MALLOC_ARENA_TEST変数をVE向けに設定する場合には、VE_MALLOC_ARENA_TESTを設定してください。 "VE_"を付加する対象は以下の環境変数です。 VE_MEMUSAGE_PROG_NAME VE_MEMUSAGE_OUTPUT VE_MEMUSAGE_BUFFER_SIZE VE_MEMUSAGE_NO_TIMER VE_MEMUSAGE_TRACE_MMAP |
||||
c) VEでは、以下の環境変数に"VE_"プリフィックスが必要です。 VE_LD_WARN VE_LD_DEBUG VE_LD_AUDIT VE_LD_VERBOSE VE_LD_PRELOAD VE_LD_PROFILE VE_LD_BIND_NOW VE_LD_BIND_NOT VE_LD_SHOW_AUXV VE_LD_HWCAP_MASK VE_LD_ORIGIN_PATH VE_LD_LIBRARY_PATH VE_LD_DEBUG_OUTPUT VE_LD_DYNAMIC_WEAK VE_LD_USE_LOAD_BIAS VE_LD_POINTER_GUARD VE_LD_PROFILE_OUTPUT VE_LD_TRACE_PRELINKING VE_LD_TRACE_LOADED_OBJECTS VE_GCONV_PATH VE_GETTEXT_LOG_UNTRANSLATED VE_LANGUAGE VE_OUTPUT_CHARSET VE_LOCPATH VE_I18NPATH VE_GETCONF_DIR VE_SOTRUSS_FROMLIST VE_SOTRUSS_EXIT VE_SOTRUSS_WHICH VE_SOTRUSS_OUTNAME VE_SOTRUSS_TOLIST VE_MALLOC_TRACE VE_MALLOC_CHECK_ |
||||
9 | プロファイリング | 1.プロファイリング対象のコンテキストスイッチ等でVEプロセスの動作が一時中断された場合、実行時間が正確に測定できません。 2. gprofによるプロファイリングを行う際、SIGALRMは使用することができません。 |
通常、gprofはsetitimer()をITIMER_PROFフラグと共にcallしますが、VEはITIMER_PROFをサポートしないため、ITIMER_REALフラグと共にをcallします。 setitimer()の詳細に関しては、”システムコールの相違点”ドキュメントを参照ください。 |
|
10 | system() API | VE では、VE プログラムの中でセット/クリアした環境変数は、system() APIによって起動された子プロセスに引き継がれません。 シナリオ:ユーザがコマンドプロンプトで環境変数を設定(export)したとします。system() で起動した子プロセスが環境変数使うことを意図して、子プロセスをsystem()で実行する前に、メインプログラムがその環境変数を unsetenv を用いてクリアします。 このシナリオでは、コマンドプロンプトで設定された環境変数が、子プロセスから 見えます。 |
VE プロセスの system() 要求は VEOS ではなく、VH OS (Linux) によって実行されます。VE 内での環境変数の更新は VH の環境に反映されていないため、子プロセスは変更を引き継ぎません。 | |
11 | system() API | VEのアーキテクチャにおいて、VEプロセスが新しいVEプログラムをロードして実行するためにsystem() APIを呼び出すとき、新しく作られたVEタスクの全てのシグナルハンドラは、SIG_DFLにリセットされます。 | VE用のsystem() APIは新しいVHプロセスを作成します。この新しく作られたVHプロセスは、VEのバイナリを引数としてVHのexecve()を呼び出すことで、新しいVEのバイナリをロードし、実行します。これはつまり、新しいVEのバイナリをロードするためにve_execを呼び出すことになります。 ve_execのVEOSへのリクエストは、system() APIにより呼び出されたVEプロセスとの親子関係を持たない新しいVEプロセスを作ることになります。そのため、新しく作られたプロセスの全てのシグナルハンドラのルーチンはSIG_DFLにリセットされます。 |
|
12 | pthread_detach( ) API | pthread_join() ですでに合流されたスレッドをデタッチした場合、未定義な動作となります。 | VE
では、pthread_join() により既に合流されたスレッドに対して、続けて pthread_detach() でデタッチした場合の動作は未定義な動作となります。 これは、pthread_join() が呼び出された時点で、pthread 構造体が解放されているためです。しかし、VH の glibc はキャッシュを保持しており、いくつかの要因によりスレッド ID を保持している場合があります。そのため、VH の glibc は、pthread_join() により既に合流されたスレッドに対して pthread_detach() でデタッチした場合にエラーを返すことがあります。 |
|
備考 | ||||
システムコールに関するx86/Linux環境との相違点に関しては"システムコールの相違点"のドキュメントに記載しています。 |