2010-03-29 10 views
39

He estado jugando con OpenCL recientemente, y puedo escribir kernels simples que usan solo memoria global. Ahora me gustaría comenzar a usar la memoria local, pero parece que no puedo entender cómo usar get_local_size() y get_local_id() para calcular un "fragmento" de salida a la vez.¿Cómo uso la memoria local en OpenCL?

Por ejemplo, supongamos que quería convertir el kernel de ejemplo OpenCL Hello World de Apple a algo que utiliza la memoria local. ¿Como lo harias? Aquí está el código fuente del núcleo original de:

__kernel square(
    __global float *input, 
    __global float *output, 
    const unsigned int count) 
{ 
    int i = get_global_id(0); 
    if (i < count) 
     output[i] = input[i] * input[i]; 
} 

Si este ejemplo no puede ser fácilmente convertida en algo que muestra cómo hacer uso de la memoria local, cualquier otro ejemplo sencillo es suficiente.

Respuesta

30

Echa un vistazo a las muestras en los SDK de NVIDIA o AMD, deben indicarte la dirección correcta. Matrix transpose usaría memoria local, por ejemplo.

Usando su kernel de cuadratura, puede organizar los datos en un buffer intermedio. Recuerde pasar el parámetro adicional.

__kernel square(
    __global float *input, 
    __global float *output, 
    __local float *temp, 
    const unsigned int count) 
{ 
    int gtid = get_global_id(0); 
    int ltid = get_local_id(0); 
    if (gtid < count) 
    { 
     temp[ltid] = input[gtid]; 
     // if the threads were reading data from other threads, then we would 
     // want a barrier here to ensure the write completes before the read 
     output[gtid] = temp[ltid] * temp[ltid]; 
    } 
} 
+4

He leído el material introductorio de NVIDIA, y todavía encuentro los ejemplos demasiado complejos. Estoy buscando un ejemplo unidimensional simple de usar memoria local para mojarme los pies. – splicer

+6

¡Gracias por agregar el código en su última edición! Parece que no puedo hacer funcionar tu núcleo ... ¿Cómo usaría clSetKernelArg() para la temperatura? ¿Debo usar clCreateBuffer() para la temperatura? Además, hay algunos errores tipográficos en su kernel: "temp * temp" debe ser "temp [ltid] * temp [ltid]", y se debe insertar un parche de cierre antes de la última línea. – splicer

+0

Corriendo en la CPU bajo Snow Leopard, probé clSetKernelArg (kernel, 2, sizeof (cl_float), NULL); pero se bloquea. ¿Algunas ideas? – splicer

27

Hay otra posibilidad de hacerlo, si el tamaño de la memoria local es constante. Sin necesidad de utilizar un puntero en la lista de parámetros núcleos, la memoria intermedia local puede ser declarado dentro del kernel que acaba declarando que __local:

__local float localBuffer[1024]; 

Esto elimina código debido a menos llamadas clSetKernelArg.

+0

Esto es cierto, pero sería mucho más útil si no tuviera que saber el tamaño de la matriz en tiempo de ejecución. Esto es deseable cuando se encapsula la funcionalidad OpenCL dentro de la clase de objeto. Por ejemplo, ver el comentario de EdwardLuong arriba; sería genial si su sugerencia pudiera funcionar (no parece funcionar para mi hardware). Gracias. –

4

En OpenCL, la memoria local está destinada a compartir datos entre todos los elementos de trabajo en un grupo de trabajo. Y generalmente requiere hacer una llamada de barrera antes de que se puedan usar los datos de la memoria local (por ejemplo, un elemento de trabajo desea leer una información de memoria local escrita por los otros elementos de trabajo). La barrera es costosa en hardware. Tenga en cuenta que la memoria local debe usarse para la lectura/escritura de datos repetidos. El conflicto bancario debe evitarse tanto como sea posible.

Si no tiene cuidado con la memoria local, puede terminar con peor rendimiento en algún momento que usando la memoria global.

Cuestiones relacionadas