Например, когда я использую систему с несколькими графическими процессорами с CUDA C / C ++ и GPUDirect 2.0 P2P и использую вложенные коммутаторы PCI-Express, как показано на рисунке, то я должен знать, сколько коммутаторов между любыми двумя графическими процессорами использует их идентификатор шины PCI. , для оптимизации передачи данных и распределения расчетов.
Или, если я уже знаю аппаратную топологию PCIe с PCIe-коммутаторами, то я должен знать, к какому аппаратному слоту PCIe на плате подключена любая видеокарта.
Как я знаю, даже если я уже знаю аппаратную топологию PCIe с PCIe-коммутаторами, эти идентификаторы не привязаны жестко к слотам PCIe на плате, и эти идентификаторы могут изменяться и отличаться от запуска к запуску системы:
Как лучше всего определить топологию шины PCIe с подробным деревом устройств и количеством слотов PCIe на плате? в Windows и Linux?
Вот версия скрипта, которая не нуждается в разборе реестра. Вся информация (используемая здесь) доступна в win32_pnpentity.
Function Get-BusFunctionID {
gwmi -namespace root\cimv2 -class Win32_PnPEntity |% {
if ($_.PNPDeviceID -like "PCI\*") {
$locationInfo = $_.GetDeviceProperties('DEVPKEY_Device_LocationInfo').deviceProperties.Data
if ($locationInfo -match 'PCI bus (\d+), device (\d+), function (\d+)') {
new-object psobject -property @{
"Name" = $_.Name
"PnPID" = $_.PNPDeviceID
"BusID" = $matches[1]
"DeviceID" = $matches[2]
"FunctionID" = $matches[3]
}
}
}
}
}
Устройства PCI (конечные точки) имеют уникальный адрес. Этот адрес состоит из 3 частей:
Например, функция 3 устройства 12 на шине 3 записана в виде BDF: 03:0C.3
, Расширенная нотация BDF добавляет домен (в основном 0000) в качестве префикса: 0000:03:0c.3
,
Linux перечисляет эти устройства в /sys/bus/pci/devices
paebbels@debian8:~$ ll /sys/bus/pci/devices/
drwxr-xr-x 2 root root 0 Aug 19 11:44 .
drwxr-xr-x 5 root root 0 Aug 5 15:14 ..
lrwxrwxrwx 1 root root 0 Aug 19 11:44 0000:00:00.0 -> ../../../devices/pci0000:00/0000:00:00.0
lrwxrwxrwx 1 root root 0 Aug 19 11:44 0000:00:01.0 -> ../../../devices/pci0000:00/0000:00:01.0
lrwxrwxrwx 1 root root 0 Aug 19 11:44 0000:00:07.0 -> ../../../devices/pci0000:00/0000:00:07.0
lrwxrwxrwx 1 root root 0 Aug 19 11:44 0000:00:07.1 -> ../../../devices/pci0000:00/0000:00:07.1
...
lrwxrwxrwx 1 root root 0 Aug 19 11:44 0000:00:18.6 -> ../../../devices/pci0000:00/0000:00:18.6
lrwxrwxrwx 1 root root 0 Aug 19 11:44 0000:00:18.7 -> ../../../devices/pci0000:00/0000:00:18.7
lrwxrwxrwx 1 root root 0 Aug 19 11:44 0000:02:00.0 -> ../../../devices/pci0000:00/0000:00:11.0/0000:02:00.0
lrwxrwxrwx 1 root root 0 Aug 19 11:44 0000:02:01.0 -> ../../../devices/pci0000:00/0000:00:11.0/0000:02:01.0
lrwxrwxrwx 1 root root 0 Aug 19 11:44 0000:02:02.0 -> ../../../devices/pci0000:00/0000:00:11.0/0000:02:02.0
lrwxrwxrwx 1 root root 0 Aug 19 11:44 0000:02:03.0 -> ../../../devices/pci0000:00/0000:00:11.0/0000:02:03.0
lrwxrwxrwx 1 root root 0 Aug 19 11:44 0000:03:00.0 -> ../../../devices/pci0000:00/0000:00:15.0/0000:03:00.0
Здесь вы можете видеть, что sys-fs перечисляет устройства с 00 по 03 шины 02 как подключенные к шине 00, устройство 11, функция 0
Исходя из этой информации, вы можете перестроить полное дерево шин PCI. Дерево всегда одинаково после загрузки, если только вы не добавляете и не удаляете устройства.
Диспетчер устройств Windows предлагает ту же информацию. Диалог свойств показывает тип устройства, поставщика и местоположение: например, PCI bus 0, device 2, function 0
для интегрированной графики Intel HD 4600.
В настоящее время я не знаю, как вы можете получить эту информацию с помощью сценариев или языка программирования в среде Windows, но в Интернете есть коммерческие и бесплатные инструменты, которые предоставляют эту информацию. Может быть, есть API.
В Windows вы можете использовать, например: следующий скрипт Powershell-Script с инструментом devcon.exe из набора драйверов устройств Windows:
Function Get-BusFunctionID {
$Devices = .\devcon.exe find PCI\*
for($i=0; $i -lt $Devices.length; $i++) {
if(!($Devices[$i] -match "PCI\\*")) {
continue
}
$DevInfo = $Devices[$i].split(":")
$deviceId = $DevInfo[0]
$locationInfo = (get-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Enum\$deviceID" -name locationinformation).locationINformation
$businfo = Resolve-PCIBusInfo -locationInfo $locationinfo
new-object psobject -property @{
"Name" = $DevInfo[1];
"PnPID" = $DevInfo[0]
"PCIBusID" = $businfo.BusID;
"PCIDeviceID" = $businfo.DeviceID;
"PCIFunctionID" = $businfo.FunctionID
}
}
}
Function Resolve-PCIBusInfo {
param (
[parameter(ValueFromPipeline=$true,Mandatory=$true)]
[string]
$locationInfo
)
PROCESS {
[void]($locationInfo -match "\d+,\d+,\d+")
$busId,$deviceID,$functionID = $matches[0] -split ","
new-object psobject -property @{
"BusID" = $busID;
"DeviceID" = "$deviceID""FunctionID" = "$functionID"}
}
}
Пример использования:
Get-BusFunctionID | Where-Object {$_.PCIBusID -eq 0 -and $_.PCIDeviceID -eq 0} | Format-Table
Get-BusFunctionID | Sort-Object PCIBusID, PCIDeviceID, PCIFunctionID | Format-Table -GroupBy PCIBusID
Get-BusFunctionID | Sort-Object PCIBusID, PCIDeviceID, PCIFunctionID | Out-GridView
Для Windows готов запустить Powershell-скрипт:
Function Get-BusFunctionID {
#gwmi -query "SELECT * FROM Win32_PnPEntity"$Devices = get-wmiobject -namespace root\cimv2 -class Win32_PnPEntity
for($i=0; $i -lt $Devices.length; $i++) {
if(!($Devices[$i].PNPDeviceID -match "PCI\\*")) {
continue
}
$deviceId = $Devices[$i].PNPDeviceID
$locationInfo = (get-itemproperty -path "HKLM:\SYSTEM\CurrentControlSet\Enum\$deviceID" -name locationinformation).locationINformation
$businfo = Resolve-PCIBusInfo -locationInfo $locationinfo
new-object psobject -property @{
"Name" = $Devices[$i].Name;
"PnPID" = $Devices[$i].PNPDeviceID
"PCIBusID" = $businfo.BusID;
"PCIDeviceID" = $businfo.DeviceID;
"PCIFunctionID" = $businfo.FunctionID
}
}
}
Function Resolve-PCIBusInfo {
param (
[parameter(ValueFromPipeline=$true,Mandatory=$true)]
[string]
$locationInfo
)
PROCESS {
[void]($locationInfo -match "\d+,\d+,\d+")
$busId,$deviceID,$functionID = $matches[0] -split ","
new-object psobject -property @{
"BusID" = $busID;
"DeviceID" = "$deviceID""FunctionID" = "$functionID"}
}
}
Пример использования:
Get-BusFunctionID | Where-Object {$_.PCIBusID -eq 0 -and $_.PCIDeviceID -eq 0} | Format-Table
Get-BusFunctionID | Sort-Object PCIBusID, PCIDeviceID, PCIFunctionID | Format-Table -GroupBy