如何调试Sycl运行时编译出现的段错误(segfault)问题?
SYCL运行时编译段错误的调试方法与问题排查
我有一个最小化SYCL程序,在运行时编译阶段触发段错误(segfault)。已经完成最小化案例的制作,核心想了解这类问题的调试方法,以及如何判断是编译器Bug还是代码Bug。正常情况下运行时编译失败应抛出异常,而非直接崩溃,希望能通过获取DPCPP运行时信息进一步简化案例。
重现细节
代码
#include <CL/sycl/queue.hpp> #include <CL/sycl/device.hpp> #include <CL/sycl/context.hpp> #include <CL/sycl.hpp> #include <iostream> namespace { auto is_sign_same(sycl::short3 idx1, sycl::short3 idx2) { return (idx1 < 0) == (idx2 < 0); } } // namespace int main() { sycl::device device = sycl::device{sycl::gpu_selector{}}; std::cout << "\n\nRunning occupancy grid profile. The profile will have the following " "properties:\n\n Device:\t" << device.get_info<sycl::info::device::name>() << "\n\n"; sycl::context context{device}; sycl::property_list properties{sycl::property::queue::enable_profiling()}; sycl::queue queue{device, properties}; auto event = queue.submit( [](sycl::handler& cgh) { // 1. 必须捕获该变量才会崩溃,若移到内核内定义则不会失败 sycl::id<3> robot_index{0, 0, 0}; sycl::stream out(1024, 256, cgh); cgh.parallel_for( sycl::range<3>{4, 4, 4}, [out, robot_index](sycl::id<3> id) { sycl::short3 new_signed_idx{short(0)}; // 2. 不能移除两个sycl::short3的减法操作,否则不会失败 sycl::short3 old_signed_idx = sycl::short3{ (short)id.get(0), (short)id.get(1), (short)id.get(2)} - sycl::short3{ (short)robot_index.get(0), (short)robot_index.get(1), (short)robot_index.get(2)}; // 3. 不能将该函数调用替换为内联操作,否则不会失败 auto s_same = is_sign_same(new_signed_idx, old_signed_idx); out << s_same; } ); } ); return 0; }
编译命令
/opt/intel/oneapi/compiler/2022.1.0/linux/bin/dpcpp -fclang-abi-compat=7 -fsycl --gcc-toolchain=/usr -sycl-std=2020 -fp-model=precise -Wall -Werror -fsycl -O2 -g -DNDEBUG -std=gnu++17 sgfaulting_file.cpp
栈跟踪信息
程序运行触发段错误,通过GDB获取的栈跟踪如下:
(gdb) where #0 0x00007f49e3683b8c in ?? () from /usr/lib/x86_64-linux-gnu/libigc.so.1 #1 0x00007f49e36b440c in ?? () from /usr/lib/x86_64-linux-gnu/libigc.so.1 #2 0x00007f49e36b0dda in ?? () from /usr/lib/x86_64-linux-gnu/libigc.so.1 #3 0x00007f49e36b430f in ?? () from /usr/lib/x86_64-linux-gnu/libigc.so.1 #4 0x00007f49e36bac6a in ?? () from /usr/lib/x86_64-linux-gnu/libigc.so.1 #5 0x00007f49e36b0bed in ?? () from /usr/lib/x86_64-linux-gnu/libigc.so.1 #6 0x00007f49e36b430f in ?? () from /usr/lib/x86_64-linux-gnu/libigc.so.1 #7 0x00007f49e36bac6a in ?? () from /usr/lib/x86_64-linux-gnu/libigc.so.1 #8 0x00007f49e36bf027 in ?? () from /usr/lib/x86_64-linux-gnu/libigc.so.1 #9 0x00007f49e36bf908 in ?? () from /usr/lib/x86_64-linux-gnu/libigc.so.1 #10 0x00007f49e35ab7bc in ?? () from /usr/lib/x86_64-linux-gnu/libigc.so.1 #11 0x00007f49e35abfba in ?? () from /usr/lib/x86_64-linux-gnu/libigc.so.1 #12 0x00007f49e35ae90d in ?? () from /usr/lib/x86_64-linux-gnu/libigc.so.1 #13 0x00007f49e36ec3d4 in ?? () from /usr/lib/x86_64-linux-gnu/libigc.so.1 #14 0x00007f49e35b21fb in ?? () from /usr/lib/x86_64-linux-gnu/libigc.so.1 #15 0x00007f49e36ced9a in ?? () from /usr/lib/x86_64-linux-gnu/libigc.so.1 #16 0x00007f49f487f1bb in ?? () from /usr/lib/x86_64-linux-gnu/intel-opencl/libigdrcl.so #17 0x00007f49f43ef178 in ?? () from /usr/lib/x86_64-linux-gnu/intel-opencl/libigdrcl.so #18 0x00007f49f4397b33 in ?? () from /usr/lib/x86_64-linux-gnu/intel-opencl/libigdrcl.so #19 0x00007f49f9327aa4 in cl::sycl::detail::ProgramManager::build(...) () from /opt/intel/oneapi/compiler/2022.1.0/linux/lib/libsycl.so.5 #20 0x00007f49f9321336 in cl::sycl::detail::ProgramManager::getBuiltPIProgram(...) () from /opt/intel/oneapi/compiler/2022.1.0/linux/lib/libsycl.so.5 #21 0x00007f49f932243c in cl::sycl::detail::ProgramManager::getOrCreateKernel(...) () from /opt/intel/oneapi/compiler/2022.1.0/linux/lib/libsycl.so.5 #22 0x00007f49f93630f1 in cl::sycl::detail::enqueueImpKernel(...) () from /opt/intel/oneapi/compiler/2022.1.0/linux/lib/libsycl.so.5 #23 0x00007f49f9369f3b in cl::sycl::detail::ExecCGCommand::enqueueImp() () from /opt/intel/oneapi/compiler/2022.1.0/linux/lib/libsycl.so.5 #24 0x00007f49f93566c5 in cl::sycl::detail::Command::enqueue(...) () from /opt/intel/oneapi/compiler/2022.1.0/linux/lib/libsycl.so.5 #25 0x00007f49f9373b7b in cl::sycl::detail::Scheduler::addCG(...) () from /opt/intel/oneapi/compiler/2022.1.0/linux/lib/libsycl.so.5 #26 0x00007f49f93aef30 in cl::sycl::handler::finalize() () from /opt/intel/oneapi/compiler/2022.1.0/linux/lib/libsycl.so.5 #27 0x00007f49f93dc3ea in cl::sycl::detail::queue_impl::finalizeHandler(...) () from /opt/intel/oneapi/compiler/2022.1.0/linux/lib/libsycl.so.5 #28 0x00007f49f93dc13b in cl::sycl::detail::queue_impl::submit_impl(...) () from /opt/intel/oneapi/compiler/2022.1.0/linux/lib/libsycl.so.5 #29 0x00007f49f93db744 in cl::sycl::detail::queue_impl::submit(...) () from /opt/intel/oneapi/compiler/2022.1.0/linux/lib/libsycl.so.5 #30 0x00007f49f93db715 in cl::sycl::queue::submit_impl(...) () from /opt/intel/oneapi/compiler/2022.1.0/linux/lib/libsycl.so.5 #31 0x00000000004026d8 in cl::sycl::queue::submit<main::{lambda(cl::sycl::handler&)#1}>(...) at /opt/intel/oneapi/compiler/2022.1.0/linux/bin-llvm/../include/sycl/CL/sycl/queue.hpp:275 #32 main () at occupancy_grid_point_cloud_creation.cpp:31
关键栈帧:
cl::sycl::detail::ProgramManager::build
设备信息
sycl-ls输出:
[opencl:gpu:2] Intel(R) OpenCL HD Graphics, Intel(R) UHD Graphics [0x9bc4] 3.0 [22.28.23726.1]
注:使用host或cpu selector运行程序时可正常构建并执行;修改程序的细微细节(代码注释中已说明)也可避免段错误。
调试与排查步骤
1. 开启运行时调试日志
设置环境变量获取编译过程的详细信息,定位崩溃环节:
export SYCL_PI_TRACE=2:输出PI层(Plugin Interface)的调用日志,查看程序构建、内核创建的每一步export IGC_DEBUG=1:开启Intel Graphics Compiler(IGC)调试日志,栈跟踪显示崩溃在libigc.so,该变量能输出编译器内部错误信息export SYCL_DEBUG=1:开启SYCL运行时调试输出,捕获异常与状态变化
2. 验证代码的SYCL合规性
- 向量操作检查:
sycl::short3的<运算符返回bool3(逐元素比较结果),直接用==比较两个bool3是否符合预期?当前is_sign_same返回的是bool3,而sycl::stream对向量布尔值的输出是否存在未定义行为?可尝试修改为return all((idx1 < 0) == (idx2 < 0));(返回单布尔值),看是否还会崩溃 - 检查变量捕获与生命周期:确认
robot_index作为捕获变量的生命周期是否符合SYCL要求
3. 隔离版本与编译配置问题
- 升级编译器:你的DPC++版本为2022.1.0,属于较旧版本,升级到最新oneAPI版本大概率能修复已知编译器Bug
- 调整优化等级:去掉
-O2,用-O0编译,排查是否为优化阶段触发的Bug - 尝试AOT编译:添加
-fsycl-targets=spir64_gen(针对Intel GPU)进行提前编译,将运行时崩溃转为编译期错误,更易定位
4. 进一步缩小崩溃案例
根据已有的观察(注释中的三个触发条件),逐步简化代码:
- 移除
sycl::stream,看崩溃是否消失 - 内联
is_sign_same函数实现,对比差异 - 修改
short3减法操作的写法,定位触发崩溃的最小代码单元
5. 判断Bug类型
- 若仅GPU设备崩溃,Host/CPU正常,大概率是编译器/设备运行时Bug(如IGC对GPU向量操作的处理错误)
- 若修改代码合规性后崩溃消失,说明代码存在未定义行为或不符合SYCL标准的写法
- 升级编译器后崩溃消失,说明是旧版本编译器Bug
临时规避方案
根据代码注释中的观察,可通过以下方式绕过崩溃:
- 将
robot_index移到内核内部定义 - 内联
is_sign_same函数的实现 - 修改
short3减法操作的写法
内容的提问来源于stack exchange,提问作者Fantastic Mr Fox
相关产品推荐
相关产品推荐

