CANN Runtime EE1021 资源创建失败(Resource_Error)错误码排查指南
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
导读
EE1021 是 CANN Runtime 在主机(Host)侧创建信号量、线程等系统资源失败时上报的错误码,属于 RTS(Runtime System)错误类别下的资源类错误(Resource_Error)。本文从错误码定义、上报格式、触发源码路径到排查方法逐层展开,帮助开发者在遇到The runtime module failed to create host ... through API ...报错时,快速定位资源瓶颈并完成恢复。
错误码基本信息
EE1021 在 error_code.json 中登记为:
{ "errClass": "RTS Errors", "errTitle": "Resource_Error", "ErrCode": "EE1021", "ErrMessage": "The runtime module failed to create host %s through API %s.", "Arglist": "resource_type, api", "suggestion": { "Possible Cause": "Failed to create resources such as semaphores, locks, or threads due to insufficient system resources.", "Solution": "Stop unnecessary threads and ensure that the required resource is available." } }该错误码在 error_code_meta.h 中对应的宏定义为:
/* EE1021 - Resource_Error */ X(EE1021, "EE1021", ("resource_type", "api"), "The runtime module failed to create host %s through API %s. ErrorCode=EE1021.\n", DLOG_ERROR)可以看到 EE1021 携带两个动态参数resource_type(资源类型)和api(失败接口名),并按DLOG_ERROR级别记录日志。日志级别可通过环境变量ASCEND_GLOBAL_LOG_LEVEL控制,相关说明见 env_vars 目录。
错误信息格式解析
文档给出的报错格式如下:
The runtime module failed to create host %s through API %s.其中占位符含义为:
| 占位符 | 含义 | 典型取值 |
|---|---|---|
%s(第一个) | 资源类型(resource_type) | semaphore(信号量)、thread(线程)、lock(锁)等主机侧资源 |
%s(第二个) | 失败的标准接口名(api) | sem_init、pthread_create、pthread_setname_np、pthread_join等 |
值得说明的是,在真实的 Runtime 日志输出中,报错文本后还会附带错误码后缀,完整输出形如The runtime module failed to create host semaphore through API sem_init. ErrorCode=EE1021.,便于日志检索时直接用EE1021关键字过滤。日志文件的位置与生成方式可参考 log_ref 目录。
报错示例解读
文档给出的典型报错示例如下:
The runtime module failed to create host semaphore through API sem_init.这条报错对应 Runtime 内部调用sem_init(实际封装为mmSemInit)初始化信号量失败。结合源码可以还原出真实的触发链路:
- direct_hwts_engine.cc 中,HWTS 引擎创建回收线程(Recycle Thread)时执行
mmSemInit(&recycleThreadSem_, 0U),失败后上报:
const rtError_t error = mmSemInit(&recycleThreadSem_, 0U); if (error != RT_ERROR_NONE) { DELETE_O(recycleThread_); RT_LOG_OUTER_MSG_IMPL(ErrorCode::EE1021, "semaphore", "sem_init"); return RT_ERROR_MEMORY_ALLOCATION; }- stars_engine.cc 中,Stars 引擎在
CreateRecycleThread中存在完全相同的信号量初始化失败处理逻辑,同样上报EE1021, "semaphore", "sem_init"。
这两个引擎都是 Runtime 维护任务回收与线程生命周期的核心组件,说明该错误码出现的位置集中在 Runtime 初始化阶段的后台线程/信号量装配路径上。
可能原因
按照文档与 error_code.json 中suggestion字段的说明,EE1021 的根本原因是系统资源不足导致 Runtime 无法创建信号量、锁或线程等主机侧资源。从源码调用点归纳,常见诱因包括:
- 进程/线程数量达到系统上限:
pthread_create失败时,通常是进程内线程数达到RLIMIT_NPROC限制,或内核threads-max已达上限。 - 信号量资源耗尽:
sem_init返回失败,可能是内核信号量队列或 POSIX 信号量相关资源不足。 - 内存不足:创建线程需要分配线程栈,内存耗尽时
pthread_create也会失败。 - 线程命名失败:
pthread_setname_np失败虽然不致命(Runtime 仅记录日志后继续),但也会以 EE1021 形式暴露,提示系统或平台对线程名长度等存在限制。
典型触发场景与源码佐证
场景一:线程创建失败(pthread_create)
在 osal.cc 的LocalThread::Start中,Runtime 创建本地线程时先以默认栈大小尝试,失败后会循环增大栈大小重试,重试仍失败则上报 EE1021:
for (uint32_t i = 0U; i < PTHREAD_STACK_SIZE_EXT_MAX_TIME; i++) { error = mmCreateTaskWithThreadAttr(&interThread_, &userBlock_, &threadAttr); if (error == EN_OK) { ... return EN_OK; } threadAttr.stackSize += PTHREAD_STACK_SIZE; } RT_LOG_OUTER_MSG_IMPL(ErrorCode::EE1021, "thread", "pthread_create"); return error;线程栈大小优先取自设备属性中的pthreadStackSize,未配置时使用系统默认栈(见同文件GetThreadStackSize),这一逻辑说明线程栈分配对系统内存有一定需求。
场景二:线程设置名称失败(pthread_setname_np)
在线程入口函数LocalThread::ThreadProc中,Runtime 调用mmSetThreadName为线程命名,失败时记录:
const int32_t ret = mmSetThreadName(RtPtrToPtr<mmThread*>(&threadHandle), self->name_); if (ret != EN_OK) { RT_LOG_OUTER_MSG_IMPL(ErrorCode::EE1021, "thread", "pthread_setname_np"); }场景三:线程回收失败(pthread_join)
在LocalThread::Join与进程退出路径ThreadGuard::ThreadExit中,mmJoinTask失败也会上报EE1021, "thread", "pthread_join"(osal.cc)。这类失败通常发生在资源紧张导致线程无法正常退出的情况下。
测试用例佐证
单元测试中有专门模拟sem_init失败的用例,例如 aicpu_cust_work_test.cc 中的CreateWorkTest_sem_init_fail:
TEST_F(AICPUCusWorkerTEST, CreateWorkTest_sem_init_fail) { MOCKER(sem_init).stubs().will(returnValue(-1)); ... }该用例通过 mock 使sem_init返回 -1 来验证资源创建失败时的错误处理路径,与 EE1021 的触发条件完全对应,可用于理解失败分支的行为。
错误上报机制简述
EE1021 最终通过RT_LOG_OUTER_MSG_IMPL宏进入日志链路,宏定义位于 base.hpp,其可展开形态将错误码、参数与标准库调用失败信息组合后输出到 Runtime 日志。ErrorCode::EE1021枚举在 rt_log.h 中定义,保证错误码在整个 Runtime 内部以编译期常量形式引用。
排查步骤
当程序运行日志中出现EE1021且伴随sem_init、pthread_create等接口名时,建议按以下顺序排查:
- 确认错误上下文:在 Runtime 日志中检索
EE1021关键字,确认报错时resource_type与api的具体取值,判断是信号量创建失败还是线程创建失败。 - 检查进程线程数限制:
- 查看用户进程/线程上限:
ulimit -u; - 查看内核线程上限:
cat /proc/sys/kernel/threads-max; - 统计当前进程线程数:
ps -eLf | grep <进程名> | wc -l或ps -o nlwp -p <pid>。
- 查看用户进程/线程上限:
- 检查系统内存:使用
free -g观察可用内存是否充足,重点确认是否存在内存泄漏或大页占用导致线程栈分配失败。 - 检查信号量相关资源:若报错为
sem_init,可结合ipcs -s观察系统中信号量数量是否接近内核限制。 - 减少无关负载后复现:停止同一主机上其他不必要的线程密集型进程,缩小问题范围,确认是否为多进程并发触发资源争抢。
解决方法与预防建议
针对文档给出的官方建议"停止不必要的线程,并确保所需资源可用",结合实践可细化为:
- 释放或关闭无关进程:结束同一机器上不再使用的后台进程与服务,为 Runtime 腾出线程和内存配额。
- 调整线程/进程资源限制:在确认业务安全的前提下,通过
ulimit -u提高用户进程上限,或在系统配置中调大kernel.threads-max。 - 优化应用自身并发模型:多进程场景下控制进程数,避免每个进程都初始化独立 Runtime 实例,减少同时创建的后台线程总数。
- 评估内存占用:确保主机内存余量足以支撑 Runtime 各引擎线程(回收线程、监控线程、打印线程等)的栈空间分配,必要时释放缓存或扩容。
- 排查线程命名冲突:若报错为
pthread_setname_np,检查平台对线程名长度的限制,并避免使用超长或含特殊字符的线程名。
由于 EE1021 属于主机侧资源类错误,其排查核心始终围绕"线程、信号量、内存三类资源是否达到瓶颈"展开,可结合 Runtime 故障排查 与 日志查看说明 进一步定位。
【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考