3 Stimmen

Leistung der statischen gegenüber der dynamischen CUDA Shared-Memory-Allokation

Ich habe 2 Kernel, die genau dasselbe tun. Einer von ihnen allokiert den gemeinsam genutzten Speicher statisch, während der andere den Speicher zur Laufzeit dynamisch allokiert. Ich verwende den gemeinsam genutzten Speicher als 2D-Array. Für die dynamische Zuweisung habe ich ein Makro, das den Speicherort berechnet. Die Ergebnisse, die von den 2 Kernels erzeugt werden, sind jedoch genau gleich. Die Zeitmessungsergebnisse, die ich von beiden Kernels erhalten habe, unterscheiden sich um das 3-Fache! Die statische Speicherzuordnung ist viel schneller. Es tut mir leid, dass ich meinen Code nicht posten kann. Kann jemand eine Begründung dafür geben?

3 Stimmen

Hast du den von NVCC mit der -ptx-Option erzeugten PTX-Code überprüft? Wenn es offensichtliche Unterschiede im Ausgabecode gibt, kann das helfen zu erklären, warum ein Kernel schneller ist.

1 Stimmen

Es kann mit den Compiler-Optimierungen zusammenhängen. Können Sie beide Codes mit der Option -O0 kompilieren?

4 Stimmen

Sind Sie sicher, dass Ihre dynamische Größenberechnung die gleiche Größe wie das statische Array hat? Wenn es größer ist (vielleicht versehentlich), dann könnte die Auslastung des Kerns reduziert werden. Übrigens, um tatsächliche Antworten zu erhalten, müssen Sie konkrete Details angeben - zum Beispiel einen Code.

3voto

Vitality Punkte 19407

Ich habe keine Beweise dafür, dass die statische gemeinsame Speicherzuweisung schneller ist als die dynamische gemeinsame Speicherzuweisung. Wie oben in den Kommentaren bestätigt wurde, wäre es unmöglich, Ihre Frage ohne Replikator zu beantworten. Zumindest im Fall des unten stehenden Codes sind die Zeitmessungen für denselben Kernel, wenn er mit statischen oder dynamischen gemeinsamen Speicherzuweisungen ausgeführt wird, genau gleich:

#include 
#include 

#define BLOCK_SIZE 512

/********************/
/* CUDA ERROR CHECK */
/********************/
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, char *file, int line, bool abort=true)
{
    if (code != cudaSuccess) 
    {
        fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
        if (abort) exit(code);
    }
}

/***********************************/
/* SHARED MEMORY STATIC ALLOCATION */
/***********************************/
__global__ void kernel_static_memory_allocation(int *d_inout, int N)
{
    __shared__ int s[BLOCK_SIZE];

    const int tid   = threadIdx.x;
    const int i     = blockIdx.x * blockDim.x + threadIdx.x;

    if (i < N) {

        s[tid] = d_inout[i];
        __syncthreads();

        s[tid] = s[tid] * s[tid];
        __syncthreads();

        d_inout[i] = s[tid];
    }
}

/************************************/
/* SHARED MEMORY DYNAMIC ALLOCATION */
/************************************/
__global__ void kernel_dynamic_memory_allocation(int *d_inout, int N)
{
    extern __shared__ int s[];

    const int tid   = threadIdx.x;
    const int i     = blockIdx.x * blockDim.x + threadIdx.x;

    if (i < N) {

        s[tid] = d_inout[i];
        __syncthreads();

        s[tid] = s[tid] * s[tid];
        __syncthreads();

        d_inout[i] = s[tid];
    }
}

/********/
/* MAIN */
/********/
int main(void)
{
    int N = 1000000;

    int* a = (int*)malloc(N*sizeof(int));

    for (int i = 0; i < N; i++) { a[i] = i; }

    int *d_inout; gpuErrchk(cudaMalloc(&d_inout, N * sizeof(int))); 

    int n_blocks = N/BLOCK_SIZE + (N%BLOCK_SIZE == 0 ? 0:1);

    gpuErrchk(cudaMemcpy(d_inout, a, N*sizeof(int), cudaMemcpyHostToDevice));

    float time;
    cudaEvent_t start, stop;
    cudaEventCreate(&start);
    cudaEventCreate(&stop);
    cudaEventRecord(start, 0);  
    kernel_static_memory_allocation<<>>(d_inout, N);
    gpuErrchk(cudaPeekAtLastError());
    gpuErrchk(cudaDeviceSynchronize());
    cudaEventRecord(stop, 0);
    cudaEventSynchronize(stop);
    cudaEventElapsedTime(&time, start, stop);
    printf("Statische Allokation - vergangene Zeit:  %3.3f ms \n", time);

    cudaEventRecord(start, 0);  
    kernel_dynamic_memory_allocation<<>>(d_inout, N);
    gpuErrchk(cudaPeekAtLastError());
    gpuErrchk(cudaDeviceSynchronize());
    cudaEventRecord(stop, 0);
    cudaEventSynchronize(stop);
    cudaEventElapsedTime(&time, start, stop);
    printf("Dynamische Allokation - vergangene Zeit:  %3.3f ms \n", time);

}

Der mögliche Grund dafür ist, dass die disassemblierten Codes für die beiden Kerne vollkommen identisch sind und sich nicht ändern, selbst wenn int N = 1000000; durch int N = rand(); ersetzt wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X