GPU 內核虛擬化 - 原理篇

cgpu

目前市面上大部分文章都只提了一下通過攔截驅動 ioctl、mmap、read、write 接口的調用來實現內核虛擬化,但是具體怎麼實現沒有描述。

內核虛擬化是從阿里最先有的,這篇 ** 文章 [1]** 對 cgpu 是分析的最深入的。也提供了一個之前版本的代碼:https://github.com/lvmxh/cgpu.git

由於代碼裏面的核心部分 cgpu.o 沒有開源,所以只能分析一些非核心的實現。

內核攔截

首先我們要知道設備是如何被調用的,設備在 Linux 中一個文件描述符,所以應用程序就是通過系統調用 open、read、write、mmap、ioctl 等等操作來直接操作設備文件描述符,比如 /dev/nvidia0 .

在內核空間中 Linux 有一個驅動程序的結構體定義 file_operations ,它會把系統調用的 open、read 等等操作都通過驅動程序來實現。

有了核心原理我們就可以去分析 cgpu 這個項目了。那具體想知道在調用 nvidia 設備的過程中執行了哪些系統調用,可以使用 strace 命令去獲取。

通過如下的命令可以獲取執行 nvidia-smi 命令過程中的系統調用。

$ strace -e trace=mmap nvidia-smi
$ strace -e trace=ioctl nvidia-smi
$ strace nvidia-smi

cgpu 核心框架

cgpu 中有三個文件 cgpu-km.c 和 cgpu-procfs.c 和 os-interface.c ,核心入口是 cgpu-km.c, 因爲它提供了 module_init 和 module_exit。

cgpu-km.c 文件分析

核心的就是我們先看它聲明的驅動程序接口,主要定義如下的操作。在 cgpu 的最新版依然是隻實現瞭如下幾個函數,說明實現這個函數就可以實現虛擬化了。

static struct file_operations cgpu_km_fops = {
    .owner     = THIS_MODULE,
    .poll      = cgpu_km_poll,
    .unlocked_ioctl = cgpu_km_unlocked_ioctl,
    .compat_ioctl = cgpu_km_compat_ioctl,
    .mmap      = cgpu_km_mmap,
    .open      = cgpu_km_open,
    .release   = cgpu_km_close,
};

上面涉及到的幾個函數都沒有源代碼定義,可以通過 objdump -t cgpu.o 命令來查看都是定義在 cgpu.o 文件中的。

下面來分析驅動程序被加載的時候都幹了些什麼?

static int __init cgpu_km_init(void)
{
    int ret = 0;
    int num = 0;
    # 這個函數也是定義 cgpu.o 裏面的
    num = cgpu_initialize();
    # 這裏是註冊字符設備,名字是 cgpu-km
    ret = register_chrdev(0, "cgpu-km", &cgpu_km_fops);
    ...
    cgpu_major = ret;
    # 這個函數是在 cgpu-procfs.c 文件中定義的,我們稍後分析。
    ret = cgpu_km_procfs_init(num);
    if (ret) {
        pr_err("failed to init cgpu km procfs\n");
        unregister_chrdev(cgpu_major, "cgpu-km");
    }

    return ret;
}

下面是驅動被卸載的時候執行的清理邏輯;

static void __exit cgpu_km_exit(void)
{
  # 同樣是定義在 cgpu.o 文件中
    cgpu_finalize();
    # 在 cgpu-procfs.c 文件中定義
    cgpu_km_procfs_deinit();
    # 移除cgpu-km的字符設備註冊
    unregister_chrdev(cgpu_major, "cgpu-km");
}

cgpu-procfs.c 文件分析

cgpu 提供內核態參數設置的接口是 procfs,並不是 sysfs。

os-interface.c 文件分析

這個文件裏面通過內核線程和 queue 實現的 cGPU 調度算法;來控制一張卡上的多任務切換。

編譯

目前我在 ubuntu22.04 版本下成功編譯了這個項目,因爲我使用的是高內核的版本,所以需要修改代碼裏面一些過時的系統調用,可以直接使用我修改過的。

https://github.com/lengrongfu/study-demo/blob/main/gpu/cgpu/README.md

參考資料

[1] 文章:
https://www.cnblogs.com/shaohef/p/13616687.html

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/itLrrVyQ4AnJhFjWpQ1m5g