CANN Runtime ASCEND_TRACE_RECORD_NUM 详解:Trace 日志目录老化规格的原理与配置实践
2026/9/18 12:01:28 网站建设 项目流程

CANN Runtime ASCEND_TRACE_RECORD_NUM 详解:Trace 日志目录老化规格的原理与配置实践

【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime

本文围绕 CANN Runtime 的环境变量ASCEND_TRACE_RECORD_NUM展开:它用于控制$HOME/ascend/atrace/下 trace 事件子目录的老化(自动清理)规格。读完本文,你将理解该变量的取值范围、默认值与校验规则、trace 目录/文件的命名结构、Host 与 Device 分别计数清理的底层实现,以及如何在生产环境中合理配置该参数以规避磁盘空间耗尽问题。

1. 功能定位:trace 日志为什么需要“老化”

trace 机制是指在程序运行过程中将软件栈的维测信息先记录在内存中,当程序运行出错或进程结束时才落盘到文件,从而避免运行过程中频繁产生和记录日志文件而影响性能(参见 查看trace日志)。需要注意的是,当前仅 Ascend EP 标准形态支持该功能。

trace 日志的落盘根目录默认为$HOME/ascend/atrace/,且该目录是容器或物理机内所有应用程序共同使用的——新应用进程会不断产生新的事件目录,日志会不断增多。若用户不定期清理(例如使用系统自带的 logrotate 实现日志切分),可能导致磁盘空间不足,影响业务正常运行。ASCEND_TRACE_RECORD_NUM正是为此设计的“自动老化”开关:它限制单个 trace 根目录下事件子目录的保留数量,超过上限时由 trace 记录器自动删除时间戳较老的目录。

该环境变量收录于环境变量参考总表 环境变量参考,本文即其 ASCEND_TRACE_RECORD_NUM 文档 的展开。

2. ASCEND_TRACE_RECORD_NUM 配置详解

2.1 功能与取值范围

该变量设置 trace 日志文件的老化规格,取值范围为[10, 1000],具体指以下目录路径下事件子目录的老化规格:

$HOME/ascend/atrace/trace_{进程组pid}_{首次加载trace动态库的进程pid}_{首次加载trace动态库的时间戳}/

其下的子目录形如:

schedule_event_{当前进程pid}_{目录生成时的时间戳}

几个关键语义需要特别注意:

  • Host 侧与 Device 侧分开计数:Host 侧的 trace 日志文件和 Device 侧的 trace 日志文件分开计数,配置后将分别控制 Host 和 Device 的目录数量。也就是说,若配置为 15,则 Host 侧最多保留 15 个事件子目录,Device 侧也各自最多保留 15 个,二者互不挤占额度。
  • 老化对象是“子目录”而非“文件”:超过数量上限后,被删除的是时间戳较老的整个schedule_event_...子目录(目录内的 trace 文件随之删除),而不是单个文件内的滚动截断。
  • 默认值为 10:不设置该环境变量时,老化规格默认为 10 个目录(源码中TRACE_DIR_NUM_DEFAULT 10,见 trace_recorder.c)。

2.2 配置示例

export ASCEND_TRACE_RECORD_NUM=15

表示$HOME/ascend/atrace/trace_{进程组pid}_{首次加载trace动态库的进程pid}_{首次加载trace动态库的时间戳}/下最多生成 15 个名称为schedule_event_{当前进程pid}_{目录生成时的时间戳}的目录。超过该目录数量后,会自动删除时间戳较老的目录。

从源码看,该变量在 trace 动态库初始化阶段被解析:trace_recorder.c 中的TraceInitDirNum函数先读取环境变量(通过环境量索引MM_ENV_ASCEND_TRACE_RECORD_NUM = 4001,定义见 mmpa_env_define.h),然后进行校验:

STATIC void TraceInitDirNum(TraceRecorderMgr* mgr) { mgr->maxDirNum = TRACE_DIR_NUM_DEFAULT; // 默认值 10 const char* env = NULL; MM_SYS_GET_ENV(MM_ENV_ASCEND_TRACE_RECORD_NUM, (env)); if (env == NULL) { ADIAG_INF("doesn't set env ASCEND_TRACE_RECORD_NUM, use default dir num=%d.", mgr->maxDirNum); return; } int32_t value = -1; if ((AdiagStrToInt(env, &value) == TRACE_SUCCESS) && (value <= TRACE_DIR_NUM_MAX) && (value >= TRACE_DIR_NUM_MIN)) { mgr->maxDirNum = value; // 合法值:[10, 1000] } else { ADIAG_WAR("invalid value [%s] for ASCEND_TRACE_RECORD_NUM, expected range: [10, 1000]. Use default dir num=%d.", env, mgr->maxDirNum); // 非法值:告警并回退默认 10 } }

由此可归纳出完整的取值行为表:

| 配置情况 | 行为 | | -- | -- | | 不设置 | 使用默认值 10,并打印doesn't set env ASCEND_TRACE_RECORD_NUM, use default dir num=10.| | 设置为 [10, 1000] 内的整数 | 生效,并打印set dir num=N by env ASCEND_TRACE_RECORD_NUM.| | 设置为空串、非数字、小数、或越界值(如 5、1001) | 打印告警invalid value [...] expected range: [10, 1000],回退为默认值 10,不会导致进程失败 |

这体现了典型的“软失败”设计:环境变量配置错误只降级为默认行为,不影响业务进程。

3. trace 目录结构与文件命名规范

3.1 三级目录的命名

从 trace_recorder.c 的TraceRecorderGetDirPath函数可以看到,trace 日志采用三级目录结构,各级格式为:

~/ascend/atrace/ # 落盘根目录(见第 5 节,可被 ASCEND_WORK_PATH 改写) └── trace_{进程组pid}_{首次加载trace动态库的进程pid}_{首次加载trace动态库的时间戳}/ └── {event_name}_event_{当前进程pid}_{目录生成时的时间戳}/ # 例如 schedule_event_12345_20260917103000123456

源码中的目录拼接格式串印证了上述结构:

// ~/ascend/atrace/trace_{attr_group_id}_{attr_pid}_{attr_time} "%s/%s/%s_%d_%d_%s", g_recorderMgr->rootPath, TRACE_FILE_SUB_PATH, TRACE_DIR_HEAD, TraceAttrGetPgid(), TraceAttrGetPid(), TraceAttrGetTime() // ~/ascend/atrace/trace_.../{tracer_name}_event_{pid}_time "%s/%s/%s_%d_%d_%s/%s_event_%d_%s", ..., dirInfo->eventName, dirInfo->pid, dirInfo->dirTime

其中event_name为事件类型,取值为:

  • schedule:业务流程异常(如算子执行报错等)或运行过程中的轨迹信息;
  • stackcore:进程崩溃或收到异常信号;
  • exit:进程正常退出析构。

目录创建时权限为0750,目录内 trace 文件以O_CREAT | O_WRONLY | O_APPEND方式打开(文件权限0640,见 trace_recorder.c 与 L516),保证同一用户可写、同组可读,符合日志类文件的常规安全配置。

3.2 子目录内的 trace 文件

每个事件子目录内会写入若干 trace 文件,文件命名与用途如下(来自 查看trace日志 的说明):

| 存储路径 | 说明 | | -- | -- | |schedule_tracer_ts_{device_id}.txt| 当发生 AI Core Error、notify wait 超时时,Task Schedule 回传到 host 侧的维测信息,包括寄存器、硬件 buffer、bitmap 等 | |stackcore_tracer_{signal}_{tid}_{program_name}_{time}.txt| Host 业务进程崩溃时记录的轻量级 core 文件,包括栈帧地址和基地址,需要使用 asys 工具解析 | |schedule_tracer_{object_name}.txt| Runtime、HCCL 等模块在运行过程中上报的轨迹信息,记录进程运行过程 | |schedule_tracer_{object_name}.bin| AICPU 等模块在运行过程中上报的轨迹信息,以二进制格式存储,需要使用 asys 工具解析 |

schedule事件为例,其 tracer 名称常量TRACER_SCHEDULE_NAME "schedule"定义于 trace_types.h,Device 侧 schedule 事件的目录信息构造见 atrace_client_core.c——注意其中TraceDirInfo的第四个字段(isDevice)被置为true,这正是 Host/Device 分开计数的入口。

3.3 Host 与 Device 分开计数的实现

trace_recorder.h 中的全局管理器结构体清晰展示了“两个独立目录链表”的设计:

typedef struct { int32_t maxDirNum; // default is 10, controlled by env ASCEND_TRACE_RECORD_NUM, range [10, 1000] AdiagLock lock; char rootPath[MAX_FILEDIR_LEN + 1U]; // ~/ascend/atrace TraceDirList hostDirList; // Host 侧事件子目录链表 TraceDirList deviceDirList; // Device 侧事件子目录链表 TraceDirNode* exitDir; // exit 事件单独存放 char corePath[MAX_FULLPATH_LEN + 1U]; } TraceRecorderMgr;

maxDirNum即环境变量解析后写入的上限值;hostDirListdeviceDirList是两条独立的双向链表(节点定义见 trace_recorder.h),每条链表各自维护count与自旋锁lock,因此“Host 和 Device 分别控制目录数量”是结构层面的保证,而非简单的共享配额。

4. 老化机制的源码级实现

4.1 何时触发老化

老化不是在后台线程里周期扫描,而是惰性触发:每当需要为一个新的 trace 事件子目录落盘时,TraceRecorderGetDirPath先构造目标目录路径并mkdir,随后调用TraceRecorderSaveNode将其登记到链表;登记时才检查配额。核心逻辑见 trace_recorder.c:

STATIC void TraceRecorderSaveNode(const TraceDirInfo* dirInfo, TraceDirNode* dirNew) { // if exit_event, no need to aging if (strncmp(dirInfo->eventName, TRACER_EVENT_EXIT, strlen(TRACER_EVENT_EXIT)) == 0) { if (g_recorderMgr->exitDir != NULL) { ADIAG_SAFE_FREE(g_recorderMgr->exitDir); } g_recorderMgr->exitDir = dirNew; return; } TraceDirList* dirList = (dirInfo->isDevice) ? &g_recorderMgr->deviceDirList : &g_recorderMgr->hostDirList; // delete node and age the dir if (dirList->count >= g_recorderMgr->maxDirNum) { TraceDirNode* deleteNode = TraceRecorderListPopHead(dirList); TraStatus ret = TraceRmdir(deleteNode->dirPath); // 删除最老的目录 if (ret != 0) { ADIAG_WAR("can not remove dir %s, ret=%d, strerr=%s.", ...); } ADIAG_SAFE_FREE(deleteNode); } // append new node TraceRecorderListAppend(dirList, dirNew); }

由此可以确认老化策略的完整语义:

  1. 按链表顺序即时间顺序:新目录总是Append到链尾,链头始终是时间戳最老的目录;count >= maxDirNum时从链头PopHeadrmdir整目录,实现“删最老、留最新”的 LRU 语义。
  2. 并发安全:链表操作全程持有dirList->lockTraceRecorderListPopHead/TraceRecorderListAppend/TraceRecorderListFind均有加锁),且GetFd路径外层还持有g_recorderMgr->lock,保证多线程并发落盘时的正确性。
  3. 同名目录去重TraceRecorderFindExistingDir会先在链表中按路径查找,已存在的目录直接复用节点而不重复计数(见 trace_recorder.c)。
  4. 删除失败不阻断业务rmdir失败时仅打印can not remove dir告警,新目录照常追加,不会向业务返回错误。

4.2 特例:exit 事件目录不参与老化

注意TraceRecorderSaveNode开头的分支:exit事件(进程正常退出析构时记录)的目录被单独存放在g_recorderMgr->exitDir指针中,不进入 host/device 链表、不占用maxDirNum配额、也不参与老化。源码注释// if exit_event, no need to aging明确了这一设计意图——进程退出是排障的关键现场,其 trace 目录需要跨“老化周期”保留。

4.3 单元测试对老化行为的验证

仓库中的单元测试 trace_recorder_utest.cc 直接验证了上述机制,可作为行为正确性的依据:

  • TraceRecorderGetFd_SameDirAgingKeepsWritable(L688-L716):设置setenv("ASCEND_TRACE_RECORD_NUM", "10", 1)后连续 11 次获取 fd,验证老化过程不破坏当前正在写目录的可写性;
  • TraceRecorderGetFd_ConcurrentDirAgingKeepsFirstOpen(L718-L764):通过 mockTraceOpen阻塞首个打开操作,再启动老化线程连续创建 10 个新目录(L122-L138),验证并发老化时首个已打开的 fd 依然有效,即“老化最老目录”不会波及正在写入的目录;
  • 多处测试在EXPECT_EQ(TRACE_SUCCESS, TraceRecorderInit())前统一通过setenv/unsetenv控制该环境变量,覆盖默认值与配置值的初始化路径。

这些用例说明老化实现面向多进程、多线程的共享落盘场景做了专门的并发正确性验证。

5. 与其他环境变量的协同:根目录从哪里来

ASCEND_TRACE_RECORD_NUM控制的是“目录数量”,而目录的“位置”由另一条解析链决定。trace_recorder.c 的TraceInitRootPath逻辑为:

  1. 若编译期定义了ATRACE_ROOT_PATH,直接使用该宏;
  2. 否则优先读取环境变量ASCEND_WORK_PATHTraceGetEnvPath,见 L161-L177),要求路径存在且可写,必要时逐级mkdir并做realpath规范化;
  3. 再否则回退到用户主目录下的$HOME/ascend/

因此完整组合配置示例为:

# 自定义 trace 落盘根目录(可选) export ASCEND_WORK_PATH=/home/test # 事件子目录老化上限,[10, 1000],默认 10 export ASCEND_TRACE_RECORD_NUM=15

配置后,/home/test/atrace/trace_.../下的schedule_event_...子目录按 15 个的规格自动老化。两个变量分别控制“在哪”与“留多少”,互不干扰。

6. 使用约束与支持范围

  • 使用约束:无。该变量可独立配置,不依赖其他环境变量;配置非法时自动回退默认值,不产生副作用。
  • 支持的型号:全量芯片支持。
  • 适用前提:老化清理依托 trace 机制落盘行为,而 trace 机制当前仅 Ascend EP 标准形态支持(参见 查看trace日志);在未启用 trace 落盘的环境中,该变量不会引起任何目录清理动作。

7. 实践建议

结合源码行为,给出三条可落地的配置建议:

  1. 容量估算:每个事件子目录内含一个或多个schedule_tracer_*.txt/.bin文件,异常密集场景(高频报错的联调环境)下目录生成速度可能很快。配置较大的ASCEND_TRACE_RECORD_NUM会保留更长的排障窗口,但需评估$HOME/ascend/atrace(或ASCEND_WORK_PATH)所在分区的剩余空间;反之长期运行的稳定业务可保持默认 10,让最老目录尽快被回收。
  2. 保留现场优先:由于exit事件目录不参与老化,进程退出类现场天然保留;但schedule/stackcore目录会被按数量淘汰,若某次异常的现场已被老化删除,则无法事后追捞——对排障要求高的节点建议适当调大该值(如 100 以上),并配合 logrotate 做二级兜底。
  3. 验证配置是否生效:配置生效与否可直接观察 trace 根目录下的目录数量,或在维测日志中检索关键字get dir num by env ASCEND_TRACE_RECORD_NUM/set dir num=(生效日志)与invalid value [...] for ASCEND_TRACE_RECORD_NUM(回退告警),均可用于快速确认当前运行参数。

8. 小结

ASCEND_TRACE_RECORD_NUM是 CANN Runtime trace 子系统中一个“小变量、大作用”的老化规格参数:取值范围 [10, 1000]、默认 10、非法值静默回退;它通过TraceRecorderMgr中 Host/Device 两条独立目录链表实现分开计数,在每次新事件目录落盘时以 LRU 方式删除最老目录,且对exit事件目录予以豁免。源码实现位于 trace_recorder.c 与 trace_recorder.h,单元测试位于 trace_recorder_utest.cc,配合 查看trace日志 与 环境变量参考 可形成对该功能的完整认知闭环。

【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询