2012-06-26 11 views
8

Chciałbym wywołać coś takiego jak usleep() wewnątrz jądra CUDA. Podstawowym celem jest sprawienie, aby wszystkie rdzenie GPU były uśpione lub zajęte przez kilka mililitrów - jest to część niektórych testów poprawności, które chcę wykonać dla aplikacji CUDA. Moja próba robi to poniżej:Równoważnik usleep() w jądrze CUDA?

#include <unistd.h> 
#include <stdio.h> 
#include <cuda.h> 
#include <sys/time.h> 

__global__ void gpu_uSleep(useconds_t wait_time_in_ms) 
{ 
    usleep(wait_time_in_ms); 
} 

int main(void) 
{ 
    //input parameters -- arbitrary 
    // TODO: set these exactly for full occupancy 
    int m = 16; 
    int n = 16; 
    int block1D = 16; 
    dim3 block(block1D, block1D); 
    dim3 grid(m/block1D, n/block1D); 

    useconds_t wait_time_in_ms = 1000; 

    //execute the kernel 
    gpu_uSleep<<< grid, block >>>(wait_time_in_ms); 
    cudaDeviceSynchronize(); 

    return 0; 
} 

otrzymuję następujący błąd, gdy próbuję skompilować ten korzystając nvcc:

error: calling a host function("usleep") from a __device__/__global__ 
     function("gpu_uSleep") is not allowed 

Oczywiste jest, że nie wolno mi użyć funkcji gospodarza, takich jak usleep() wewnątrz jądra. Co byłoby dobrą alternatywą do tego?

Odpowiedz

9

Możesz zająć się czekaniem z pętlą, która brzmi: clock().

poczekać co najmniej 10.000 cykli zegarowych:

clock_t start = clock(); 
clock_t now; 
for (;;) { 
    now = clock(); 
    clock_t cycles = now > start ? now - start : now + (0xffffffff - start); 
    if (cycles >= 10000) { 
    break; 
    } 
} 
// Stored "now" in global memory here to prevent the 
// compiler from optimizing away the entire loop. 
*global_now = now; 

Uwaga: To jest niesprawdzone. Kod, który obsługuje przepełnienia został pożyczony od this answer przez @Pedro. Aby uzyskać szczegółowe informacje na temat działania clock(), zapoznaj się z jego odpowiedzią i sekcją B.10 Instrukcji programowania CUDA C 4.2. Istnieje również polecenie clock64().

+0

Dzięki! Chciałbym użyć clock64(), aby móc liczyć dłużej i zmniejszyć wpływ przewalutowania. Kiedy kompiluję jądro CUDA, które zawiera wywołanie clock64(), otrzymuję komunikat "błąd: identyfikator" clock64 "jest niezdefiniowany." Kiedy używam zegara(), program kompiluje się poprawnie. Używam nvcc 4.0. Bazując na szybkim wyszukiwaniu google, wygląda na to, że clock64() ma być w cuda/nvcc 4.0. Wszelkie przemyślenia, jak rozwiązać ten problem? – solvingPuzzles

+2

Potrzebujesz również możliwości obliczeniowych> = 2.0, aby uzyskać 'clock64()'. –

+0

interesujące. Używam GTX480, który nvidia wymienia jako posiadający zdolność obliczeniową 2.0. – solvingPuzzles

17

Można obracać na zegarze() lub clock64(). CUDA SDK concurrentKernels sample robi to co następuje:

__global__ void clock_block(clock_t *d_o, clock_t clock_count) 
{ 
    clock_t start_clock = clock(); 
    clock_t clock_offset = 0; 
    while (clock_offset < clock_count) 
    { 
     clock_offset = clock() - start_clock; 
    } 
    d_o[0] = clock_offset; 
} 

Polecam używając clock64(). clock() i clock64() są w cyklach, więc będziesz musiał zapytać o częstotliwość za pomocą funkcji cudaDeviceProperties(). Częstotliwość może być dynamiczna, więc trudno będzie zagwarantować dokładną pętlę spinową.

+3

+1 za uwagę na temat częstotliwości –

+1

Nigdy nie jest za późno, aby przyjąć solidną odpowiedź, zwłaszcza, że ​​nazwa jądra jest tak zabawna. Czy to było celowe? – JorenHeit