2013-04-20 8 views
9

Qual è il modo migliore di utilizzare le costanti in CUDA?Utilizzo di costanti con CUDA

Un modo è quello di definire costanti nella memoria costante, come:

// CUDA global constants 
__constant__ int M; 

int main(void) 
{ 
    ... 
    cudaMemcpyToSymbol("M", &M, sizeof(M)); 
    ... 
} 

Un modo alterativa sarebbe usare il preprocessore C:

#define M = ... 

penserei definire costanti con il preprocessore C è molto più veloce. Quali sono quindi i vantaggi dell'utilizzo della memoria costante su un dispositivo CUDA?

+1

le costanti che sono note al momento della compilazione devono essere definite utilizzando le macro del preprocessore (ad esempio '# define'). In altri casi, '__constant__' [variabili] (http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#constant) può essere una delle opzioni che il programmatore CUDA usa per ottimizzare il codice che accede variabili calcolate che non cambiano. Nota che il tuo uso di "" M "' per fare riferimento a un simbolo non è più valido in cuda 5. –

+0

Sarebbe interessante sapere quanto sia la differenza di runtime tra queste due possibilità. Sto lavorando su alcuni codici cfd e vorrei passare i parametri come opzioni al programma, quindi sarebbe necessario utilizzare il primo approccio. D'altra parte, se utilizzo macro di preprocessore, ciò non sarebbe possibile. – jrsm

+0

Poiché il secondo esempio non genera alcun codice macchina di alcun tipo, non è una domanda sensata. È necessario porre uno scenario di utilizzo di runtime effettivo al fine di dare un senso a questa domanda. Per il caricamento iniziale di un singolo valore scalare immediato in una variabile o registro, il secondo metodo sarà sempre più veloce. –

risposta

9
  1. costanti che sono noti al momento della compilazione devono essere definiti usando macro preprocessore (ad esempio #define) o tramite C/C++ const variabili in ambito globale/file.
  2. L'utilizzo di __constant__ memory può essere utile per i programmi che utilizzano determinati valori che non cambiano per la durata del kernel e per i quali sono presenti determinati modelli di accesso (ad esempio, tutti i thread accedono allo stesso valore nello stesso momento). Questo non è migliore o più veloce delle costanti che soddisfano i requisiti del precedente articolo 1.
  3. Se il numero di scelte da effettuare da un programma sono relativamente poco numerosi, e queste scelte influenzano l'esecuzione del kernel, un possibile approccio per l'ottimizzazione in fase di compilazione potrebbe essere quella di utilizzare templated code/kernels
+2

L'uso di costanti di stile C/C++, macro del preprocessore o modelli C++ può essere più veloce dell'utilizzo della memoria __constant__ per molteplici ragioni: 1. Il compilatore può applicare ulteriori ottimizzazioni e 2. la costante può essere incorporata nell'istruzione come immediata. Gli accessi alla cache costanti possono perdere la cache costante aggiungendo ulteriore latenza. –

+0

Le costanti '# define'd dei tipi non banali sono lente a causa delle chiamate ai costruttori in ogni thread ogni volta? –

4

regolare C/Costanti di stile C++: le costanti CUDA C (a sua volta una modifica di C99) sono entità assolute di tempo di compilazione. Ciò non sorprende, dato che la quantità di ottimizzazione che si verifica in NVCC è MOLTO coinvolta data la natura dell'elaborazione della GPU.

#define: i macro sono come sempre molto ineleganti ma utili in un pizzico.

Lo specifier variabile __constant__ è, tuttavia, un animale completamente nuovo e qualcosa di un termine improprio a mio parere. Io sedare quella Nvidia ha here nello spazio sottostante:

Il __constant__ qualificazione, eventualmente utilizzati insieme con __device__, dichiara una variabile che:

  • risiede nello spazio di memoria costante,
  • La durata di un'applicazione,
  • È accessibile da tutti i thread all'interno della griglia e dall'host tramite la libreria di runtime (cudaGetSymbolAddress()/ cudaGetSymbolSize()/cudaMemcpyToSymbol()/cudaMemcpyFromSymbol()).

documentazione Nvidia specifica che __constant__ è disponibile a registro velocità livello (quasi zero latenza) a condizione che sia la stessa costante accedano tutte fili di ordito.

Sono dichiarati a livello globale nel codice CUDA. TUTTAVIA, in base all'esperienza personale (e attualmente in corso), bisogna fare attenzione con questo specificatore quando si tratta di compilare separatamente, come la separazione del codice CUDA (.cu e.file cuh) dal codice C/C++ inserendo funzioni wrapper in intestazioni in stile C.

A differenza delle tradizionali variabili "costanti" specificate, tuttavia, queste vengono inizializzate in fase di esecuzione dal codice host che alloca la memoria del dispositivo e infine avvia il kernel. Ripeto che sto attualmente lavorando codice che dimostra questi possono essere impostati in runtime utilizzando cudaMemcpyToSymbol() prima dell'esecuzione del kernel.

Sono abbastanza pratici per non dire altro data la velocità del livello di cache L1 che è garantita per l'accesso.