9

私たちのFortranコードの1つをプロファイリングすると、計算時間の大部分(22.1%と17.2%)を占める2つのサブルーチンがあります。各ルーチンでは、時間の約5%がメモリの割り当てと解放に費やされます。これらのルーチンは次のようになります

MODULE foo

CONTAINS

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

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

MODULE foo

CONTAINS

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

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

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

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

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

work_array.f

MODULE work_array
IMPLICIT NONE

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

END MODULE work_array

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

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と無料はどこから来ていますか?これらのアレイを一度割り当てるようにこれを設定するにはどうすればよいですか?

4

2 に答える 2

5

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

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

于 2012-06-27T06:19:30.360 に答える
0

プログラムの初期化時に単一の割り当てで済む場合は、配列を割り当て可能として定義する理由はありません。コモンに入れます。

固定サイズのみが必要で、実行時までそのサイズがわからない場合は、最後のオプションである初期化時の単一の割り当てを使用する必要があります。ただし、これによって割り当てパフォーマンス ヒットが増加したことには意味がありません。詳細を説明するには、定義と割り当てコードを確認する必要があります。

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

于 2012-07-08T00:11:52.520 に答える