2017-11-03 8 views
1

나는 다음과 같은 문제가, 내가 가장 좋은 방법이다 궁금 해요 :오픈 CL : 동적 메모리 할당, 더 나은 동시에 유휴 작업 항목 또는 서면을 사용하는 것입니다

__kernel void test(__global int* output){ 

    // ... Code execution to define myValue. 

    // V1 : Threads are idle and wait for the first Work-item to write 
    // the output value. 
    if(get_global_id(0) == 0) output[0] = myValue; 

    // V2 : All work-items perform the same action and try to write in 
    // same global memory. (Is there any lock ?) 
    output[0] = myValue;  
} 

모두가 노력하고 있습니다 내 AMD GPU에. 그러나 나는 어느 것이 최선의 접근인지는 모른다.

는 편집 : (IM은 현재 자사가 간다 최신지고, 그 작업 이후) 칸나의 답변에 따라

, 나는 더 많은 정보를 더 많은 코드를 추가했다.

내 목표는 각 커널에서 head/next_head를 추적하고 작업 그룹 사이에 메모리 블록 포인터의 일관성을 유지하는 것입니다.

첫 번째 접근법에서는 전역 메모리 ptr에서 헤드를 직접 수정합니다. 작업 그룹 번호가 높을 때 블록 위치의 디 - 싱크가 다음 코드와 함께 나타나면 문제가 발생합니다. 코드 실행이 나중에 get_global_id를 기반으로하는 블록을 사용하고 있음에도 불구하고 예상대로 실행되며 각 작업 그룹은 동일한 블록 ptr에 액세스합니다.

그래서 코드를 향상시키고 향후 '병목 현상'이 없는지 확인하기 위해 OpenCL 우수 사례를 찾고 있습니다. 다음 코드에 대해 조언을 구하십시오.

__global void* malloc(size_t sizePtr, __global uchar* heap, ulong* head){ 
    // Get the new ptr inside the heap 
    __global void* ptr = heap + head[0]; 

    // Increment the head. 
    head[0] = head[0] + sizePtr; 

    return ptr; 
} 

__kernel void test(__global uchar* heap, 
        __global ulong* head, 
        __global ulong* next){ 

    // Each work-item set its own local head based on the 
    // global variable. So every thread in any work-group 
    // will start at the same head in the heap. 
    ulong local_head = head[0]; 

    // If get_global_size(0) is 1000. We allocate 1000 + 4000. 
    const uint g_size = get_global_size(0); 

    // Get pointers in a Huge memory block (heap) which allows 
    // to have less memory transfer in-between kernel. 
    // Just need to keep track of them (work in-progess). 
    __global uchar* block1 = malloc(sizeof(uchar) * g_size , heap, &local_head); 
    __global int* block2 = malloc(sizeof(int) * g_size , heap, &local_head); 

    // Process the blocks in here, access them via the get_global_id(0) 
    // as index. 

    // V1 
    if(get_global_id(0) == 0) next[0] = local_head; 

    // V2 
    next[0] = local_head; 

    // If head was 0, the next is now 5000 for all the work-items, 
    // whenever the work-group they are in. 
} 

답변

1

warp 기반 GPU에서는 확실히 V1이 좋습니다.

V1의 장점은 다른 모든 워프의 조기 종료와 메모리 트래픽 감소입니다.

OpenCL에는 잠금 장치가 없으므로 원자 적 조작을 사용하는 자체 잠금 구성조차 작동하지 않을 수 있습니다.

+0

워프 기반 GPU는 무엇입니까? 그것에 관한 어떤 언급? 내가 원하는 것을하기 위해 자물쇠 나 원자 조작이 필요하지 않습니다. 모든 작업 항목이 동일한 myValue를 제공하지만 한 번만해야합니다. V1과 V2 모두 작동합니다. 나는 어느 것이 최고인지 이해하고 싶다. 소규모 작업 그룹 대 대형 워크 그룹을 선호해야합니까? WG가 많으면 V1에서 먼저 종료되지만 global_id == 0 인 WG는 유휴 상태로 인해 다른 것보다 길어집니다. 맞습니까? – Vuwox

+0

또 다른 질문이 내 마음에 온다. GPU가 워프 기반이 아닌 경우 최상의 솔루션과 이유는 무엇입니까? CPU에서 OpenCL 커널을 실행하면 가장 좋은 방법은 무엇입니까? 그 대답의 버전을 구현합니다 : https://stackoverflow.com/a/25446487/1524511. 자세한 정보는 Update1을 참조하십시오. – Vuwox

+0

'malloc' 코드는 thread-safe하지는 않습니다 (특히'head [0] = head [0] + sizePtr'), 병렬 적으로 쓰면 잘 끝나지 않을 것이라는 것에 동의합니다. – Dithermaster