¿NVidia RDMA GPUDirect siempre opera solo direcciones físicas (en el espacio de direcciones físicas de la CPU)?

StackOverflow https://stackoverflow.com/questions/19841815

Pregunta

Como la conocemos: http://en.wikipedia.org/wiki/IOMMU#Advantages

La paginación de la memoria periférica puede ser compatible con un IOMMU.Un periférico que usa la extensión de la interfaz de solicitud de la página PCI-SIG PCIe Directs Services (ATS) puede detectar y indicar la necesidad de los servicios de Memory Manager.

enter image description here

Pero cuando usamos nVidia GPU con CUDA >= 5.0, podemos usar RDMA GPUDirect y sabemos que:

http://docs.nvidia.com/cuda/gpudirect-rdma/index.html#how-gpudirect-rdma-works

Tradicionalmente, recursos como ventanas de barra se asignan al espacio de direcciones de usuario o kernel utilizando la MMU de la CPU como direcciones de E/S de memoria (MMIO).Sin embargo, porque Los sistemas operativos actuales no tienen mecanismos suficientes para intercambiar regiones MMIO entre los conductores, El controlador NVIDIA Kernel exporta las funciones para realizar las traducciones y asignaciones de direcciones necesarias.

http://docs.nvidia.com/cuda/gpudirect-rdma/index.html#supported-systems

RDMA para GPUDirect actualmente depende de todas las direcciones físicassiendo el mismo desde el punto de vista de los dispositivos PCI.Esto lo hace incompatible con IOMMUS y, por lo tanto, deben estar deshabilitados para RDMA para que Gpudirect funcione.

Y si asignamos y asignamos CPU-RAM a UVA, como aquí:

#include <iostream>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"

int main() {
    // Can Host map memory
    cudaSetDeviceFlags(cudaDeviceMapHost);  

    // Allocate memory
    unsigned char *host_src_ptr = NULL;
    cudaHostAlloc(&host_src_ptr, 1024*1024, cudaHostAllocMapped);
    std::cout << "host_src_ptr = " << (size_t)host_src_ptr << std::endl;

    // Get UVA-pointer
    unsigned int *uva_src_ptr = NULL;
    cudaHostGetDevicePointer(&uva_src_ptr, host_src_ptr, 0);
    std::cout << "uva_src_ptr  = " << (size_t)uva_src_ptr << std::endl;

    int b;  std::cin >> b;
    return 0;
}

Obtenemos punteros iguales en Windwos7x64, eso significa que cudaHostGetDevicePointer() hacer nada:

host_src_ptr = 68719476736

uva_src_ptr = 68719476736

¿Qué significa "mecanismos suficientes para intercambiar regiones MMIO entre controladores", a qué mecanismo se refiere aquí y por qué no puedo usar IOMMU usando la dirección virtual para acceder a través de PCIe a la región física de BAR, otro dispositivo mapeado en memoria a través de PCIe? ?

¿Y esto significa que RDMA GPUDirect siempre opera solo direcciones físicas (en el espacio de direcciones físicas de la CPU), pero por qué enviamos a la función del kernel? uva_src_ptr que es igual a host_src_ptr - ¿puntero simple en el espacio de direcciones virtuales de la CPU?

¿Fue útil?

Solución

El IOMMU es muy útil porque proporciona un conjunto de registros de mapeo.Puede hacer que cualquier memoria física aparezca dentro del rango de direcciones al que puede acceder un dispositivo y también puede hacer que los buffers físicamente dispersos parezcan contiguos para los dispositivos.Esto no es bueno para tarjetas PCI/PCI-Express de terceros o máquinas remotas que intentan acceder al desplazamiento físico sin procesar de una GPU nVidia, ya que esto puede resultar en no de hecho acceder a las regiones previstas de la memoria o inhibir/restringir dichos accesos por tarjeta por parte de la unidad IOMMU.Esto debe ser deshabilitado, entonces, porque

"RDMA para GPUDirect actualmente depende de Todas las direcciones físicas son las mismas desde el punto de vista de los dispositivos PCI."

-nVidia, Consideraciones de diseño para rDMA y GPUDirect

Cuando los controladores intentan utilizar la MMU de la CPU y asignar regiones de E/S asignadas en memoria (MMIO) para usarlas dentro del espacio del kernel, normalmente mantienen la dirección devuelta de la asignación de memoria para ellos mismos.Debido a que cada controlador opera dentro de su propio contexto o espacio de nombres, intercambiar estas asignaciones entre los controladores de nVidia y los controladores de otros proveedores que deseen admitir rDMA+GPUDirect sería muy difícil y daría como resultado una solución específica del proveedor (posiblemente incluso producto (específico si los controladores varían mucho entre productos de terceros).Además, los sistemas operativos actuales no tienen ninguna buena solución para intercambiar asignaciones MMIO entre controladores, por lo que nVidia exporta varias funciones que permiten a los controladores de terceros acceder fácilmente a esta información desde el propio espacio del kernel.

nVidia impone el uso de "direccionamiento físico" para acceder a cada tarjeta a través de rDMA para GPUDirect.Esto simplifica enormemente el proceso de mover datos desde una computadora al bus PCI-Express de un sistema remoto utilizando el esquema de direccionamiento físico de esa máquina sin tener que preocuparse por problemas relacionados con el direccionamiento virtual (por ejemplo,resolución de direcciones virtuales a físicas).Cada tarjeta tiene una dirección física en la que reside y se puede acceder a ella en este desplazamiento;solo se debe agregar una pequeña cantidad de lógica al controlador de terceros que intenta realizar operaciones rDMA.Además, estos registros de dirección base de 32 o 64 bits son parte del espacio de configuración PCI estándar, por lo que la dirección física de la tarjeta podría obtenerse fácilmente simplemente leyendo de su BAR en lugar de tener que obtener una dirección asignada que obtuvo el controlador de nVidia. al adjuntarlo a la tarjeta.Universal Virtual Addressing (UVA) de nVidia se encarga de las asignaciones de direcciones físicas antes mencionadas a una región de memoria aparentemente contigua para espacio de usuario aplicaciones, así:

CUDA Virtual Address Space

Estas regiones de la memoria se dividen a su vez en tres tipos:CPU, GPU y GRATIS, todos documentados aquí.

Sin embargo, volvamos a su caso de uso:ya que estas en espacio de usuario, no tiene acceso directo al espacio de direcciones físicas del sistema y las direcciones que está utilizando probablemente sean direcciones virtuales proporcionadas por UVA de nVidia.Suponiendo que no se realizaron asignaciones previas, su asignación de memoria debería residir en el desplazamiento +0x00000000, lo que daría como resultado que usted vea el mismo desplazamiento de la GPU.Si tuviera que asignar un segundo búfer, me imagino que vería que este búfer comienza inmediatamente después del final del primer búfer (en el desplazamiento +0x00100000 de la base dirección virtual de la GPU en su caso de asignaciones de 1 MB).

si estuvieras en espacio-kernel, sin embargo, y si escribiera un controlador para la tarjeta de su empresa para utilizar rDMA para GPUDirect, usaría las direcciones físicas de 32 o 64 bits asignadas a la GPU por el BIOS y/o el sistema operativo del sistema para los datos rDMA directamente hacia y desde el GPU, en sí.

Además, puede valer la pena señalar que no todos los motores DMA realmente admiten direcciones virtuales para transferencias; de hecho, la mayoría requiere direcciones físicas, como el manejo de direcciones virtuales desde un motor DMA. puede volverse complejo (página 7), por lo que muchos motores DMA carecen de soporte para esto.

Sin embargo, para responder la pregunta del título de su publicación:Actualmente, nVidia solo admite direccionamiento físico para rDMA+GPUDirect en el espacio del kernel.Para espacio de usuario aplicaciones, siempre utilizará la dirección virtual de la GPU que le proporcionó la UVA de nVidia, que se encuentra en el espacio de direcciones virtuales de la CPU.


En relación con su aplicación, aquí hay un desglose simplificado del proceso que puede realizar para las operaciones rDMA:

  1. Su espacio de usuario La aplicación crea buffers, que están dentro del alcance del espacio de direccionamiento virtual unificado que proporciona nVidia (direcciones virtuales).
  2. Haz una llamada a cuPointerGetAttribute(...) obtener tokens P2P;Estos tokens pertenecen a la memoria dentro del contexto de CUDA.
  3. Envía toda esta información a espacio-kernel de alguna manera (por ej.IOCTL, lectura/escritura en su controlador, etc.).Como mínimo, querrás que estas tres cosas terminen en tu espacio-kernel conductor:
    • Token(s) P2P devueltos por cuPointerGetAttribute(...)
    • Dirección(es) virtual(es) UVA del(los) buffer(s)
    • Tamaño del buffer(s)
  4. Ahora traduzca esas direcciones virtuales a sus direcciones físicas correspondientes llamando a las funciones del espacio del kernel de nVidia, ya que estas direcciones se guardan en las tablas de páginas de nVidia y se puede acceder a ellas con las funciones exportadas de nVidia, como por ejemplo: nvidia_p2p_get_pages(...), nvidia_p2p_put_pages(...), y nvidia_p2p_free_page_table(...).
  5. Utilice estas direcciones físicas adquiridas en el paso anterior para inicializar su motor DMA que manipulará esos buffers.

Puede encontrar una explicación más detallada de este proceso. aquí.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top