关于WSL 2中CUDA支持的出现

微软在2020年5月的Build大会上回应了众多用户的要求,为Linux 2Windows子系统(WSL 2)引入了一项新功能-支持视频加速器。这将允许您在WSL 2中运行临时计算应用程序。 GPU支持将为专业工具铺平道路,并帮助解决WSL 2中目前仅在Linux上才可能实现的任务。现在,可以使用GPU的功能在Windows中解决类似的任务。 在此,WSL附带对NVIDIA CUDA硬件和软件并行计算体系结构的支持非常重要







该材料由NVIDIA专家准备,我们正在翻译该材料。在这里,我们将讨论WSL 2的Public Preview版本中对CUDA的期望。





在WSL 2容器中运行Linux上使用的AI框架



什么是WSL?



WSL是Windows 10的一项功能,它使您可以直接在Windows上使用Linux命令行工具,而不必处理应用双重启动配置的复杂性。WSL是与Microsoft Windows紧密集成的容器化环境。这使您可以将Linux应用程序与传统Windows应用程序以及通过Microsoft Store分发的现代应用程序一起运行。



WSL主要是面向开发人员的工具。如果您正在Linux容器中处理某些项目,则意味着您可以使用熟悉的Linux工具在Windows计算机上本地执行相同的操作。通常,要在Windows上运行此类应用程序,您需要花费大量时间来配置系统,还需要一些第三方框架,库。现在,随着WSL 2的发布,一切都发生了变化。多亏了WSL 2,Windows领域才全面支持Linux内核。



WSL 2和GPU准虚拟化技术(GPU准虚拟化,GPU-PV)使Microsoft将Linux对Windows的支持提高到一个新的水平,从而有可能启动针对GPU设计的计算负载。下面我们将详细讨论WSL 2中GPU使用情况。



如果您对WSL 2中的视频加速器支持主题感兴趣,请查看资料和存储库。



CUDA转WSL



为了利用WSL 2中的GPU功能,您需要在计算机上具有支持Microsoft WDDM的视频驱动程序。此类驱动程序是由NVIDIA等视频卡制造商创建的。



CUDA技术使您可以为NVIDIA视频加速器开发程序。多年来,Windows上的WDDM都支持此技术。微软的新WSL 2容器提供了CUDA技术可以利用的GPU加速计算功能,从而允许基于CUDA的程序在WSL中运行。有关更多详细信息,请参阅《WSL 用户指南》中CUDA。



WSL中的CUDA支持包含在WDDM 2.9的NVIDIA驱动程序中。这些驱动程序易于在Windows上安装。 WSL CUDA用户模式驱动程序(libcuda.so)会在容器内部自动变为可用,并且加载程序可以检测到它们。



NVIDIA驱动程序开发团队已在CUDA驱动程序中添加了WDDM和GPU-PV支持。这样做是为了使这些驱动程序可以在Windows上运行的Linux环境中工作。这些驱动程序仍处于“预览”状态,只有在它们发布之后,才会发布具有GPU支持的WSL正式版本。有关驱动程序版本的详细信息,请参见此处



下图显示了如何在Linux guest虚拟机内将CUDA驱动程序连接到WDDM的图。





在Linux来宾系统上运行的启用CUDA的用户模式WDDM驱动程序



假设您是在快速环(内部版本20149或更高版本)的Microsoft Windows Insider程序(WIP)的最新Windows程序集上安装WSL发行版的开发人员。如果您已切换到WSL 2,并且拥有NVIDIA GPU,则可以试用该驱动程序并在WSL 2中运行您的GPU计算代码。所有您需要做的就是在Windows主机上安装驱动程序并打开WSL容器。在这里,您将能够使用CUDA处理应用程序,而无需付出任何额外的努力。下图显示了使用CUDA功能的TensorFlow应用程序如何在WSL 2容器中运行。





在WSL 2中运行的TensorFlow容器



CUDA现在在WSL中可用的事实使应用程序可以在WSL中运行,而以前只能在常规Linux环境中运行。



NVIDIA仍在积极致力于该项目,并对其进行改进。除其他事项外,我们正在努力为WDDM添加以前专门为Linux设计的API。这将导致以下事实:在WSL中,无需用户付出额外的努力,就可以运行越来越多的应用程序。



我们关注的另一个问题是性能。如前所述,WSL 2中的GPU支持非常重视GPU-PV技术。在不使用流水线的情况下,这可能会对GPU上小任务的执行速度产生负面影响。我们现在正在努力尽可能减少这些影响。



NVML



原始驱动程序包不包含NVML技术,我们正通过计划向WSL添加NVML支持和对其他库的支持来努力解决此问题。



我们从主要的CUDA驱动程序开始,该驱动程序即使在WSL CUDA支持的初期,也将允许用户运行大多数现有的CUDA应用程序。但事实证明,某些容器和应用程序甚至在加载CUDA之前就使用NVML获取GPU信息。这就是为什么向WSL添加NVML支持是我们的首要任务之一。很有可能不久我们将能够分享一些有关解决此问题的好消息。



WSL中的GPU容器



除了对DirectX和CUDA的WSL 2支持之外,NVIDIA还努力在WSL 2中添加对NVIDIA Container Toolkit(以前称为nvidia-docker2)的支持。数据科学家创建的容器化GPU应用程序现在可以在运行Windows的计算机上的WSL 2中运行,而无需对其进行任何更改即可运行在本地或云Linux环境上。



为此不需要某些特殊的WSL软件包。 NVIDIA运行时库(libnvidia-container)可以动态检测libdxcore并在GPU加速的WSL 2环境中运行代码时使用它。就像在Linux上一样,在安装Docker和NVIDIA Container Toolkit软件包后,这种情况会自动发生。这使您无需付出额外的努力即可在WSL 2中运行使用GPU的容器。



我们强烈建议希望使用此选项的用户--gpus安装最新版本的Docker工具(19.03或更高版本)。要启用WSL 2支持,请按照Linux发行说明进行操作并安装可用的最新版本nvidia-container-toolkit



这个怎么运作?使用libnvidia-container库解决了WSL 2的所有特定任务。现在,该库可以在运行时检测到libdxcore.so的存在,并使用该库来检测该接口可见的所有GPU。



如果这些GPU需要在容器中使用,则使用libdxcore.so调用驱动程序存储位置,调用包含Windows主机系统和WSL 2所有驱动程序库的文件夹。libnvidia-container.so库负责配置容器。以一种可能正确访问驱动程序存储的方式。该库负责配置WSL 2支持的基本库。下图示意性地显示了该库。





WSL 2中libnvidia-container.so使用的驱动程序存储发现和容器映射方案



也不同于WSL外部使用的逻辑。使用libnvidia-container.so可以完全抽象该过程,并且对最终用户应尽可能透明。此早期版本的局限性之一是您不能在具有多个GPU的环境中选择GPU。所有GPU在容器中始终可见。



在WSL容器中,您可以运行任何您已经熟悉的NVIDIA Linux容器。 NVIDIA支持专业人员使用的最有趣的Linux工具和工作流程。从 NVIDIA NGC下载您感兴趣的容器,然后尝试一下。



现在,我们将讨论如何在WSL 2中运行TensorFlow和N体容器,这些容器旨在使用NVIDIA GPU来加快计算速度。



发射N体容器 



使用安装脚本安装Docker:



user@PCName:/mnt/c$ curl https://get.docker.com | sh


安装NVIDIA Container Toolkit。从nvidia-docker2 v2.3和libnvidia-container 1.2.0-rc.1运行时库开始,可以使用WSL 2支持。



设置存储库stableexperimentalGPG密钥。实验存储库中提供了对支持WSL 2的运行时代码的更改。



user@PCName:/mnt/c$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID)

user@PCName:/mnt/c$ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -

user@PCName:/mnt/c$ curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

user@PCName:/mnt/c$ curl -s -L https://nvidia.github.io/libnvidia-container/experimental/$distribution/libnvidia-container-experimental.list | sudo tee /etc/apt/sources.list.d/libnvidia-container-experimental.list


安装NVIDIA运行时程序包及其依赖项:



user@PCName:/mnt/c$ sudo apt-get update
user@PCName:/mnt/c$ sudo apt-get install -y nvidia-docker2


让我们打开一个WSL容器并在其中启动Docker守护程序。如果一切都正确完成-之后,您会看到服务消息dockerd



user@PCName:/mnt/c$ sudo dockerd




启动Docker守护程序



在另一个WSL窗口中,加载并启动N-body模拟容器。执行此任务的用户必须具有足够的权限来加载容器。以下命令可能需要使用sudo运行。在输出中,您可以看到有关GPU的信息。



user@PCName:/mnt/c$ docker run --gpus all nvcr.io/nvidia/k8s/cuda-sample:nbody nbody -gpu -benchmark




发射N体容器



运行TensorFlow容器



我们将在WSL 2环境中的Docker中测试另一个流行的容器-TensorFlow。



下载TensorFlow Docker映像。为了避免连接到Docker时出现问题,请在sudo模式下运行以下命令:



user@PCName:/mnt/c$ docker pull tensorflow/tensorflow:latest-gpu-py3


让我们将TensorFlow教程15中经过稍微修改的GPU 教程版本保存C主机系统上的磁盘上默认情况下,该磁盘以方式安装在WSL 2容器中/mnt/c



user@PCName:/mnt/c$ vi ./matmul.py
import sys
import numpy as np
import tensorflow as tf
from datetime import datetime

device_name = sys.argv[1]  # Choose device from cmd line. Options: gpu or cpu
shape = (int(sys.argv[2]), int(sys.argv[2]))
if device_name == "gpu":
    device_name = "/gpu:0"
else:
    device_name = "/cpu:0"

tf.compat.v1.disable_eager_execution()
with tf.device(device_name):
    random_matrix = tf.random.uniform(shape=shape, minval=0, maxval=1)
    dot_operation = tf.matmul(random_matrix, tf.transpose(random_matrix))
    sum_operation = tf.reduce_sum(dot_operation)

startTime = datetime.now()
with tf.compat.v1.Session(config=tf.compat.v1.ConfigProto(log_device_placement=True)) as session:
        result = session.run(sum_operation)
        print(result)

#  
print("Shape:", shape, "Device:", device_name)
print("Time taken:", datetime.now() - startTime)


以下是从安装在容器中的磁盘上运行该脚本的结果C该脚本首先使用GPU执行,然后使用CPU执行。为方便起见,此处的输出已减少。



user@PCName:/mnt/c$ docker run --runtime=nvidia --rm -ti -v "${PWD}:/mnt/c" tensorflow/tensorflow:latest-gpu-jupyter python /mnt/c/matmul.py gpu 20000




执行matmul.py脚本的结果



在WSL 2容器中使用GPU时,与在CPU上执行代码相比,可以显着提高代码执行速度。



让我们进行另一个旨在研究GPU计算性能的实验。它与Jupyter Notebook手册中的代码有关。启动容器后,您应该看到指向Jupyter Notebook服务器的链接。



user@PCName:/mnt/c$ docker run -it --gpus all -p 8888:8888 tensorflow/tensorflow:latest-gpu-py3-jupyter




启动Jupyter Notebook



您现在应该能够在Jupyter Notebook环境中运行演示。请注意,要使用Microsoft Edge浏览器连接到Jupyter Notebook,必须使用而不是127.0.0.1localhost



转到tensorflow-tutorials并启动记事本classification.ipynb



要查看GPU加速的结果,请转到菜单Cell,选择Run All并查看WSL 2 Jupyter Notebook容器中的日志。





Jupyter笔记本杂志



此演示,和其他一些人在该容器中,让你看到虚拟化层的问题,解决小任务时涉及到一个不合理的高附加的系统负载。上面我们已经讨论过了。由于我们在这里启动了非常小的训练模型,因此它们在GPU上的执行时间少于解决同步问题所需的时间。解决WSL 2中的此类“玩具”问题时,CPU可能比GPU更高效。我们致力于解决此问题,努力将其表现形式限制为仅很小的工作量,而没有应用流水线。



WSL概述



为了了解WSL 2中如何添加GPU支持,我们现在讨论在Windows上运行Linux的感觉以及容器如何查看硬件。



微软在2016年的Build大会上介绍了WSL技术。该技术很快得到了广泛的应用,并在需要运行基于Windows的应用程序(例如Office)以及Linux和相关程序的开发工具的Linux开发人员中流行。



WSL 1系统允许未经修改的Linux二进制文件运行。但是,此处使用Linux内核仿真层,该层已实现为NT内核子系统。该子系统处理来自Linux应用程序的调用,将它们重定向到适当的Windows 10机制。



WSL 1是一个有用的工具,但与所有Linux应用程序都不兼容,因为它需要模拟所有的Linux系统调用。此外,文件系统操作速度很慢,这导致某些应用程序的性能降低到令人无法接受的地步。



考虑到这一点,Microsoft决定采取其他方式,并发布了WSL 2,这是WSL的新版本。 WSL 2容器在虚拟化环境中运行完整的Linux发行版,但仍充分利用了新的Windows 10容器化系统。



虽然WSL 2使用Windows 10的Hyper-V服务,但它不是传统的虚拟机,而是轻量级的虚拟化帮助程序引擎。该机制负责管理与物理内存关联的虚拟内存,从而允许WSL 2容器通过访问Windows主机系统来动态分配内存。



创建WSL 2的主要目标之一是提高使用文件系统的性能,并确保与所有系统调用的兼容性。此外,WSL 2旨在提高WSL和Windows之间的集成水平。这使您可以使用Windows命令行工具方便地使用在容器中运行的Linux系统。这也提高了主机文件系统的可用性,该主机文件系统自动安装在容器文件系统的所选目录中。



WSL 2作为预览功能在Windows Insider程序中引入,并在最新的Windows 10更新版本2004中发布。



WSL 2是Windows的最新版本,具有更多的增强功能,这些功能会影响从网络堆栈到基本VHD存储引擎的所有内容。WSL 2中所有新功能的描述都超出了本材料的范围。您可以在页面上对WSL 2和WSL 1进行比较来了解更多有关它们的信息



Linux核心WSL 2



WSL 2中使用的Linux内核由Microsoft根据kernel.org上提供的源代码,基于最新的稳定分支进行编译。该内核已经针对WSL 2进行了专门调整,针对大小和性能进行了优化,以在Windows上运行Linux。Windows Update机制支持该内核。这意味着用户不必担心下载最新的安全更新和内核改进。所有这些都是自动完成的。



Microsoft在WSL中支持多个Linux发行版。该公司遵循开源社区的规则,在WSL2-Linux-Kernel GitHub存储库中发布了WSL 2内核源代码,并进行了与Windows 10集成所需的修改。 



WSL中的GPU支持



Microsoft已在WSL 2容器中添加了对使用GPU-PV技术的真实GPU的支持。在这里,操作系统的图形核心(dxgkrnl)将来自来宾虚拟机中运行的用户模式组件的调用编组到主机上的内核模式驱动程序。



Microsoft已将该技术开发为WDDM功能,并且自其诞生以来已经发布了多个Windows版本。这项工作是在独立硬件供应商(Independent Hardware Vendor,IHV)的协助下进行的。从Windows Insider计划中提供的产品预览版开始,NVIDIA图形驱动程序就已经支持GPU-PV。在运行Hyper-V的虚拟机中,以来宾模式运行的Windows操作系统可以访问当前支持的所有NVIDIA GPU。



为了利用WSL 2中的GPU-PV功能,Microsoft必须为Linux来宾创建其图形框架的基础:WDDM支持GPU-PV协议。新的Microsoft驱动程序位于dxgkrnl之后,该系统负责在Linux上支持WDDM。可以在WSL2-Linux-Kernel存储库中找到驱动程序代码



预计Dxgkrnl将在WDDM 2.9的WSL 2容器中提供GPU加速支持。微软表示dxgkrnl是基于GPU-PV协议的Linux GPU驱动程序,与具有类似名称的Windows驱动程序无关。



当前,您可以下载NVIDIA WDDM 2.9驱动程序的预览版。... 在接下来的几个月中,将通过Windows WIP版本中的Windows Update分发该驱动程序,从而无需手动下载和安装该驱动程序。



GPU-PV基础



dxgkrnl驱动程序使新的/ dev / dxg设备在Linux客户机中的用户模式下可用。Windows上可用的D3DKMT内核服务层也已作为dxcore库的一部分移植到Linux。它使用一组专用IOCTL调用与dxgkrnl进行交互。



dxgkrnl的Linux来宾版本使用多个VM总线通道连接到Windows主机上的dxg内核。主机上的dxg内核处理Linux进程中的内容,就像使用WDDM的常规Windows应用程序中的内容一样。即,dxg内核将接收到的内容发送到KMD(内核模式驱动程序,这是每种HIV独有的内核模式驱动程序)。内核模式驱动程序准备接收到的内容以发送给硬件GPU。下图显示了Linux设备/ dev / dxg与KMD之间的交互的简化图。





Windows主机组件如何使dxg设备在Linux guest虚拟机中工作的简化图



涉及在 Windows guest虚拟机中提供此行为时,NVIDIA驱动程序已经在Windows 10中支持GPU-PV已有一段时间了。NVIDIA GPU可用于使用Microsoft的虚拟化层在所有Windows 10应用程序中加速计算和图形输出。使用GPU-PV还可以使用vGPU。以下是一些类似应用程序的示例:





这就是使用NVIDIA GeForce GTX 1070视频加速器在Windows Sandbox容器中运行DirectX应用程序的样子。





Windows Sandbox容器中的图形加速由NVIDIA GeForce GTX 1070执行



自定义模式支持



为了向WSL添加对图形渲染的支持,Microsoft的相应开发团队还将dxcore用户模式组件移植到Linux。



dxcore库提供了一个API,使您可以检索有关系统上可用的WDDM兼容图形卡的信息。该库被认为是Windows和Linux上DXGI适配器工具的跨平台,低级替代。该库还使用D3DKMT API层来抽象访问dxgkrnl服务(Linux上为IOCTL调用,Windows上为GDI调用),CUDA和其他依赖WSL WDDM支持的用户模式组件使用该层。



微软表示,dxcore库(libdxcore.so)将在Windows和Linux上均可用。NVIDIA计划在驱动程序中添加DirectX 12支持和CUDA API。这些附加组件针对WDDM 2.9提供的新WSL功能。代表API的两个库都将连接到dxcore,以便它们可以向dxg提供有关如何在主机系统上封送其KMD请求的指令。



尝试新的WSL 2功能



是否想在仍然享受Linux环境便利的同时将Windows PC用于真正的机器学习和人工智能任务?如果是这样,WSL的CUDA支持为您提供了一个绝佳的机会。在WSL环境中,CUDA Docker容器被证明是数据科学家中最受欢迎的计算环境。





在这里,您可以了解有关WSL中使用CUDA技术的更多信息。在这里,在CUDA和WSL专用论坛上,您可以与我们分享您对这些技术的印象,观察和想法。



您是否在WSL 2中尝试过CUDA?






All Articles