0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

HyperVの仮想マシンへのファイルコピー手段の速度比較

Posted at

Hyper-Vの仮想マシンにファイルをコピーする時、方法によってどれくらいコピー時間が変わってくるのか気になったので計測しました。

※どれも一度だけ計測した結果で環境によっても違うかもしれないので参考程度です。

計測環境

  • ホスト
    • OS: Windows 11 (Build 23615.1000)
    • CPU: Intel Core i7-7700K
    • RAM: DDR4-2133 32GB
    • SSD: Samsung 960EVO 500GB
  • ゲスト
    • OS: Windows 11 (Build 22621.3007)
    • CPU: 4コア割り当て
    • RAM: 8GB割り当て

計測方法

PowerShellのスクリプト等を使って以下のA., B.の組み合わせについて確認した。なお、アーカイブの作成にはCompress-Archive -CompressionLevel NoCompressionを使用した。

  • A. 中身が乱数の10GB分のファイルを以下の容量・数で生成する
    • 1GB x 10ファイル
    • 1MB x 10000ファイル
  • B. コピーの方法
    • Copy-VHD
      • ホスト側で仮想マシンにコピーしたいファイルが入ったVHDを作成後、仮想マシンにVHDをマウントしてコピー
    • Copy-VMFile
      • ファイルを1つのファイルにアーカイブ後1Copy-VMFileを使ってコピー
    • Copy-Item
      • Copy-Item-ToSessionを使ってコピー
    • Copy-Item-Smb
      • Copy-Itemを使って仮想マシンの共有フォルダにコピー
      • 仮想マシン側では事前にC:\を読み書き可能な形で共有しておく
    • Copy-Item-Compress
      • A.のファイルを1つのファイルにアーカイブ後、Copy-Item-ToSessionを使ってコピー
    • Copy-Item-Smb-Compress
      • A.のファイルを1つのファイルにアーカイブ後、Copy-Itemを使って仮想マシンの共有フォルダにコピー
検証に使用したコード

テスト用データの生成 (※WSLで実行する想定です)

generate.sh
#!/bin/sh

mkdir 1x10000
(
	cd 1x10000
	for i in $(seq 1 10000); do
		dd if=/dev/urandom of=$i.bin bs=1M count=1
	done
)
mkdir 1000x10
(
	cd 1000x10
	for i in $(seq 1 10); do
		dd if=/dev/urandom of=$i.bin bs=1000M count=1
	done
)

速度計測スクリプト
他の環境で動かすことを想定していないので、想定しない動作をしないか確認してから実行してください。

bench.ps1
$vmname = "Windows 11"
$username = "User"
$password = "user"

$vm = Get-VM -Name $vmname
$networkAdapter = Get-VMNetworkAdapter -VM $vm
$ipAddresses = $networkAdapter.IPAddresses
$ipAddress = $ipAddresses[0]

$hostWork = "C:\work"
$guestWork = "C:\work"
$hostCompressTmp = "$hostWork\tmp.zip"
$guestCompressTmp = "$guestWork\tmp.zip"

$vhdPath = "C:\work\tmp.vhdx"
$vhdSize = 15GB

$password = ConvertTo-SecureString "$password" -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ($username, $password)
$session = New-PSSession -VMName $vmname -Credential $credential

function Initialize-WorkingDirectory
{
    Invoke-Command -Session $session -ScriptBlock {
        if (Test-Path $using:guestWork) {
            Remove-Item -Path $using:guestWork -Recurse -Confirm:$false
        }
        New-Item -ItemType Directory -Path $using:guestWork > $null
    }
}

function Bench-Copy-Item($dir)
{
    $result = Measure-Command { Copy-Item -ToSession $session -Path $dir -Destination C:\work -Recurse }
    return @{
        "Result"=$result;
    }
}

function Bench-Copy-Item-Compress($dir)
{
    $result1 = Measure-Command { Prepare-Compress $dir }
    $result2 = Measure-Command { Copy-Item -ToSession $session -Path $hostCompressTmp -Destination $guestCompressTmp }
    $result3 = Measure-Command { Invoke-Command -Session $session -ScriptBlock { Expand-Archive -Path $using:guestCompressTmp -DestinationPath $using:guestWork } }
    Release-Compress
    return @{
        "Compress"=$result1;
        "Result"=$result2;
        "Decompress"=$result3;
    }
}

function Bench-Copy-VMFile($dir)
{
    $result1 = Measure-Command { Prepare-Compress $dir }
    $result2 = Measure-Command { Copy-VMFile $vmname -SourcePath $hostCompressTmp -DestinationPath $guestCompressTmp -CreateFullPath -FileSource Host }
    $result3 = Measure-Command { Invoke-Command -Session $session -ScriptBlock { Expand-Archive -Path $using:guestCompressTmp -DestinationPath $using:guestWork } }
    Release-Compress
    return @{
        "Compress"=$result1;
        "Result"=$result2;
        "Decompress"=$result3;
    }
}

function Bench-Copy-Item-Smb($dir)
{
    New-PSDrive -Name "Z" -PSProvider FileSystem -Root "\\$ipAddress\c" -Credential $credential > $null
    $result = Measure-Command { Copy-Item -Path $dir -Destination Z:\work -Recurse }
    Remove-PSDrive -Name "Z"
    return @{
        "Result"=$result;
    }
}

function Bench-Copy-Item-Smb-Compress($dir)
{
    New-PSDrive -Name "Z" -PSProvider FileSystem -Root "\\$ipAddress\c" -Credential $credential > $null
    $result1 = Measure-Command { Prepare-Compress $dir }
    $result2 = Measure-Command { Copy-Item -Path $hostCompressTmp -Destination Z:\work\tmp.zip }
    $result3 = Measure-Command { Invoke-Command -Session $session -ScriptBlock { Expand-Archive -Path $using:guestCompressTmp -DestinationPath $using:guestWork } }
    Release-Compress
    Remove-PSDrive -Name "Z"
    return @{
        "Compress"=$result1;
        "Result"=$result2;
        "Decompress"=$result3;
    }
}

function Bench-Copy-VHD($dir)
{
    if (Test-Path $vhdPath) {
        Remove-Item $vhdPath
    }
    $result1 = Measure-Command {
        New-VHD -Path $vhdPath -SizeBytes $vhdSize -Dynamic > $null
        $vhdx = Mount-VHD -Path $vhdPath -Passthru
        $disk = Initialize-Disk -Number $vhdx.Number -PassThru | New-Partition -AssignDriveLetter -UseMaximumSize | Format-Volume -NewFileSystemLabel "Bench"
        $driveLetter = ($disk | Get-Partition).DriveLetter

        Copy-Item -Path $dir -Destination "${driveLetter}:\" -Recurse

        Dismount-VHD -Path $vhdPath
    }
    $result2 = Measure-Command { Add-VMHardDiskDrive -VMName $vmName -Path $vhdPath }
    $result3 = Measure-Command {
        Invoke-Command -Session $session -ScriptBlock {
            $driveLetter = Get-Volume | Where-Object { $_.FileSystemLabel -eq "Bench" } | Select-Object -ExpandProperty DriveLetter
            Copy-Item -Path "${driveLetter}:\*" -Destination $using:guestWork -Recurse
        }
    }
    $result4 = Measure-Command { Get-VMHardDiskDrive -VMName $vmName | Where-Object { $_.Path -eq $vhdPath } | Remove-VMHardDiskDrive }
    return @{
        "Prepare"=$result1;
        "AttachVHD"=$result2;
        "Result"=$result3;
        "DetachVHD"=$result4;
    }
}

function Prepare-Compress($dir)
{
    if (Test-Path $hostCompressTmp) {
        Remove-Item -Path $hostCompressTmp -Recurse -Confirm:$false
    }
    Compress-Archive -Path $dir -DestinationPath $hostCompressTmp -Force -CompressionLevel NoCompression
}

function Release-Compress
{
    if (Test-Path $hostCompressTmp) {
        Remove-Item -Path $hostCompressTmp -Recurse -Confirm:$false
    }
}

$benchmarks = @{
    "Copy-Item"=${function:Bench-Copy-Item};
    "Copy-Item-Smb"=${function:Bench-Copy-Item-Smb};
    "Copy-VMFile"=${function:Bench-Copy-VMFile};
    "Copy-Item-Compress"=${function:Bench-Copy-Item-Compress};
    "Copy-Item-Smb-Compress"=${function:Bench-Copy-Item-Smb-Compress};
    "Copy-VHD"=${function:Bench-Copy-VHD};
}

$filePattern = @{
    "1000x10"="C:\work\1000x10";
    "1x10000"="C:\work\1x10000";
    #"test"="C:\work\test";
}

foreach($benchName in $benchmarks.Keys) {
    $func = $benchmarks[$benchName]
    
    foreach ($fileName in $filePattern.Keys) {
        $path = $filePattern[$fileName]

        Initialize-WorkingDirectory
        $results = & $func $path
        Write-Output "$benchName($fileName)"
        foreach ($resultName in $results.Keys) {
            $result = $results[$resultName]

            Write-Output "`t${resultName}: ${result}"
        }
    }
}

結果

1GB x 10ファイル 1MB x 10000ファイル
Copy-VHD 00:01:26.22 00:01:18.84
Copy-VMFile 00:06:12.45 00:07:33.64
Copy-Item 00:19:19.66 00:28:11.62
Copy-Item-Smb 00:00:34.31 00:01:47.18
Copy-Item-Compress 00:21:12.26 00:23:54.06
Copy-Item-Smb-Compress 00:01:59.29 00:04:30.71
  • コピーの方法と合計サイズが同じでも、大きいファイルが少し、小さいファイルが大量で比較すると、方法によっては最大数倍時間が変わってくることがある。 (Copy-Item-Smb)
  • Copy-Item + 1MB x 10000ファイルのパターンでしか早くなっていないので、小さいファイルが大量にあったとしても基本的にはそのままコピーするのが早い。
  • 今回の結果からすると、仮想マシンへのファイルコピーで一番良いのはWindowsの共有経由でコピー、次点でVHDファイルを使ってコピー2が良さそう。

VHDを作成する計測の詳細

Copy-VHDでVHDの作成(VHDファイル自体の作成、フォーマット、VHDへのファイルのコピー)にかかった時間は以下の通り。

1GB x 10ファイル 1MB x 10000ファイル
Copy-VHD 00:00:43.78 00:00:41.36

アーカイブを作成する計測の詳細

アーカイブを作成してから仮想マシンへコピーする計測の詳細は以下の通り。

作成 展開 コピーのみ
1GB x 10ファイル 1MB x 10000ファイル 1GB x 10ファイル 1MB x 10000ファイル 1GB x 10ファイル 1MB x 10000ファイル
Copy-VMFile 00:00:54.63 00:03:05.60 00:01:40.63 00:01:20.90 00:03:37.18 00:03:07.14
Copy-Item-Compress 00:00:52.37 00:02:28.02 00:00:38.73 00:01:23.23 00:19:29.68 00:19:56.84
Copy-Item-Smb-Compress 00:00:53.81 00:02:36.31 00:00:48.77 00:01:20.91 00:00:28.18 00:00:39.45
  • 同じ計測データを元にアーカイブを作成・展開しているのに、圧縮で30秒、展開で1分程度の違いが出ているので、やはり何度か計測した方が良さそう
  1. Copy-VMFileではフォルダのコピーができないため。

  2. VHDファイルを使うのであれば、わざわざ仮想マシン内にファイルをコピーせずにVHD内のファイルをそのまま読み書きをするという手もある。その場合、VHDの作成から仮想マシン内へのコピーにかかっているのが1分20秒前後で、後述の「VHDを作成する計測の詳細」からVHDの作成自体にかかっている時間は40秒程度なので、40秒程度でファイルの読み書きができる状態にできる。

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?