CUDA 驅動軟件架構(譯)
概述
簡而言之,CUDA 驅動程序負責管理 GPU 資源並調度 GPU 上的計算任務。
驅動程序爲用戶提供 API,用於在 GPU 上分配內存、將數據複製到分配的內存區域、從內存區域中複製數據以及在內存區域之間複製數據,並啓動對數據進行操作的 GPU 內核。
驅動程序還提供了 CUDA 與其他用戶 API 之間的互操作性。這種互操作性使用戶能夠在 CUDA 和其他 API 之間高效地共享 GPU 內存。它還允許在不同 API 中發生的 GPU 操作之間進行高效同步,而無需 CPU 等待 GPU 操作完成。
驅動程序管理 GPU 運行 GPU 內核所需的所有資源。這包括用戶 API 調用顯式分配的資源以及內部所需的輔助資源。它還協調 GPU 和 CPU 之間的工作,以確保它們高效協作。
術語表
Unit:Unit 是指在其實現的功能內具有高度內聚性、與它交互的其他實體之間耦合度低,並且可以進行獨立測試的最小軟件單位。
Component:一組邏輯上相互關聯的單元,用於實現所需的功能。CUDA 驅動程序就是一個組件。
Driver:本文檔中單獨使用的 “driver” 一詞指的是“CUDA 驅動程序”。其他驅動程序則通過全稱(例如 OpenGL 驅動程序)或通過限定詞來區分(例如“其他驅動程序”、“內核模式驅動程序”)。
API:應用程序編程接口(Application Programming Interface)。
OS:操作系統(Operating System),例如 Linux、Windows、QNX。
CPU:運行操作系統和系統中其他應用程序的處理器。
GPU:圖形處理單元(Graphics Processing Unit)。
Kernel、GPU kernel,Compute Kernel:一段旨在 GPU 上執行的可執行代碼。單獨使用的 “kernel” 一詞即爲此含義。這可能會與操作系統內核混淆,因此爲了避免混淆,我們通過限定詞來指代操作系統內核,例如“OS Kernel”、“Linux Kernel"。
架構特性
延遲完成
CUDA 驅動程序採用了一種延遲任務完成(deferred task completion)模型**。**它通常被稱爲異步(asynchronous 或 async)模型,因爲任務的完成可能不會在觸發該任務的函數調用返回之前發生。
換句話說,用戶 API 函數和驅動程序內部函數可能會在其預期操作完成之前返回,並且在這些操作的效果對調用者可見之前返回。
這種異步執行模型非常強大,因爲它將 CPU 的執行與 GPU 的執行解耦,直到這種耦合變得必要爲止(例如,將結果從 GPU 讀取回 CPU 時,GPU 需要完成其工作)。這使得 CPU 和 GPU 可以獨立地向前推進,而不必彼此同步執行。
這使得 CPU 可以向 GPU 提交任務並立即返回,而無需等待 GPU 操作完成。通常情況下,提交任務所需的時間與 GPU 完成計算所需的時間相比非常短。由於立即返回,CPU 可以騰出時間執行其他任務,例如準備下一次提交。
只有在預期操作完成後才返回的函數調用被稱爲同步(synchronous 或 sync)函數。這類函數導致 CPU 等待 GPU 操作完成的行爲稱爲 CPU 同步(CPU synchronization),通常簡稱爲同步(synchronization)
錯誤報告
由於採用了延遲完成(deferred completion)模型,由函數調用觸發的異步操作即使在調用返回後仍可能繼續運行。異步操作期間生成的錯誤可能在調用返回時未被報告。更具體地說,當函數能夠成功將異步操作加入 GPU 隊列時,函數的返回值將表示成功。異步操作中遇到的任何錯誤將在下一個可用的時機報告。
驅動程序會嘗試儘早檢測並返回這些錯誤。大多數 API 和驅動程序函數可以返回由先前的異步操作產生的錯誤,即使被調用的 API 或函數本身並未生成任何錯誤。
在最壞的情況下,下一個必須等待 GPU 工作完成的同步函數調用將返回掛起的錯誤。
批量執行
在延遲完成(Deferred Completion)中描述的異步函數調用還允許驅動程序緩衝請求的操作,並以批量的方式將任務提交給 GPU。
在某些平臺上,這種做法可以改善性能特性。它還可以用於滿足資源限制的需求。
生產者消費者模型
GPU 以消費者模式工作,它從 CPU 讀取命令並執行請求的任務。驅動程序則充當 GPU 的命令生產者。
在這種生產者 - 消費者模型中,驅動程序和 GPU 通過通道(channels)進行通信,通道是一種順序命令隊列(in-order command queues)。順序隊列意味着命令按照它們被提交的順序依次執行。
架構
層級概覽
CUDA 軟件堆棧具有以下分層結構:
接口導出
應用程序和 CUDA 庫使用 CUDA Runtime 和 CUDA Driver API。
CUDA Tools 接口 被調試器和性能分析器等工具使用。此接口中的函數未在 CUDA Runtime 或 CUDA Driver 中導出以供鏈接,因此對用戶應用程序是隱藏的。
CUDA Driver API 層 是通過從頭文件自動生成樣板函數代碼來實現的。每個驅動程序 API 函數充當調用 CUAPI 函數 的封裝器,並可選擇調用工具回調函數以進行 API 跟蹤。自動生成該層的代碼避免了手工編寫重複代碼的繁瑣過程,從而防止錯誤。
接口請求
CUDA 驅動程序允許應用程序以 PTX 中間語言 的形式提供 GPU 二進制文件。這些二進制文件需要先編譯成 GPU 可執行代碼,然後才能在 GPU 上執行。這一過程被稱爲 運行時編譯(run-time compilation) 或 即時編譯(just-in-time compilation, JIT),驅動程序依賴於一個設備編譯器來完成此任務。
在某些平臺上,設備編譯器被構建爲一個獨立的共享庫,驅動程序會鏈接到它。而在其他平臺上,設備編譯器則被編譯爲驅動程序本身的一部分。
CUI 層
核心概念
CUI 層 是 CUDA 驅動程序的核心。爲了描述其結構,我們首先需要理解一些核心概念。
CUDA 上下文
CUDA 上下文(CUDA Context),通常簡稱爲上下文(Context),是一個軟件容器,用於封裝在單個 GPU 上一起管理的一組資源。單個 GPU 可以擁有多個這樣的資源集,因此可以關聯多個上下文。
CUDA 驅動程序中的資源對象和句柄通常僅在創建它們的上下文中具有意義且可用。然而,在某些情況下,資源(例如內存對象)可以通過顯式映射到其他上下文(而非創建它們的上下文)來實現上下文之間的共享。
硬件抽象層
硬件抽象層(HAL)抽象了 GPU 的功能,並使其餘代碼能夠忽略不同 GPU 架構之間硬件功能的差異。
HAL 使得單個 CUDA 驅動程序二進制文件能夠與當前驅動程序支持的任何已安裝 GPU 協同工作。
設備模型抽象層
CUDA 驅動程序依賴於操作系統內核和操作系統設備驅動程序來訪問 GPU。設備模型抽象層(DMAL) 抽象了不同操作系統設備模型之間的差異,使其餘代碼能夠獨立於設備模型。
這使得單個驅動程序代碼庫可以通過包含針對目標操作系統的正確 DMAL 代碼,在不同的操作系統上運行。
功能組織
核心概念並不一定以獨立單元的形式存在於 CUI 層 中。多個單元可能共同使用或貢獻於這些核心概念。
例如,上下文(Context) 是一個聚合結構,包含多個單元的部分數據。每個這樣的單元都會填充並使用其所屬部分的上下文。
同樣,設備模型抽象層(DMAL) 和 硬件抽象層(HAL) 由多個功能組組成。實現特定功能的單元也會實現 DMAL 或 HAL 或兩者的相應部分。
例如,CUSW_UNIT_LAUNCH 單元實現了內核啓動功能,因此它也包含了 HAL 中與啓動相關函數的實現。
功能組
儘管功能組實現了驅動程序功能的不同部分,但它們密切相關,並相互依賴以確保正確運行。以下部分將對這些功能組進行描述。
上下文
上下文(Context)充當 GPU 上操作的核心協調者。它的大部分工作是通過調用其他功能組來完成的。
上下文還保存了一些執行狀態
內存管理
內存管理依賴於執行(Execution)。對於某些操作(如釋放內存),內存必須未被 GPU 主動使用。在這種情況下,釋放操作需要等待正在使用該內存對象的任務執行完成
GPU 代碼管理
GPU 可執行代碼存儲在 GPU 內存中。
GPU 代碼可能需要在 GPU 執行之前進行編譯。這種編譯非常耗時。爲了避免每次應用程序運行時重新編譯此類代碼,編譯生成的 GPU 二進制文件會被存儲在基於磁盤的緩存中。
執行
執行(Execution) 涉及在 CPU 和 GPU 上調度任務、在任務之間進行同步以及爲任務管理 GPU 資源。
互操作性
CUDA 驅動程序可以與非 CUDA 的 API 共享內存和同步對象。這是通過使用操作系統內核模式驅動程序接口將這些對象從其他 API 映射到 CUDA 中來實現的。
Unit 概要
驅動配置
驅動程序的配置可分爲兩個獨立的階段:
-
驅動程序構建時 驅動程序通過構建過程被編譯成特定平臺的共享庫文件。
-
驅動程序運行時 這是指應用程序在目標平臺上運行並使用驅動程序的階段。
驅動程序的構建時配置通過 NVIDIA 廣泛的 NVCONFIG 基礎設施進行管理。
驅動程序的運行時配置可以通過 API 調用、環境變量和應用配置文件(通過配置文件或註冊表設置)來完成。
部署視圖
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/L3u-u2--rupTPS39Pk5f2g