El estudio de optimización de trasplante de algoritmo integrado señala la programación 6-CUDA


Referencia:
agregar descripción del enlace

El nombre chino de CUDA (Compute Unified Device Architecture) se denomina arquitectura de dispositivo informático unificado. Los estudiantes en el campo de la visión de la imagen estarán expuestos a CUDA más o menos. Después de todo, para optimizar el rendimiento y la velocidad, CUDA es una herramienta muy importante. CUDA es un pozo que es difícil de pasar por alto para los estudiantes de visión. Debes pisarlo ser práctico. La programación CUDA es realmente fácil de comenzar y difícil de dominar. No debería ser muy difícil para los estudiantes con conocimientos de arquitectura de computadoras y programación en lenguaje C comenzar con la programación CUDA. Este artículo lo ayudará a comprender los puntos de conocimiento más importantes de la programación CUDA a través de los siguientes cinco aspectos y comenzar rápidamente:

  • Características de la arquitectura de la GPU
  • Modelo de hilo CUDA
  • Modelo de memoria CUDA
  • Modelo de programación CUDA
  • Pequeño ejemplo de la aplicación CUDA

1. Características de la arquitectura de la GPU

Primero, hablemos de computación en serie y computación en paralelo. Sabemos que la clave para la informática de alto rendimiento es utilizar procesadores de varios núcleos para la informática en paralelo.

Cuando resolvemos una tarea de un programa de computadora, nuestra idea natural es descomponer la tarea en una serie de pequeñas tareas y completar estas pequeñas tareas una por una. En los cálculos en serie, nuestra idea es dejar que nuestro procesador procese una tarea de cálculo a la vez y luego calcule la siguiente tarea después de procesar una tarea de cálculo, hasta que se completen todas las tareas pequeñas, luego esta gran tarea del programa también se termina. Como se muestra en la figura siguiente, son los pasos de cómo usamos las ideas de programación en serie para resolver problemas.

Pero las deficiencias de la computación en serie son muy obvias. Si tenemos procesadores multinúcleo, podemos usar procesadores multinúcleo para procesar múltiples tareas al mismo tiempo, y estas pequeñas tareas no están relacionadas (no es necesario que dependan unas de otras , por ejemplo, mis tareas informáticas no utilizan los resultados de sus cálculos), entonces, ¿por qué utilizamos la programación en serie? Para acelerar aún más la velocidad de cálculo de las tareas grandes, podemos asignar algunos módulos independientes a diferentes procesadores para el cálculo simultáneo (esto es en paralelo) y finalmente integrar estos resultados para completar el cálculo de una tarea. La siguiente figura es para descomponer una gran tarea de computación en pequeñas tareas y luego asignar pequeñas tareas independientes a diferentes procesadores para computación en paralelo y finalmente resumir los resultados a través de un programa en serie para completar la tarea de computación total.

Por lo tanto, si un programa puede realizar computación en paralelo, la clave es que tenemos que analizar en qué módulos de ejecución se puede dividir el programa, cuáles de estos módulos de ejecución son independientes y cuáles dependen en gran medida de un acoplamiento fuerte, módulos independientes que podemos probar. para diseñar computación en paralelo y aprovechar al máximo las ventajas de los procesadores de múltiples núcleos para acelerar aún más nuestras tareas de computación. Para el módulo de acoplamiento fuerte, usamos programación en serie y utilizamos la idea de programación en serie + paralelo para completar una computación de alto rendimiento.

A continuación, hablemos de la diferencia entre CPU y GPU, y sus respectivas características. Hablamos sobre el concepto de "multi-core" muchas veces cuando hablamos de computación en paralelo y serial. Ahora comencemos este tema desde la perspectiva de "core ".. Primero, la CPU se compone de varios núcleos optimizados para el procesamiento en serie secuencial. La GPU está compuesta por miles de núcleos más pequeños y eficientes, que están específicamente diseñados para manejar múltiples tareas al mismo tiempo y pueden manejar de manera eficiente tareas paralelas. Es decir, aunque cada núcleo de la CPU es sumamente capaz, es muy potente en tareas de procesamiento, pero tiene menos núcleos y no rinde bien en computación en paralelo; por otro lado, la GPU, aunque su potencia de cómputo por núcleo es no es fuerte, la ventaja es que hay muchos núcleos, que pueden manejar múltiples tareas de computación al mismo tiempo, y hacen un buen trabajo apoyando la computación en paralelo.

Las diferentes características de hardware de la GPU y la CPU determinan sus escenarios de aplicación. La CPU es el núcleo de la operación y el control de la computadora, y la GPU se utiliza principalmente para el procesamiento de gráficos e imágenes. La forma de la imagen presentada en la computadora es una matriz. Nuestro procesamiento de imágenes consiste en manipular varias matrices para realizar cálculos, y muchas operaciones matriciales se pueden paralelizar, lo que agiliza el procesamiento de imágenes. Por lo tanto, la GPU está en el campo de los gráficos e imágenes También existe la oportunidad de flexionar sus músculos. La siguiente figura muestra un sistema de hardware de computadora con múltiples GPU. Se puede ver que una memoria de GPU tiene muchos SP y varios tipos de memoria. Estos hardware son la base para que la GPU realice una computación paralela eficiente.

Ahora comparemos las características de la CPU y la GPU desde la perspectiva del procesamiento de datos. La CPU necesita una gran versatilidad para manejar varios tipos de datos, como enteros, números de punto flotante, etc., y debe ser buena para manejar una gran cantidad de saltos de rama e interrupciones de procesamiento causados ​​por juicios lógicos, por lo que la CPU es realmente un tipo fuerte muy capaz, puede manejar muchas cosas correctamente. Por supuesto, necesitamos darle muchos recursos para su uso (varios hardware), lo que también hace que la CPU sea imposible de tener demasiados núcleos (el número total de núcleos no supera los 16). La GPU se enfrenta a datos altamente unificados, independientes y a gran escala y a un entorno informático puro que no necesita ser interrumpido.La GPU tiene muchos núcleos (la arquitectura Fermi tiene 512 núcleos), aunque su núcleo La capacidad es mucho menos potente que el núcleo de la CPU, pero tiene más
ventajas. Muestra la ventaja de "mucha gente y más poder" cuando se trata de tareas informáticas sencillas. Este es el encanto de la informática paralela.

Para resumir las características de los dos son:

  • CPU: bueno en el control de procesos y procesamiento lógico, estructuras de datos irregulares, estructuras de almacenamiento impredecibles, programas de un solo subproceso, algoritmos intensivos en ramas
  • GPU: Bueno en computación paralela de datos, estructura de datos regular, modo de almacenamiento predecible.
  • Inserte la descripción de la imagen aquí
    En la arquitectura informática actual, para completar la computación en paralelo CUDA, la GPU por sí sola no puede completar la tarea de computación. La CPU debe utilizarse para cooperar para completar una tarea de computación en paralelo de alto rendimiento.

En términos generales, la parte paralela se ejecuta en la GPU y la parte en serie se ejecuta en la CPU, lo que es una computación heterogénea. Específicamente, la computación heterogénea significa que los procesadores de diferentes arquitecturas cooperan entre sí para completar las tareas de computación. La CPU es responsable del flujo general del programa y la GPU es responsable de las tareas de cálculo específicas.Cuando los subprocesos de la GPU completan las tareas de cálculo, copiamos los resultados calculados en el lado de la GPU al lado de la CPU para completar una tarea de cálculo.

Por lo tanto, la división general del trabajo para las aplicaciones que usan la GPU para lograr la aceleración es: la GPU completa el código de cálculo intensivo (aproximadamente el 5% de la cantidad de código) y la CPU ejecuta el código de serie restante.

2. Modelo de hilo CUDA

A continuación, presentamos la estructura de organización de subprocesos de CUDA. En primer lugar, todos sabemos que el hilo es la unidad más básica de ejecución del programa, y ​​la computación paralela de CUDA se realiza mediante la ejecución en paralelo de miles de hilos. El siguiente diagrama estructural ilustra los diferentes niveles de la estructura de la GPU.

El modelo de subprocesamiento de CUDA se ha resumido de la siguiente manera:

1. Hilo: hilo, unidad básica del paralelismo

2. Thread Block: Thread block, un grupo de hilos que cooperan entre sí. El bloque de hilos tiene las siguientes características:

  • Permitir sincronizar entre sí
  • Los datos se pueden intercambiar rápidamente a través de la memoria compartida
  • Organizar en 1, 2 o 3 dimensiones

3. Cuadrícula: un conjunto de bloques de hilo

  • Organizar en 1 y 2 dimensiones
  • Memoria global compartida

Kernel : el programa principal que se ejecuta en la GPU. Esta función del kernel se ejecuta en una determinada cuadrícula.

Un núcleo <->
Cada bloque y subproceso de One Grid tiene su propia ID, y encontramos el subproceso y el bloque de subprocesos correspondientes a través del índice correspondiente.

threadIdx, blockIdx
ID de bloque: 1D o 2D
ID de hilo: 1D, 2D o 3D

Para comprender el kernel, debe tener una comprensión clara de la jerarquía de subprocesos del kernel. En primer lugar, hay muchos subprocesos ligeros paralelizados en la GPU. Cuando se ejecuta el kernel en el dispositivo, se inician muchos subprocesos. Todos los subprocesos iniciados por un kernel se denominan cuadrícula. Los subprocesos de la misma cuadrícula comparten el mismo espacio de memoria global. La cuadrícula es la primera estructura de subproceso. Nivel y la cuadrícula se puede dividir en muchos bloques de subprocesos (bloque), un bloque de subprocesos contiene muchos subprocesos, este es el segundo nivel. La estructura de organización de dos capas de los hilos se muestra en la figura anterior. Esta es una organización de hilo en la que tanto la cuadrícula como el bloque son 2-dim. Tanto la cuadrícula como el bloque se definen como variables de tipo dim3. Dim3 se puede considerar como una variable de estructura que contiene tres miembros enteros sin signo (x, y, z). Cuando se define, el valor predeterminado se inicializa en 1. Por lo tanto, la cuadrícula y el bloque se pueden definir de manera flexible como estructuras 1-dim, 2-dim y 3-dim. Cuando se llama al kernel, las dimensiones de la cuadrícula y los hilos utilizados por el kernel también deben especificarse ejecutando la configuración <<< grid , bloque >>> Dimensiones del bloque. Por ejemplo, tomemos la imagen de arriba como ejemplo para analizar cómo indexar el hilo que queremos a través del método de marca <<< cuadrícula, bloque >>>>. <<< grid, block >>> de CUDA es en realidad un método de indexación multinivel. El índice de primer nivel es (grid.xIdx, grid.yIdy), y el ejemplo correspondiente en la figura anterior es (1, 1). it Podemos encontrar la ubicación de este bloque de subprocesos, y luego iniciamos el índice secundario (block.xIdx, block.yIdx, block.zIdx) para ubicar el subproceso especificado. Esta es nuestra estructura de organización de subprocesos CUDA.

Inserte la descripción de la imagen aquí
Aquí quiero hablar de SP y SM (Stream Processor), mucha gente se confundirá con estos dos términos profesionales.

  • SP: La unidad de procesamiento más básica, el procesador de transmisión, también conocido como núcleo CUDA. Todas las instrucciones y tareas específicas finales se procesan en el SP. La GPU realiza computación en paralelo, es decir, muchos SP procesan al mismo tiempo.

  • SM: Múltiples SP más algunos otros recursos forman un multiprocesador de transmisión. También llamado núcleo de GPU, otros recursos como programador warp, registro, memoria compartida, etc. SM puede considerarse como el corazón de la GPU (en comparación con el núcleo de la CPU), el registro y la memoria compartida son recursos escasos de SM. CUDA asigna estos recursos a todos los subprocesos que residen en SM. Por lo tanto, estos recursos limitados hacen que los warps activos en cada SM tengan restricciones muy estrictas, lo que también limita la capacidad en paralelo.
    Cabe señalar que el número de SPs contenidos en cada SM difiere según la arquitectura de la GPU: la arquitectura Fermi GF100 tiene 32, GF10X tiene 48, la arquitectura Kepler es 192 y Maxwell tiene 128.

En resumen, SP es la unidad de hardware de ejecución de subprocesos. SM contiene varios SP. Una GPU puede tener varios SM (por ejemplo, 16). Finalmente, una GPU puede contener miles de SP. Tantos núcleos "se ejecutan al mismo tiempo", la velocidad se puede imaginar, estas comillas son solo para mostrar que, de hecho, la lógica del software es que todos los SP son paralelos, pero físicamente no todos los SP pueden realizar cálculos al mismo tiempo ( por ejemplo, solo tenemos 8 SM con 1024 bloques de subprocesos que deben programarse para su procesamiento), porque algunos estarán en un estado suspendido, listo y otro, que está relacionado con la programación de subprocesos de GPU.

La siguiente figura explicará el modelo de subprocesamiento de CUDA desde una perspectiva de hardware y una perspectiva de software.
Inserte la descripción de la imagen aquí

  • Cada subproceso es ejecutado por cada procesador de subprocesos (SP)
  • El bloque de subprocesos es ejecutado por un procesador multinúcleo (SM)
  • Un kernel se ejecuta en realidad mediante una cuadrícula, y un kernel solo se puede ejecutar en una GPU a la vez

El bloque es un concepto de software. Un bloque solo puede ser programado por un sm. Al desarrollar, los programadores pueden decirle al hardware de la GPU cuántos subprocesos tengo y cómo organizar los subprocesos estableciendo los atributos del bloque. La programación específica es responsabilidad del planificador de warps SM, una vez asignado el bloque al SM, el bloque permanecerá en el SM hasta el final de la ejecución. Un SM puede tener varios bloques al mismo tiempo, pero se requiere la ejecución de la secuencia. La siguiente figura muestra la arquitectura de hardware dentro de la GPU:
Inserte la descripción de la imagen aquí

3. Modelo de memoria CUDA

El modelo de memoria en CUDA se divide en los siguientes niveles:

  • Cada hilo usa sus propios registros
  • Cada hilo tiene su propia memoria local (memoria local)
  • Cada bloque de subprocesos tiene su propia memoria compartida (memoria compartida), y todos los subprocesos en todos los bloques de subprocesos comparten este recurso de memoria
  • Cada cuadrícula tiene su propia memoria global (memoria global), que puede ser utilizada por subprocesos de diferentes bloques de subprocesos.
  • Cada cuadrícula tiene su propia memoria constante (memoria constante) y memoria de textura (memoria de textura), que puede ser utilizada por subprocesos de diferentes bloques de subprocesos.

La velocidad a la que los subprocesos acceden a estos tipos de memoria es registro> memoria local> memoria compartida> memoria global

La siguiente figura muestra el nivel de estas memorias en la arquitectura de la computadora.
Inserte la descripción de la imagen aquí

4. Modelo de programación CUDA

He hablado anteriormente de tantos puntos de conocimiento relacionados con el hardware, y ahora finalmente puedo comenzar a hablar sobre cómo CUDA escribe programas.

Comencemos con un vistazo a los términos comunes de CUDA:
Inserte la descripción de la imagen aquí

La primera clave de programación para dominar: palabras clave

¿Cómo escribimos un programa o función que se pueda ejecutar en la GPU?

Puede utilizar palabras clave para indicar si un programa determinado se ejecuta en la CPU o en la GPU. Como se muestra en la siguiente tabla, por ejemplo, usamos __global__ para definir una función del kernel, que se llama en la CPU y se ejecuta en la GPU. Tenga en cuenta que el valor de retorno de la función __global__ debe establecerse en void.Inserte la descripción de la imagen aquí

El segundo punto de programación: transmisión de datos

¿Cómo escribir la transferencia de datos entre CPU y GPU?

Primero introduzca la interfaz de función de asignación de memoria de GPU y recuperación de memoria:

cudaMalloc(): 在设备端分配global memory
cudaFree(): 释放存储空间

La interfaz de función para la transmisión de datos entre los datos de la CPU y los datos de la GPU es la misma. Usan los parámetros de función pasados ​​(tipo de enumeración) para indicar la dirección de transmisión:

cudaMemcpy(void *dst, void *src, size_t nbytes,enum cudaMemcpyKind direction)

enum cudaMemcpyKind:

cudaMemcpyHostToDevice(CPU到GPU)
cudaMemcpyDeviceToHost(GPU到CPU)
cudaMemcpyDeviceToDevice(GPU到GPU)

Supongo que te gusta

Origin blog.csdn.net/mao_hui_fei/article/details/114258912
Recomendado
Clasificación