La razón del rendimiento relativamente pobre de la memoria compartida CUDA cuando se utilizan matrices más grandes puede tener que ver con el hecho de que cada multiprocesador tiene una cantidad limitada de memoria compartida disponible.
Cada multiprocesador aloja varios procesadores; para dispositivos modernos, generalmente 32, la cantidad de hilos en una urdimbre. Esto significa que, en ausencia de divergencia o paradas de memoria, la tasa promedio de procesamiento es de 32 instrucciones por ciclo (la latencia es alta debido a la canalización).
CUDA planifica varios bloques para un multiprocesador. Cada bloque consta de varias urdimbres. Cuando una urdimbre se detiene en un acceso de memoria global (incluso los accesos fusionados tienen una alta latencia), se procesan otras distorsiones. Esto efectivamente oculta la latencia, por lo que la memoria global de alta latencia es aceptable en las GPU. Para ocultar eficazmente la latencia, necesitas suficientes warps adicionales para ejecutar hasta que el warp estancado pueda continuar. Si todos los warps se detienen en los accesos a la memoria, ya no se puede ocultar la latencia.
La memoria compartida se asigna a bloques en CUDA y se almacena en un solo multiprocesador en el dispositivo GPU. Cada multiprocesador tiene una cantidad relativamente pequeña y fija de espacio de memoria compartida. CUDA no puede programar más bloques para multiprocesadores de los que los multiprocesadores pueden admitir en términos de memoria compartida y uso de registros. En otras palabras, si la cantidad de memoria compartida en un multiprocesador es X y cada bloque requiere Y de memoria compartida, CUDA no programará más bloques de piso (X/Y) a la vez para cada multiprocesador (podría ser menor ya que hay otras restricciones, como el uso del registro).
Ergo, al aumentar el uso de la memoria compartida de un bloque, es posible que esté reduciendo el número de warps activos (la ocupación) de su núcleo, lo que perjudica el rendimiento. Debería examinar su código de kernel compilando con el indicador -Xptxas = "- v"; esto debería darle registro y compartir el uso de la memoria constante & para cada kernel. Utilice esta información y los parámetros de inicio del kernel, así como otra información requerida, en la versión más reciente de la Calculadora de ocupación CUDA para determinar si puede verse afectado por la ocupación.
EDIT:
Para hacer frente a la otra parte de su pregunta, suponiendo que no haya conflictos de bancos de memoria compartida y perfecta coalescencia de memoria global accesos ... hay dos dimensiones a esta respuesta: la latencia y ancho de banda. La latencia de la memoria compartida será menor que la de la memoria global, ya que la memoria compartida está en chip. El ancho de banda será muy similar. Ergo, si puede ocultar la latencia de acceso a la memoria global mediante coalescencia, no hay penalización (nota: el patrón de acceso es importante aquí, en esa memoria compartida permite patrones de acceso potencialmente más diversos con poca o ninguna pérdida de rendimiento, por lo que puede ser beneficioso al uso de la memoria compartida, incluso si puede ocultar toda la latencia de la memoria global).
Excelente descripción. – harrism
Gracias. Esto es muy útil. – Ross
¿Por qué el ancho de banda sería el mismo? ¿O lo dijiste solo por el M2050? – einpoklum