2010-04-12 16 views
11

Cuando estaba terminando de codificar mi proyecto para una clase de programación multinúcle, encontré algo realmente extraño que quería discutir contigo.Mi kernel OpenCL es más lento en hardware más rápido ... ¿Pero por qué?

Nos pidieron que creáramos cualquier programa que mostrara una mejora significativa en la programación de una plataforma multi-core. Decidí probar y codificar algo en la GPU para probar OpenCL. Elegí el problema de la convolución matricial porque estoy bastante familiarizado con él (lo he paralelizado antes con open_mpi con gran velocidad para imágenes grandes).

Así que aquí está, selecciono un archivo GIF grande (2.5 MB) [2816X2112] y ejecuto la versión secuencial (código original) y obtengo un promedio de 15.3 segundos.

Luego, ejecuto la nueva versión de OpenCL que acabo de escribir en mi GeForce 9400M integrado en MBP y obtengo un promedio de 1.26s. ¡Hasta ahora todo bien, es una aceleración de 12X!

Pero ahora voy a mi panel de ahorro de energía para activar el "Modo de rendimiento gráfico". Ese modo apaga la GeForce 9400M y enciende la Geforce 9600M GT que tiene mi sistema. Apple dice que esta tarjeta es dos veces más rápida que la integrada.

Adivina qué, mi tiempo usando la tarjeta gráfica kick-culo son 3,2 segundos en promedio ... Mi 9600M GT parece ser más de dos veces más lenta que la 9400M ..

Para aquellos de ustedes que están inclinados OpenCL , Copio todos los datos en búferes remotos antes de comenzar, por lo que el cálculo real no requiere ida y vuelta al ariete principal. Además, dejo que OpenCL determine el tamaño de trabajo local óptimo ya que he leído que han realizado una implementación bastante buena para calcular ese parámetro.

¿Alguien tiene una pista?

edición: el código fuente completo con archivos make aquí http://www.mathieusavard.info/convolution.zip

cd gimage 
make 
cd ../clconvolute 
make 
put a large input.gif in clconvolute and run it to see results 
+0

¿Ha reiniciado el equipo después de cambiar la tarjeta gráfica? AFAIK esto es requerido en estas computadoras. –

+0

He desconectado ... cuando quiere cambiar la tarjeta gráfica, lo obliga a cerrar la sesión e iniciar sesión + mi programa muestra el nombre de la tarjeta gráfica que se utiliza actualmente, así puedo asegurarme de cuál se está ejecutando ... – matdumsa

+0

intenté reiniciar .. también intenté aumentar el tamaño del problema usando una imagen de 3264x2448 con una máscara 12X12 solo para encontrar los mismos resultados ... – matdumsa

Respuesta

1

me encontré con el mismo problema cuando estaba probando a cabo OpenCL en mi MacBook. Creo que es porque la GeForce 9400M tiene una mayor velocidad de bus para el banco de memoria principal que la Geforce 9600M GT. Entonces, aunque la Geforce 9600M GT tiene mucha más potencia que la GeForce 9400M, el tiempo requerido para copiar la memoria a la GPU es demasiado larga para ver el beneficio de la GPU más poderosa en su situación. También podría ser causado por tamaños inadecuados de grupos de trabajadores.

También encontré este sitio muy útil en mi experiencia OpenCL.

http://www.macresearch.org/opencl

+0

Gracias Kendall, pero el asunto de macresearch.org es en lo que basé mi código en realidad: P El tamaño del grupo de trabajo es automáticamente establecer pasando en el parámetro nulo. – matdumsa

+1

Intenta usar diferentes tamaños. El valor predeterminado no siempre es el mejor. –

+0

ok, así que probé un tamaño diferente ... el tamaño de autodetección es 16 en ambas tarjetas ... Puedo obtener hasta 17 pero disminuye el rendimiento en ambas tarjetas ... Obtengo un error superior a 17. Raro, raro, raro ... – matdumsa

1

El rendimiento no es la única diferencia entre una GeForce 9400M y una Geforce 9600M GT. Una gran es que una es discreta GPU. Con este recorrido un montón de diferencias, entre las que la siguiente puede tener un impacto:

  • tendencia de los conductores a lote más comandos
  • memoria no es uniforme. la GPU generalmente solo accede a su propia memoria, y el controlador mueve la memoria hacia adelante y hacia atrás sobre el bus PCI-E.

Estoy seguro de que me falta algo ...

Aquí hay un montón de ideas que puede probar:

  • evitar clFinish llamando. La forma en que lo llamas entre la carga de la memoria y la ejecución obliga al conductor a hacer más trabajo de lo necesario. Pone la GPU.
  • perfila tu código para ver qué se está tomando el tiempo. Todavía no conozco el soporte para el análisis de rendimiento CL, pero con sus llamadas clFinish, le da una estimación de primer orden simplemente midiendo el lado de la CPU. Tenga en cuenta que, en general, es difícil distinguir lo que se debe a la latencia y lo que se debe al rendimiento.
+0

Gracias Bahbar, traté de eliminar el cl_finish sugerido pero sin éxito ... Luego traté de eliminarlos todos (incluso el inseguro) y sigo teniendo el mismo tiempo de ejecución ... Sin embargo, una cosa interesante es que los tiempos de ejecución OpenCL tardan el doble largo (ambos GeForce) si desenchufo el cable de alimentación de mi computadora y lo dejo funcionar con batería .. – matdumsa

2

Obtengo los mismos resultados, y no estoy seguro de por qué. Mi kernel implica un mínimo de copia hacia/desde (preselecciono todos los datos necesarios para todas las llamadas al kernel, y solo devuelvo una imagen de 512x512). Es un raytracer, por lo que el kernel funciona mucho más que la copia de vuelta (400 ms a 10 ms). Aún así, el 9600M GT es aproximadamente 1.5x-2x más lento.

De acuerdo con el listado de nVidia, la 9600M GT debe tener 32 SP (el doble de la 9400M). Es presumiblemente mayor también.

El 9600M GT parece más rápido en algunos casos, p. juegos. Ver estos enlaces: http://www.videocardbenchmark.net/video_lookup.php?cpu=GeForce+9600M+GT http://www.videocardbenchmark.net/video_lookup.php?cpu=GeForce+9600M+GT

Según ars technica:

Además, un dato interesante acerca de la implementación de Snow Leopard es revelado por las primeras pruebas. Aunque Snow Leopard no parece habilitar las GPU duales o la conmutación de GPU sobre la marcha para máquinas que usan el chipset NVIDIA GeForce 9400M, una limitación heredada de Leopard, parece que el sistema operativo puede usar ambos recursos como OpenCL simultáneamente. Entonces, incluso si tiene habilitada la 9600M GT en su MacBook Pro, si se encuentra el código OpenCL en una aplicación, Snow Leopard puede enviar ese código para ser procesado por los 16 núcleos de la GPU que permanecen inactivos en la 9400M. Sin embargo, lo contrario no es cierto: cuando se ejecuta una MacBook Pro con solo 9400M habilitado, la 9600M GT se apaga por completo para ahorrar energía y no se puede usar como un recurso OpenCL.

Esto parece ser lo contrario de lo que estamos viendo. Además, estoy configurando explícitamente un contexto CL en un solo dispositivo a la vez.

Hay algunas sugerencias en el ars forums que el 9600M GT no admite dobles también, lo que explicaría este problema. Podría tratar de escribir un punto de referencia sintético para probar esta hipótesis.

10

El 9400M está integrado a su controlador de memoria mientras que el 9600M GT es una tarjeta discreta que está conectada a su controlador de memoria a través del bus PCI-e. Esto significa que cuando transfiere la memoria al 9400M, solo la asigna a la RAM del sistema. El 9600M, por otro lado, envía los datos a través del PCI-e a la memoria gráfica dedicada en la tarjeta. Esta transferencia es lo que hace que su punto de referencia parezca más lento.

Si desea comparar el rendimiento de las dos tarjetas gráficas, debe utilizar la función de creación de perfiles OpenCL en lugar de la función de reloj que está utilizando actualmente.

cl_int clGetEventProfilingInfo (cl_event event, cl_profiling_info param_name, size_t param_value_size, void *param_value, size_t *param_value_size_ret)

Pasar la función del evento que se creó cuando estabas encolamos el Kernel y pasarle el CL_PROFILING_COMMAND_START para el segundo argumento para obtener el punto de partida del Kernel en nanosegundos y CL_PROFILING_COMMAND_END para obtener el punto final del el kernel Asegúrese de utilizar este comando DESPUÉS de que la ejecución del kernel haya finalizado (los eventos mantienen sus valores hasta que salgan del alcance). También puede obtener el tiempo que llevó transferir los datos al dispositivo aplicando esta función a los eventos. desde el enqueueing del buffer. Aquí hay un ejemplo:

 TRACE("Invoking the Kernel") 
    cl::vector<cl::Event> matMultiplyEvent; 
    cl::NDRange gIndex(32,64); 
    cl::NDRange lIndex(16,16); 

    err = queueList["GPU"]->enqueueNDRangeKernel(
               matrixMultiplicationKernel, 
               NULL, 
               gIndex, 
               lIndex, 
               &bufferEvent, 
               matMultiplyEvent); 
    checkErr(err, "Invoke Kernel"); 


    TRACE("Reading device data into array"); 
    err = queueList["GPU"]->enqueueReadBuffer(thirdBuff, 
               CL_TRUE, 
               0, 
               (matSize)*sizeof(float), 
               testC, 
               &matMultiplyEvent, 
               bufferEvent); 
    checkErr(err, "Read Buffer"); 
    matMultiplyEvent[0].wait(); 
    for (int i = 0; i < matSize; i++) { 
     if (i%64 == 0) { 
      std::cout << "\n"; 
     } 
     std::cout << testC[i] << "\t"; 
    } 
    long transferBackStart = bufferEvent[0].getProfilingInfo<CL_PROFILING_COMMAND_START>(); 
    long transferBackEnd = bufferEvent[0].getProfilingInfo<CL_PROFILING_COMMAND_END>(); 
    double transferBackSeconds = 1.0e-9 * (double)(transferBackEnd- transferBackStart); 

    long matrixStart = matMultiplyEvent[0].getProfilingInfo<CL_PROFILING_COMMAND_START>(); 
    long matrixEnd = matMultiplyEvent[0].getProfilingInfo<CL_PROFILING_COMMAND_END>(); 
    double dSeconds = 1.0e-9 * (double)(matrixEnd - matrixStart); 

Este ejemplo utiliza el contenedor C++ pero el concepto debe ser el mismo.

Espero que esto ayude.

+0

Gracias, pronto probaré lo que usted propone ver si eso lo explica: P – matdumsa

0

Soy nuevo en OpenCL, así que puedo ser un poco ingenuo, pero dudo que tengas que acceder al panel de ahorro de energía para cambiar el dispositivo de cálculo OpenCL. Creo que eliges el dispositivo cuando configuras el contexto OpenCL en tu código.

Mi hipótesis: 1) Cuando ejecuta su código sin deshabilitar primero su GPU integrada, OpenCL elige su GPU discreta como dispositivo de cómputo. Su código se ejecuta en la GPU discreta (rápida). 2) Cuando desactiva la GPU integrada primero, fuerza la carga de ejecutar la GUI de OS X en su tarjeta discreta. Cuando ejecuta su código, se ejecuta en la GPU discreta, pero se disputa con su GUI por los recursos.

Esta respuesta viene 11 meses después de que se hizo la pregunta, pero es de esperar que va a ser útil a alguien ...

Cuestiones relacionadas