在NUMA机器上使用CUDA进行多GPU编程

3

我目前正在将一个算法移植到两个GPU上。硬件的设置如下:

  • 作为NUMA系统的两个CPU,因此主内存分为两个NUMA节点。
  • 每个GPU物理连接到其中一个GPU。(每个PCIe控制器有一个GPU)

我在主机上创建了两个线程来控制GPU。这些线程被绑定到各自的NUMA节点,即每个线程都在一个CPU插座上运行。我如何确定GPU的编号,以便我可以使用cudaSetDevice()选择直接连接的GPU?


3
这被称为设置CPU/GPU亲和性。据我所知,在编程方式下进行此操作并不简单。当然,您可以手动映射系统并以硬编码的方式使用它。但是要自动执行此操作,我熟悉的方法涉及使用每个GPU的PCI总线ID,然后遍历系统PCI设备树以发现哪个PCIE根复杂在同一树中。你是在运行Linux还是Windows?这里是Linux中的一个实现。 - Robert Crovella
2个回答

6

正如我在评论中提到的那样,这是一种CPU GPU亲和性类型。这是我编写的一个Bash脚本,我相信它将在RHEL/CentOS 6.x操作系统上提供有用的结果。它可能无法在许多旧版或其他Linux发行版上正常工作。您可以像这样运行脚本:

./gpuaffinity > out.txt

您可以在程序中读取out.txt文件,以确定哪些逻辑CPU核心对应哪些GPU。例如,在具有两个6核处理器和4个GPU的NUMA Sandy Bridge系统上,示例输出可能如下所示:

0     03f
1     03f
2     fc0
3     fc0

该系统有4个GPU,编号从0到3。每个GPU编号后面跟着一个“核心掩码”。核心掩码对应于与特定GPU“接近”的内核,以二进制掩码表示。因此,对于GPU 0和1,系统中的前6个逻辑内核(03f二进制掩码)最接近。对于GPU 2和3,系统中的第二组6个逻辑内核(fc0二进制掩码)最接近。

您可以在程序中读取文件,也可以使用脚本中说明的逻辑在程序中执行同样的功能。

您还可以像这样调用脚本:

./gpuaffinity -v

这将提供稍微更详细的输出。

下面是bash脚本:

#!/bin/bash
#this script will output a listing of each GPU and it's CPU core affinity mask
file="/proc/driver/nvidia/gpus/0/information"
if [ ! -e $file ]; then
  echo "Unable to locate any GPUs!"
else
  gpu_num=0
  file="/proc/driver/nvidia/gpus/$gpu_num/information"
  if [ "-v" == "$1" ]; then echo "GPU:  CPU CORE AFFINITY MASK: PCI:"; fi
  while [ -e $file ]
  do
    line=`grep "Bus Location" $file | { read line; echo $line; }`
    pcibdf=${line:14}
    pcibd=${line:14:7}
    file2="/sys/class/pci_bus/$pcibd/cpuaffinity"
    read line2 < $file2
    if [ "-v" == "$1" ]; then
      echo " $gpu_num     $line2                  $pcibdf"
    else
      echo " $gpu_num     $line2 "
    fi
    gpu_num=`expr $gpu_num + 1`
    file="/proc/driver/nvidia/gpus/$gpu_num/information"
  done
fi

5

nvidia-smi 工具可以告诉 NUMA 架构的拓扑结构。

% nvidia-smi topo -m
        GPU0    GPU1    GPU2    GPU3    CPU Affinity
GPU0     X      PHB     SOC     SOC     0-5
GPU1    PHB      X      SOC     SOC     0-5
GPU2    SOC     SOC      X      PHB     6-11
GPU3    SOC     SOC     PHB      X      6-11

Legend:

  X   = Self
  SOC  = Connection traversing PCIe as well as the SMP link between CPU sockets(e.g. QPI)
  PHB  = Connection traversing PCIe as well as a PCIe Host Bridge (typically the CPU)
  PXB  = Connection traversing multiple PCIe switches (without traversing the PCIe Host Bridge)
  PIX  = Connection traversing a single PCIe switch
  NV#  = Connection traversing a bonded set of # NVLinks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接