WSL vs VM for 開発作業

はじめに

本記事はLinux Advent Calendar 2017の最終日、25日目の記事です。

みなさんはWindows Subsystem for Linux(WSL)というWindowsのソフトウェアをご存知でしょうか。これはUbuntu, openSUSE, あるいはSUSE Linux Enterpriseという3つのLinux distributionをWindowsから使えるという機能です。Microsoftストアから無償でインストール可能です。低レイヤの細かいところ(/procや/sysのファイルが少なかったり、ほとんどのデバイスファイルが無かったり)は違うのですが、おおよそ通常のLinuxディストリビューションと同様に使える優れものです。

本記事は、Linuxソフトウェア開発環境という目的に絞って、WSLと、Windows上で動作するVirtualBoxにインストールしたLinux(以下、VMと記載)を比較した結果を記載します。

比較項目

WSLもVMも、開発環境として使うためには、まずは導入コストが気になります。本記事では次のような導入コストに関する比較をしました。

  • インストール所要時間
  • 起動速度、および起動時のメモリ消費量

それに加えて、ソフトウェアを開発するにあたっての頻出操作に関する速度を比較しました。

  • ソース読み書きの体感速度
  • git checkoutの速度
  • タグジャンプファイル(cscope)作成速度
  • ビルド速度

比較結果の要約

  • 導入コストはWSLのほうがVMよりも低い
  • WSLは中小規模のソフトウェアの開発には問題なく使えるが、大規模ソフトウェアの開発は速度的な問題で厳しい。今後の改善に期待

データ採取環境

  • PCのスペック
  • CPU: Ryzen 1800x (8 core, HT off)
  • メモリ: 32GB
  • ストレージ: 512GB NVMe SSD
  • OS: Windows 10 Home Fall Creators Update(バージョン1709), ビルド16299.64
  • WSL: Ubuntu 16.04 (カーネルは4.4.0-43-Microsoft)
  • VMM: VirtualBox

  • VM(上記の実機上に構築)のスペック

  • VCPU数: 8
  • メモリ: 16GB
  • ストレージ: 20GB
  • OS: Ubuntu 16.04 (カーネルは4.10.0-38-generic)

比較結果

インストールの手間

WSLとVM, それぞれについて手作業でインストールして、その所要時間を計測しました。

WSL[分] VM[分]
3 21

WSLのほうがはるかに速いという結果が得られました。なお、WSLのインストール手順は次の通りです。

  1. Microsoftストアにおいて"Ubuntu"で検索
  2. インストールボタンを押す
  3. パスワード設定

VMのインストール手順についてはVirtual BoxのインストールからVMをインストールした後に起動開始するまでの時間を含めています。Virtual Boxが既に手元にある場合、Vagrantなどによって既製のVMを使う場合はまた話が変わってきますが、それは今回は考えないものとします。

起動コスト

起動所要時間、および、インストール直前とインストール直後のWindowsのメモリ消費量から求めたWSLとVMのメモリ消費量を示します。

項目 WSL VM
起動速度[秒] 1 15
起動直後のメモリ使用量[MB] 15 860

起動速度についてはVMがやや待たされるのに対してWSLはほぼ一瞬ですので、WSLのほうが有利です。メモリ使用量についても、VMは900MB弱使用するのに対してWSLはほとんど消費しません。筆者の環境はそれなりにメモリを積んでいますが、メモリ量が少ないマシンをお使いのかたにはWSLは魅力的な選択肢となるでしょう。

頻出操作の速度

これについては中小規模と大規模のソフトウェアという2つの軸で比較しました。中小規模のものとしてはソースの規模が6万行程度のmdadmを、大規模のものとしてはソースの規模が2,300万行程度のlinuxを使いました。それぞれみなさんが普段開発されるソフトウェアに近いほうの結果を見ていただければいいかと思います。

速度の測定については、ソースの読み書き速度(emacsを使用)については、かなりダサいのですが「使っていてもっさり感を感じるかどうか」という雑な指標です。いい方法が思いつきませんでした。すいません。

中小規模ソフトウェア(mdadm)

ソースの読み書き速度については両者において大した違いは出ませんでした。どちらも合格です。

それ以外については次のような結果が得られました。

項目 WSL VM
git checkout(バージョン3.4->4.0)[秒] 0.470 0.008
タグジャンプファイル作成[秒] 0.278 0.029
ビルド(8並列)[秒] 4.20 1.23

WSLのほうがVMよりも数倍から数十倍遅いという結果になりました。しかし絶対値が小さいために、WSLにおいても一瞬引っかかりを感じる程度でさしたるストレスは感じませんでした。これについてはWSLは十分に実用的だと判断しました。

大規模ソフトウェア(linux)

ソースの読み書き速度については、中小規模のソフトウェアの場合と同様、大した違いは出ませんでした。

それ以外については次のような結果になりました。

項目 WSL VM
git checkout(バージョン4.0->4.14)[秒] 270 5.5
タグジャンプファイル作成[秒] 86.0 39.7
ビルド(8並列)[秒] 439 169

中小規模のソフトウェア同様、数倍から数十倍遅いという結果になりました。しかし、絶対値が分単位なので、WSLにおいては非常に待ち時間が長いと感じました。個人的にはこういう用途にはVMを使いたいと思いました。

考察

大規模環境とみなしたLinuxにおけるgit checkout速度、タグジャンプファイル作成速度、およびビルド速度について、何が遅いのかを調査してみました。

git checkout

プロセスの処理か、システムコールか、待ちか

まずはtimeコマンドによって得られるreal, usr, sysの値をもとに、WSLの処理が遅い原因が次のうちにどこ(あるいは複数の組み合わせ)にあるのかを突き止めることにしました。

  • プロセス自身の処理時間
  • カーネルの処理時間
  • I/Oなどによる待ち時間
WSL VM
real 254 5.35
usr 4.70 3.59
sys 95.1 1.78

ユーザ空間の処理時間には大した違いはありません。WSLはユーザプロセスはコードの変換なしでネイティブ動作させており、システムコールだけをエミュレーションしているため、これは納得できる話です。カーネル内実行時間についてはWSLのほうがVMに比べて数十倍多かったです。カーネル内処理に余分に時間がかかっていることがわかります。

git checkoutは並列動作しないため、real - usr - sysの値がそのまま処理の待ち時間となります。

WSL VM
待ち時間[秒] 154.2 -0.01

VMの待ち時間が負数になっていますが、これは0の誤差範囲内の値だと考えてください

これを見ると、VMは待ち時間がほとんど無かったにも関わらず、WSLは全体の半分以上の時間が待ち時間だったことがわかります。

個々のシステムコールの調査

前節の結果を踏まえて、次は一体どんなシステムコール、およびその待ち時間に時間を要したのかを調査しました。調査にあたっては、各種処理をstrace -f -Tによってトレースを仕込んだ上で実行することによって、個々のシステムコールにかかる時間を測定しました。この方法はstrace自体のオーバーヘッドによって全体の所要時間は変わってしまうのですが、何に時間がかかったのかという、おおよその傾向は掴めます1

ここでは処理中に実行したシステムコールの中で、WSLにおける合計所要時間の一番長いものから5つについて、合計所要時間と一回当たりの平均所要時間を記載しました。VMにおける対応するデータも併記しました。

WSL VM
close()[秒] 188 0.584
write()[秒] 118 1.46
open()[秒] 33.2 0.889
unlink()[秒] 29.6 0.822
lstat()[秒] 29.6 4.71

上記のようなファイルアクセス周りのシステムコールに大きく時間がとられていることがわかりました。とくにclose()とwrite()の割合が多かったです。close()はファイルを閉じるだけという処理内容から見ると、時間がかかりすぎに見えます。write()については、VMはページキャッシュに書き込んですぐ戻ってきているように見えますが、WSLはそうなっているようには見えません。

なお、これらシステムコールの所要時間にはカーネルがCPUを使っていた時間だけでなく、その過程でI/Oの完了などを待っていた時間を含みます。このため、これらの所要時間の総和は全体の処理の所要時間(real)よりはるかに長くなるので、注意が必要です。

タグジャンプファイル作成

プロセスの処理か、システムコールか、待ちか

WSL VM
real 95.2 39.9
usr 48.7 48.3
sys 60.5 12.2

まずユーザ空間の処理時間はgit checkoutの場合と同様、大して変わりません。それに対してカーネル空間の処理時間は5倍程度WSLのほうが長かったです。

タグジャンプファイル作成処理は並列動作するので、real - (usr + sys)/8がコアあたりのおおよその平均待ち時間と考えられます。

WSL VM
コアあたりの平均待ち時間[秒] 81.5 32.3

git checkoutの場合とは異なり、VMについても待ち時間が発生していますが、WSLのほうがVMよりも数倍大きな値になりました。

個々のシステムコールの調査

WSL VM
futex()[秒] 412 175
write()[秒] 117 32.3
read()[秒] 18.5 21.1
lstat()[秒] 7.18 1.91
access()[秒] 6.44 2.08

futex()とwrite()が速度差の支配的因子であることがわかります。futex()は排他制御に用いるシステムコールです。それに加えてgit checkout()のときと同様、write()をはじめとするファイルアクセス処理に多くの時間を費やしていることがわかりました。ただし、VMの場合もwrite()はページキャッシュへのアクセスだけではおさまっていないようです。

ビルド

プロセスの処理か、システムコールか、待ちか

WSL VM
real 281 97.6
usr 604 605
sys 905 51.6

これまでと同様、ユーザ空間での実行時間は同じです。その一方、カーネルの実行時間はWSLがVMの18倍にのぼりました。

ビルド処理は並列動作するので、real - (usr + sys)/8をコアあたりの平均待ち時間と考えました。

WSL VM
コアあたりの平均待ち時間[秒] 92.3 15.5

両者共に長い待ち時間がありますが、平均待ち時間はWSLがVMの6倍強になっています。

個々のシステムコールの分析

WSL VM
read()[秒] 15500 3610
write()[秒] 2850 23.2
open()[秒] 970 0.00237
execve()[秒] 319 8.21
close()[秒] 288 75.7

これまでと同様、ファイルアクセス処理に多くの時間がかかっていることがわかりました。read()についてはどちらもストレージデバイスに読みに行っているように見えますが、WSLのほうがはるかに遅いです。write()については、VMは全てまたはほとんどがページキャッシュへの書き込みだけで復帰しているように見えますが、WSLに関しては多くが長時間待たされているらしく、100倍以上の速度差が出ています。

まとめ

ユーザ空間の処理速度はほとんど変わらないもののカーネル空間の処理の影響でWSLはVMよりも低速であることがわかりました。とくにファイルアクセス関連のものについては待ちになるケースが多いこと、かつ、待ち時間も長くなる傾向にあることがわかりました。

個々のシステムコールにおける所要時間のうちわけ(カーネル処理 or 待ち)や、タグジャンプファイル作成処理においてはread()速度が変わらない点など、深堀りできそうな要素はいくらでもあるのですが、とりあえず今日は力尽きたのでここまでです。

おわりに

いかがでしたでしょうか。本記事における調査はあくまで筆者の独断と偏見に基づくものなので、みなさまも他に気になる点があれば、色々と性能測定してみると楽しいと思います。

筆者はWSLはネイティブ環境あるいはVM上にインストールしたLinuxの代替品ではなく、それらよりも用途が限定されるものの、より気軽に使えるソフトウェアというとらえかたをしています。今のところは次のような用途に使っています。

  • 中小規模のソースを読む
  • やっつけスクリプトなどの短いソースの読み書きと動作確認
  • 文書作成
  • sshによるリモート接続
  • 電卓(python -c)

かなりできることは少ないという印象ですが、実際に使ってみると、これだけでもかなり嬉しいものです。

個人的にはWSLはファイルシステムアクセス速度が速くなれば導入コストが安い、かつ、開発に必要な各種処理も高速な、理想的な開発環境になると思っています。今後の改善に期待です。なお、Microsoft社も(当然)この問題を認識しているらしく、将来のバージョンでは改善予定があるようです


  1. WSLにおける、もっとよい性能測定の方法をご存知のかたがいれば教えてほしいです。