2016-09-08 9 views
1

동시에 3 개의 대기열을 장치 측에서 대기 할 수있는 특별한 "대기 이벤트"기능이있어 모든 대기열을 연속적으로 기다리지 않습니다. 호스트 측면?모든 대기열에 대해 3 개의 대기열 + 1 개의 종료 또는 장치 측 검사 점

다른 명령 대기열이 동일한 (수직) 장벽/검사 점에 도달하여 장치 측에서 기다리고 계속 대기 할 때까지 대기해야하는 검사 점 명령이 명령 대기열에있어 호스트 측 왕복이 필요하지 않습니다. ?

지금, 나는 두 개의 서로 다른 버전의 시도 : 두 번째는 좀 더 빠른

clWaitForEvents(3, evt_); 

int evtStatus0 = 0; 
clGetEventInfo(evt_[0], CL_EVENT_COMMAND_EXECUTION_STATUS, 
    sizeof(cl_int), &evtStatus0, NULL); 

while (evtStatus0 > 0) 
{ 

    clGetEventInfo(evt_[0], CL_EVENT_COMMAND_EXECUTION_STATUS, 
     sizeof(cl_int), &evtStatus0, NULL); 
    Sleep(0); 
} 

int evtStatus1 = 0; 
clGetEventInfo(evt_[1], CL_EVENT_COMMAND_EXECUTION_STATUS, 
    sizeof(cl_int), &evtStatus1, NULL); 

while (evtStatus1 > 0) 
{ 

    clGetEventInfo(evt_[1], CL_EVENT_COMMAND_EXECUTION_STATUS, 
     sizeof(cl_int), &evtStatus1, NULL); 
    Sleep(0); 
} 


int evtStatus2 = 0; 
clGetEventInfo(evt_[2], CL_EVENT_COMMAND_EXECUTION_STATUS, 
    sizeof(cl_int), &evtStatus2, NULL); 

while (evtStatus2 > 0) 
{ 

    clGetEventInfo(evt_[2], CL_EVENT_COMMAND_EXECUTION_STATUS, 
     sizeof(cl_int), &evtStatus2, NULL); 

    Sleep(0); 
} 

(나는 다른 사람에서 그것을보고) 모두 3 플러시 명령 후 실행 .

CodeXL 프로파일 러 결과를 보면 처음에는 끝점 사이를 기다리고 일부 작업은 겹쳐 보이지 않습니다. 두 번째는 3 개의 완료 지점이 모두 3 밀리 초 내에 있음을 보여 주므로 더 빠르고 더 긴 부분이 겹쳐집니다 (동시에 읽기 + 쓰기 + 계산).

호스트 측에서 1 대기 명령만으로이를 수행 할 수있는 방법이 있다면 "플러시"버전이어야하지만 찾을 수 없습니다.

각 파이프 라인 단계 사이에 플러시를 추가하는 대신 아래 그림을 얻을 수있는 방법이 있습니까?

queue1 write checkpoint write checkpoint write 
queue2 -    compute checkpoint compute checkpoint compute 
queue3 -      checkpoint read checkpoint read  

모든 체크 포인트는 수직으로 동기화되어야하며 신호가 주어질 때까지 이러한 모든 동작이 시작되지 않아야합니다. 예를 들면 :

queue1.ndwrite(...); 
queue1.ndcheckpoint(...); 
queue1.ndwrite(...); 
queue1.ndcheckpoint(...); 
queue1.ndwrite(...); 
queue2.ndrangekernel(...); 
queue2.ndcheckpoint(...); 
queue2.ndrangekernel(...); 
queue2.ndcheckpoint(...); 
queue2.ndrangekernel(...); 
queue3.ndread(...); 
queue3.ndcheckpoint(...); 
queue3.ndread(...); 
queue3.ndcheckpoint(...); 
queue3.ndread(...); 

queue1.flush() 
queue2.flush() 
queue3.flush() 

queue1.finish() 
queue2.finish() 
queue3.finish() 

체크 포인트는 모든 장치 측에서 처리 만 3 마무리 명령이 호스트 측에서 필요한

내가 3-3 큐를 결합하는 방법 (모든 큐에 대한 더 나은, 단 1 마무리?) 이벤트 "clWaitForEvents (3, evt_);" 현재 :

hCommandQueue->commandQueue.enqueueBarrierWithWaitList(NULL, &evt[0]); 
hCommandQueue2->commandQueue.enqueueBarrierWithWaitList(NULL, &evt[1]); 
hCommandQueue3->commandQueue.enqueueBarrierWithWaitList(NULL, &evt[2]); 

이 "대기열 차단 벽"이 다른 대기열과 대화 할 수 있다면 어떻게 할 수 있습니까? 모든 대기열이 완료되거나 나중에 삭제하거나 다시 사용할 수있을 때까지 호스트 측 이벤트를 유지해야합니까?

hCommandQueue->commandQueue.enqueueBarrierWithWaitList(NULL, &evt[0]); 
hCommandQueue2->commandQueue.enqueueBarrierWithWaitList(evt_0, &evt[1]); 
hCommandQueue3->commandQueue.enqueueBarrierWithWaitList(evt_0_and_1, &evt[2]); 

in the end wait for only evt[2] maybe or using only 1 same event for all: 

hCommandQueue->commandQueue.enqueueBarrierWithWaitList(sameEvt, &evt[0]); 
hCommandQueue2->commandQueue.enqueueBarrierWithWaitList(sameEvt, &evt[1]); 
hCommandQueue3->commandQueue.enqueueBarrierWithWaitList(sameEvt, &evt[2]); 

where to get sameEvt object? 

사람이 시도 : 문서에서, 그래서 어쩌면처럼 처음의 이벤트와 함께 세 번째로 넣을 수 제 큐와 두 번째의 장벽 이벤트에 넣을 수있는 첫 번째 장벽의 이벤트처럼 보인다? 장벽이있는 모든 대기열을 시작하여 호스트 측에서 일부 이벤트를 발생시킬 때까지 시작하지 않거나 "대기열에 넣기"의 실행이 % 100을 "내리기 전까지 시작하지 마라"라고 신뢰할 수 있습니까? 호스트에서 디바이스로 이벤트를 발생시키는 방법 (sameEvt에는 "raise"기능이 없습니다. clCreateUserEvent입니까?)

모든 3 개의 대기열은 순서가 맞춰져 있고 같은 맥락입니다. 모든 그래픽 카드에서 순서가 잘못된 형식을 지원하지 않습니다. C++ 바인딩이 사용되고 있습니다.

또한 enqueueWaitList (이 기능이 중단 되었습니까?) 및 clEnqueueMarker가 있지만 사용 방법을 모르며 Khronos의 웹 사이트에 문서가 없습니다.

답변

1

질문이 너무 많아서 유일한 해결책을 제공하는 변형이 너무 많아서 가장 적합한 해결책을 찾을 수 있다고 일반적으로 대답하려고 노력합니다.

대기열이 이벤트를 통해 동기화 할 수있는 것보다 동일한 컨텍스트 (동일한 컨텍스트 내의 다른 장치 일 수 있음)에 바인딩되는 경우. 나는. 하나의 대기열에 제출 된 명령에서 이벤트를 얻고이 이벤트를 사용하여 다른 대기열에 제출 된 명령을 동기화 할 수 있습니다 (예 : 이 예에서

queue1.enqueue(comm1, /*dependency*/ NULL, /*result event*/ &e1); 
queue2.enqueue(comm2, /*dependency*/ &e1, /*result event*/ NULL); 

, comm2comm1 완료를 기다릴 것이다.

먼저 명령을 대기열에 추가해야하지만 실행하지 못하게하려면 사용자 이벤트 (clCreateUserEvent)를 만들고 수동으로 신호를 보냅니다 (clSetUserEventStatus). 구현시 대기열에 들어서 자마자 명령을 처리 할 수 ​​있습니다 (드라이버는 flush을 기다릴 필요가 없습니다).

장벽은 이전에 대기열에 제출 된 모든 명령을 기다리기 때문에 과도한 것처럼 보입니다. 모든 이벤트를 기다리고 다른 명령에 사용할 이벤트를 제공하는 데 사용할 수있는 clEnqueueMarker을 실제로 사용할 수 있습니다.

내가 아는 한 더 이상 필요하지 않으면 언제든지 이벤트를 유지할 수 있습니다. 구현은 내부 목적으로 필요한 경우 이벤트 수명을 연장해야합니다.

나는 enqueueWaitList을 모른다.

오프 토픽 : 계산 사이에 별다른 종속성이 필요없는 경우 TBB flow graphopencl_node을 고려할 수 있습니다. opencl_node은 동기화를 위해 이벤트를 사용하고 가능한 경우 "호스트 장치"동기화를 방지합니다. 그러나 동일한 장치에 대해 여러 대기열을 사용하는 것은 까다로울 수 있습니다.

내가 아는 한 Intel HD Graphics 530은 순서가 잘못된 대기열 (적어도 호스트 쪽)을 지원합니다.

+0

감사합니다. 마커를 첫 번째 대기열에 넣은 후 플러시 + 완료 후 1 초 후에 clsetusereventstatus로 설정했습니다. 그것은 모든 대기열을 정확하게 1 초 시작했습니다. 단일 마커를 사용하여 마커를 사용하지만 장치 측 이벤트를 기다리는 엔드 포인트와 동일하게 시도합니다. –

1

당신은 훨씬 더 어려워지고 있습니다. 쓰기 대기열에서 이벤트를 취하십시오. 이것을 컴퓨팅 큐의 계산 조건으로 사용하고 다른 이벤트를 가져옵니다. 이것을 읽기 대기 행렬의 읽기 조건으로 사용하십시오. 다른 동기화를 수행 할 이유가 없습니다. 참고 : 스펙에 대한 나의 해석은 이벤트를 다른 대기열의 조건으로 사용하기 전에 이벤트를 가져온 대기열을 clfush해야한다는 것입니다.

+0

3 개의 대기열에있는 단방향 이벤트 체인을 시도해 보니 드라이버가 서로 겹쳐서 위치를 정렬 할 수 없어 모든 연속 된 작은 커널이 생성됩니다. 1 대기열 (주문한)이 127 밀리 초 동안 걸리는 동안 140 밀리 초가 걸렸습니다. 동일한 이벤트를 다른 대기열 (자체 대기열에 필요하지 않음)에 추가 할 때 양방향 이벤트는 중복 된 실행 만 가능하며 읽기 + 쓰기 + 계산은 112ms가됩니다. CodeXL의 타임 라인 그래프가 잘못 표시되거나 내 C# 스톱워치 타이머가 잘못되었거나 드라이버가 작동하지 않습니다. 계산이 시작되기 전에 쓰기를 완전히 완료합니다. 그런 다음 계산이 끝나면 읽기가 시작됩니다. 그러나 모든 경우에 이벤트의 대기 시간은 1 ~ 2ms입니다. –

+0

아마도 R7-240은 계산이 존재하지 않으므로 하드웨어에서 3 대기열 동시성 (소프트웨어를 에뮬레이트)을 할 수 없기 때문에 타이밍을 반으로해야합니다 (쓰기가 중복됩니다)? 어쩌면 계산 + 읽기 또는 계산 + 쓰기 가능일까요? –

+0

당신이 옳았습니다. 더 열심히 할 필요가 없었습니다.방금 4 개의 큐를 사용하여 파이프 라이닝을 수직 대신에 수평으로 만들었고 이벤트가 없으므로 명령 사이에 아무런 구멍이 보이지 않아 오버랩되었습니다 (또한 +1 큐는 효율성을 약간 더 높이기도 함) –