2012-06-26 22 views
8

Fortranのコードの1つをプロファイリングすると、計算時間の大部分(22.1%と17.2%)を占めるサブルーチンが2つあります。各ルーチンでは、時間の約5%がメモリの割り当てと解放に費やされます。これらのルーチンはFortran:動的配列vs.自動配列メモリ割り当ての回避

MODULE foo 

CONTAINS 

SUBROUTINE bar(...) 
... 
IMPLICIT NONE 
... 
REAL, ALLOCATABLE, DIMENSION(:,:) :: work 
... 
ALLOCATE (work(size1,size2)) 
... 
DEALLOCATE (work) 
END SUBROUTINE bar 
... 
END MODULE foo 

のように見える私はALLOCATEとDEALLOCATEを取り除くしたいと思いますので、これらのサブルーチンは、私のベンチマークで〜4000〜5000倍程度に呼び出されます。これらを自動配列に変更すると、にプロファイラ出力が変更されます。

MODULE foo 

CONTAINS 

SUBROUTINE bar(...) 
... 
IMPLICIT NONE 
... 
REAL, DIMENSION(size1,size2) :: work 
... 
END SUBROUTINE bar 
... 
END MODULE foo 

はのgfortranがスタックしていないこと、ヒープ上でこれらを割り当てているが、私はこれらの配列が大きくなりすぎたときに発生したときに心配ですように私には見えます

Running Time  Symbol Name 
20955.0ms 17.0% __totzsp_mod_MOD_totzsps 
    7.0ms 0.0%  malloc 
    5.0ms 0.0%  free 
    2.0ms 0.0%  user_trap 

16192.0ms 13.2% __tomnsp_mod_MOD_tomnsps 
    20.0ms 0.0%  free 
    3.0ms 0.0%  malloc 
    1.0ms 0.0%  szone_size_try_large 

への結果のプロファイルを変更します。

私が取っている2番目のアプローチは、これらの配列を一度割り当て、割り当てを解除することです。

work_array.f

MODULE work_array 
IMPLICIT NONE 

REAL(rprec), ALLOCATABLE, DIMENSION(:,:) :: work 

END MODULE work_array 

Iは、コードの異なる部分に一度これらを割り当てます。さて、私のサブルーチンは次のように見えます

MODULE foo 

CONTAINS 

SUBROUTINE bar(...) 
... 
USE work_array 
IMPLICIT NONE 
... 
END SUBROUTINE bar 
... 
END MODULE foo 

しかし、コードを実行すると、プロファイルが悪化します。

Running Time  Symbol Name 
30584.0ms 21.6% __totzsp_mod_MOD_totzsps 
3494.0ms 2.4%  free 
3143.0ms 2.2%  malloc 
    27.0ms 0.0%  DYLD-STUB$$malloc_zone_malloc 
    19.0ms 0.0%  szone_free_definite_size 
    6.0ms 0.0%  malloc_zone_malloc 

24325.0ms 17.1% __tomnsp_mod_MOD_tomnsps 
2937.0ms 2.0%  free 
2456.0ms 1.7%  malloc 
    23.0ms 0.0%  DYLD-STUB$$malloc_zone_malloc 
    3.0ms 0.0%  szone_free_definite_size 

これらの余分なmallocはどこから来ていますか?これを設定してこれらの配列を一度割り当てることができますか?

+1

Fortranのヒープ配列は、暗黙の 'malloc' /' free'呼び出しによって、各関数呼び出しで割り当てられ、割り当て解除されます。これらは、この点では 'ALLOCATABLE'配列と変わりません。 –

+1

私はこれがifortで起こるとは思わないでしょう。私はあなたの2番目のアプローチを常に使用しています。つまり、割り当てを解除して再割り当てせずに何度も使用する事前割り当てバッファを持っています。 – bdforbes

+0

あらかじめプロファイルを割り当てておくと、プロファイルが悪化する可能性はありません。理由を把握しましたか? – Lupocci

答えて

4

work配列のみbarサブルーチン内で使用されているので、あなたはそれにsave属性を追加することができますし、サブルーチンが最初に呼び出されたときにそれを割り当てます。 work1またはwork2が以前の呼び出しと異なる場合は、その場合に配列を再割り当てできます。

サブルーチンが不要になると、割り当て解除の問題が残ります。プログラムの全ライフタイム中に呼び出す必要がある場合は、プログラムが終了するとOSがメモリの割り当てを解除する必要があるため、問題はありません。一方、初期化中に必要な場合は、必要がなくてもメモリは割り当てられたままになります。メモリ使用量が問題になる場合は、work配列の割り当てを解除するように指示する引数をサブルーチンに追加できます。

0

プログラムの初期化時に1回の割り当てで取得できる場合は、配列が割り当て可能として定義される理由はありません。それを共通のものに入れてください。

固定サイズのみが必要だが、実行時までサイズが分からない場合は、最終オプションとして初期化時に1つの割り当てを行う必要があります。しかし、これが割り当てパフォーマンスのヒットを増加させたことは意味をなさない。私は、より多くのことを言うには、定義と割り当てコードを参照する必要があります。

割り当てられているものは仮想メモリなので、配列が大きすぎて使用可能なアドレス空間に影響を与えない限り、「メモリ使用量」は実際には問題にはなりません。

関連する問題