1
0

More than 1 year has passed since last update.

Hyper-V GPU-P セットアップ

Last updated at Posted at 2023-02-13

概要

<前提条件>
・Windows 11 Pro
・Windows で仮想マシン作成済み
・Nvidia Driver

<目次>
 1. GPU-P セット
 2. ホスト側のドライバーをゲストにコピー
   使い方
 3. 引用元、参照元、参考先

GPU-P セット

 GPU-P を自動で設定するためのスクリプト
・自己責任で♪
・文字コード Shift-JIS(ANSI) で保存する
・ダブルクリックで実行

GPU-P_set.cmd
@echo off && goto PreCheck
<# コマンドプロンプト----------------------------------
  :PreCheck
     setlocal
       for /f "tokens=3 delims=\ " %%A in ('whoami /groups^|find "Mandatory Label"') do set LEVEL=%%A
       if not "%LEVEL%"=="High"  goto GETadmin
     goto Excute
  :GETadmin
     endlocal
     echo "%~nx0": elevating self
     echo    Are you OK ?
     del "%temp%\getadmin.vbs"                                    2>NUL
       set vbs=%temp%\getadmin.vbs
       echo Set UAC = CreateObject^("Shell.Application"^)          >> "%vbs%"
       echo Dim stCmd                                              >> "%vbs%"
       echo stCmd = "/c """"%~s0"" " ^& "%~dp0" ^& Chr(34)         >> "%vbs%"
       echo UAC.ShellExecute "cmd.exe", stCmd, "", "runas", 1      >> "%vbs%"
       pause
       "%temp%\getadmin.vbs"
     del "%temp%\getadmin.vbs"
     goto :eof
  :Excute
     endlocal
     set "Dir=%~1"
     powershell -NoProfile -ExecutionPolicy Unrestricted "$s=[scriptblock]::create((gc \""%~f0"\"|?{$_.readcount -gt 1})-join\"`n\");&$s" "'%Dir%'" &exit /b
-------------------------------------------------------#>
  Param([string] $SptDirPATH)
  write-host "Script Start......`($SptDirPATH`)"
####################################
###   Powershell Script HERE!!   ###
####################################
<# バッファーサイズの調整 #>
# WindowSize の既定値を変数に格納
$defaultWS = $host.UI.RawUI.WindowSize

# BufferSize を 140 に変更
(Get-Host).UI.RawUI.BufferSize `
   = New-Object "System.Management.Automation.Host.Size" (140,$host.UI.RawUI.BufferSize.Height)

# WindowSize は既定値に設定
$host.UI.RawUI.WindowSize = $defaultWS


<# 0 #>
# すでに設定されているアダプターの確認
$0VMName = (Read-Host アダプターを追加するVM名を入力してください)

# セットしたVMが存在するか確認
$VMall = Get-VM
$VMalls = $VMall.Name | Out-String -Stream
# 条件分岐
if ($VMalls.Contains("$0VMName"))
  {Write-Host プロセスを進めます}
Else
  {# 入力された値が 不適合
   Write-Host 入力された文字が不適切です。処理を中断します。
   Write-Host "続行するには何かキーを押してください..."
   $host.UI.RawUI.ReadKey() | Out-Null
   exit
   } 

# すでに設定されているアダプターの削除
$ErrorActionPreference = 'Stop'
try {
    Remove-VMGpuPartitionAdapter -VMName "$0VMName"
    ""
    Write-Host "このVMに設定されていたGPU-Partitionが削除されました"
} catch {
    ""
    Write-Host "このVMにGPU-Partitionは設定されていません"
}
$ErrorActionPreference = "Continue"


<# 1 #>
# ユーザーから入力を受け付けて入力内容を $percent に格納
""
Write-Host "※整数値を入力してください"
[int]$1percentMIN =(Read-Host "MIN:分割する最小の量を入力してください(%:  0~100)")
[int]$1percentMAX =(Read-Host "MAX:分割する最大の量を入力してください(%:MIN~100)")
[int]$1percentOPT =(Read-Host "OPT:分割する最適の量を入力してください(%:MIN~MAX)")

# 条件分岐
if (($1percentMIN -ge 0) -and
    ($1percentMIN -le 100) -and

    ($1percentMAX -ge 1) -and
    ($1percentMAX -ge ($1percentMIN)) -and
    ($1percentMAX -le 100) -and

    ($1percentOPT -ge 1) -and
    ($1percentOPT -ge $1percentMIN) -and
    ($1percentOPT -le ($1percentMAX))){
	# 処理(if,elseそれぞれ何かしら必要)
    Write-Host プロセスを進めます
}Else{
    # 入力された数字が 不適合
    Write-Host 入力された文字が不適切です。処理を中断します。
    Write-Host "続行するには何かキーを押してください..."
    $host.UI.RawUI.ReadKey() | Out-Null
    exit
}


<# 2 #>
# インスタンスパス、GPU名、変数等を取得する

[int]$Count = (Get-VMHostPartitionableGpu).Count

# 接続されている GPU の数で分岐
If($Count -ge 2) {
   (Get-VMHostPartitionableGpu).Name `
      | ForEach-Object `
           -Begin { 
              # 変数を初期化
              Remove-Variable Add, Sub, End 2>${NULL}
              # 変数を宣言、準備、設定
              $Space = ($Host.UI.RawUI.WindowSize.Width - 11)
              [Array]$Sub = [System.Management.Automation.Host.ChoiceDescription]::new("(&整数を入力)", "説明")
              $Name_HashTable = [Ordered]@{}
              [int]$Num = 1
             } `
           -Process { 
             # PnP Util で使えるように調整
              $InsID = ($_ -split '\\?\',0,'Simplematch' -split '#{')[1].Replace('#','\')
              Set-Variable "2InsID$Num" "$InsID"
             # PnP Util から GPU名 を取得
              $GPUName = (Get-PnpDevice -InstanceId $InsID).FriendlyName
              Set-Variable "Name$Num" "$GPUName"
             # PromptForChoice の選択肢を準備
              $One = "$GPUName(&$Num)"
              $CRLF = $One.PadRight($Space)+"`b"
              [Array]$Add = [System.Management.Automation.Host.ChoiceDescription]::new("$CRLF", "$_")
             # ループの最後とそれ以外で分岐
              If($Num -ne $Count)
                {$Sub = @($Sub;$Add)}
              Else 
                {$CRLF = $One.PadRight($Space*2)+"`b"
                 $Sub = @($Sub;[System.Management.Automation.Host.ChoiceDescription]::new("$CRLF", "$_`r`n`b"))}
             # GPU-P 用のインスタンスパスを格納
              $Name_HashTable.Add("$Num","$_")
              $Num += 1
             } `
           -End { 
             # おまかせの選択肢の追加
              [Array]$End = [System.Management.Automation.Host.ChoiceDescription]::new("指定しない(&$Num)`r`n`b", "システムに任せます。`r`n`r`n`b")
              $Sub = @($Sub;$End)
             }

  # PromptForChoice で実行するものを設定
   1..($Num-1) | ForEach-Object `
                    -Begin { $Options = @('{') } `
                    -Process { 
                       $Arg1 = (Get-Variable "Name$_").Value
                       $Arg2 = $Name_HashTable["$_"]
                       $Options += "$_ `{Write-Host `"$Arg1 が選択されました`" ;`$AGPUName = `"$Arg1`" ;`$2gpuNAME = `"$Arg2`" ;break `};" 
                      } `
                    -End { $Options += @('}') }
  # 選択肢を画面表示
   $Result = $Host.UI.PromptForChoice("【確認】","--番号を選び、入力してください--`r`n ",$Sub,$Num)
  # 選択に応じたコマンドを実行
   If($Result -ne $Num)
     {. ([Scriptblock]::Create("switch ($Result) $Options"))}
}

# GPU が1つ 又は おまかせ にした場合に実行する
If(!($Count -ge 2) -OR ($Result -eq $Num)) {
   Write-Host "GPUを引数にセットします"
   $2gpuNAME `
      = ( Get-VMHostPartitionableGpu `
             | Select-Object Name `
             | Get-Member -Membertype NoteProperty `
             | Select-Object Definition `
             | Format-Table -AutoSize -Wrap `
             | Out-String -Stream `
             | Select-String string `
         )  -replace "string Name="

   # GPU名を取得
   $2InsID = ($2gpuNAME -split '\\?\',0,'Simplematch' -split '#{')[1].Replace('#','\')
   $AGPUName = (Get-PnpDevice -InstanceId $2InsID).FriendlyName
}

# 取得した内容を表示
""
Write-Host (@"
$0VMName に
GPU : $2gpuNAME
(※$AGPUName)
を GPU-Partition として適用します
"@)
""


<# 3 #>
# Get-VMHostPartitionableGpuから割り当てられるGPUの総量を取得
$3gpuAvailableVRAM = Get-VMHostPartitionableGpu | Out-String -Stream | Select-String AvailableVRAM
$3gpuAvailableEncode = Get-VMHostPartitionableGpu | Out-String -Stream | Select-String AvailableEncode
$3gpuAvailableDecode = Get-VMHostPartitionableGpu | Out-String -Stream | Select-String AvailableDecode
$3gpuAvailableCompute = Get-VMHostPartitionableGpu | Out-String -Stream | Select-String AvailableCompute

# GPUの各総量を数値としてそれぞれ格納
$3gpuAvailableVRAMA = [int]($3gpuAvailableVRAM -replace "[a-zA-Z]" -replace '[" *"]' -replace ":")
$3gpuAvailableEncodeA = [decimal]($3gpuAvailableEncode -replace "[a-zA-Z]" -replace '[" *"]' -replace ":")
$3gpuAvailableDecodeA = [int]($3gpuAvailableDecode -replace "[a-zA-Z]" -replace '[" *"]' -replace ":")
$3gpuAvailableComputeA = [int]($3gpuAvailableCompute -replace "[a-zA-Z]" -replace '[" *"]' -replace ":")


<# 4 #>
# LOG の保存先ディレクトリを作成
$DIRpath=$SptDirPATH.TrimEnd('\') + "\LOG"
if ( -not ( Test-Path -Path "$DIRpath" )){ New-Item "$DIRpath" -ItemType Directory > $null }
Get-Date | Out-String -Stream | ?{$_ -ne ""} | Out-File "$DIRpath\GPU-P_log.txt" -Append -Force


<# 5 #>
# パーティション分割値を求める
$VRAMdivideMIN = [Math]::Round($($3gpuAvailableVRAMA * ($1percentMIN / 100)),0)
$VRAMdivideMAX = [Math]::Round($($3gpuAvailableVRAMA * ($1percentMAX / 100)),0)
$VRAMdivideOPT = [Math]::Round($($3gpuAvailableVRAMA * ($1percentOPT / 100)),0)

$ENCODEdivideMIN = [Math]::Round($($3gpuAvailableEncodeA * ($1percentMIN / 100)),0)
$ENCODEdivideMAX = [Math]::Round($($3gpuAvailableEncodeA * ($1percentMAX / 100)),0)
$ENCODEdivideOPT = [Math]::Round($($3gpuAvailableEncodeA * ($1percentOPT / 100)),0)

$DECODEdivideMIN = [Math]::Round($($3gpuAvailableDecodeA * ($1percentMIN / 100)),0)
$DECODEdivideMAX = [Math]::Round($($3gpuAvailableDecodeA * ($1percentMAX / 100)),0)
$DECODEdivideOPT = [Math]::Round($($3gpuAvailableDecodeA * ($1percentOPT / 100)),0)

$COMPUTEdivideMIN = [Math]::Round($($3gpuAvailableComputeA * ($1percentMIN / 100)),0)
$COMPUTEdivideMAX = [Math]::Round($($3gpuAvailableComputeA * ($1percentMAX / 100)),0)
$COMPUTEdivideOPT = [Math]::Round($($3gpuAvailableComputeA * ($1percentOPT / 100)),0)


# 計算結果を表示する
$5VRAMdisplay = [pscustomobject]([ordered]@{"------VRAM------" = ""; MIN = " $VRAMdivideMIN"; OPT = " $VRAMdivideOPT"; MAX = " $VRAMdivideMAX"; Available = " $3gpuAvailableVRAMA";})
$5ENCODEdisplay = [pscustomobject]([ordered]@{"-----Encode-----" = ""; MIN = " $ENCODEdivideMIN"; OPT = " $ENCODEdivideOPT"; MAX = " $ENCODEdivideMAX"; Available = " $3gpuAvailableEncodeA";})
$5DECODEdisplay = [pscustomobject]([ordered]@{"-----Decode-----" = ""; MIN = " $DECODEdivideMIN"; OPT = " $DECODEdivideOPT"; MAX = " $DECODEdivideMAX"; Available = " $3gpuAvailableDecodeA";})
$5COMPUTEdisplay = [pscustomobject]([ordered]@{"-----Compute----" = ""; MIN = " $COMPUTEdivideMIN"; OPT = " $COMPUTEdivideOPT"; MAX = " $COMPUTEdivideMAX"; Available = " $3gpuAvailableComputeA";})

""
Write-Host "# confimation"

Write-Output "VM  : $0VMName" | Out-File "$DIRpath\GPU-P_log.txt" -Append
Write-Output "GPU : $GPUName" | Out-File "$DIRpath\GPU-P_log.txt" -Append
Write-Output "Instance ID A : $2InsID" | Out-File "$DIRpath\GPU-P_log.txt" -Append
Write-Output "Instance ID B : $2gpuNAME" | Out-File "$DIRpath\GPU-P_log.txt" -Append

$5VRAMdisplay | Out-String -Stream | ?{$_ -ne ""} | Tee-Object -FilePath "$DIRpath\GPU-P_log.txt" -Append
$5ENCODEdisplay | Out-String -Stream | ?{$_ -ne ""} | Tee-Object -FilePath "$DIRpath\GPU-P_log.txt" -Append
$5DECODEdisplay | Out-String -Stream | ?{$_ -ne ""} | Tee-Object -FilePath "$DIRpath\GPU-P_log.txt" -Append
$5COMPUTEdisplay | Out-String -Stream | ?{$_ -ne ""} | Tee-Object -FilePath "$DIRpath\GPU-P_log.txt" -Append

""
Write-Host "※ログの出力先は `"$DIRpath\GPU-P_log.txt`""

Write-Output "" | Out-File "$DIRpath\GPU-P_log.txt" -Append -Force
Write-Output "" | Out-File "$DIRpath\GPU-P_log.txt" -Append -Force


<# 6 #>
# 実行するか確認
$title = "【確認】"
$message = @"
上記の通りにGPUPartitionをセットします。
この操作を実行しますか?
"@

$tChoiceDescription = "System.Management.Automation.Host.ChoiceDescription"
$tOptions = @(
    New-Object $tChoiceDescription ("はい(&Yes)",     "この操作を実行し、次のステップへ進みます。")
    New-Object $tChoiceDescription ("いいえ(&No)",    "この操作をキャンセルし、中断します。")
)

$tResult = $host.ui.PromptForChoice($title, $message, $tOptions, 0)
switch ($tResult)
  {
    0 {"「はい」が選ばれました。"; break}
    1 {"「中断」が選ばれました。"; break}
  }

if ($tResult -ne 0) { exit }


<# 7 #>
# GPU-P.Adapterを追加する
If(!($Count -ge 2) -OR ($Result -eq $Num)) {
   # システムが指定
   Add-VMGpuPartitionAdapter -VMName "$0VMName"
}Else{
   # GPUを指定する場合
   Add-VMGpuPartitionAdapter -VMName "$0VMName" -InstancePath "$2gpuNAME"
}

# 追加したアダプターを設定する
#VRAM
Set-VMGpuPartitionAdapter -VMName "$0VMName" -MinPartitionVRAM $VRAMdivideMIN
Set-VMGpuPartitionAdapter -VMName "$0VMName" -MaxPartitionVRAM $VRAMdivideMAX
Set-VMGpuPartitionAdapter -VMName "$0VMName" -OptimalPartitionVRAM $VRAMdivideOPT

#Encode
Set-VMGpuPartitionAdapter -VMName "$0VMName" -MinPartitionEncode $ENCODEdivideMIN
Set-VMGpuPartitionAdapter -VMName "$0VMName" -MaxPartitionEncode $ENCODEdivideMAX
Set-VMGpuPartitionAdapter -VMName "$0VMName" -OptimalPartitionEncode $ENCODEdivideOPT

#Decode
Set-VMGpuPartitionAdapter -VMName "$0VMName" -MinPartitionDecode $DECODEdivideMIN
Set-VMGpuPartitionAdapter -VMName "$0VMName" -MaxPartitionDecode $DECODEdivideMAX
Set-VMGpuPartitionAdapter -VMName "$0VMName" -OptimalPartitionDecode $DECODEdivideOPT

#Compute
Set-VMGpuPartitionAdapter -VMName "$0VMName" -MinPartitionCompute $COMPUTEdivideMIN
Set-VMGpuPartitionAdapter -VMName "$0VMName" -MaxPartitionCompute $COMPUTEdivideMAX
Set-VMGpuPartitionAdapter -VMName "$0VMName" -OptimalPartitionCompute $COMPUTEdivideOPT


<# 8 #>
# CPU Write-Combiningの有効化
Set-VM -GuestControlledCacheTypes $true -VMName "$0VMName"

# MMIO領域の構成
Set-VM -LowMemoryMappedIoSpace 1Gb -VMName "$0VMName"
Set-VM -HighMemoryMappedIoSpace 33280Mb -VMName "$0VMName"


<# 9 #>
# 確認( = Get-VMGpuPartitionAdapter "$0VMName" -verbose )
Get-VMGpuPartitionAdapter -VMName "$0VMName"

# 終了メッセージ
Write-Host "すべてのプロセスは終了しました"
####################################
###            FINISH            ###
####################################
  Write-Host "---Script Finish---"
  Write-Host "画面を閉じるには何かキーを押してください..."
  $host.UI.RawUI.ReadKey() | Out-Null
  EXIT

ホスト側のドライバーをゲストにコピー

 ホスト側のドライバーを取得するバッチファイル
・自己責任で♪
・文字コード Shift-JIS(ANSI) で保存する
・ダブルクリックで実行

※注意※
以下の内、”NVWMI”フォルダが存在するディレクトリを選択する
・nv_dispsig.inf_amd64_~
・nv_dispsi.inf_amd64_~
・nv_dispi.inf_amd64_~

Driver_Copy.cmd
@echo off
::::::::::::::::::::::::::::::
  :PreCheck
     setlocal
       for /f "tokens=3 delims=\ " %%A in ('whoami /groups^|find "Mandatory Label"') do set LEVEL=%%A
       if not "%LEVEL%"=="High"  goto GETadmin
     goto Execute
  :GETadmin
     endlocal
     echo "%~nx0": elevating self
     echo    Are you OK ?
     del "%temp%\getadmin.vbs"                                    2>NUL
       set vbs=%temp%\getadmin.vbs
       echo Set UAC = CreateObject^("Shell.Application"^)          >> "%vbs%"
       echo Dim stCmd                                              >> "%vbs%"
       echo stCmd = "/c """"%~s0"" " ^& "%~dp0" ^& Chr(34)         >> "%vbs%"
       echo UAC.ShellExecute "cmd.exe", stCmd, "", "runas", 1      >> "%vbs%"
       pause
       "%temp%\getadmin.vbs"
     del "%temp%\getadmin.vbs"
     goto :eof
  :Execute
     endlocal
::::::::::::::::::::::::::::::
::::::::::
set "directory=C:\Windows\System32\DriverStore\FileRepository"
dir /b "%directory%\nv_disp*" /A:-d >NUL 2>&1 || echo "ファイル"は無し : OK
dir /b "%directory%\nv_disp*" /A:d && echo 存在確認 : OK

::::::::::
for /f %%A in ('dir /b ^"%directory%\nv_disp*^" /A:d') do @echo.&&@echo.^<%%A^>&&@dir /b "%directory%\%%A" /A:d
echo.
echo.

::::::::::
set "Dir=%~1"
echo  コピーするドライバーのバージョン名を入力してください
echo  例)...version...: 526.98
echo.
set /p "number=...version...: "
echo.
echo.
echo  コピーするフォルダー名を入力してください
echo  例)...nv_dispi~.inf_amd64_~...: nv_dispsig.inf_amd64_3785fc0bbhsid471
echo.
set /p "Folder=...nv_dispi~.inf_amd64_~...: "
set "send=%Dir%Drivers\%number%"
set "send_1=%send%\System32\HostDriverStore\FileRepository\%Folder%"
set "send_2=%send%\System32"

::::::::::
xcopy "%directory%\%Folder%" "%send_1%" /i /c /f /e /s /h /k /r
xcopy "C:\Windows\System32\NV*.*" "%send_2%" /i /c /f /h /k /r

::::::::::
pause
exit
  1. すべての VM をシャットダウン
    (Get-VM).Name | Stop-VM -Force
  2. VHDX のパスを取得
    (Get-VM).Name | Get-VMHardDiskDrive | Select-Object VMName,Path
  3. GPU-P をセットしたい VM の VHDX をマウント
    ※対象の VHDX をダブルクリック
  4. VHDX 内の SystemDrive\Windows\ に Driver_Copy.cmd でコピーされた System32 フォルダーをコピー
 使い方

1 ダブルクリック
スクリーンショット (509).png
2 対話画面で入力
※ここで "NVWMI" が含まれるフォルダを入力
スクリーンショット (596).png
3 確認
スクリーンショット (510).png
"バッチファイルがあるディレクトリ\Drivers\537.45\System32"
スクリーンショット (507).png
4 3で確認した "バッチファイルがあるディレクトリ\Drivers\537.45\System32" の中身を、マウントした VHDX の "SystemDrive\Windows\System32" の中にコピー

引用元、参照元、参考先

Hyper-VでGPU(3Dアクセラレーション)を利用する方法 Windows 10以降編 (GPU-P)
https://qiita.com/Hyper-W/items/3a2c7ff1d983deb80070
Windows11上でGPU有効な仮想Windows11を動かす
https://qiita.com/botter99/items/c0022ed1906a74decc37
Easy-GPU-PV
https://github.com/jamesstringerparsec/Easy-GPU-PV
2 Gamers 1 GPU with Hyper V GPU-P (GPU Partitioning finally made possible with HyperV)
https://forum.level1techs.com/t/2-gamers-1-gpu-with-hyper-v-gpu-p-gpu-partitioning-finally-made-possible-with-hyperv/172234

Batch_Script_Run_As_Admin.cmd
https://stackoverflow.com/questions/11525056/how-to-create-a-batch-file-to-run-cmd-as-administrator

バッチファイルにPowerShellスクリプトを埋め込む その2
https://www.pg-fl.jp/program/tips/ps1bat2.htm
バッチファイルで、管理者権限で実行しているかを確認する方法
http://nsb.homeip.net/wp/?p=1002
PowerShellによるHyper-V環境の管理
https://www.school.ctc-g.co.jp/columns/microsoft/microsoft20.html
PowerShellの二重引用符文字列のクセがすごい
https://qiita.com/diontools/items/9f5e30f6935a83dfd22a
【PowerShell】Hyper-Vの仮想マシン一覧を取得する
https://kharuka2016.hatenablog.com/entry/2017/01/06/220301
PowerShell Replace 文字列を置き換える
https://itsakura.com/powershell-replace
PowerShellでNew-Itemの出力結果を表示させない方法
https://tex2e.github.io/blog/powershell/New-Item
PowerShellの2>$1(エラー出力を標準出力に表示させない)正しい書き方
https://kbn48.com/technical/217
PowerShellのコマンドでHyper-VのVMIDからavhdxファイルのサイズを求めたい
https://teratail.com/questions/54967
PowerShell で選択肢メニューと、それに伴う分岐処理を簡潔に書きたい
https://qiita.com/yumura_s/items/274e8e49c975cce3a2ce

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0