部署测试 Gemini
1. System Structure
Gemini 由三部分组成:
- Scheduler:一个守护进程,管理令牌。基于在资源配置文件(resource-config.txt)中提供的信息,调度器确定要授予令牌的对象。客户端只有在持有有效令牌时才能启动 CUDA 核心。
- hook library:一个拦截 CUDA 相关函数调用的库。它利用 LD_PRELOAD 机制,强制在任何其他动态链接库之前加载我们的 Hook 库
- pod manager:一个代理,用于将消息转发给应用程序/调度器。它充当调度器的客户端,每个通过此 Pod 管理器向调度器发送请求的应用程序共享令牌
2. Build & Run
启动容器:
1
docker run --gpus all --privileged -v $(pwd):/workspace -it --rm tlcpack/ci-gpu:20230504-142417-4d37a0a0 /bin/bash
获取项目:
1
2
git clone git@github.com:NTHU-LSALAB/Gemini.git
mv Gemini/ gemini
也尝试过:
1
2
3
wget https://github.com/NTHU-LSALAB/Gemini/archive/refs/tags/v1.1-kubeshare.tar.gz
tar -xzvf v1.1-kubeshare.tar.gz
mv Gemini-1.1-kubeshare/ gemini
这两个的代码不一样。
目前决定使用第二种方法。
2.1 Build
1
make [CUDA_PATH=/path/to/cuda/installation] [PREFIX=/place/to/install] [DEBUG=1]
实际在我的容器内的运行指令为:
1
make CUDA_PATH=/usr/local/cuda-11.8 DEBUG=1
2.2 Run
就是运行 /tool 文件夹下的 Python 脚本
2.2.1 launch backend
launch-backend.py
:启动 scheduler 和 pod manegers
By default scheduler uses port
50051
, and pod managers use ports starting from50052
(50052
,50053
, …).
执行命令:
1
python3 launch-backend.py ../bin/gem-schd ../bin/gem-pmgr --ip 127.0.0.1 --port 50051 --config ../resource-config.txt
2.2.2 launch-command
launch-command.py
:启动 applications
1
python3 launch-command.py --name client1 --port 50052 --ip 127.0.0.1 --timeout 10 "/root/test 100"
对于该问题,做了以下尝试:
尝试一:
尝试将 API hook 编译出来的库添加到 LD_PRELOAD 中:
1 export LD_PRELOAD=/root/gemini/lib/libgemhook.so.1注:这个命令仅在当前终端有效
但是似乎并没有什么用
尝试二:
注:以下只对 git clone 下来的代码可以尝试(虽然结果也是不行),因为 release 中的 hook.cpp 代码不一样
修改
hook.cpp
第 74 行:
1 (fnDlsym)__libc_dlsym(__libc_dlopen_mode("libdl.so.2", RTLD_LAZY), "dlsym");为:
1 (fnDlsym)__libc_dlsym(__libc_dlopen_mode("libc.so", RTLD_LAZY), "dlsym");但是仍然不行
尝试三:
尝试将所有的
__libc_dlopen_mode
修改为dlopen
注释掉 extern “C” {void *__libc_dlopen_mode(const char *name, int mode);}
将之后的所有
__libc_dlopen_mode
修改为dlopen
所以也类似的修改
__libc_dlsym
修改为dlsym
出现了新的问题, 通常表示程序在尝试初始化一个对象时发生了递归,而这个对象的构造需要在程序启动时就完成。这有时候会发生在全局对象或静态实例的初始化时,尤其是当这些对象的构造函数中涉及到复杂的逻辑或对其他尚未初始化的全局资源的依赖时。
改用 git clone 版本的代码:
一样的问题
尝试四:
尝试 v1.1-bare-metal
1 2 3 wget https://github.com/NTHU-LSALAB/Gemini/archive/refs/tags/v1.1-bare-metal.tar.gz tar -xzvf v1.1-bare-metal.tar.gz mv Gemini-1.1-bare-metal/ gemini仍然后找不到
__libc_dlopen_mode
的问题:重试尝试 3:
尝试五:
基于 v1.1-bare-metal:
阅读 Makefile:
由于我使用的是 a100,所以 SMS 应修改为 80
同时,下载 g++-8:
sudo apt-get install g++-8
目前先使用 Ubuntu18.04 的 docker
docker build :
1 2 docker build -t xaubuntu1804 . docker run --gpus all --privileged -v $(pwd):/workspace -d xaubuntu1804安装 cuda-11.0:
1 2 3 4 5 6 7 wget https://developer.download.nvidia.com/compute/cuda/11.0.1/local_installers/cuda_11.0.1_450.36.06_linux.run sudo sh cuda_11.0.1_450.36.06_linux.run vim ~/.bashrc export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda-11.0/lib64 export PATH=$PATH:/usr/local/cuda-11.0/bin export CUDA_HOME=$CUDA_HOME:/usr/local/cuda-11.0 source ~/.bashrcmake:
1 make CUDA_PATH=/usr/local/cuda-11.0 DEBUG=1似乎可行,因为没有修改 hook.cpp,也没有报错:
但是莫名其妙不会向下执行。
可能是 hostname 的原因,阅读源码发现,Pod manager 是将 hostname 作为 Pod name,通过在终端输入命令hostname
,得到主机的名称:bb409cb7adff。后续阅读代码发现,并不是这回事,是未给出 Pod Name 时才采用 host name卡住是卡在:执行到 cudaEventCreate 就会卡住
之后输出所有拦截到的 cuda 调用,发现最后是卡在:
似乎 cuda11.0 不支持这个 api:
cuda/README.md at master · tmcdonell/cuda (github.com)
尝试升级一下 cuda 到 11.7
1 2 wget https://developer.download.nvidia.com/compute/cuda/11.7.0/local_installers/cuda_11.7.0_515.43.04_linux.run sudo sh cuda_11.7.0_515.43.04_linux.runmake 时:
运行结果:
能运行了,但是它拦截了吗?
似乎是没拦截到,不确定,但是很奇怪的一点是,initialize() 函数里面的应该有的输出一个也没有
保留这个容器:3d46283b5e06
改用 cuda11.1:
1 2 wget https://developer.download.nvidia.com/compute/cuda/11.1.0/local_installers/cuda_11.1.0_455.23.05_linux.run sh cuda_11.1.0_455.23.05_linux.run和 cuda11.0 一样卡住,卡住位置也一样。
尝试 kubeshare 1.1:
尝试六:
突然发现可以使用实验室集群中的 1080Ti,可以使用与 Gemini 原始配置中的 cuda10,所以新建 Ubuntu18.04 的容器,在其中安装 cuda10.0,尝试运行。
首先,创建容器,直接使用「尝试五」中的 Dockerfile 即可,然而实际运行不起来,不知道为什么,所以直接 docker pull 了 ubuntu 18:04,手动安装了必要的包,然后安装 cuda10.0:
1 wget https://developer.nvidia.com/compute/cuda/10.0/Prod/local_installers/cuda_10.0.130_410.48_linux结果是卡在:(仍然是 hook.cpp 中的 cudaEventCreate)
再尝试 kubeshare:
1 wget https://github.com/NTHU-LSALAB/Gemini/archive/refs/tags/v1.1-kubeshare.tar.gz尝试 cuda11.0:
与在 a100 上一样的情景:
尝试七:
仍然使用 a100,cuda 11.0,使用自己仓库里面的 gemini 代码(即 git clone gemini 的源码,修改了 Makefile,增加了 hook.cpp 的调试信息)
1 2 3 4 5 6 7 8 9 10 11 docker run --gpus all --privileged -v $(pwd):/workspace -d xaubuntu1804 wget https://developer.download.nvidia.com/compute/cuda/11.0.1/local_installers/cuda_11.0.1_450.36.06_linux.run sh cuda_11.0.1_450.36.06_linux.run vim ~/.bashrc export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda-11.0/lib64 export PATH=$PATH:/usr/local/cuda-11.0/bin export CUDA_HOME=$CUDA_HOME:/usr/local/cuda-11.0 source ~/.bashrc make CUDA_PATH=/usr/local/cuda-11.0 DEBUG=1 python3 launch-backend.py ../bin/gem-schd ../bin/gem-pmgr --ip 127.0.0.1 --port 50051 --config ../resource-config.txt python3 launch-command.py --name client1 --port 50052 --ip 127.0.0.1 "/root/test"目前实际拦截的 cuda API 有:
cuLaunchCooperativeKernel
cuLaunchKernel
cuMipmappedArrayDestroy
cuMipmappedArrayCreate
cuArrayDestroy
cuArray3DCreate_v2
cuArrayCreate_v2
cuMemcpyDtoHAsync_v2
cuMemcpyDtoH_v2
cuMemcpyHtoD_v2
- 等等
要测试的是:
注释掉 cudaEventCreate:
可以跑起来了!
客户端:
host 端:
检查是否能够正确 prehook 和 posthook:在处理代码中增加调试输出信息,一旦真的进入这些函数,就会有相应的输出:
可以进入到 prehook 和 posthook 代码
未解决
另外,注意到输出的调试信息中,有一个 ERROR:
是在代码:
1 2 CUdevice device; CUresult rc = cuCtxGetDevice(&device);返回值 rc 为 201,代表
CUDA_ERROR_INVALID_CONTEXT
。这意味着尝试在无效或未初始化的 CUDA 上下文中执行操作。具体来说,cuCtxGetDevice(&device)
调用返回此错误,表明当前没有有效的 CUDA 上下文可供使用。单独拿出来运行也会:
似乎是因为没有显式的 CUDA 上下文,在测试代码中,先创建上下文,然后运行
cuCtxGetDevice(&device)
就不会报错尝试修改 hook.cpp,在初始化时创建上下文。
但是 cuCtxCreate 也会被拦截。运行起来卡在了 cuCtxCreate,所以是不是死锁了。
注释掉,只保留 cuInit,但还是有
E/ failed to get current device: 201
TODO
同时在两个 client 运行有大量计算需求的 cuda 代码,看是否真的限制住了。
前提是学习 profiling 工具