2016-12-01 21 views
2

나는 arrayfire를 사용하여 GPU (OpenCL)의 도움을 받아 일부 C++ 코드의 속도를 향상시킵니다. 나는 af :: array의 600MB 이상을 가지고 있는데, 이는 열 차원을 따라 뒤집은 다음이를 조 변경해야합니다.arrayfire에서 flip 및 transpose가있는 memcpy를 피하는 방법은 무엇입니까?

지금까지 C++ 루틴으로 거의 모든 작업을 수행했습니다. 그러나 지금은 AF로하고 싶지만 AF 라이브러리의 과도한 메모리 사용을 알아 차리고 싶습니다.

1) 300MB 배열의 플립 또는 T와 같은 작업이 900MB 이상의 메모리를 사용해야하는 이유는 완전히 알 수 없습니다. 2) 배열 foo의 복사본을 만드는 것을 피하는 방법을 알고 싶습니다. 나는 별도의 함수 내에서 작업을 캡슐화하여 모든 복사본을 제거 할 것이라고 생각했습니다.

나는 다음과 같은 코드를 가지고 : 속도가 다음 메모리 사용 덜 중요하지만이 AF 프레임 워크 내에서이 작업을 수행 할 선호하는 것 있도록

void prepare_array(af::array &a) { 
    af::array b = af::flip(a, 1);    // ~1400MB 
    a = b.T();         // ~3000MB 
} 

af::array foo = af::randn(768,16384,3,1,c64); // ~300MB 
prepare_array(foo); 
af::deviceGC();        // ~600MB 

내가 한 번만이 작업을 수행해야합니다.

는 (모든 메모리 사용 통계는 데비안에 NVIDIA 커널 드라이버 패키지에서 gpustat 함께 읽습니다.)

메모리 사용량이 너무 CPU 백엔드에 대한 과도한이다. 응답 우마르 - 아르 샤드에


감사 : 나는 MEM-사용을 나는 CPU의 코드를 실행 마지막 프로파일했을 때 - 똑같이 행동 것을 가정합니다. GPU에서 gpustat와 nvidia-smi를 모두 사용하여 측정 값을 두 번 확인했습니다. 실제로 코드는 측정치가 다르며 설명대로했습니다. 이제 모든 GPU는 완벽하게 이해됩니다.

아마도 foo는 실수 부분 만 사용되기 때문에 f64는 처음에는 f64에만 있고 flip 또는 transposition을 사용하면 c64가됩니다.

이 웹 사이트와 함께 "할당으로 인해 암시 적 장치가 모든 대기열에서 동기화됩니다"라는 사실은 http://forums.accelereyes.com/forums/viewtopic.php?f=17&t=43097&p=61730&hilit=copy+host+memory+into+an+array#p61727 및 af :: printMemInfo()입니다. 은 결국 AF의 메모리 처리 대부분을 파악하는 데 도움이되었습니다. 내 프로그램을 크게 가속화합니다. 내가 원하는하지 않았기 때문에 그러나 이것은 매우 복잡

// Generate/store data in std::array<af::cdouble> foo_unwrap = new af::cdouble[768*16384*3*1]; 

// Flip/Transpose foo_unwrap in plain C/C++, like in: 
// for(column = 0; column < max_num_column/2; column++) 
// swap column with max_num_column-1-column 
// 
// http://www.geeksforgeeks.org/inplace-m-x-n-size-matrix-transpose/ 
// but for Column-Major Order matrices 
// 
// and afterwards whenever needed do ad-hoc: 
af::cdouble* first_elem = (af::cdouble*) &(foo_unwrap[0]); // to ensure correct type detection via AF 
af::array foo = af::array(768,16384,3,1, first_elem, afDevice); 

을 지금 여전히 유일한 대안은 (가능한 한 적은 오버 헤드 나)이 두 작업을 현재 위치에서 할 수있는위한 그러나

은 사용하는 것입니다 열 -/열 - 주요 형식과 색인 마법에 대해 걱정할 필요가 있습니다. 그래서 나는 여전히 제안을 찾고있다.

+0

그래,'gpustat'가 무엇을하고 있는지 모르지만 실제로 숫자가 틀리다 (Umar의 답변 참조). 더 나은 정보를 얻으려면'nvidia-smi'를 사용할 수 있습니다. 'af :: deviceMemInfo'를 사용하여 arrayfire가 내부적으로 어떤 일을하는지 볼 수 있습니다. –

+0

일반적으로 ArrayFire로 작업 할 때 치수를 1 차원, 열, 행이 아닌 두 번째 차원으로 취급합니다. 일관성있는 한 차원의 표현은 중요하지 않습니다. 물론 이것은 선형 대수 연산에는 적용되지 않지만 AF (matmul)의 일부 함수는 배열을 데이터 순서없이 정렬하지 않은 것처럼 계산을 수행하는 옵션 매개 변수를 가지고 있습니다. 응용 프로그램에 대한 추가 컨텍스트도 도움이 될 수 있습니다. 그래서 이런 종류의 토론을위한 최고의 포럼이 아닙니다. 우리는 Google 그룹 및 거성에 상당히 적극적입니다. –

답변

2

ArrayFire는 불필요한 할당 및 할당 해제를 피하기 위해 메모리 관리자를 사용합니다. 이는 모든 할당이 암 # 적 장치를 트리거하여 특정 플 '폼의 모든 대기열에서 동기화되기 때.에 필요합니다. 이것은 매우 값 비쌉니다. 그래서 ArrayFire는 범위를 벗어나 필요한 경우 다시 사용하는 af::array을 추적합니다. 또한 ArrayFire는 시작할 때 메모리를 할당합니다.

귀하의 경우에는 randu 호출에서 ~ 600MB를 할당합니다 (c64은 복잡한 이중이므로 각 요소는 16 바이트 임). b에 저장되는 반전 작업을위한 또 다른 600MB 할당이 있습니다. Transpose는 600MB를 할당하지만 재사용을 위해 이전 값을 예약합니다. 이 시점에서이 작업으로 인해 약 1800MB의 메모리가 할당되었습니다.

prepared_array 함수 호출에서 돌아 오면 b는 범위를 벗어나서 삭제 대상으로 표시됩니다. 이 시점에서 각각 600MB에 3 개의 버퍼가 있습니다. 두 개의 버퍼가 사용되지 않지만 ArrayFire는 향후 작업에서 해당 버퍼를 사용할 수 있습니다. 사용하지 않은 배열은 모두 deviceGC 함수를 호출하면 해제됩니다. 유사한 크기의 배열을 할당 할 가능성이 있기 때문에 사용하지 않는 것이 좋습니다.

af::printMemInfo() 기능을 사용하여 ArrayFire에서 할당 한 내용을 추적 할 수 있습니다.

Disclamer : 나는 ArrayFire 개발자 중 한 명입니다.

+0

또한 전치 행렬이 정사각형 인 경우 [transposeInPlace] (http://arrayfire.org/docs/group__blas__func__transpose.htm#gae77f8ba484534fe5bf85c73f8641c133)를 사용할 수 있습니다. – shehzan