孔杰 山东科技大学计算机学院CogTwins Lab(Cognitive Industrial Digital Twins Lab | Official web of Cognitive Industrial Digital Twins Lab team)
在高性能计算 (HPC) 环境下,我们经常需要结合 CPU 和 GPU 等多种硬件加速器协同工作。以下分享对于ONNX Runtime 在推理时出现线程亲和性设置错误的实际问题及解决思路:在讲解过程中,我们会介绍相关技术背景(如线程亲和性、ROCm、LD_LIBRARY_PATH
等),帮助初学者理解整个排查流程。
线程亲和性设置失败
在进行模型推理时,出现如下错误日志:
2023-05-18 08:24:58.694 [E:onnxruntime:Default, env.cc:251]
pthread_setaffinity_np failed for thread: 531, index: 6, mask: {7, 39, },
error code: 22 error msg: Invalid argument. Specify the number of threads explicitly so the affinity is not set.
线程亲和性是什么?
线程亲和性(Thread Affinity)是指将线程绑定到特定 CPU 核上运行,以尽量让线程在同一个或同一组处理器核上执行,从而提高缓存利用率和性能。例如,Linux 默认会让线程倾向于“绑”在上次运行过的 CPU 核上,以减少缓存丢失。但是有时应用需要手动绑定线程到指定核上,这就称为“硬”亲和性。在此错误中,ONNX Runtime 在后台尝试为每个线程绑定亲和性时失败了。
错误原因分析
错误信息中提示 Invalid argument. Specify the number of threads explicitly so the affinity is not set.,意思是未显式指定线程数,导致尝试设置亲和性时出错。一旦我们没有显式设置线程数量,ONNX Runtime 默认会为每个物理核心创建线程池并设置亲和性。如果某些 CPU 核不可用或参数不符,就会触发 pthread_setaffinity_np 返回 22(无效参数)。简单来说,这是 ONNX Runtime 在多核系统中自动分配线程发生的一个提示:告诉我们应该手动指定线程数,避免自动亲和性设置。
解决方案
可以通过显式设置线程数来避免亲和性问题,具体有以下几种方法:
-
在代码中指定线程数:创建
SessionOptions
时,设置inter_op_num_threads
(操作之间并行线程)和intra_op_num_threads
(单次操作内部并行线程)为合适的值。显式设置线程总数后,ONNX Runtime 将不再自动设置亲和性。例如,如果机器上有 4 个核,可以这样设置:import onnxruntime as ort sess_opts = ort.SessionOptions() sess_opts.inter_op_num_threads = 4 # 操作之间并行线程数 sess_opts.intra_op_num_threads = 4 # 操作内部并行线程数 session = ort.InferenceSession('model.onnx', sess_opts) # 显式设置后,错误提示会消失,并且性能在合理使用核数时能得到保证。
-
设置环境变量:可以通过设置 OpenMP 环境变量
OMP_NUM_THREADS
来影响线程数(ONNX Runtime 会参考该变量)。例如,在 Linux 环境下:# 设置 OMP_NUM_THREADS 环境变量 export OMP_NUM_THREADS=4
-
调整容器配置:在本次问题中,我们在重建容器时显式指定使用4 张异构加速卡(例如 4 张不同型号的 GPU)并设置相应的线程数,使得推理时每个加速卡对应的线程数明确,避免了自动亲和性设置引发的问题。
通过上述方法显式指定线程数量后,再次运行推理脚本,线程亲和性错误即解决。需要注意的是,这个错误本身并不一定会导致推理失败(通常只是警告),但为了日志清晰和预防潜在性能问题,建议按照以上方法明确线程数。
总结
-
线程亲和性(CPU 亲和性)是将线程绑定到特定 CPU 核的机制,有助于提高缓存命中率。如果 ONNX Runtime 报错线程亲和性失败(error code 22),通常只需显式指定线程数(如设置
intra_op_num_threads
/inter_op_num_threads
或OMP_NUM_THREADS
),这样就不会自动设置亲和性。 -
在 HPC 开发中,遇到报错要先看日志、定位根因:对照错误信息中的关键字(如
affinity
、Segmentation fault
),结合系统环境(多核配置、GPU 驱动等)分析原因,并尝试调整环境变量或程序配置来解决。以上经验可供其他初学者参考和借鉴。