当前位置: 首页 > 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.jsqmd.com/news/849115/

相关文章:

  • GIS技巧100例23-ArcGIS像元统计实战:从月度栅格到年度气候指标
  • 别再为Keil 5报错头疼了!STM32F401CCU6固件库移植保姆级避坑指南(V1.8.0)
  • AI产品经理入门实战:如何理解意图识别?
  • AArch64架构Watchpoint机制详解与调试实践
  • 如何3步掌握Path of Building物品制作:终极实战指南
  • 通过Taotoken用量看板分析团队大模型API消耗模式与优化点
  • 2026年选对工作钢格板厂家,这三大核心标准决定你的采购成败
  • 【RuoYi】数据分页功能分析 —— 以登录日志页面为例
  • 【原创】智询管理系统操作说明
  • Spring Boot 3.0升级踩坑记:手把手教你解决 ‘javax.servlet.http不存在‘ 的报错
  • 技术动态 | 大模型驱动情报领域知识图谱构建新范式:ERC-KG方法精确率高达94.32% - 解放军网络空间部队信工大等
  • 无人机精准着陆:NMPC-CBF技术实现厘米级控制
  • 023、无传感器位置估计基础
  • 大模型微调实战:用LoRA技术微调LLaMA 2模型
  • 别硬熬本科论文!paperxie 智能写作,把 4 步流程焊死在你的效率里
  • 告别Meson和CMake:手把手教你用老式configure交叉编译GLib 2.46.2(附arm-linux.cache模板)
  • 5分钟终极指南:用m4s-converter永久保存你的B站缓存视频
  • 2026年平台踩踏钢格板厂家推荐,这5家靠谱又耐用
  • EPnP算法中的‘控制点’到底是什么?一个类比带你轻松理解SLAM中的坐标变换核心
  • 传统后端程序员必看:3-6个月转型高薪AI应用开发
  • 跳出无效熬夜怪圈:paperxie 用四步闭环,重构本科毕业论文写作逻辑
  • JetBrains IDE试用期重置终极指南:三步实现无限期使用
  • IDEA插件EasyYapi实战:如何为Dubbo/Feign等RPC接口自动生成API文档?
  • 桌面音乐可视化革命:Lano Visualizer如何让你的音乐“看得见“
  • 套了层AI皮,就敢叫AI原生?
  • 【Android车载学习笔记】第三天:AAOS发展历
  • 从零实现倒排索引召回:一个轻量级推荐系统的核心引擎
  • Redis分布式锁进阶第一十二篇拆解
  • 如何一键自动化部署Office:LKY Office Tools完整配置指南
  • 基于SpringBoot的搬家货车预约系统毕业设计源码