3

공통 블록을 사용하여 코드를 통해 모든 곳에서 사용되는 배열을 저장하는 mpi 버전의 프로그램이 있습니다. 불행하게도, 단지 런타임으로 만 알려진 공통 블록 크기로 배열을 선언 할 방법이 없습니다. 따라서 해결 방법으로 배열 안에 할당 할 수있는 배열을 허용하는 모듈로 배열을 이동하기로 결정했습니다. 즉, COMMON 블록의 모든 배열이 사라지고 대신 ALLOCATE가 사용되었습니다. 그래서, 이것은 제가 프로그램에서 변경된 유일한 것입니다. 불행히도, 프로그램의 성능은 끔찍했습니다 (일반적인 블록 실현과 비교했을 때). mpi 설정과 관련하여 각 계산 노드에는 단일 mpi 프로세스가 있으며 각 mpi 프로세스에는 단일 스레드가 있습니다. 여기에 묻는 similar 질문은 여기에 있지만 각각의 프로세스가 단일 스레드를 가지고있는 경우에 어떻게 적용 할 수 있을지 생각하지 마십시오. 어떤 도움을 주셔서 감사합니다.할당 가능한 배열 성능

"소스 파일":

SUBROUTINE ZEROSET() 
    INCLUDE 'FILE_1.INC' 
    INCLUDE 'FILE_2.INC' 
    INCLUDE 'FILE_3.INC' 
    .... 
    INCLUDE 'FILE_N.INC' 

    ARRAY_1 = 0.0 
    ARRAY_2 = 0.0 
    ARRAY_3 = 0.0 
    ARRAY_4 = 0.0 
    ... 
    ARRAY_N = 0.0 
END SUBROUTINE 

당신이 볼 수있는 바와 같이, 영점()가 더 병렬이 없습니다 여기에

(아래 의사 코드이다) 내가 무엇에 대해 말하고 설명하는 간단한 예입니다 또는 MPI 물건. FILE_1.INC, FILE_2, ..., FILE_N.INC는 ARRAY_1, ARRAY_2 ... ARRAY_N이 COMMON 블록에 정의 된 파일입니다. 그와 같은 것

REAL ARRAY_1 
COMMON /ARRAY_1/ ARRAY_1(NX, NY, NZ) 

여기서 NX, NY, NZ는 PARAMETER 지시문을 사용하여 잘 정의 된 매개 변수입니다. 내가 모듈을 사용하는 경우 FILE_I.INC 그냥 변경 후

REAL, ALLOCATABLE:: ARRAY_I(:,:,:) 

그리고처럼 보이는, 그래서 , 나는 그냥 모든 일반적인 블록을 파괴 "를 사용 FILE_I"에 위의 진술 " 'FILE_I.INC'포함". 실제로 병렬 프로그램이 실행될 때 하나의 특정 프로세스에는 전체 (NX, NY, NZ) 도메인이 필요하지 않으므로 매개 변수를 계산 한 다음 ARRAY_I (한 번만!)를 할당합니다.

서브 루틴 ZEROSET()은 COMMON 블록에서는 0.18 초, 모듈에서는 (배열의 차원이 런타임에서 계산 될 때) 0.36으로 실행됩니다. 따라서 성능이 2 배나 악화되었습니다.

이제 모든 것이 분명해지기를 바랍니다. 너를 아주 도와 줘서 고맙다.

+2

이것은 병렬 실행과 어떻게 관련되어 있습니까? 성능 저하가 직렬 실행에서 아직 보이지 않습니까? 얼마나 자주 배정합니까? 가짜 인수에 할당 가능 속성이 있습니까? – haraldkl

+1

mpi와 관련된 문제가 아닌 것 같습니다. 공유 메모리 또는 분산 메모리를 사용하고 있습니까? 당신은 메모리 병목 현상이있을 수 있지만, 코드의 일반적인 블록 버전이 잘 작동하기 때문에 당신이 모든 것을 올바르게했다면, 그렇지 않습니다. 할당 방법 및 용도에 대한 샘플 코드를 포함하십시오. 배열을 한 번 할당하고 할당을 해제하면 (각각 프로그램의 시작과 끝) 성능이 저하되지 않아야합니다. – milancurcic

+0

성능이 '끔찍한'것은 매우 정량적이지 않습니다. 얼마나 느린가요? 위에서 말했듯이 시리얼 문제를 먼저 확인하십시오. – steabert

답변

3

모듈에서 할당 가능한 배열을 사용하면 컴파일러에서 컴파일 타임에 크기에 대해 알지 못하기 때문에 성능이 저하 될 수 있습니다.

subroutine X 
    use Y ! Has allocatable array A(N,N) in it 
    call Z(A,N) 
    end subroutine 

    subroutine Z(A,N) 
    Integer N 
    real A(N,N) 
    do stuff here 
    end 

그런 다음이 코드 :

subroutine X 
    use Y ! Has allocatable array A(N,N) in it 
    do stuff here 
    end subroutine 

이 컴파일러는 배열되는 N × N 것을 알고 것이며,이 N을 통해 루프입니다 않고 수를이 코드를 여러 컴파일러 훨씬 더 나은 성능을 얻을 것이다 그 사실을 이용하십시오 (대부분의 코드는 배열에서 그렇게 작동합니다). 또한 "do stuff stuff"에서 서브 루틴이 호출 된 후 컴파일러는 배열 "A"가 크기를 변경했거나 메모리에서 위치를 이동하고 다시 검사 할 수 있다고 가정해야합니다. 그것은 최적화를 죽입니다.

이렇게하면 대부분의 실적을 회복 할 수 있습니다.

일반 블록은 메모리의 특정 위치에도 있으며 최적화도 가능합니다.

0
는 포트란 성능을 사용하여 배열에 올 때 난 그냥 이러한 이유로 생각할 수

: 힙 VS 스택에

  1. 배열을,하지만이 거대한 성능에 영향을 줄 수 의심한다. 여기, 그렇게 할 수있는 가장 좋은 방법은 배열에 의존하기 때문에, using arrays efficiently
+0

링크가 끊어져서 동일한 기사로 생각되는 내용의 편집을 제출했습니다. 내가 틀렸다면 고쳐주세요. – astay13

0

는 사실 내 생각에이 페이지를 참조 서브 루틴에 문제를 배열을 전달

  • , 힙 메모리 대 스택과 함께, 실제로 컴파일러 최적화를 기반으로합니다. 사용중인 컴파일러에 따라 좀 더 효율적인 메모리 블랭킹을 수행 할 수 있으며 고정 된 메모리 덩어리의 경우 서브 루틴 내에서 범위와 위치를 확인할 필요조차 없습니다. 따라서, 고정 크기의 어레이에서 오버 헤드가 거의 발생하지 않을 것입니다. 이 루틴은 매우 자주 호출됩니까? 아니면이 0.18 초를 걱정합니까? 실제로 관련성이있는 경우 가장 좋은 옵션은 0 설정을 제거하는 것입니다. 대신 예를 들어 첫 번째 반복 루프를 분리하여 초기화에 사용하면 추가 메모리 액세스를 도입 할 필요가 없습니다. 단지 0으로 초기화하기 위해서입니다. 그러나 어떤 코드를 복사 할 것입니다 ...