Introducción a la optimización del rendimiento de CPU y GPU
En la computación de alto rendimiento y el procesamiento de tareas paralelas a gran escala, las GPU se han convertido en aceleradores indispensables. Para aprovechar al máximo las capacidades de cómputo de la GPU, es crucial optimizar las relaciones entre CPU y GPU mediante la asignación y vinculación razonable de los núcleos de la CPU a las GPU. Este artículo explorará en profundidad los conceptos de sockets y NUMA (Acceso a Memoria No Uniforme) y discutirá cómo implementar la vinculación de núcleos de CPU y GPU basada en estas arquitecturas de hardware para garantizar un rendimiento óptimo del sistema.
Concepto de Socket
¿Qué es un Socket?
Un socket generalmente se refiere a la ranura de instalación física de la CPU en la placa base. Cada socket corresponde a una CPU física, que normalmente contiene múltiples núcleos y uno o más niveles de caché (por ejemplo, cachés L1, L2, L3). En sistemas con múltiples sockets (por ejemplo, servidores duales o cuádruples), cada socket tiene una CPU física conectada mediante una interconexión de alta velocidad (por ejemplo, QPI de Intel o Infinity Fabric de AMD).
Características de los Sistemas Multi-Socket
En sistemas multi-socket, la CPU de cada socket puede acceder a su memoria local y también acceder a la memoria de otros sockets. Este patrón de acceso a memoria introduce el concepto de NUMA, cuyo objetivo es optimizar la eficiencia del acceso a la memoria.
Arquitectura NUMA (Acceso a Memoria No Uniforme)
¿Qué es NUMA?
NUMA significa Non-Uniform Memory Access, es decir, acceso a memoria no uniforme. A diferencia del acceso uniforme a memoria tradicional (UMA), en la arquitectura NUMA la memoria del sistema se divide en varias regiones, cada una asociada a una CPU (socket) específica. Acceder a la memoria local (dentro del mismo socket) es más rápido que acceder a la memoria remota (de otro socket), lo que resulta en una latencia mayor.
Nodos NUMA y Latencia de Acceso a Memoria
En los sistemas NUMA, cada socket y su memoria directamente conectada forman un nodo NUMA. El acceso a la memoria dentro del mismo nodo NUMA es más rápido, mientras que el acceso a memoria entre nodos incurre en una latencia mayor debido a la transmisión adicional por el bus. Optimizar la afinidad entre memoria y CPU, asegurando que las tareas se ejecuten dentro del mismo nodo NUMA, es un paso crítico de optimización del rendimiento.
Relación Física entre CPU y GPU
Arquitectura de Hardware de GPU
Las GPU generalmente se comunican con las CPU a través de buses PCIe (Peripheral Component Interconnect Express). En sistemas multi-socket, las GPU suelen estar conectadas a un solo socket (y su nodo NUMA correspondiente) y no a través de sockets. Esto significa que, en la operación real, la GPU tiene un mayor ancho de banda y menor latencia con los núcleos de CPU y la memoria del socket al que está conectada.
Afinidad entre CPU y GPU
La comunicación entre CPU y GPU depende principalmente de la transferencia de datos. Los datos se transfieren de la CPU a la GPU y viceversa, lo que implica operaciones de acceso a memoria que afectan significativamente el rendimiento. Si el núcleo de CPU vinculado a la GPU se encuentra dentro del mismo nodo NUMA que la GPU, la latencia de transferencia de datos se reduce significativamente. Por lo tanto, vincular los núcleos de CPU a las GPU es un paso clave para optimizar el rendimiento.
Estrategia de Vinculación de Núcleos de GPU y CPU basada en Afinidad
En el despliegue contenerizado con Docker, implementar la vinculación por afinidad entre GPU y CPU es crucial para mejorar el rendimiento de las tareas contenerizadas. Las funciones de control de recursos de CPU y GPU de Docker permiten un control preciso sobre los núcleos de CPU y los dispositivos GPU utilizados por los contenedores.
Asignación de Recursos de CPU y GPU en Contenedores
Los contenedores Docker permiten un control preciso de los recursos de CPU y GPU asignados. Al especificar los núcleos de CPU y los dispositivos GPU que usará un contenedor, se puede implementar la vinculación por afinidad para optimizar el rendimiento.
Configuración de CPU en Docker
En Docker, la asignación de recursos de CPU se puede controlar usando los siguientes parámetros:
--cpuset-cpus: Especifica los núcleos de CPU físicos que puede usar el contenedor. Por ejemplo,--cpuset-cpus="0-3"limita el contenedor a usar los núcleos de CPU 0 a 3.--cpu-shares: Controla el peso del uso de CPU del contenedor, pero no restringe el uso de núcleos específicos.--cpus: Limita el número total de núcleos de CPU (en núcleos virtuales) que puede usar el contenedor.
Configuración de GPU en Docker
La vinculación de dispositivos GPU se puede lograr usando los siguientes parámetros de Docker:
--gpus: Especifica los dispositivos GPU a los que puede acceder el contenedor. Por ejemplo,--gpus '"device=0"'asigna la GPU 0 al contenedor.
Implementación de Vinculación de Núcleos de GPU y CPU en Docker
Para implementar la vinculación de núcleos de GPU y CPU en contenedores Docker, combine la configuración de CPU y GPU. Aquí hay un ejemplo de cómo vincular núcleos de CPU específicos y una GPU al iniciar un contenedor Docker:
docker run --cpuset-cpus="0-3" --gpus '"device=0"' --memory="8g" my_gpu_container
En este comando:
--cpuset-cpus="0-3"vincula el contenedor a los núcleos de CPU 0 a 3, que deberían estar dentro del mismo nodo NUMA que la GPU 0.--gpus '"device=0"'asigna la GPU 0 al contenedor.--memory="8g"limita el uso de memoria del contenedor a 8 GB, asegurando que la asignación de memoria también esté alineada con la afinidad de CPU/GPU.
Logrando una Vinculación Óptima
Para garantizar una vinculación óptima en los contenedores, primero determine la topología física de la máquina. Use nvidia-smi topo -m para ver la topología de la máquina:
nvidia-smi topo -m
A partir de la salida, puede determinar la configuración NUMA de la máquina y las asignaciones de GPU. Por ejemplo, si la máquina tiene dos nodos NUMA, NUMA 0 con 4 GPU y NUMA 1 con 4 GPU, puede identificar la afinidad entre GPU y CPU para cada nodo NUMA.
Pseudocódigo para el Cálculo de Afinidad
Aquí hay un pseudocódigo simplificado para calcular la afinidad y determinar los IDs de GPU y CPU:
type Affinity struct {
}
// Calcula si se cumple la afinidad y devuelve los IDs de GPU y CPU correspondientes
func calAffinity(affinity *Affinity, cpuUse []int, gpuUse []int, gpuReq int, cpuReq int) (bool, []int, []int) {
return true, []int{}, []int{}
}
Este método se puede usar para determinar si un nodo cumple con los requisitos de vinculación óptima. Cuando existen múltiples nodos, este método se puede usar para evaluar y seleccionar el nodo más adecuado.
Novita AI ha desarrollado un motor de contenedores adaptado para la próxima generación de computación de IA, que ajusta algoritmos dinámicamente para monitorear el uso del hardware en tiempo real y realizar optimizaciones de extremo a extremo. Los usuarios pueden disfrutar del rendimiento computacional más potente sin preocuparse por los detalles técnicos de NUMA.
Los usuarios también pueden realizar configuraciones NUMA más avanzadas en el panel de control. Si tiene más requisitos relacionados, ¡no dude en contactarnos en Discord!
Visite Novita AI para obtener más detalles.

