当前位置: 首页 > news >正文

Gdev 至 Rust 移植工程(七)

从 C 到 Rust:GDEV GPU 运行时移植纪实

在 QEMU 环境中进行测试

背景

前四阶段的翻译工作已全部完成(31 文件,10,300 行 Rust,196 个纯软件测试通过),并在开发机上成功编译出libgdev_layer4.so。但开发机(glibc 2.33+)与目标 QEMU 环境(CentOS 7,glibc 2.17)的 ABI 差异在第一次部署时暴露了一系列链接与运行时错误,在此期间由于测试环境不方便,我将模拟器放到了本机上,整理方便agent能理解的仅用于编译测试的环境用的时间比较多,目前是nfs挂载源码到qemu上实现同步改动,然后qemu上进行编译环境和测试题并测试,最后让agent理解该测试流程之后开始正式调试launch。


glibc 版本

将开发机上编译的.so替换进 QEMU 后,编译 C 测试程序时立即报错:

undefined reference to`fstat64@GLIBC_2.33' undefined reference to`pthread_key_create@GLIBC_2.34'

原因是 Rust 标准库在编译时锁定了宿主 glibc 的高版本符号。尝试用.symver汇编技巧创建兼容库libglibc_compat.so虽然在链接阶段通过了,但运行时动态链接器ld.so直接拒绝加载—— ELF 头部DT_VERNEED字段明确要求GLIBC_2.34,版本检查失败,进程直接终止。

最终解:在 QEMU 虚拟机(CentOS 7)内安装 Rust 1.72,将整个gdev-rust工程上传,本地cargo build --release。产出的.so天然链接 glibc 2.17,彻底消除了所有版本兼容问题。


设备计数

编译通过后运行./user_test立刻段错误:

[root@qemu-ai-ep launch2]# ./user_testsize=0x10000, dev_num=0fil[1013.290821]user_test[1741]: segfault at 7ffdf92ff000ip00007f15e0165c9b sp 00007ffdf92fe578 error 4e size=211762inlibc-2.17.so[7f15e00d1000+1c3000]dev count0--- -----cubin=0x7f15e110a010------- Segmentation fault

QEMU 里明明有四个 aicard 设备节点(/dev/aicard0~aicard3),但sdInit()内部调用gdev_count()始终返回 0。

根因:原翻译的gdev_count()只统计了“已调用gopen()的槽位”,而系统启动时还没有任何进程打开设备,槽位全空,自然返回 0。

修复:将gdev_count()的实现改为用stat()系统调用直接探测/dev/aicard0aicard1等设备文件是否存在。与原始 C 代码中gdev_getinfo_device_count()的行为保持一致。改动仅一行逻辑,dev count立刻正确输出 4。

[root@qemu-ai-ep launch2]# ./user_test -s 0x10000 -d 0size=0x10000, dev_num=0filesize=211762dev count4--------cubin=0x7f915e5c2010-------

缺少设备句柄导致内存分配失败

设备计数正确后,接着报错:

Sdaa runtime errorinline104offilelaunch.c:sdaaErrorOutOfMemory

错误链:sdaaMallocsd_mem_allocsd_ctx_get_current()找不到上下文 → 句柄为 0 →gmalloc(0, size)必然失败。

根因enumerate_devices()只做了设备计数(stat),但从没有调用gopen()真正打开设备并获取内核句柄。没有句柄,任何内存分配都无法和内核通信。

短期方案:为加快调试节奏,暂时采用纯软件模拟——实现一个软件后备路径,将设备内存操作全部重定向到 Rust 的HashMap<u64, Vec<u8>>中。

这样一来,所有memcpy HtoD/DtoH/DtoD都在软件层完成,launch也直接在 CPU 上解析参数块并执行向量加法。

测试结果:

[root@qemu-ai-ep launch2]# ./user_testsize=0x10000, dev_num=0filesize=211762[DEBUG]enumerate_devices: entering[DEBUG]enumerate_devices: calling sd_init(0)[DEBUG]enumerate_devices: rawcount=4[DEBUG]enumerate_devices:minor=0gopen→handle=0x1[DEBUG]enumerate_devices:minor=1gopen→handle=0x2[DEBUG]enumerate_devices:minor=2gopen→handle=0x3[DEBUG]enumerate_devices:minor=3gopen→handle=0x4[DEBUG]enumerate_devices: opened4handles[DEBUG]enumerate_devices: sd_ctx_create(0,0)11[DEBUG]enumerate_devices: done,count=4dev count4--------cubin=0x7f2934e2c010-------[DEBUG]register_fat_binary:ptr=0x7ffd06c389e0name=unnamed[DEBUG]register_fat_binary: about to lock_runtime[DEBUG]register_fat_binary: locked[DEBUG]register_fat_binary: handleassigned=0[DEBUG]register_fat_binary: about toread4096bytes from ptr[DEBUG]register_fat_binary:cubin_data.len=4096[DEBUG]register_fat_binary:handle=0x0[DEBUG]register_function:handle=0x0name=add_test[DEBUG]register_function: registered,kernels.len=1[DEBUG]malloc:size=0x10000,device_count=4,handles.len=4[DEBUG]malloc: usinghandle=0x1[DEBUG]malloc: gmalloc→addr=0x61000100c000[DEBUG]malloc:size=0x10000,device_count=4,handles.len=4[DEBUG]malloc: usinghandle=0x1[DEBUG]malloc: gmalloc→addr=0x61000101c000[DEBUG]malloc:size=0x10000,device_count=4,handles.len=4[DEBUG]malloc: usinghandle=0x1[DEBUG]malloc: gmalloc→addr=0x61000102c000[DEBUG]memcpy:dst=0x61000100c000src=0x2517010count=65536kind=HostToDevice[DEBUG]memcpy: usinghandle=0x1[DEBUG]memcpy:ok=true[DEBUG]memcpy:dst=0x61000101c000src=0x2527020count=65536kind=HostToDevice[DEBUG]memcpy: usinghandle=0x1[DEBUG]memcpy:ok=true[DEBUG]launch:entry=add_test[DEBUG]launch:kernel_registered=true[DEBUG]launch:handle=0x1param_size=32[DEBUG]launch: glaunch→ok=truekid=0[DEBUG]launch SW:A=0x61000100c000B=0x61000101c000C=0x61000102c000n=16384[DEBUG]launch SW: wrote65536bytes toC=0x61000102c000 launch_sync time:0.292000[DEBUG]memcpy:dst=0x2537030src=0x61000102c000count=65536kind=DeviceToHost[DEBUG]memcpy: usinghandle=0x1[DEBUG]memcpy:ok=true[DEBUG]free:ptr=0x61000102c000[DEBUG]free: gfree→Ok(65536)[DEBUG]free:ptr=0x61000101c000[DEBUG]free: gfree→Ok(65536)[DEBUG]free:ptr=0x61000100c000[DEBUG]free: gfree→Ok(65536)Test passed: size=0x10000, dev_num=0

全链路在无硬件的纯软件模拟下跑通——证明四层翻译的调度、内存管理、参数打包、错误传播逻辑都是正确的。


未完成的工作

软件测试虽然通过,但数据根本没有进入 aicard 硬件。真正驱动 GPU 需要将 C 源码gdev_aidev.c(297 行)中的 19 个硬件后端函数翻译为 Rust 并注册到GdevCompute的函数指针表里。

同时,部分对外 API 在翻译中为了快速闭环被临时设为 stub(返回“未实现”)。现将未完成部分统计如下:

1. 公开 API 层的 stub(16 个)

这些函数在外部调用时会得到SDAA_ERROR_NOT_YET_IMPLEMENTED,不影响核心 launch/memcpy 流程:

#所属阶段函数原因
1-3Layer2gipc_get_mem_handle, gipc_open_mem_handle, gipc_close_mem_handle跨进程共享内存
4Layer3sd_func_get_attributeC 代码原就是 weak stub
5-7Layer4device_synchronize, thread_synchronize, set_device_limit全局同步 / 平台特定
8-9Layer4host_register, host_unregistermmap 固定页
10-12Layer4ipc_get/open/close_mem_handle跨进程句柄
13Layer4print_info设备 print buffer
14-16Layer4trans_encode, trans_decode, transformerTransformer 推理

占比:365 个总 API 函数中,16 个 stub(4.4%),全部位于非核心路径。

2. GdevCompute 函数指针(11 个未实现)

这 19 个函数指针是“硬件会话”的真正执行者。每次glaunchgmemcpy最终都要通过它们操作 ring buffer 和 ioctl。目前状态:

状态函数说明
✅ 已实现 (8)launch, fence_read, fence_write, fence_reset, memcpy, memcpy_async, init, load核心启动、DMA、fence
❌ 未实现 (11)event_read, event_read_timestamp, event_write, event_reset, swait_event, printbuffer, transencode, transdecode, transformer, membar, notify_intr, memset事件、调试、Transformer 等

已实现的 8 个覆盖了最小可用集(launch + memcpy + fence 同步),但要完整运行 QEMU 中的 C 测试样例还需要补全事件(event)相关的 5 个函数,目前这8个还有待考证,需要在qemu环境下进一步测试。


http://www.zskr.cn/news/1325502.html

相关文章:

  • Arduino入门教程五|串口通信详解(3个实验+if条件判断,保姆级入门)
  • 2026年选对工作钢格板厂家,这三大核心标准决定你的采购成败
  • Google Cloud Dataflow 背后的流式处理模型
  • 5分钟搞定!NewGAN-Manager终极配置指南:让Football Manager游戏体验焕然一新
  • 堆叠集成方法
  • 离谱!上海交大一学生私吞 5000 奖金,还用豆包 P 假收据骗队友。网友:学历虽高但人品太低
  • AI浪潮下:程序员的挑战、应对与未来出路
  • 无人机精准着陆:NMPC-CBF技术实现厘米级控制
  • 当STM32内存不够用:手把手教你用FSMC扩展1MB外部SRAM做数据缓存(附性能测试对比)
  • 别硬熬本科论文!paperxie 智能写作,把 4 步流程焊死在你的效率里
  • 【最新源码】在线学习交流平台c116
  • EPnP算法中的‘控制点’到底是什么?一个类比带你轻松理解SLAM中的坐标变换核心
  • Perplexity酒店搜索API调用失败率骤增47%?我们逆向拆解了其最新Query Rewrite引擎(含12个避坑checklist)
  • 从回调函数本质理解CAPL的on事件:一个老司机的调试视角与高效用法
  • Tabbit:美团Tabbit AI浏览器实测:从“看网页”到“替我干活”
  • 基于SpringBoot的搬家货车预约系统毕业设计源码
  • 024、反电动势法位置估计
  • 零基础学网安先来看这个,能帮你少走很多弯路!
  • 做工业视觉别只会YOLOv10!工程师必备OpenCV核心实战能力全解
  • 保姆级教程:用MTK Client工具备份你的小度音响/车机系统分区(附驱动安装与端口进入技巧)
  • c++11的初见
  • 聚焦经营分析核心指标,构建闭环体系,《经营分析指标体系指南》:是什么、怎么做 、案例、经营分析指标清单及关键路径····
  • LinkSwift网盘直链助手:让你的下载体验更简单高效
  • 《龙虾OpenClaw系列:从嵌入式裸机到芯片级系统深度实战60课》060、未来趋势与芯片设计者的思考
  • XUnity.AutoTranslator终极指南:让外语Unity游戏瞬间变中文的免费神器
  • 从滑动变阻器到真实传感器:STM32CubeMX ADC单通道采集光照/温度实战(附校准技巧)
  • 挑选专业语音工具不会选?这5个实用标准帮到你
  • 大模型微调实战:用LoRA技术微调LLaMA 2模型
  • 【RuoYi】数据分页功能分析 —— 以登录日志页面为例
  • GIS技巧100例23-ArcGIS像元统计实战:从月度栅格到年度气候指标