已合并
docs:典型案例补充导读 #381
cai-weiwei1989创建于 7月24日
docs:典型案例补充导读 #381
已合并
共 34 个文件变更+172-2328
| @@ -58,7 +58,7 @@ msProf 工具内置在 CANN Toolkit 开发套件中,推荐直接下载 CANN | |||
| 58 | 58 | ||
| 59 | ## 💡 典型案例 | 59 | ## 💡 典型案例 |
| 60 | 60 | ||
| 61 | -通过典型问题场景帮助用户理解并掌握工具使用,请参见《[msProf 典型案例](docs/zh/best_practices/basic_cases.md)》。 | 61 | +通过典型问题场景帮助用户理解并掌握工具使用,请参见《[msProf 典型案例](docs/zh/best_practices/README.md)》。 |
| 62 | 62 | ||
| 63 | ## ❓ FAQ | 63 | ## ❓ FAQ |
| 64 | 64 | ||
| @@ -0,0 +1,33 @@ | |||
| 1 | +# msProf 典型案例 | ||
| 2 | + | ||
| 3 | +本章节通过性能调优的典型场景提供对应的性能调优案例,包含如下案例。 | ||
| 4 | + | ||
| 5 | +**基础案例** | ||
| 6 | + | ||
| 7 | +- [ResNet50推理模型性能分析](basic_cases.md) | ||
| 8 | + | ||
| 9 | +**Host侧** | ||
| 10 | + | ||
| 11 | +- 模型代码类 | ||
| 12 | + - [代码高耗时函数段优化](code_high_latency_function.md) | ||
| 13 | + - [下发性能不及预期](dispatch_small_batch_performance.md) | ||
| 14 | + - [算子编译高耗时](operator_compilation_latency.md) | ||
| 15 | + - [同步接口频繁调用](sync_api_frequent_call.md) | ||
| 16 | +- 系统调度类 | ||
| 17 | + - [CPU Cache Miss资源冲突与受限](cpu_cache_miss_conflict.md) | ||
| 18 | + - [CPU 线程频繁切换](cpu_thread_frequent_switching.md) | ||
| 19 | + - [GIL锁抢占问题分析](gil_lock_preemption.md) | ||
| 20 | + - [IRQ中断打断问题分析](irq_interruption.md) | ||
| 21 | + - [内核进程频繁切换](kernel_thread_switching.md) | ||
| 22 | + - [Pthread线程锁等待](pthread_lock_wait.md) | ||
| 23 | + - [Python GC回收高耗时](python_gc_high_latency.md) | ||
| 24 | + - [系统调用高耗时函数](syscall_high_latency.md) | ||
| 25 | + | ||
| 26 | +**Device侧** | ||
| 27 | + | ||
| 28 | +- NPU通信 | ||
| 29 | + - [通信地址不对齐导致性能下降](communication_address_misalignment.md) | ||
| 30 | + | ||
| 31 | +- 内存 | ||
| 32 | + - [内存碎片](memory_fragmentation.md) | ||
| 33 | + - [内存泄漏](memory_leak.md) | ||
| @@ -1,278 +0,0 @@ | |||
| 1 | -# 异步双发未生效问题调优指导实例 | ||
| 2 | - | ||
| 3 | -## 场景说明 | ||
| 4 | - | ||
| 5 | -异步双发也称异步调度,目标是在模型推理服务化过程中,将CPU侧调度、Host侧任务下发、NPU侧模型执行以及通信过程尽量重叠,减少同步等待和调度空洞。该能力通常需要环境变量、流水优化、启动参数、硬件软件版本和通信配置共同满足条件。如果配置不完整或存在冲突,服务可能能够正常启动,但异步调度未实际触发,最终表现为吞吐提升不明显、Decode时延不降或CPU/NPU流水没有被掩盖。 | ||
| 6 | - | ||
| 7 | -本文以异步双发未生效为例,介绍如何使用msServiceProfiler采集BatchSchedule、ModelExecute和Communication数据,判断异步调度是否实际生效,并给出环境变量、流水优化、启动参数、兼容性和配置冲突方向的排查方案。 | ||
| 8 | - | ||
| 9 | -## 问题现象 | ||
| 10 | - | ||
| 11 | -**典型表现** | ||
| 12 | - | ||
| 13 | -- 设置异步调度相关环境变量后,吞吐、首Token时延或Decode时延没有明显改善。 | ||
| 14 | -- Timeline中BatchSchedule、Host下发、ModelExecute仍呈现严格串行关系,未出现调度与执行重叠。 | ||
| 15 | -- CPU侧调度线程等待NPU执行完成后才继续提交下一轮任务,流水空洞明显。 | ||
| 16 | -- Decode_Generate_Speed_Latency_curve未下降,Request_Latency_curve的P90/P99仍偏高。 | ||
| 17 | -- 单机PD分离或多卡场景中,通信等待掩盖失败,Communication域耗时持续暴露在关键路径上。 | ||
| 18 | -- 服务启动日志未出现异步调度启用信息,或启动参数、环境变量未被框架识别。 | ||
| 19 | - | ||
| 20 | -**影响范围** | ||
| 21 | - | ||
| 22 | -| 影响项 | 表现 | | ||
| 23 | -| --- | --- | | ||
| 24 | -| 吞吐 | CPU调度与NPU执行无法重叠,tokens/s提升不明显。 | | ||
| 25 | -| Decode时延 | Decode阶段仍受同步下发和通信等待影响。 | | ||
| 26 | -| 端到端时延 | Request Latency P90/P99难以下降。 | | ||
| 27 | -| 资源利用率 | NPU执行间存在空洞,CPU/NPU流水不连续。 | | ||
| 28 | -| PD分离性能 | KV Cache传输和通算融合未充分掩盖,跨阶段等待增加。 | | ||
| 29 | - | ||
| 30 | -## 数据采集 | ||
| 31 | - | ||
| 32 | -### 功能说明 | ||
| 33 | - | ||
| 34 | -使用msServiceProfiler采集BatchSchedule、ModelExecute、Communication和Request域数据,通过Timeline、span_info、batch.csv、forward.csv、pd_split_communication.csv和可视化曲线,判断异步调度是否生效。 | ||
| 35 | - | ||
| 36 | -### 注意事项 | ||
| 37 | - | ||
| 38 | -- 采集前需记录服务启动命令、环境变量、MindIE版本、CANN版本、硬件型号和部署形态。 | ||
| 39 | -- 建议分别采集“未开启异步调度”和“开启异步调度”两组数据,使用相同压测流量做对比。 | ||
| 40 | -- 若需要进一步分析Host与Device之间的任务下发耗时,可开启acl任务耗时采集,但需评估额外开销。 | ||
| 41 | -- 多卡或PD分离场景需同时采集Communication域,否则无法判断通信等待是否被异步调度掩盖。 | ||
| 42 | - | ||
| 43 | -### 配置示例 | ||
| 44 | - | ||
| 45 | -创建ms_service_profiler_config.json,采集调度、执行、通信和请求数据。 | ||
| 46 | - | ||
| 47 | -```json | ||
| 48 | -{ | ||
| 49 | - "enable": 1, | ||
| 50 | - "prof_dir": "${HOME}/.ms_server_profiler", | ||
| 51 | - "profiler_level": "INFO", | ||
| 52 | - "domain": "Request;BatchSchedule;ModelExecute;Communication", | ||
| 53 | - "acl_task_time": 1, | ||
| 54 | - "acl_prof_task_time_level": "L0" | ||
| 55 | -} | ||
| 56 | -``` | ||
| 57 | - | ||
| 58 | -设置采集配置路径。 | ||
| 59 | - | ||
| 60 | -```bash | ||
| 61 | -export SERVICE_PROF_CONFIG_PATH=/path/to/ms_service_profiler_config.json | ||
| 62 | -``` | ||
| 63 | - | ||
| 64 | -解析时导出Span数据,便于观察BatchSchedule和forward是否重叠。 | ||
| 65 | - | ||
| 66 | -```bash | ||
| 67 | -ms_service_profiler_parse --input-path ${PROF_DIR} --output-path ${OUTPUT_DIR} --span | ||
| 68 | -``` | ||
| 69 | - | ||
| 70 | -## 生效判断 | ||
| 71 | - | ||
| 72 | -### 预期生效特征 | ||
| 73 | - | ||
| 74 | -异步双发生效后,通常可以观察到以下特征: | ||
| 75 | - | ||
| 76 | -- Timeline中下一轮BatchSchedule或Host下发与上一轮ModelExecute存在时间重叠。 | ||
| 77 | -- CPU侧调度Span不再完全等待NPU侧forward结束后才开始下一轮。 | ||
| 78 | -- Decode阶段连续性增强,forward.csv中相邻Decode执行间隔缩短。 | ||
| 79 | -- Communication域耗时被部分掩盖,不再完整暴露在Request关键路径中。 | ||
| 80 | -- Decode_Generate_Speed_Latency_curve、Request_Latency_curve或吞吐指标有可观测改善。 | ||
| 81 | - | ||
| 82 | -### 未生效特征 | ||
| 83 | - | ||
| 84 | -若异步双发未生效,通常表现为: | ||
| 85 | - | ||
| 86 | -- BatchSchedule.csv中的调度开始时间总是在上一轮forward结束之后。 | ||
| 87 | -- forward.csv中相邻执行之间存在明显空洞。 | ||
| 88 | -- Communication耗时与ModelExecute串行排列,未与计算阶段重叠。 | ||
| 89 | -- 开关打开前后Batch_Size_curve相似,但吞吐和Decode时延几乎无变化。 | ||
| 90 | -- 服务日志中未打印异步调度启用、流水队列启用或相关启动参数生效信息。 | ||
| 91 | - | ||
| 92 | -## 定位方法 | ||
| 93 | - | ||
| 94 | -1. 检查环境变量是否在服务启动前生效。 | ||
| 95 | - - 确认启动脚本中已配置`MINDIE_ASYNC_SCHEDULING_ENABLE=1`。 | ||
| 96 | - - 确认变量设置在服务进程启动之前,而不是启动后在交互终端中临时设置。 | ||
| 97 | - - 容器部署时需确认环境变量传入容器内部,并可被服务进程读取。 | ||
| 98 | - | ||
| 99 | -2. 检查流水优化是否同时开启。 | ||
| 100 | - - 异步调度通常需要配合`TASK_QUEUE_ENABLE=2`使用。 | ||
| 101 | - - 若只开启异步调度,不开启流水优化,CPU/NPU重叠可能无法达到预期。 | ||
| 102 | - - 通过Timeline观察Host下发和Device执行是否形成连续流水。 | ||
| 103 | - | ||
| 104 | -3. 检查启动参数是否显式启用。 | ||
| 105 | - - 部分框架不只依赖环境变量,还要求启动命令包含异步调度参数。 | ||
| 106 | - - 在vLLM-Ascend等场景中,需确认是否传入`--async-scheduling`。 | ||
| 107 | - - 若框架启动脚本封装了参数,需要检查最终生效的真实启动命令。 | ||
| 108 | - | ||
| 109 | -4. 检查硬件和软件版本。 | ||
| 110 | - - 确认硬件型号支持异步调度特性,例如目标昇腾卡型是否在支持范围内。 | ||
| 111 | - - 确认CANN、MindIE和推理框架版本支持当前异步调度能力。 | ||
| 112 | - - 对已知存在兼容性问题的旧版本,建议升级后重新验证。 | ||
| 113 | - | ||
| 114 | -## 原因分析与解决方案 | ||
| 115 | - | ||
| 116 | -### 环境变量未正确配置 | ||
| 117 | - | ||
| 118 | -**原因** | ||
| 119 | - | ||
| 120 | -异步调度的核心开关未设置、设置值错误、设置时机晚于服务启动,或容器/启动脚本未继承该变量,都会导致异步双发未生效。 | ||
| 121 | - | ||
| 122 | -**解决方案** | ||
| 123 | - | ||
| 124 | -在服务启动前配置环境变量。 | ||
| 125 | - | ||
| 126 | -```bash | ||
| 127 | -export MINDIE_ASYNC_SCHEDULING_ENABLE=1 | ||
| 128 | -``` | ||
| 129 | - | ||
| 130 | -容器部署时,将变量写入容器启动命令或服务启动脚本中,并在服务日志中确认变量已被读取。若使用systemd、Kubernetes或平台化拉起方式,需要检查最终进入服务进程的环境变量,而不是只检查当前Shell。 | ||
| 131 | - | ||
| 132 | -### 未开启流水优化 | ||
| 133 | - | ||
| 134 | -**原因** | ||
| 135 | - | ||
| 136 | -异步调度需要与流水队列能力配合,才能将任务下发、调度和执行重叠。若`TASK_QUEUE_ENABLE`未设置为推荐值,可能仍呈现同步串行提交。 | ||
| 137 | - | ||
| 138 | -**解决方案** | ||
| 139 | - | ||
| 140 | -在启动前开启流水优化。 | ||
| 141 | - | ||
| 142 | -```bash | ||
| 143 | -export TASK_QUEUE_ENABLE=2 | ||
| 144 | -``` | ||
| 145 | - | ||
| 146 | -开启后重新采集Timeline。若BatchSchedule和ModelExecute仍完全串行,继续检查启动参数、版本和冲突配置。 | ||
| 147 | - | ||
| 148 | -### 启动参数未启用 | ||
| 149 | - | ||
| 150 | -**原因** | ||
| 151 | - | ||
| 152 | -部分框架需要在启动命令中显式打开异步调度。只配置环境变量时,框架层可能不会进入异步调度分支。 | ||
| 153 | - | ||
| 154 | -**解决方案** | ||
| 155 | - | ||
| 156 | -检查服务启动命令。以需要显式参数的框架为例,启动时增加异步调度参数。 | ||
| 157 | - | ||
| 158 | -```bash | ||
| 159 | ---async-scheduling | ||
| 160 | -``` | ||
| 161 | - | ||
| 162 | -如果使用脚本封装启动命令,需确认该参数没有被配置模板覆盖或过滤。建议在日志中打印最终启动参数,便于复盘。 | ||
| 163 | - | ||
| 164 | -### 硬件或软件版本不兼容 | ||
| 165 | - | ||
| 166 | -**原因** | ||
| 167 | - | ||
| 168 | -异步调度能力依赖硬件、CANN、MindIE和框架版本。旧版本可能不支持该能力,或存在异步调度与通信、内存管理相关的兼容性问题。 | ||
| 169 | - | ||
| 170 | -**解决方案** | ||
| 171 | - | ||
| 172 | -- 确认硬件型号支持异步调度,例如目标环境是否为支持该特性的昇腾卡型。 | ||
| 173 | -- 确认CANN版本、MindIE版本和推理框架版本满足异步调度要求。 | ||
| 174 | -- 对已知存在兼容性问题的旧版本,升级到支持异步调度的稳定版本后重新验证。 | ||
| 175 | -- 升级前后分别采集msServiceProfiler数据,使用相同压测条件对比Decode时延和Timeline重叠情况。 | ||
| 176 | - | ||
| 177 | -### 通信或内存配置冲突 | ||
| 178 | - | ||
| 179 | -**原因** | ||
| 180 | - | ||
| 181 | -部分通信或内存相关环境变量会改变执行图、通信路径或任务提交方式,可能导致异步调度未触发,或异步收益被通信同步等待抵消。 | ||
| 182 | - | ||
| 183 | -**解决方案** | ||
| 184 | - | ||
| 185 | -排查以下配置是否与当前异步调度场景冲突。 | ||
| 186 | - | ||
| 187 | -```bash | ||
| 188 | -unset HCCL_OP_EXPANSION_MODE | ||
| 189 | -unset ATB_LLM_HCCL_ENABLE | ||
| 190 | -``` | ||
| 191 | - | ||
| 192 | -单机PD分离场景中,建议开启通算融合。 | ||
| 193 | - | ||
| 194 | -```bash | ||
| 195 | -export ATB_LLM_LCOC_ENABLE=1 | ||
| 196 | -``` | ||
| 197 | - | ||
| 198 | -多卡场景需确认HCCL/LCCL配置正确,避免通信初始化、rank配置或网络问题导致异步调度收益无法体现。 | ||
| 199 | - | ||
| 200 | -### Prefix Cache、LCCL等协同特性缺失 | ||
| 201 | - | ||
| 202 | -**原因** | ||
| 203 | - | ||
| 204 | -异步调度只能减少调度和执行之间的等待,若Prefill重复计算、KV Cache传输慢或通信库未优化,整体性能仍可能无明显改善。 | ||
| 205 | - | ||
| 206 | -**解决方案** | ||
| 207 | - | ||
| 208 | -- 单机PD分离场景中,结合Prefix Cache减少重复Prefill计算。 | ||
| 209 | -- 启用LCCL通信库,降低KV Cache传输和Decode通信开销。 | ||
| 210 | -- 对Communication域进行采集,确认通信耗时是否被计算阶段掩盖。 | ||
| 211 | -- 若通信仍暴露在关键路径中,优先优化通信配置,再评估异步调度收益。 | ||
| 212 | - | ||
| 213 | -## 插桩建议 | ||
| 214 | - | ||
| 215 | -若框架允许自定义插桩,可在异步调度关键阶段增加Span和Event,便于确认异步任务提交和回收是否发生。 | ||
| 216 | - | ||
| 217 | -```C++ | ||
| 218 | -auto submitSpan = PROF(INFO, SpanStart("AsyncSubmit")); | ||
| 219 | - | ||
| 220 | -// CPU侧异步提交下一轮任务 | ||
| 221 | - | ||
| 222 | -PROF(submitSpan.SpanEnd()); | ||
| 223 | - | ||
| 224 | -PROF(INFO, Event("AsyncTaskQueued")); | ||
| 225 | - | ||
| 226 | -auto waitSpan = PROF(INFO, SpanStart("AsyncWait")); | ||
| 227 | - | ||
| 228 | -// 等待异步任务完成或回收结果 | ||
| 229 | - | ||
| 230 | -PROF(waitSpan.SpanEnd()); | ||
| 231 | -``` | ||
| 232 | - | ||
| 233 | -采集队列深度和异步命中次数。 | ||
| 234 | - | ||
| 235 | -```C++ | ||
| 236 | -PROF(INFO, Metric("asyncQueueDepth", asyncQueueDepth).MetricScope("scheduler", rankId).Launch()); | ||
| 237 | -PROF(INFO, MetricInc("asyncDispatchCount", 1).MetricScope("rank", rankId).Launch()); | ||
| 238 | -``` | ||
| 239 | - | ||
| 240 | -若`asyncDispatchCount`长时间为0,说明异步分支未进入;若`asyncQueueDepth`持续为0,说明任务没有形成有效流水。 | ||
| 241 | - | ||
| 242 | -## 优化验证 | ||
| 243 | - | ||
| 244 | -建议按以下顺序验证,每次只改变一个变量。 | ||
| 245 | - | ||
| 246 | -| 步骤 | 验证内容 | 观察指标 | | ||
| 247 | -| --- | --- | --- | | ||
| 248 | -| 基线采集 | 关闭异步调度,采集同步执行数据 | Timeline、BatchSchedule.csv、forward.csv | | ||
| 249 | -| 开启异步变量 | 配置MINDIE_ASYNC_SCHEDULING_ENABLE=1 | 是否进入异步分支、Decode时延 | | ||
| 250 | -| 开启流水优化 | 配置TASK_QUEUE_ENABLE=2 | BatchSchedule与ModelExecute是否重叠 | | ||
| 251 | -| 增加启动参数 | 配置--async-scheduling | 框架日志、Timeline重叠 | | ||
| 252 | -| 排除冲突配置 | 清理冲突通信或内存变量 | Communication耗时、Request Latency | | ||
| 253 | -| 协同优化 | 开启LCCL、Prefix Cache或通算融合 | Decode时延、吞吐、PD通信耗时 | | ||
| 254 | - | ||
| 255 | -优化有效时,通常会看到以下结果: | ||
| 256 | - | ||
| 257 | -- BatchSchedule和ModelExecute在Timeline上出现重叠。 | ||
| 258 | -- forward.csv中相邻Decode执行间隔缩短。 | ||
| 259 | -- Communication域耗时被部分掩盖。 | ||
| 260 | -- Decode_Generate_Speed_Latency下降。 | ||
| 261 | -- Request_Latency的P90/P99下降。 | ||
| 262 | -- 吞吐提升,NPU执行空洞减少。 | ||
| 263 | - | ||
| 264 | -## 推荐处理策略 | ||
| 265 | - | ||
| 266 | -| 问题类型 | 推荐方案 | | ||
| 267 | -| --- | --- | | ||
| 268 | -| 异步开关未生效 | 启动前设置MINDIE_ASYNC_SCHEDULING_ENABLE=1,并确认服务进程可读取。 | | ||
| 269 | -| 开关开启但无收益 | 同时设置TASK_QUEUE_ENABLE=2,检查Timeline是否出现流水重叠。 | | ||
| 270 | -| 框架未进入异步分支 | 在启动命令中显式配置--async-scheduling,并检查最终启动参数。 | | ||
| 271 | -| 旧版本兼容问题 | 升级CANN、MindIE或推理框架到支持异步调度的稳定版本。 | | ||
| 272 | -| 通信配置抵消收益 | 检查HCCL/LCCL配置,清理冲突变量,必要时开启通算融合。 | | ||
| 273 | -| 单机PD分离收益不足 | 配合ATB_LLM_LCOC_ENABLE=1、Prefix Cache和LCCL通信库。 | | ||
| 274 | -| 多卡场景仍串行 | 检查rank配置、网络通信、Communication域耗时和跨卡同步点。 | | ||
| 275 | - | ||
| 276 | -## 总结 | ||
| 277 | - | ||
| 278 | -异步双发未生效通常不是单一开关问题,而是环境变量、流水优化、框架启动参数、硬件软件版本和通信配置共同决定。定位时应先通过msServiceProfiler采集BatchSchedule、ModelExecute和Communication数据,判断调度、执行、通信是否在Timeline上形成重叠。优化时优先确认`MINDIE_ASYNC_SCHEDULING_ENABLE=1`、`TASK_QUEUE_ENABLE=2`和框架启动参数是否生效,再排查版本兼容、冲突环境变量、HCCL/LCCL通信配置、PD分离通算融合和Prefix Cache等协同能力。 | ||
| @@ -1,19 +1,15 @@ | |||
| 1 | -# msProf工具使用案例——ResNet50推理模型性能分析 | 1 | +# ResNet50推理模型性能分析 |
| 2 | - | ||
| 3 | -## 一、案例名称 | ||
| 4 | - | ||
| 5 | -**使用msProf命令行工具采集并分析ResNet50推理模型在昇腾NPU上的性能数据** | ||
| 6 | 2 | ||
| 7 | 本案例以ResNet50推理模型为例,演示如何使用华为昇腾MindStudio提供的msProf性能分析工具,完成性能数据的采集、解析与瓶颈定位。 | 3 | 本案例以ResNet50推理模型为例,演示如何使用华为昇腾MindStudio提供的msProf性能分析工具,完成性能数据的采集、解析与瓶颈定位。 |
| 8 | 4 | ||
| 9 | -### 1.1 前置准备 | 5 | +# 1. 前置准备 |
| 10 | 6 | ||
| 11 | -#### 1.1.1 环境要求 | 7 | +## 1.1 环境要求 |
| 12 | 8 | ||
| 13 | - 已安装**CANN Toolkit开发套件包**和**ops算子包** | 9 | - 已安装**CANN Toolkit开发套件包**和**ops算子包** |
| 14 | - 已安装**MindStudio Insight**可视化分析工具 | 10 | - 已安装**MindStudio Insight**可视化分析工具 |
| 15 | 11 | ||
| 16 | -#### 1.1.2 配置环境变量 | 12 | +## 1.2 配置环境变量 |
| 17 | 13 | ||
| 18 | 执行以下命令配置CANN环境变量(以cann-9.1.0为例): | 14 | 执行以下命令配置CANN环境变量(以cann-9.1.0为例): |
| 19 | 15 | ||
| @@ -21,7 +17,7 @@ | |||
| 21 | source /usr/local/Ascend/cann/set_env.sh | 17 | source /usr/local/Ascend/cann/set_env.sh |
| 22 | ``` | 18 | ``` |
| 23 | 19 | ||
| 24 | -#### 1.1.3 验证工具可用性 | 20 | +## 1.3 验证工具可用性 |
| 25 | 21 | ||
| 26 | 执行以下命令确认msProf工具版本正常: | 22 | 执行以下命令确认msProf工具版本正常: |
| 27 | 23 | ||
| @@ -35,15 +31,13 @@ msprof --version | |||
| 35 | npu-smi info | 31 | npu-smi info |
| 36 | ``` | 32 | ``` |
| 37 | 33 | ||
| 38 | -#### 1.1.4 准备ResNet50推理脚本 | 34 | +## 1.4 准备ResNet50推理脚本 |
| 39 | 35 | ||
| 40 | 确保`resnet50_infer.py`推理脚本可在昇腾NPU上正常运行,脚本中需包含模型加载、数据预处理及推理执行逻辑。 | 36 | 确保`resnet50_infer.py`推理脚本可在昇腾NPU上正常运行,脚本中需包含模型加载、数据预处理及推理执行逻辑。 |
| 41 | 37 | ||
| 42 | -### 1.2 使用工具 | 38 | +# 2. 使用工具 |
| 43 | 39 | ||
| 44 | -#### 1.2.1 性能数据采集 | 40 | +## 2.1 性能数据采集 |
| 45 | - | ||
| 46 | -**(1)执行性能数据采集命令** | ||
| 47 | 41 | ||
| 48 | 使用msProf命令行工具采集推理模型的性能数据: | 42 | 使用msProf命令行工具采集推理模型的性能数据: |
| 49 | 43 | ||
| @@ -76,7 +70,7 @@ msprof --output=/home/projects/output /home/projects/MyApp/out/main parameter1 p | |||
| 76 | msprof --output=/home/projects/output /home/projects/MyApp/out/sample_run.sh param1 param2 | 70 | msprof --output=/home/projects/output /home/projects/MyApp/out/sample_run.sh param1 param2 |
| 77 | ``` | 71 | ``` |
| 78 | 72 | ||
| 79 | -#### 1.2.2 性能数据解析 | 73 | +## 2.2 性能数据解析 |
| 80 | 74 | ||
| 81 | 采集完成后,执行以下命令解析性能数据,生成可分析的报告: | 75 | 采集完成后,执行以下命令解析性能数据,生成可分析的报告: |
| 82 | 76 | ||
| @@ -86,18 +80,18 @@ msprof --export=on --output="./prof_data" | |||
| 86 | 80 | ||
| 87 | 解析后会在`--output`指定的目录下生成`PROF_XXX`目录(或`OPPROF`目录,取决于采集模式),存放自动解析后的性能数据。 | 81 | 解析后会在`--output`指定的目录下生成`PROF_XXX`目录(或`OPPROF`目录,取决于采集模式),存放自动解析后的性能数据。 |
| 88 | 82 | ||
| 89 | -#### 1.2.3 查看性能数据 | 83 | +## 2.3 查看性能数据 |
| 90 | 84 | ||
| 91 | -**(1)查看生成的文件结构** | 85 | +1. 查看生成的文件结构 |
| 92 | 86 | ||
| 93 | -```bash | 87 | + ```bash |
| 94 | -ls -la ./prof_data/PROF_XXX/ | 88 | + ls -la ./prof_data/PROF_XXX/ |
| 95 | -``` | 89 | + ``` |
| 96 | 90 | ||
| 97 | - | 91 | +  |
| 98 | 92 | ||
| 99 | -采集解析数据格式和交付件请参见《[profile_data_file_references](../user_guide/profile_data_file_references.md)》 | 93 | + 采集解析数据格式和交付件请参见《[profile_data_file_references](../user_guide/profile_data_file_references.md)》 |
| 100 | 94 | ||
| 101 | -**(2)使用MindStudio Insight可视化分析** | 95 | +2. 使用MindStudio Insight可视化分析 |
| 102 | 96 | ||
| 103 | -进入`PROF_XXX/mindstudio_profiler_output`目录,将性能数据导入MindStudio Insight工具进行可视化分析。MindStudio Insight提供了多种数据呈现形式,包括时间线视图、通信分析、计算耗时等可视化呈现,帮助用户快速定位性能瓶颈。 | 97 | + 进入`PROF_XXX/mindstudio_profiler_output`目录,将性能数据导入MindStudio Insight工具进行可视化分析。MindStudio Insight提供了多种数据呈现形式,包括时间线视图、通信分析、计算耗时等可视化呈现,帮助用户快速定位性能瓶颈。 |
| @@ -1,148 +0,0 @@ | |||
| 1 | -# 同一Batch内请求长度不均问题分析 | ||
| 2 | - | ||
| 3 | -## 【问题背景】 | ||
| 4 | - | ||
| 5 | -某客户在昇腾A2集群上部署基于 MindIE-LLM 的 LLaMA2-70B 推理服务,上线后压测发现:在固定并发数(QPS=20)下,服务化吞吐量只有预期值的 **55%** 左右,P99 TTFT 高达 **820ms**(SLA 约束 300ms),P99 TPOT 高达 **85ms**(SLA 约束 30ms)。但通过 `npu-smi info` 观察,NPU 平均利用率(AICore)显示为 **78%**,AIPower 正常,温度未触发限频。表面看"硬件没跑满,业务侧却慢"——这是典型的服务化层调度问题。 | ||
| 6 | - | ||
| 7 | -进一步压测数据如下: | ||
| 8 | - | ||
| 9 | -| 并发数 | 理论吞吐 (tokens/s) | 实测吞吐 (tokens/s) | 吞吐达成率 | P99 TTFT (ms) | P99 TPOT (ms) | | ||
| 10 | -| ------ | ------------------- | ------------------- | ---------- | ------------- | ------------- | | ||
| 11 | -| 10 | 1200 | 980 | 81.7% | 210 | 28 | | ||
| 12 | -| 20 | 2400 | 1320 | **55.0%** | **820** | **85** | | ||
| 13 | -| 40 | 4800 | 2280 | 47.5% | 1850 | 142 | | ||
| 14 | -| 80 | 9600 | 3920 | 40.8% | OOM/超时 | OOM/超时 | | ||
| 15 | - | ||
| 16 | -吞吐达成率随并发数增加反而**显著下降**,与"硬件未跑满"的现象矛盾,初步怀疑**服务化调度层有结构性瓶颈**。 | ||
| 17 | - | ||
| 18 | ---- | ||
| 19 | - | ||
| 20 | -## 【问题现象】 | ||
| 21 | - | ||
| 22 | -服务化调度层在 Continuous Batching 模式下,同一个 Decode batch 内混入了**刚刚完成 Prefill 的超长请求**和**已经在 Decode 阶段的若干短请求**。Decode 步的执行时间不再只取决于当前 batch 的平均长度,而被最长的那个 Prefill 主导,导致: | ||
| 23 | - | ||
| 24 | -- **短请求被拖慢**:原本应该在 ~25ms 内出一个 Token 的短请求,因为等长请求 Prefill 完成,实际等到 80-100ms 才出 token(TPOT 退化 3-4 倍) | ||
| 25 | -- **Decode 步时长周期性尖峰**:在 timeline 上,Decode 算子时长呈"短-长-短-长"锯齿状波动 | ||
| 26 | -- **AICore 利用率"虚高"**:NPU 一直在算(Prefill 阶段是计算密集型),但算的不是有效业务 token | ||
| 27 | -- **KV Cache 申请抖动**:长请求 Prefill 进来时,框架需要紧急申请大块 KV cache,导致调度器 stall,挤占后续请求的入队 | ||
| 28 | - | ||
| 29 | -**核心矛盾**:硬件利用率 78% 看上去不低,但**单位时间内的有效 token 产出**(output tokens/s)远低于预期。 | ||
| 30 | - | ||
| 31 | ---- | ||
| 32 | - | ||
| 33 | -## 【定位过程】 | ||
| 34 | - | ||
| 35 | -先用 msServiceProfiler 采集全链路服务化 trace,拿到 request/batch/kv cache 三表原始数据;然后导入 MindStudio Insight,从 Summary 看到关键指标的统计性异常(吞吐/延迟/批长度分布),再到 Timeline 页面选典型"坏 batch"和"好 batch"做对比,**一眼定位"Decode 被 Prefill 拖慢"这一根因**。 | ||
| 36 | - | ||
| 37 | -### 步骤 1:用 msServiceProfiler 采集全链路服务化数据 | ||
| 38 | - | ||
| 39 | -**目的**:拿到请求级、Batch 级、KV Cache 级数据,建立端到端时间线,作为后续 Insight 可视化的数据源。 | ||
| 40 | - | ||
| 41 | -**配置文件**(`/home/user/mindie/ms_service_profiler_config.json`): | ||
| 42 | - | ||
| 43 | -```json | ||
| 44 | -{ | ||
| 45 | - "enable": 1, | ||
| 46 | - "prof_dir": "/home/user/mindie/prof_data", | ||
| 47 | - "acl_task_time": 1, | ||
| 48 | - "l2_cache": 0, | ||
| 49 | - "data_frame": 1 | ||
| 50 | -} | ||
| 51 | -``` | ||
| 52 | - | ||
| 53 | -**配置环境变量并启动 MindIE Service**: | ||
| 54 | - | ||
| 55 | -```bash | ||
| 56 | -export SERVICE_PROF_CONFIG_PATH="/home/user/mindie/ms_service_profiler_config.json" | ||
| 57 | -bash /usr/local/Ascend/mindie/latest/scripts/start.sh \ | ||
| 58 | - --model-path /data/llama2-70b-fp16 \ | ||
| 59 | - --tensor-parallel-size 4 \ | ||
| 60 | - --max-batch-size 64 \ | ||
| 61 | - --max-prefill-tokens 8192 | ||
| 62 | -``` | ||
| 63 | - | ||
| 64 | -**等待60秒后关闭采集**(避免数据量爆炸): | ||
| 65 | - | ||
| 66 | -```json | ||
| 67 | -{ | ||
| 68 | - "enable": 0, | ||
| 69 | - "prof_dir": "/home/user/mindie/prof_data" | ||
| 70 | -} | ||
| 71 | -``` | ||
| 72 | - | ||
| 73 | -**调用 parse 子命令解析**: | ||
| 74 | - | ||
| 75 | -```bash | ||
| 76 | -pip install -U msserviceprofiler | ||
| 77 | -python3 -m ms_service_profiler.parse \ | ||
| 78 | - --input-path=/home/user/mindie/prof_data \ | ||
| 79 | - --output-path=/home/user/mindie/prof_parsed | ||
| 80 | -``` | ||
| 81 | - | ||
| 82 | -**产物**: | ||
| 83 | - | ||
| 84 | -- `prof_parsed/analysis.db`:SQLite 数据库,可直接被 MindStudio Insight 导入 | ||
| 85 | -- `prof_parsed/rank*/request_*.csv`:每个 rank 的请求级数据 | ||
| 86 | -- `prof_parsed/rank*/batch_*.csv`:Batch 级数据 | ||
| 87 | -- `prof_parsed/rank*/kvcache_*.csv`:KV Cache 数据 | ||
| 88 | - | ||
| 89 | ---- | ||
| 90 | - | ||
| 91 | -### 步骤 2:用 MindStudio Insight 看 Summary + Timeline 定位根因 | ||
| 92 | - | ||
| 93 | -启动 Insight 并导入 `analysis.db`: | ||
| 94 | - | ||
| 95 | -#### 2.1 Summary 页面:先看宏观指标 | ||
| 96 | - | ||
| 97 | -进入 **Summary** 页面,重点看三个视图: | ||
| 98 | - | ||
| 99 | -1. **端到端性能折线图**:TTFT / TPOT / 吞吐随时间变化,能看到"周期性尖峰" | ||
| 100 | -2. **Batch 数据统计**:每个 batch 的 seq_cnt、max_len、min_len、batch_time 分布 | ||
| 101 | -3. **Request 长度分布**:prompt_len 的直方图(确认是真实的长尾分布,不是异常配置导致) | ||
| 102 | - | ||
| 103 | -**关键观察**:在 Summary 上能直观看到 **batch 耗时(batch_time)与 batch 内长度比(len_ratio)呈强正相关**——大部分 batch 耗时 < 50ms,少量 batch 耗时飙到 150-180ms,**这些离群点正好对应长度比 > 16 的 batch**。 | ||
| 104 | - | ||
| 105 | -#### 2.2 Timeline 页面:选典型 batch 对比 | ||
| 106 | - | ||
| 107 | -进入 **Timeline** 页面,先在 batch 列表里挑两个极端样本: | ||
| 108 | - | ||
| 109 | -- **坏 batch:b-15892**(seq_cnt=8,max_len=4096,min_len=64,**len_ratio=64**) | ||
| 110 | -- **好 batch:b-16301**(seq_cnt=6,max_len=512,min_len=256,**len_ratio=2**) | ||
| 111 | - | ||
| 112 | -把这两个 batch 的时间区间(各取 ~500ms 窗口)放大对比。 | ||
| 113 | - | ||
| 114 | -**预期看到**(**图 1:bad batch b-15892 timeline**): | ||
| 115 | - | ||
| 116 | -<div align="center"><img src="../figures/bad_batch_timeline.png" /></div> | ||
| 117 | - | ||
| 118 | -- 8 个序列同处一个 decode 步:1 个长请求(prompt=4096)正在做 Prefill(黄绿色长条带,跨度约 140ms),其余 7 个短请求被 stall | ||
| 119 | -- 整批 Decode step 的算子条带**全部被拉成 ~180ms**,所有算子(FlashAttention、MLP、RMSNorm 等)几乎"无边界"地首尾相连 | ||
| 120 | -- 没有任何一个 Decode step 落在 30ms 正常区间 | ||
| 121 | -- 算子条带之间没有清晰的分隔,呈现"被压平"的形态 | ||
| 122 | - | ||
| 123 | -**对比看**(**图 2:good batch b-16301 timeline**): | ||
| 124 | - | ||
| 125 | -<div align="center"><img src="../figures/good_batch_timeline.png" /></div> | ||
| 126 | - | ||
| 127 | -- 6 个序列长度相近(256-512 tokens),都在 Decode 阶段,没有 Prefill 干扰 | ||
| 128 | -- 每个 Decode step 时长约 **32ms**,算子条带边界清晰 | ||
| 129 | -- 算子和算子之间有明显的微小 gap(host 调度开销),呈现"健康"的条带节奏 | ||
| 130 | -- Decode step 之间也存在自然间隔(因为 batch 在等下一轮新请求或 KV 分配) | ||
| 131 | - | ||
| 132 | ---- | ||
| 133 | - | ||
| 134 | -## 【问题根因】 | ||
| 135 | - | ||
| 136 | -**根因类型**:框架适配错误(MindIE-LLM 1.0.RC2 的调度器未对请求长度做充分分桶/排序) | ||
| 137 | - | ||
| 138 | -## 【定位方法论总结】 | ||
| 139 | - | ||
| 140 | -1. **步骤 1:msServiceProfiler 采集 + 解析** | ||
| 141 | - - 写配置(enable=1, acl_task_time=1, data_frame=1)→ 启动服务 → 60s 业务采样 → 关闭 → `ms_service_profiler.parse` 解析 | ||
| 142 | - - 产物 `analysis.db` 是后续所有分析的数据源 | ||
| 143 | - | ||
| 144 | -2. **步骤 2:MindStudio Insight 宏观 + 微观对比** | ||
| 145 | - - **Summary 页面**:先看 batch_time 分布,挑出离群点(> 100ms 的 batch),同时看 len_ratio 分布,找到两者相关性 | ||
| 146 | - - **Timeline 页面**:从离群 batch 中挑典型(坏样本 len_ratio > 16),再挑一个正常 batch(len_ratio < 4)做**直接对比** | ||
| 147 | - - 坏 batch 的典型特征:1 个超长 Prefill 主导整批、Decode step 全部被拉成 ~180ms、算子条带首尾相连无边界 | ||
| 148 | - - 好 batch 的典型特征:Decode step 节奏稳定(~32ms/拍)、算子条带边界清晰、host 调度有规律 | ||
| @@ -1,12 +1,14 @@ | |||
| 1 | -# 一、问题背景 | 1 | +# 代码高耗时函数段优化 |
| 2 | + | ||
| 3 | +## 1. 问题背景 | ||
| 2 | 4 | ||
| 3 | 在NPU业务执行过程中,业务执行时间不及预期,通过采集profiling数据确认,部分算子执行较慢,需对算子或操作做相关优化修改。 | 5 | 在NPU业务执行过程中,业务执行时间不及预期,通过采集profiling数据确认,部分算子执行较慢,需对算子或操作做相关优化修改。 |
| 4 | 6 | ||
| 5 | -# 二、问题来源 | 7 | +## 2. 问题来源 |
| 6 | 8 | ||
| 7 | 性能调优 | 9 | 性能调优 |
| 8 | 10 | ||
| 9 | -# 三、问题现象 | 11 | +## 3. 问题现象 |
| 10 | 12 | ||
| 11 | 通过insight打开msprof.json或者trace_view.json。可观察到某些算子的执行时间较长。打开op_statistic.csv,检查对应算子,确认算子性能不符合预期,执行时间较长,存在优化收益。 | 13 | 通过insight打开msprof.json或者trace_view.json。可观察到某些算子的执行时间较长。打开op_statistic.csv,检查对应算子,确认算子性能不符合预期,执行时间较长,存在优化收益。 |
| 12 | 14 | ||
| @@ -14,7 +16,7 @@ | |||
| 14 | 16 | ||
| 15 |  | 17 |  |
| 16 | 18 | ||
| 17 | -# 四、定位过程 | 19 | +## 4. 定位过程 |
| 18 | 20 | ||
| 19 | 类似的优化方向可以分两方面 | 21 | 类似的优化方向可以分两方面 |
| 20 | 22 | ||
| @@ -66,16 +68,16 @@ def run(): | |||
| 66 | 68 | ||
| 67 |  | 69 |  |
| 68 | 70 | ||
| 69 | -# 五、问题根因 | 71 | +## 5. 问题根因 |
| 70 | 72 | ||
| 71 | nonzero算子是深度学习框架中常用的索引类算子,核心功能是返回输入张量中非零元素的坐标索引,并按行优先顺序输出结果。是一个典型的访存密集型操作,对昇腾达芬奇架构不友好。因此,核心的替换思路就在于避免大量的访存操作。 | 73 | nonzero算子是深度学习框架中常用的索引类算子,核心功能是返回输入张量中非零元素的坐标索引,并按行优先顺序输出结果。是一个典型的访存密集型操作,对昇腾达芬奇架构不友好。因此,核心的替换思路就在于避免大量的访存操作。 |
| 72 | 74 | ||
| 73 | -# 六、定位方法总结 | 75 | +## 6. 定位方法总结 |
| 74 | 76 | ||
| 75 | 1、通过可视化工具,从流水图和算子统计表等角度确认需要优化的算子。 | 77 | 1、通过可视化工具,从流水图和算子统计表等角度确认需要优化的算子。 |
| 76 | 78 | ||
| 77 | 2、通过分析该算子的业务行为,并综合昇腾架构,将该操作转变为更合适的亲和操作,以提高性能。 | 79 | 2、通过分析该算子的业务行为,并综合昇腾架构,将该操作转变为更合适的亲和操作,以提高性能。 |
| 78 | 80 | ||
| 79 | -# 七、对工具的改进建议 | 81 | +## 7. 对工具的改进建议 |
| 80 | 82 | ||
| 81 | 暂无 | 83 | 暂无 |
| @@ -1,10 +1,10 @@ | |||
| 1 | -# 通信地址不对齐导致性能下降问题分析 | 1 | +# 通信地址不对齐导致性能下降 |
| 2 | 2 | ||
| 3 | -## 问题背景 | 3 | +## 1. 问题背景 |
| 4 | 4 | ||
| 5 | 某大模型训练场景中,使用 8 卡 Ascend 910B 进行分布式训练,模型参数量约 70B。训练过程中发现单 step 耗时远超预期,怀疑存在通信瓶颈,需通过 profiling 工具定位具体原因。 | 5 | 某大模型训练场景中,使用 8 卡 Ascend 910B 进行分布式训练,模型参数量约 70B。训练过程中发现单 step 耗时远超预期,怀疑存在通信瓶颈,需通过 profiling 工具定位具体原因。 |
| 6 | 6 | ||
| 7 | -## 问题现象 | 7 | +## 2. 问题现象 |
| 8 | 8 | ||
| 9 | 稳定复现。8 卡训练时,单 step 通信耗时占比超过 40%,且 AllReduce 算子耗时波动较大,部分 step 的通信耗时是其他 step 的 2~3 倍。单卡推理正常,排除计算瓶颈。 | 9 | 稳定复现。8 卡训练时,单 step 通信耗时占比超过 40%,且 AllReduce 算子耗时波动较大,部分 step 的通信耗时是其他 step 的 2~3 倍。单卡推理正常,排除计算瓶颈。 |
| 10 | 10 | ||
| @@ -13,9 +13,9 @@ | |||
| 13 | 13 | ||
| 14 | > 计算耗时稳定在 ~320ms,通信耗时在 195ms~410ms 之间剧烈波动,说明通信链路存在异常。 | 14 | > 计算耗时稳定在 ~320ms,通信耗时在 195ms~410ms 之间剧烈波动,说明通信链路存在异常。 |
| 15 | 15 | ||
| 16 | -## 定位过程 | 16 | +## 3. 定位过程 |
| 17 | 17 | ||
| 18 | -### 1. 采集 profiling,确认通信瓶颈 | 18 | +### 3.1 采集 profiling,确认通信瓶颈 |
| 19 | 19 | ||
| 20 | 使用 `torch_npu.profiler` 采集完整训练 step 的 profiling 数据,确认通信耗时占比及具体算子。 | 20 | 使用 `torch_npu.profiler` 采集完整训练 step 的 profiling 数据,确认通信耗时占比及具体算子。 |
| 21 | 21 | ||
| @@ -50,11 +50,11 @@ with torch_npu.profiler.profile( | |||
| 50 | 50 | ||
| 51 | > 模式 B 比模式 A 多了一段 memcpy,耗时约 200ms。初步怀疑是输入 tensor 的地址或大小不符合 HCCL 的对齐要求,导致库内部先做了一次对齐拷贝。 | 51 | > 模式 B 比模式 A 多了一段 memcpy,耗时约 200ms。初步怀疑是输入 tensor 的地址或大小不符合 HCCL 的对齐要求,导致库内部先做了一次对齐拷贝。 |
| 52 | 52 | ||
| 53 | -### 2. 确认地址不对齐特征 | 53 | +### 3.2 确认地址不对齐特征 |
| 54 | 54 | ||
| 55 | 步骤 1 中 timeline 观察到的额外 memcpy 本身就是地址不对齐的典型特征——HCCL 通信库要求输入数据 128 字节对齐,未对齐时内部自动执行对齐拷贝,该操作在 timeline 中表现为 AllReduce 算子内的额外 memcpy。正常 step 中因内存分配恰好对齐,AllReduce 算子内仅有集合通信,无 memcpy。 | 55 | 步骤 1 中 timeline 观察到的额外 memcpy 本身就是地址不对齐的典型特征——HCCL 通信库要求输入数据 128 字节对齐,未对齐时内部自动执行对齐拷贝,该操作在 timeline 中表现为 AllReduce 算子内的额外 memcpy。正常 step 中因内存分配恰好对齐,AllReduce 算子内仅有集合通信,无 memcpy。 |
| 56 | 56 | ||
| 57 | -### 3. 追溯未对齐 tensor 的来源 | 57 | +### 3.3 追溯未对齐 tensor 的来源 |
| 58 | 58 | ||
| 59 | 确认地址不对齐后,需追溯产生未对齐 tensor 的上游算子。步骤 1 的采集配置中已开启 `with_stack=True`,timeline 中每个算子事件均记录了调用栈。在 chrome://tracing 中点击模式 B 的 AllReduce 算子,可查看其完整调用链: | 59 | 确认地址不对齐后,需追溯产生未对齐 tensor 的上游算子。步骤 1 的采集配置中已开启 `with_stack=True`,timeline 中每个算子事件均记录了调用栈。在 chrome://tracing 中点击模式 B 的 AllReduce 算子,可查看其完整调用链: |
| 60 | 60 | ||
| @@ -72,13 +72,13 @@ AllReduce (hccl) | |||
| 72 | 72 | ||
| 73 | > 由于 `torch.empty()` 返回的内存地址是否 128 字节对齐取决于内存分配器的当前状态,因此问题表现为随机波动——每次分配结果不同,AllReduce 耗时也跟随波动。 | 73 | > 由于 `torch.empty()` 返回的内存地址是否 128 字节对齐取决于内存分配器的当前状态,因此问题表现为随机波动——每次分配结果不同,AllReduce 耗时也跟随波动。 |
| 74 | 74 | ||
| 75 | -## 问题根因 | 75 | +## 4. 问题根因 |
| 76 | 76 | ||
| 77 | 自定义算子使用 `torch.empty()` 分配输出 tensor 内存时,未指定 `memory_format` 对齐参数,导致部分 tensor 的起始地址不满足 HCCL 通信库的 128 字节对齐要求。HCCL 内部检测到地址未对齐后,自动进行一次对齐拷贝,额外耗时约 200ms。 | 77 | 自定义算子使用 `torch.empty()` 分配输出 tensor 内存时,未指定 `memory_format` 对齐参数,导致部分 tensor 的起始地址不满足 HCCL 通信库的 128 字节对齐要求。HCCL 内部检测到地址未对齐后,自动进行一次对齐拷贝,额外耗时约 200ms。 |
| 78 | 78 | ||
| 79 | 该问题属于框架适配问题:用户未注意到 HCCL 通信库对输入数据的对齐约束。 | 79 | 该问题属于框架适配问题:用户未注意到 HCCL 通信库对输入数据的对齐约束。 |
| 80 | 80 | ||
| 81 | -## 问题结论 | 81 | +## 5. 问题结论 |
| 82 | 82 | ||
| 83 | 1. HCCL 通信库要求输入 tensor 地址 128 字节对齐,不满足时内部自动对齐拷贝,额外耗时约 200ms。 | 83 | 1. HCCL 通信库要求输入 tensor 地址 128 字节对齐,不满足时内部自动对齐拷贝,额外耗时约 200ms。 |
| 84 | 2. profiling timeline 中 AllReduce 算子内出现额外 memcpy,是通信地址不对齐的典型特征,可作为排查信号。 | 84 | 2. profiling timeline 中 AllReduce 算子内出现额外 memcpy,是通信地址不对齐的典型特征,可作为排查信号。 |
| @@ -91,14 +91,14 @@ if tensor.data_ptr() % 128 != 0: | |||
| 91 | tensor = tensor.contiguous() | 91 | tensor = tensor.contiguous() |
| 92 | ``` | 92 | ``` |
| 93 | 93 | ||
| 94 | -## 定位方法论总结 | 94 | +## 6. 定位方法论总结 |
| 95 | 95 | ||
| 96 | 1. 通信占比较高时,先通过 profiling 确认是带宽问题还是算子内部额外开销。 | 96 | 1. 通信占比较高时,先通过 profiling 确认是带宽问题还是算子内部额外开销。 |
| 97 | 2. 若 AllReduce 耗时波动大且 timeline 中存在额外 memcpy,优先排查 tensor 地址是否对齐。 | 97 | 2. 若 AllReduce 耗时波动大且 timeline 中存在额外 memcpy,优先排查 tensor 地址是否对齐。 |
| 98 | 3. 从调用栈向上追溯到产生 tensor 的上游算子,检查内存分配方式。 | 98 | 3. 从调用栈向上追溯到产生 tensor 的上游算子,检查内存分配方式。 |
| 99 | 4. 对齐问题通常表现为"随机性"——同一段代码因内存分配器状态不同而表现不一致。 | 99 | 4. 对齐问题通常表现为"随机性"——同一段代码因内存分配器状态不同而表现不一致。 |
| 100 | 100 | ||
| 101 | -## 对工具的改进建议 | 101 | +## 7. 对工具的改进建议 |
| 102 | 102 | ||
| 103 | - profiling timeline 中可在 AllReduce 等通信算子上直接标注 tensor 地址对齐状态,降低识别门槛 | 103 | - profiling timeline 中可在 AllReduce 等通信算子上直接标注 tensor 地址对齐状态,降低识别门槛 |
| 104 | - 建议增加 HCCL 通信对齐检查的自动化诊断能力,在采集数据中标注未对齐的通信算子 | 104 | - 建议增加 HCCL 通信对齐检查的自动化诊断能力,在采集数据中标注未对齐的通信算子 |
| @@ -1,14 +1,14 @@ | |||
| 1 | -# CPU Cache Miss资源冲突与受限问题分析 | 1 | +# CPU Cache Miss资源冲突与受限 |
| 2 | 2 | ||
| 3 | -## 问题背景 | 3 | +## 1. 问题背景 |
| 4 | 4 | ||
| 5 | 客户业务模型分别基于 Ascend+Kunpeng(A+K) 与 Ascend+X86(A+X) 两套架构部署运行。在同等业务负载、模型参数及硬件规格对标场景下,A+K 平台整体业务性能相较于 A+X 平台存在明显劣化,核心吞吐、延迟指标不达标。为明确性能差异根因,开展全链路性能拆解、调度溯源及底层CPU异常专项定位分析。 | 5 | 客户业务模型分别基于 Ascend+Kunpeng(A+K) 与 Ascend+X86(A+X) 两套架构部署运行。在同等业务负载、模型参数及硬件规格对标场景下,A+K 平台整体业务性能相较于 A+X 平台存在明显劣化,核心吞吐、延迟指标不达标。为明确性能差异根因,开展全链路性能拆解、调度溯源及底层CPU异常专项定位分析。 |
| 6 | 6 | ||
| 7 | -## 问题现象 | 7 | +## 2. 问题现象 |
| 8 | 8 | ||
| 9 | 对标 A+X 平台运行指标,A+K 平台业务核心性能指标全面落后,其中 TPOT(单Token耗时)、TTFT(首Token延迟) 指标劣化显著,整体推理吞吐偏低、请求延迟抖动较大,无法满足业务上线性能标准。初步排查无算子报错、无NPU计算异常、无通信链路报错,判定为宿主机CPU侧调度或系统层异常导致的整机性能瓶颈。 | 9 | 对标 A+X 平台运行指标,A+K 平台业务核心性能指标全面落后,其中 TPOT(单Token耗时)、TTFT(首Token延迟) 指标劣化显著,整体推理吞吐偏低、请求延迟抖动较大,无法满足业务上线性能标准。初步排查无算子报错、无NPU计算异常、无通信链路报错,判定为宿主机CPU侧调度或系统层异常导致的整机性能瓶颈。 |
| 10 | 10 | ||
| 11 | -## 定位过程 | 11 | +## 3. 定位过程 |
| 12 | 12 | ||
| 13 | 本次定位采用「性能拆解→集群rank对比→慢卡定位→空泡溯源→内核调度分析→PMU硬件指标佐证→方案验证」的逐层收敛思路,完整定位流程如下: | 13 | 本次定位采用「性能拆解→集群rank对比→慢卡定位→空泡溯源→内核调度分析→PMU硬件指标佐证→方案验证」的逐层收敛思路,完整定位流程如下: |
| 14 | 14 | ||
| @@ -29,13 +29,13 @@ | |||
| 29 | 6. 使用绑核操作,优化Cache Miss情况 | 29 | 6. 使用绑核操作,优化Cache Miss情况 |
| 30 | Cache Miss异常本质为多进程抢占CPU资源、上下文频繁切换导致缓存失效。基于宿主机绑核优化脚本进行CPU亲和性绑定优化,工具详情参考:[绑核脚本](../../../misc/host_analyzer/README.md)。通过将业务进程固定绑定至指定CPU核心,隔离无关进程抢占,减少CPU频繁调度切换,有效规避缓存刷新失效问题,从底层解决Cache Miss偏高的问题。 | 30 | Cache Miss异常本质为多进程抢占CPU资源、上下文频繁切换导致缓存失效。基于宿主机绑核优化脚本进行CPU亲和性绑定优化,工具详情参考:[绑核脚本](../../../misc/host_analyzer/README.md)。通过将业务进程固定绑定至指定CPU核心,隔离无关进程抢占,减少CPU频繁调度切换,有效规避缓存刷新失效问题,从底层解决Cache Miss偏高的问题。 |
| 31 | 31 | ||
| 32 | -## 问题根因 | 32 | +## 4. 问题根因 |
| 33 | 33 | ||
| 34 | 1. 直接根因:A+K平台部署环境未做CPU资源隔离,业务进程与系统其他进程抢占CPU核心资源,引发频繁的CPU上下文切换,导致CPU Cache Miss命中率严重劣化,CPU指令执行效率大幅下降。 | 34 | 1. 直接根因:A+K平台部署环境未做CPU资源隔离,业务进程与系统其他进程抢占CPU核心资源,引发频繁的CPU上下文切换,导致CPU Cache Miss命中率严重劣化,CPU指令执行效率大幅下降。 |
| 35 | 2. 传导瓶颈:CPU调度卡顿造成模型算子下发延迟、下发链路出现大量空泡,单Rank算子下发及通信任务耗时拉长。 | 35 | 2. 传导瓶颈:CPU调度卡顿造成模型算子下发延迟、下发链路出现大量空泡,单Rank算子下发及通信任务耗时拉长。 |
| 36 | 3. 集群级劣化:单节点慢卡形成集群短板,触发「多Rank等待单Rank」的集群阻塞效应,整体通信耗时占比飙升,最终造成TPOT、TTFT等核心性能指标全面劣化,低于A+X平台性能水平。 | 36 | 3. 集群级劣化:单节点慢卡形成集群短板,触发「多Rank等待单Rank」的集群阻塞效应,整体通信耗时占比飙升,最终造成TPOT、TTFT等核心性能指标全面劣化,低于A+X平台性能水平。 |
| 37 | 37 | ||
| 38 | -## 定位方法论总结 | 38 | +## 5. 定位方法论总结 |
| 39 | 39 | ||
| 40 | 针对 A+K架构性能劣化、集群Rank耗时不均、通信占比偏高、CPU空泡卡顿 类问题,可固化标准化定位流程,快速收敛根因: | 40 | 针对 A+K架构性能劣化、集群Rank耗时不均、通信占比偏高、CPU空泡卡顿 类问题,可固化标准化定位流程,快速收敛根因: |
| 41 | 41 | ||
| @@ -46,7 +46,7 @@ Cache Miss异常本质为多进程抢占CPU资源、上下文频繁切换导致 | |||
| 46 | 5. 硬件指标佐证:通过PMU性能指标采集,精准定位Cache Miss、CPU调度等底层硬件瓶颈; | 46 | 5. 硬件指标佐证:通过PMU性能指标采集,精准定位Cache Miss、CPU调度等底层硬件瓶颈; |
| 47 | 6. 专项优化验证:针对CPU抢占、缓存失效问题,通过绑核、资源隔离等手段落地优化,验证性能恢复效果。 | 47 | 6. 专项优化验证:针对CPU抢占、缓存失效问题,通过绑核、资源隔离等手段落地优化,验证性能恢复效果。 |
| 48 | 48 | ||
| 49 | -## 对工具的改进建议 | 49 | +## 6. 对工具的改进建议 |
| 50 | 50 | ||
| 51 | 结合本次全流程定位经验,对现有运维分析工具链提出优化建议,提升同类问题定位效率: | 51 | 结合本次全流程定位经验,对现有运维分析工具链提出优化建议,提升同类问题定位效率: |
| 52 | 52 | ||
| @@ -1,16 +1,16 @@ | |||
| 1 | # CPU 线程频繁切换 | 1 | # CPU 线程频繁切换 |
| 2 | 2 | ||
| 3 | -## 【问题背景】 | 3 | +## 1. 问题背景 |
| 4 | 4 | ||
| 5 | 某大模型分布式训练任务在 8 机 96 卡 NPU 服务器集群上运行,过程中发现一个稳定复现的异常现象:每个训练迭代步中,必然有某一张卡出现 Host 侧算子下发耗时过长的问题,这直接导致了集群内的快慢卡现象,进而造成整体 NPU 算力利用率不足。同时对 NPU 卡间通信链路进行了排查,各卡通信耗时指标均在正常范围内,排除通信层面的性能瓶颈。 | 5 | 某大模型分布式训练任务在 8 机 96 卡 NPU 服务器集群上运行,过程中发现一个稳定复现的异常现象:每个训练迭代步中,必然有某一张卡出现 Host 侧算子下发耗时过长的问题,这直接导致了集群内的快慢卡现象,进而造成整体 NPU 算力利用率不足。同时对 NPU 卡间通信链路进行了排查,各卡通信耗时指标均在正常范围内,排除通信层面的性能瓶颈。 |
| 6 | 6 | ||
| 7 | 从系统资源使用情况来看,整机 CPU 使用率整体偏高,但进一步拆解发现用户态实际用于业务计算的 CPU 占比偏低,内核态开销占比显著偏高,说明存在大量额外的系统调用开销。经过初步的问题排查与方向收敛,已初步判定该异常与 CPU 线程调度机制异常高度相关。 | 7 | 从系统资源使用情况来看,整机 CPU 使用率整体偏高,但进一步拆解发现用户态实际用于业务计算的 CPU 占比偏低,内核态开销占比显著偏高,说明存在大量额外的系统调用开销。经过初步的问题排查与方向收敛,已初步判定该异常与 CPU 线程调度机制异常高度相关。 |
| 8 | 8 | ||
| 9 | -## 【问题来源】 | 9 | +## 2. 问题来源 |
| 10 | 10 | ||
| 11 | 训练。 | 11 | 训练。 |
| 12 | 12 | ||
| 13 | -## 【问题现象】 | 13 | +## 3. 问题现象 |
| 14 | 14 | ||
| 15 | 稳定复现。 | 15 | 稳定复现。 |
| 16 | 16 | ||
| @@ -28,7 +28,7 @@ | |||
| 28 | 28 | ||
| 29 |  | 29 |  |
| 30 | 30 | ||
| 31 | -## 【定位过程】 | 31 | +## 4. 定位过程 |
| 32 | 32 | ||
| 33 | 1. 梳理 NPU 场景 PyTorch 模型训练关键业务流程,如下图所示: | 33 | 1. 梳理 NPU 场景 PyTorch 模型训练关键业务流程,如下图所示: |
| 34 | 34 | ||
| @@ -63,7 +63,7 @@ | |||
| 63 | 63 | ||
| 64 | 分析结果显示,线程切换和抢占事件占比偏高,反映出明显的 CPU 线程调度瓶颈。频繁的非自愿上下文切换推高了内核态 CPU 消耗,挤占了原本用于计算的用户态时间;这进一步导致 NPU 等待 CPU 完成数据准备的时延增加,最终形成 "CPU 拖慢 NPU" 的典型性能瓶颈。 | 64 | 分析结果显示,线程切换和抢占事件占比偏高,反映出明显的 CPU 线程调度瓶颈。频繁的非自愿上下文切换推高了内核态 CPU 消耗,挤占了原本用于计算的用户态时间;这进一步导致 NPU 等待 CPU 完成数据准备的时延增加,最终形成 "CPU 拖慢 NPU" 的典型性能瓶颈。 |
| 65 | 65 | ||
| 66 | -## 【问题根因】 | 66 | +## . 问题根因 |
| 67 | 67 | ||
| 68 | 系统侧运行着大量与模型训练无关的后台线程,这些线程与模型算子下发线程竞争 CPU 资源,直接导致算子下发线程发生频繁的非自愿上下文切换,可以通过 CPU 绑核来缓解这个问题。 | 68 | 系统侧运行着大量与模型训练无关的后台线程,这些线程与模型算子下发线程竞争 CPU 资源,直接导致算子下发线程发生频繁的非自愿上下文切换,可以通过 CPU 绑核来缓解这个问题。 |
| 69 | 69 | ||
| @@ -80,7 +80,7 @@ | |||
| 80 | 80 | ||
| 81 | 4. 隔离干扰进程:观测到大量 CSD 线程存在频繁的上下文切换,经确认属于 dpc(分布式文件共享系统)子线程。使用 MindStudio 提供的[自动化绑核](https://gitcode.com/Ascend/msprof/tree/master/misc/host_analyzer)工具,将 dpc 进程与训练进程分别绑定至不同的 CPU 核区间,实现资源隔离,避免相互抢占干扰。 | 81 | 4. 隔离干扰进程:观测到大量 CSD 线程存在频繁的上下文切换,经确认属于 dpc(分布式文件共享系统)子线程。使用 MindStudio 提供的[自动化绑核](https://gitcode.com/Ascend/msprof/tree/master/misc/host_analyzer)工具,将 dpc 进程与训练进程分别绑定至不同的 CPU 核区间,实现资源隔离,避免相互抢占干扰。 |
| 82 | 82 | ||
| 83 | -## 【定位方法论总结】 | 83 | +## 6. 定位方法论总结 |
| 84 | 84 | ||
| 85 | 1. 宏观现象分析(识别瓶颈层级): | 85 | 1. 宏观现象分析(识别瓶颈层级): |
| 86 | 86 | ||
| @@ -100,7 +100,7 @@ | |||
| 100 | 100 | ||
| 101 | - 定位到根因为后台线程竞争 CPU 资源导致频繁非自愿上下文切换后,提出绑核优化方案,并给出具体的绑核对象清单和注意事项(主进程绑核范围、干扰进程隔离等)。 | 101 | - 定位到根因为后台线程竞争 CPU 资源导致频繁非自愿上下文切换后,提出绑核优化方案,并给出具体的绑核对象清单和注意事项(主进程绑核范围、干扰进程隔离等)。 |
| 102 | 102 | ||
| 103 | -## 【对工具的改进建议】 | 103 | +## 7. 对工具的改进建议 |
| 104 | 104 | ||
| 105 | 1. ftrace_tools 的自动化分析能力增强: | 105 | 1. ftrace_tools 的自动化分析能力增强: |
| 106 | 106 | ||
| @@ -1,18 +1,20 @@ | |||
| 1 | -# 一、问题背景 | 1 | +# 下发性能不及预期 |
| 2 | + | ||
| 3 | +## 1. 问题背景 | ||
| 2 | 4 | ||
| 3 | 在NPU业务执行过程中,业务执行时间不及预期,通过采集profiling数据确认,下发较慢,硬件整体利用率偏低,急需问题定位和性能优化。 | 5 | 在NPU业务执行过程中,业务执行时间不及预期,通过采集profiling数据确认,下发较慢,硬件整体利用率偏低,急需问题定位和性能优化。 |
| 4 | 6 | ||
| 5 | -# 二、问题来源 | 7 | +## 2. 问题来源 |
| 6 | 8 | ||
| 7 | 性能调优 | 9 | 性能调优 |
| 8 | 10 | ||
| 9 | -# 三、问题现象 | 11 | +## 3. 问题现象 |
| 10 | 12 | ||
| 11 | 通过insight打开msprof.json或者trace_view.json。可观察到业务整体的free时间占比偏高,硬件资源利用率较低。 | 13 | 通过insight打开msprof.json或者trace_view.json。可观察到业务整体的free时间占比偏高,硬件资源利用率较低。 |
| 12 | 14 | ||
| 13 |  | 15 |  |
| 14 | 16 | ||
| 15 | -# 四、定位过程 | 17 | +## 4. 定位过程 |
| 16 | 18 | ||
| 17 | 首先,CANN层级是CANN软件栈的API下发的接口层,AscendHardware层则表示实际的算子执行层。对于整体业务来说,只有API快速下发,硬件长期高密度执行,才是较为合理的下发执行关系。而该关系可通过profiler提供的host_to_device连线进行观察。一个较为优秀的流水图,理应是存在一定倾斜角度,即代表硬件资源的高效利用。类似下图所示 | 19 | 首先,CANN层级是CANN软件栈的API下发的接口层,AscendHardware层则表示实际的算子执行层。对于整体业务来说,只有API快速下发,硬件长期高密度执行,才是较为合理的下发执行关系。而该关系可通过profiler提供的host_to_device连线进行观察。一个较为优秀的流水图,理应是存在一定倾斜角度,即代表硬件资源的高效利用。类似下图所示 |
| 18 | 20 | ||
| @@ -26,11 +28,11 @@ | |||
| 26 | 28 | ||
| 27 |  | 29 |  |
| 28 | 30 | ||
| 29 | -# 五、问题根因 | 31 | +## 5. 问题根因 |
| 30 | 32 | ||
| 31 | 问题本质是未充分利用硬件资源,导致一定程度的资源浪费。通过profiler提供的流水图,host_to_device连线关系,以及内存数据。能直观地呈现当前业务的瓶颈和资源使用情况。并为我们进一步调整业务做出指导,例如以调整batch size等形式,提高业务的整体性能。 | 33 | 问题本质是未充分利用硬件资源,导致一定程度的资源浪费。通过profiler提供的流水图,host_to_device连线关系,以及内存数据。能直观地呈现当前业务的瓶颈和资源使用情况。并为我们进一步调整业务做出指导,例如以调整batch size等形式,提高业务的整体性能。 |
| 32 | 34 | ||
| 33 | -# 六、定位方法总结 | 35 | +## 6. 定位方法总结 |
| 34 | 36 | ||
| 35 | 1、通过可视化工具,从timeline角度发现host和device侧的下发执行关系,并以此为基准锁定是下发层面亦或是执行层面引入的资源利用率低的问题。 | 37 | 1、通过可视化工具,从timeline角度发现host和device侧的下发执行关系,并以此为基准锁定是下发层面亦或是执行层面引入的资源利用率低的问题。 |
| 36 | 38 | ||
| @@ -38,6 +40,6 @@ | |||
| 38 | 40 | ||
| 39 | 3、基于“提高算子计算量”这一维度,调整batch size来增加资源使用,进一步达成业务性能调整的目标,并充分利用资源。 | 41 | 3、基于“提高算子计算量”这一维度,调整batch size来增加资源使用,进一步达成业务性能调整的目标,并充分利用资源。 |
| 40 | 42 | ||
| 41 | -# 七、对工具的改进建议 | 43 | +## 7. 对工具的改进建议 |
| 42 | 44 | ||
| 43 | 可以考虑在advisor中增加对于内存和下发瓶颈的检测,并给出相关业务参数调整的建议。 | 45 | 可以考虑在advisor中增加对于内存和下发瓶颈的检测,并给出相关业务参数调整的建议。 |
| @@ -1,87 +0,0 @@ | |||
| 1 | -# DP负载不均 | ||
| 2 | - | ||
| 3 | -## 问题背景 | ||
| 4 | - | ||
| 5 | -DP并行场景下,一个服务实例内存在多个DP域。正常情况下,请求和token负载应尽量均匀分配到各DP域;如果某个DP域持续承接更多请求或更重请求,它会先出现排队、KVCache高水位或执行耗时变长,最终拖慢整个实例。 | ||
| 6 | - | ||
| 7 | -## 问题来源 | ||
| 8 | - | ||
| 9 | -推理 | ||
| 10 | - | ||
| 11 | -## 问题现象 | ||
| 12 | - | ||
| 13 | -用户通常先看到实例整体吞吐低于预期,P95/P99时延升高,但单看实例级指标又不一定能解释原因。继续按`dp`维度拆开后,常见现象是: | ||
| 14 | - | ||
| 15 | -- 某些DP域running/waiting请求数长期高于其他DP域。 | ||
| 16 | -- 某些DP域prompt/generation token吞吐更高,或者batch size更大。 | ||
| 17 | -- 热点DP域的KVCache使用率更高,`free_kvcache_blocks`下降更快。 | ||
| 18 | -- 非热点DP域仍有空闲,但整体时延已经被热点DP域拉高。 | ||
| 19 | - | ||
| 20 | - | ||
| 21 | - | ||
| 22 | -## 定位过程 | ||
| 23 | - | ||
| 24 | -### 步骤 1:先确认是不是只有部分DP域在忙 | ||
| 25 | - | ||
| 26 | -在Grafana的DP维度负载面板中,按`dp`或`engine`维度比较同一时间窗口内的请求数、prompt token吞吐、generation token吞吐、batch大小和waiting请求数。 | ||
| 27 | - | ||
| 28 | -如果只有短时间分叉,且时延没有明显变化,可以先认为是流量抖动;如果某些DP域在多个连续窗口里持续更高,就进入下一步。 | ||
| 29 | - | ||
| 30 | -### 步骤 2:判断不均来自“请求更多”还是“请求更重” | ||
| 31 | - | ||
| 32 | -将Grafana中的请求数、prompt token吞吐和generation token吞吐放在一起看,判断热点DP域的负载来源: | ||
| 33 | - | ||
| 34 | -- 请求数更多、token数也更多:通常表示热点DP域承接了更多流量,需要结合调度策略、实例内DP分配策略或请求粘滞情况排查。 | ||
| 35 | -- 请求数接近,但prompt/generation token更多:通常表示热点DP域承接了更重请求,需要结合请求日志、压测数据集或请求长度统计确认是否存在长输入或长输出集中。 | ||
| 36 | -- 请求数和token数都接近,但某个DP域执行时间更长:需要结合设备监控、进程日志和Profiler排查该DP域对应进程、设备或通信是否异常。 | ||
| 37 | - | ||
| 38 | -这一步的结论会直接决定后续处理方式:调度偏斜要改分配策略,请求重量偏斜要按token或长度均衡,设备异常要先排查硬件/进程状态。 | ||
| 39 | - | ||
| 40 | -### 步骤 3:确认DP不均是否已经影响服务 | ||
| 41 | - | ||
| 42 | -仅DP曲线存在差异不足以判定故障,需要看热点DP域是否同时出现: | ||
| 43 | - | ||
| 44 | -- waiting请求增加或队列等待时间升高。 | ||
| 45 | -- KVCache使用率高、空闲Block更低。 | ||
| 46 | -- batch执行耗时或decode耗时高于其他DP域。 | ||
| 47 | -- 实例整体P95/P99时延在同一时间段升高。 | ||
| 48 | - | ||
| 49 | -如果这些信号同步出现,可初步判断DP负载不均已经形成瓶颈。 | ||
| 50 | - | ||
| 51 | -### 步骤 4:用离线Profiler定位具体调度差异 | ||
| 52 | - | ||
| 53 | -采集`Schedule`、`Request`、`KVCache`相关数据后,重点按`dp_rank`聚合: | ||
| 54 | - | ||
| 55 | -- 在`batch.csv`中比较各DP域的`batch_size`、`prefill_batch_size`、`decode_batch_size`、`prefill_scheduled_tokens`、`decode_scheduled_tokens`、`total_scheduled_tokens`和`during_time(ms)`。 | ||
| 56 | -- 在`request.csv`中按DP域统计请求数量、输入长度、输出长度、`queue_wait_time(ms)`和`first_token_latency(ms)`。 | ||
| 57 | -- 在`kvcache.csv`中按DP域比较`used_blocks`、`free_blocks`和`kvcache_usage_rate`。 | ||
| 58 | - | ||
| 59 | -如果某个DP域连续batch调度token更多、执行时间更长,同时请求等待和KVCache水位更高,可确认热点来自DP调度负载偏斜。 | ||
| 60 | - | ||
| 61 | -## 问题根因 | ||
| 62 | - | ||
| 63 | -DP域间承接的请求数量、token数量或执行能力不一致。常见根因包括调度策略未按token量均衡、长请求集中到部分DP域、DP进程或设备状态异常、各DP域配置不一致,或请求粘滞导致流量长期落在少数DP域。 | ||
| 64 | - | ||
| 65 | -## 解决方法 | ||
| 66 | - | ||
| 67 | -- 请求数分配不均:调整DP调度策略,避免按固定顺序或固定粘滞方式把请求集中到部分DP域。 | ||
| 68 | -- token重量不均:按输入/输出token量做均衡,或将长请求单独调度,避免只按请求个数均衡。 | ||
| 69 | -- KVCache压力集中:降低热点DP域进入调度的请求数量,或调整调度策略让不同DP域的KVCache水位更接近。 | ||
| 70 | -- 设备或进程异常:结合设备利用率、错误日志和Profiler执行耗时对比热点DP域和其他DP域,先恢复异常DP域能力。 | ||
| 71 | -- 配置不一致:检查服务启动参数和部署配置,确认各DP域模型、并行参数、显存配置一致。 | ||
| 72 | - | ||
| 73 | -处理后需要重新按DP维度观察token吞吐、waiting请求数、KVCache水位和P95/P99时延是否收敛。 | ||
| 74 | - | ||
| 75 | -## 定位方法论总结 | ||
| 76 | - | ||
| 77 | -针对DP负载不均场景,需要优先使用ms-service-metric按DP域比较请求数、prompt/generation token、waiting请求数、batch大小和KVCache水位,先判断是否存在持续热点DP域;确认在线指标存在持续分叉后,再使用msServiceProfiler按`dp_rank`聚合`request.csv`、`batch.csv`和`kvcache.csv`,区分请求数量偏斜、token重量偏斜、KVCache压力集中或设备/进程异常。 | ||
| 78 | - | ||
| 79 | -## 对工具的改进建议 | ||
| 80 | - | ||
| 81 | -### ms-service-metric | ||
| 82 | - | ||
| 83 | -当前在线监控已能按DP域比较请求量、token量、队列和KVCache水位。建议增加DP负载不均提示,在DP间差异持续扩大且实例整体P95/P99时延升高时,自动标记热点DP域。 | ||
| 84 | - | ||
| 85 | -### msServiceProfiler | ||
| 86 | - | ||
| 87 | -当前Profiler已能通过`request.csv`、`batch.csv`、`kvcache.csv`按`dp_rank`聚合分析调度差异。建议在离线报告中直接输出各DP域的请求数、输入输出token、batch调度token、执行耗时和KVCache水位对比。 | ||
| @@ -1,96 +0,0 @@ | |||
| 1 | -# EP负载不均 | ||
| 2 | - | ||
| 3 | -## 问题背景 | ||
| 4 | - | ||
| 5 | -MoE模型推理时,EP并行会把专家分布到不同Rank或Device上。请求经过路由后,如果少数专家被持续命中,对应Rank就会承担更多GroupedMatmul计算和dispatch/combine通信,形成慢卡,进而拉高整个MoE层耗时。 | ||
| 6 | - | ||
| 7 | -## 问题来源 | ||
| 8 | - | ||
| 9 | -推理 | ||
| 10 | - | ||
| 11 | -## 问题现象 | ||
| 12 | - | ||
| 13 | -用户通常先看到DeepSeek等MoE模型吞吐低于预期,decode耗时或端到端时延升高。进一步观察MoE相关指标时,可能出现: | ||
| 14 | - | ||
| 15 | -- 某些Expert热点明显高于同层其他Expert。 | ||
| 16 | -- 某些Rank在多个Layer上持续承接更高专家负载。 | ||
| 17 | -- EPLB更新后热点没有明显收敛。 | ||
| 18 | -- MoE层耗时升高,并伴随某些Rank/Device执行时间更长。 | ||
| 19 | - | ||
| 20 | - | ||
| 21 | - | ||
| 22 | -## 定位过程 | ||
| 23 | - | ||
| 24 | -### 步骤 1:先确认性能问题发生在MoE相关阶段 | ||
| 25 | - | ||
| 26 | -先确认用户侧吞吐下降或时延升高是否与MoE层执行耗时、decode阶段耗时同步。如果整体性能稳定,仅专家热点短时波动,一般不直接判定为EP故障。 | ||
| 27 | - | ||
| 28 | -如果decode耗时升高,同时MoE算子或MoE通信阶段变慢,再继续看专家负载。 | ||
| 29 | - | ||
| 30 | -### 步骤 2:判断是否存在持续专家热点 | ||
| 31 | - | ||
| 32 | -在Grafana的EPLB或专家热点面板中查看聚合热点指标,确认是不是少数专家长期更热: | ||
| 33 | - | ||
| 34 | -- `eplb:expert_hotness:current_max`是否长期明显高于`current_mean`。 | ||
| 35 | -- `eplb:expert_hotness:imbalance`是否持续偏高。 | ||
| 36 | -- 热点是否只在短时间出现,还是跨多个窗口持续存在。 | ||
| 37 | - | ||
| 38 | -这里的目标只是回答“有没有持续不均”。如果只有瞬时尖峰,而吞吐和时延没有同步恶化,可以先作为业务输入波动观察。 | ||
| 39 | - | ||
| 40 | -### 步骤 3:定位具体热点Layer、Rank和Expert | ||
| 41 | - | ||
| 42 | -确认存在持续不均后,在逐层专家明细面板中继续定位热点位置: | ||
| 43 | - | ||
| 44 | -- 找到哪个Layer下的Expert命中次数或hotness明显更高。 | ||
| 45 | -- 看热点Expert是否集中在同一个Rank或少数Rank上。 | ||
| 46 | -- 看同一个Rank是否在多个Layer上都承担更高热点。 | ||
| 47 | - | ||
| 48 | -如果热点分散在多个Rank,影响可能有限;如果热点集中在少数Rank,才更容易形成EP慢卡。 | ||
| 49 | - | ||
| 50 | -### 步骤 4:判断EPLB是否生效 | ||
| 51 | - | ||
| 52 | -结合Grafana中的EPLB更新前后热点分布、EPLB配置和服务启动参数判断负载均衡是否生效: | ||
| 53 | - | ||
| 54 | -- 如果更新后`update_max / update_mean`下降,`imbalance`下降,通常表示EPLB对热点有缓解。 | ||
| 55 | -- 如果更新后热点仍集中在同一批Expert或Rank,需要结合EPLB配置、专家映射配置和请求输入分布继续排查。 | ||
| 56 | -- 如果EPLB更新本身耗时过高,还要判断更新开销是否抵消了均衡收益。 | ||
| 57 | - | ||
| 58 | -这一步决定后续是调EPLB参数,还是排查专家映射配置、业务输入分布或路由策略。 | ||
| 59 | - | ||
| 60 | -### 步骤 5:用离线Profiler确认热点是否形成慢卡 | ||
| 61 | - | ||
| 62 | -在线指标能说明“哪个专家热”,但还需要用msServiceProfiler补充采集MoE相关算子和通信数据,确认热点是否已经拖慢执行: | ||
| 63 | - | ||
| 64 | -- 对比各Rank/Device的GroupedMatmul耗时,确认热点Rank是否计算更慢。 | ||
| 65 | -- 查看MoeDistributeDispatch、MoeDistributeCombine耗时,确认通信是否因热点放大。 | ||
| 66 | -- 在trace中看MoE层是否存在少数Rank执行更久、其他Rank等待同步的现象。 | ||
| 67 | - | ||
| 68 | -如果热点Expert、热点Rank和慢算子/慢通信出现在同一时间窗口,才能把根因收敛为EP负载不均。 | ||
| 69 | - | ||
| 70 | -## 问题根因 | ||
| 71 | - | ||
| 72 | -EP专家负载分配不均,少数Expert或Rank持续承接更高请求负载,并进一步造成MoE计算或通信慢卡。常见根因包括业务输入分布集中、EPLB未开启或参数不合理、专家映射不均、热点专家集中放置,以及个别Rank/Device执行能力异常。 | ||
| 73 | - | ||
| 74 | -## 解决方法 | ||
| 75 | - | ||
| 76 | -- EPLB未开启或不生效:开启EPLB,调整更新周期、窗口长度、迁移阈值或专家重映射策略。 | ||
| 77 | -- 热点专家集中在少数Rank:调整专家放置或映射,让热点Expert分散到更多Rank。 | ||
| 78 | -- 输入分布导致路由集中:结合请求日志或压测数据集分析业务请求类型,必要时做流量分组或输入分布隔离。 | ||
| 79 | -- 通信放大:检查dispatch/combine通信耗时,优化并行配置或通信路径,避免热点Rank同时承担更高计算和通信。 | ||
| 80 | -- 个别Rank异常慢:先排查设备状态、进程负载和算子执行异常,避免把设备问题误判为路由不均。 | ||
| 81 | - | ||
| 82 | -处理后需要观察热点分布是否收敛,MoE算子/通信耗时是否下降,decode时延和吞吐是否恢复。 | ||
| 83 | - | ||
| 84 | -## 定位方法论总结 | ||
| 85 | - | ||
| 86 | -针对EP负载不均场景,需要优先使用ms-service-metric观察MoE相关耗时、专家热点分布和EPLB更新前后是否收敛,先确认是否存在持续热点Expert或热点Rank;确认热点后,再使用msServiceProfiler采集MoE算子和通信数据,对比GroupedMatmul、dispatch/combine等耗时,判断热点是否真实形成慢卡,避免把短时输入波动或单个设备异常误判为EP负载不均。 | ||
| 87 | - | ||
| 88 | -## 对工具的改进建议 | ||
| 89 | - | ||
| 90 | -### ms-service-metric | ||
| 91 | - | ||
| 92 | -当前在线监控已能查看EPLB更新前后热点分布和专家热点指标。建议增加Layer、Rank、Expert维度的热点Top列表,直接展示热点Expert是否集中在少数Rank上。 | ||
| 93 | - | ||
| 94 | -### msServiceProfiler | ||
| 95 | - | ||
| 96 | -当前Profiler已能通过MoE算子和通信耗时确认热点是否形成慢卡。建议在离线报告中增加“热点Expert -> Rank/Device -> MoE算子耗时”的关联视图。 | ||
| @@ -1,225 +0,0 @@ | |||
| 1 | -# 框架调度下发不同步问题调优指导实例 | ||
| 2 | - | ||
| 3 | -## 场景说明 | ||
| 4 | - | ||
| 5 | -在大模型推理服务化场景中,框架侧通常需要完成请求入队、批处理调度、Host侧任务下发、Device侧执行、跨节点或跨卡同步等流程。若不同节点或不同Device的任务下发节奏不一致,可能出现快慢卡、同步等待时间异常、首Token时延抖动、吞吐下降等问题。 | ||
| 6 | - | ||
| 7 | -本文以PD分离、多节点并发推理场景为例,介绍如何使用msServiceProfiler采集调度链路数据,定位框架调度下发不同步问题,并根据一致性要求选择优化方案。 | ||
| 8 | - | ||
| 9 | -## 问题现象 | ||
| 10 | - | ||
| 11 | -**典型表现** | ||
| 12 | - | ||
| 13 | -- 多节点模型执行开始时间存在明显差异,部分节点已进入Device执行,部分节点仍停留在Host下发或调度等待阶段。 | ||
| 14 | -- 同一轮迭代中,不同Device的BatchSchedule、forward或自定义Span耗时差异明显,出现快慢卡现象。 | ||
| 15 | -- 同步点前后存在较长空洞,端到端时延中出现90ms以上的同步等待。 | ||
| 16 | -- Request_Latency_curve或First_Token_Latency_curve中P90/P99抖动明显,平均吞吐未达到预期。 | ||
| 17 | -- 在高并发下,关键调度线程被非关键线程抢占,主线程等待时间增加。 | ||
| 18 | - | ||
| 19 | -**影响范围** | ||
| 20 | - | ||
| 21 | -| 影响项 | 表现 | | ||
| 22 | -| --- | --- | | ||
| 23 | -| 首Token时延 | Prefill阶段调度等待增加,首Token P90/P99升高。 | | ||
| 24 | -| Decode吞吐 | 部分快卡等待慢卡,Decode步进被同步点拉长。 | | ||
| 25 | -| 资源利用率 | Device计算空洞增多,AI Core利用率下降。 | | ||
| 26 | -| 稳定性 | 流量波动时尾时延放大,跨节点同步更容易被慢节点拖累。 | | ||
| 27 | - | ||
| 28 | -## 数据采集 | ||
| 29 | - | ||
| 30 | -### 功能说明 | ||
| 31 | - | ||
| 32 | -使用msServiceProfiler采集框架调度、Host下发、Device执行和同步等待等关键阶段的Span、Event、Metric和Link数据,结合BatchSchedule.csv、forward.csv、Request_Latency_curve等数据判断调度下发是否同步。 | ||
| 33 | - | ||
| 34 | -### 注意事项 | ||
| 35 | - | ||
| 36 | -- 建议先在压测环境复现问题,再开启采集,避免采集范围过大影响线上服务。 | ||
| 37 | -- 多节点场景采集前需校准各节点系统时间,否则时间轴对齐结果可能存在偏差。 | ||
| 38 | -- 若需要分析Host与Device之间的下发耗时,可在配置中开启acl任务耗时相关采集项,但需注意该能力可能带来额外性能开销。 | ||
| 39 | -- 若已经使用msprof动态采集能力,不建议同时开启与其冲突的采集开关。 | ||
| 40 | - | ||
| 41 | -### 配置示例 | ||
| 42 | - | ||
| 43 | -创建ms_service_profiler_config.json,开启服务化性能数据采集。 | ||
| 44 | - | ||
| 45 | -```json | ||
| 46 | -{ | ||
| 47 | - "enable": 1, | ||
| 48 | - "prof_dir": "${HOME}/.ms_server_profiler", | ||
| 49 | - "profiler_level": "INFO", | ||
| 50 | - "acl_task_time": 1, | ||
| 51 | - "acl_prof_task_time_level": "L0" | ||
| 52 | -} | ||
| 53 | -``` | ||
| 54 | - | ||
| 55 | -设置环境变量并启动服务。 | ||
| 56 | - | ||
| 57 | -```bash | ||
| 58 | -export SERVICE_PROF_CONFIG_PATH=/path/to/ms_service_profiler_config.json | ||
| 59 | -``` | ||
| 60 | - | ||
| 61 | -### 插桩建议 | ||
| 62 | - | ||
| 63 | -在框架调度链路中对关键阶段增加Span采集。 | ||
| 64 | - | ||
| 65 | -```C++ | ||
| 66 | -auto scheduleSpan = PROF(INFO, SpanStart("FrameworkSchedule")); | ||
| 67 | - | ||
| 68 | -// 请求出队、batch构造、策略选择等调度逻辑 | ||
| 69 | - | ||
| 70 | -PROF(scheduleSpan.SpanEnd()); | ||
| 71 | - | ||
| 72 | -auto hostSubmitSpan = PROF(INFO, SpanStart("HostSubmit")); | ||
| 73 | - | ||
| 74 | -// Host侧任务下发、流绑定、通信任务提交等逻辑 | ||
| 75 | - | ||
| 76 | -PROF(hostSubmitSpan.SpanEnd()); | ||
| 77 | - | ||
| 78 | -auto deviceExecSpan = PROF(INFO, SpanStart("DeviceExecute")); | ||
| 79 | - | ||
| 80 | -// Device侧计算执行或等待执行完成 | ||
| 81 | - | ||
| 82 | -PROF(deviceExecSpan.SpanEnd()); | ||
| 83 | -``` | ||
| 84 | - | ||
| 85 | -对同步点和队列积压增加Event和Metric采集。 | ||
| 86 | - | ||
| 87 | -```C++ | ||
| 88 | -PROF(INFO, Event("BeforeGlobalSync")); | ||
| 89 | -PROF(INFO, Metric("dispatchQueueSize", queueSize).MetricScope("scheduler", rankId).Launch()); | ||
| 90 | -PROF(INFO, Metric("syncWaitMs", syncWaitMs).MetricScope("rank", rankId).Launch()); | ||
| 91 | -PROF(INFO, Event("AfterGlobalSync")); | ||
| 92 | -``` | ||
| 93 | - | ||
| 94 | -跨线程或跨模块链路可使用Link关联请求ID,避免只看到局部耗时。 | ||
| 95 | - | ||
| 96 | -```C++ | ||
| 97 | -PROF(INFO, Link("request_in_scheduler", "request_in_executor")); | ||
| 98 | -``` | ||
| 99 | - | ||
| 100 | -## 定位方法 | ||
| 101 | - | ||
| 102 | -1. 观察BatchSchedule.csv中同一批次在不同进程、不同Device上的开始时间和耗时。 | ||
| 103 | - - 若开始时间相差较大,优先排查调度线程、Host下发队列、跨节点时钟和负载均衡策略。 | ||
| 104 | - - 若开始时间接近但结束时间差异明显,优先排查Device执行、专家负载不均、通信等待或算子耗时差异。 | ||
| 105 | - | ||
| 106 | -2. 对比FrameworkSchedule、HostSubmit、DeviceExecute三个Span。 | ||
| 107 | - - FrameworkSchedule耗时长:说明框架调度本身存在瓶颈,可能是同步队列、串行事务、锁竞争或批处理策略造成。 | ||
| 108 | - - HostSubmit耗时长:说明Host侧下发能力不足,可能是单线程提交、流管理阻塞或通信任务提交串行化造成。 | ||
| 109 | - - DeviceExecute前存在空洞:说明任务已经完成调度但未及时进入Device执行,需检查Device队列、同步点和上游下发节奏。 | ||
| 110 | - | ||
| 111 | -3. 检查syncWaitMs和dispatchQueueSize指标。 | ||
| 112 | - - syncWaitMs在部分rank持续偏高,通常表示快卡等待慢卡。 | ||
| 113 | - - dispatchQueueSize周期性堆积,通常表示调度线程生产速度与执行线程消费速度不匹配。 | ||
| 114 | - - 队列不高但等待高,通常表示跨节点同步、通信或强一致性屏障成为瓶颈。 | ||
| 115 | - | ||
| 116 | -4. 结合Request_Latency_curve和First_Token_Latency_curve判断用户侧影响。 | ||
| 117 | - - 若平均值变化不大但P99明显升高,说明问题主要影响尾时延。 | ||
| 118 | - - 若平均值和P99同时升高,说明调度下发链路已成为整体瓶颈。 | ||
| 119 | - | ||
| 120 | -## 原因分析与解决方案 | ||
| 121 | - | ||
| 122 | -### 分布式调度差异导致快慢卡 | ||
| 123 | - | ||
| 124 | -**原因** | ||
| 125 | - | ||
| 126 | -在PD分离或多节点部署场景下,各节点模型执行开始时间不一致。快节点先到达同步点后等待慢节点,形成明显同步等待。 | ||
| 127 | - | ||
| 128 | -**解决方案** | ||
| 129 | - | ||
| 130 | -- 将调度策略调整为Host统一下发、Device按本地队列执行,减少不同节点之间的启动时间差。 | ||
| 131 | -- 对跨节点请求分配增加时间窗约束,避免同一批次被拆分到状态差异过大的节点。 | ||
| 132 | -- 对rank维度的HostSubmit开始时间进行监控,超过阈值时触发告警或降级策略。 | ||
| 133 | -- 在强同步阶段前增加轻量级对齐逻辑,避免局部节点过早进入等待。 | ||
| 134 | - | ||
| 135 | -### 同步调度串行化导致瓶颈 | ||
| 136 | - | ||
| 137 | -**原因** | ||
| 138 | - | ||
| 139 | -同步调度模式要求每个分区或每轮任务严格串行完成。若单分区内存在数千个任务,调度线程需要串行处理队列、事务、锁和状态更新,导致下发延迟放大。 | ||
| 140 | - | ||
| 141 | -**解决方案** | ||
| 142 | - | ||
| 143 | -- 若业务允许弱一致性,将同步调度改为异步调度,减少非必要阻塞。 | ||
| 144 | -- 若业务必须强一致性,增加调度分区数M,以更多调度资源换取更低单分区排队时间。 | ||
| 145 | -- 将调度状态拆分为请求级、批次级和设备级,降低全局锁粒度。 | ||
| 146 | -- 将耗时统计、日志落盘、低优先级状态更新从关键路径移出。 | ||
| 147 | - | ||
| 148 | -### 异步调度缺少背压控制 | ||
| 149 | - | ||
| 150 | -**原因** | ||
| 151 | - | ||
| 152 | -异步调度可以降低阻塞,但若没有队列上限、优先级和结果回收机制,可能造成任务堆积、乱序放大或尾时延恶化。 | ||
| 153 | - | ||
| 154 | -**解决方案** | ||
| 155 | - | ||
| 156 | -- 使用Future机制或双线程架构,将schedule线程和generator线程解耦。 | ||
| 157 | -- schedule线程负责批处理决策和任务提交,generator线程负责结果消费、后处理和下一轮触发。 | ||
| 158 | -- 在线程之间使用线程安全队列传递任务,并通过Event、条件变量或轻量级信号控制唤醒。 | ||
| 159 | -- 设置队列高水位和超时策略,避免异步任务无限堆积。 | ||
| 160 | - | ||
| 161 | -示例流程如下: | ||
| 162 | - | ||
| 163 | -```text | ||
| 164 | -请求入队 -> schedule线程构造batch -> HostSubmit异步下发 -> generator线程消费结果 -> 触发下一轮Decode | ||
| 165 | -``` | ||
| 166 | - | ||
| 167 | -### Pipeline调度策略不匹配 | ||
| 168 | - | ||
| 169 | -**原因** | ||
| 170 | - | ||
| 171 | -同步pipeline内存效率较好,但容易被慢阶段拖累;异步pipeline统计效率较高,但可能产生权重版本差异或结果修正成本。 | ||
| 172 | - | ||
| 173 | -**解决方案** | ||
| 174 | - | ||
| 175 | -- 对显存压力较大的场景,优先采用同步pipeline并通过动态规划优化内存调度。 | ||
| 176 | -- 对吞吐优先且可接受一定统计差异的训练或生成场景,可采用异步pipeline,并配合学习率调度、差异校正或阶段间缓冲。 | ||
| 177 | -- 对复杂依赖图,使用BSP超步同步控制全局一致性,在超步内部使用异步执行提升资源利用率。 | ||
| 178 | - | ||
| 179 | -### 线程QoS资源分配不合理 | ||
| 180 | - | ||
| 181 | -**原因** | ||
| 182 | - | ||
| 183 | -高并发下,关键调度线程、Host下发线程或结果回收线程可能被日志、监控、低优先级后处理线程抢占,导致主线程等待增加。 | ||
| 184 | - | ||
| 185 | -**解决方案** | ||
| 186 | - | ||
| 187 | -- 提升schedule线程、HostSubmit线程、通信提交线程的QoS等级。 | ||
| 188 | -- 降低日志、周期性监控、统计聚合等非关键线程优先级。 | ||
| 189 | -- 将关键线程绑定到稳定CPU核,减少线程迁移。 | ||
| 190 | -- 使用Metric采集关键线程队列长度、唤醒间隔和同步等待时间,评估QoS调整收益。 | ||
| 191 | - | ||
| 192 | -## 优化验证 | ||
| 193 | - | ||
| 194 | -优化后重新采集相同压测流量下的性能数据,并对比以下指标。 | ||
| 195 | - | ||
| 196 | -| 指标 | 期望结果 | | ||
| 197 | -| --- | --- | | ||
| 198 | -| FrameworkSchedule耗时 | 平均值下降,P99抖动收敛。 | | ||
| 199 | -| HostSubmit开始时间差 | 不同rank之间的开始时间差缩小。 | | ||
| 200 | -| syncWaitMs | 同步等待明显下降,快慢卡差异减少。 | | ||
| 201 | -| Request_Latency_curve | 端到端时延P90/P99下降。 | | ||
| 202 | -| First_Token_Latency_curve | 首Token尾时延下降。 | | ||
| 203 | -| Device利用率 | 计算空洞减少,利用率提升。 | | ||
| 204 | - | ||
| 205 | -若优化后同步等待仍较高,建议继续从以下方向排查: | ||
| 206 | - | ||
| 207 | -- 检查各节点系统时间是否同步。 | ||
| 208 | -- 检查网络通信耗时是否在同步点前后放大。 | ||
| 209 | -- 检查某些Device是否存在算子耗时异常或专家负载不均。 | ||
| 210 | -- 检查调度分区数M是否不足。 | ||
| 211 | -- 检查异步队列是否出现反压或结果回收不及时。 | ||
| 212 | - | ||
| 213 | -## 推荐处理策略 | ||
| 214 | - | ||
| 215 | -| 业务要求 | 推荐方案 | | ||
| 216 | -| --- | --- | | ||
| 217 | -| 允许弱一致性 | 优先采用异步调度,使用Future机制或双线程架构降低关键路径同步。 | | ||
| 218 | -| 要求强一致性 | 保留同步屏障,增加调度分区数M,优化Host统一下发和Device执行对齐。 | | ||
| 219 | -| 跨节点快慢卡明显 | 重点优化分布式调度策略,缩小各rank HostSubmit和DeviceExecute开始时间差。 | | ||
| 220 | -| 复杂依赖场景 | 使用BSP超步同步控制一致性,超步内部结合工作窃取或局部异步执行。 | | ||
| 221 | -| 高并发尾时延异常 | 调整关键线程QoS,拆分全局锁,增加队列背压和优先级控制。 | | ||
| 222 | - | ||
| 223 | -## 总结 | ||
| 224 | - | ||
| 225 | -框架调度下发不同步的核心矛盾在于同步机制的严格性与性能需求之间的冲突。定位时应先通过msServiceProfiler把调度链路拆分为FrameworkSchedule、HostSubmit、DeviceExecute和SyncWait等阶段,再结合BatchSchedule、Request_Latency和First_Token_Latency判断瓶颈位置。优化时需根据业务一致性要求选择方案:弱一致性场景优先异步化,强一致性场景优先优化分布式下发、增加调度分区并缩小rank间启动差异。 | ||
| @@ -1,16 +1,16 @@ | |||
| 1 | # GIL锁抢占问题分析 | 1 | # GIL锁抢占问题分析 |
| 2 | 2 | ||
| 3 | -## 问题背景 | 3 | +## 1. 问题背景 |
| 4 | 4 | ||
| 5 | Python 语言存在全局解释器锁(GIL)核心机制,该机制限制同一时刻仅有一个线程可占用 GIL 锁并执行 Python 字节码,无法实现多线程真正并行执行计算任务。 | 5 | Python 语言存在全局解释器锁(GIL)核心机制,该机制限制同一时刻仅有一个线程可占用 GIL 锁并执行 Python 字节码,无法实现多线程真正并行执行计算任务。 |
| 6 | 本次客户业务模型基于 Python 开发,业务逻辑中大量采用多线程架构,并行执行算子下发、数据内存搬运、任务调度等高频操作。在多线程并发场景下,多个业务线程会持续竞争唯一的 GIL 锁,频繁触发锁抢占、线程阻塞、上下文切换等行为。尤其存在线程长期持有 GIL 锁不及时释放的异常场景时,会进一步加剧线程调度不均、有效算力利用率降低的问题,最终导致模型整体运行性能损耗。 | 6 | 本次客户业务模型基于 Python 开发,业务逻辑中大量采用多线程架构,并行执行算子下发、数据内存搬运、任务调度等高频操作。在多线程并发场景下,多个业务线程会持续竞争唯一的 GIL 锁,频繁触发锁抢占、线程阻塞、上下文切换等行为。尤其存在线程长期持有 GIL 锁不及时释放的异常场景时,会进一步加剧线程调度不均、有效算力利用率降低的问题,最终导致模型整体运行性能损耗。 |
| 7 | 7 | ||
| 8 | -## 问题现象 | 8 | +## 2. 问题现象 |
| 9 | 9 | ||
| 10 | 客户原有 Python 模型业务迁移至 Ascend 平台部署运行后,整体性能未达到预期指标,运行耗时偏高、任务吞吐率不足。 | 10 | 客户原有 Python 模型业务迁移至 Ascend 平台部署运行后,整体性能未达到预期指标,运行耗时偏高、任务吞吐率不足。 |
| 11 | 初步业务排查确认,客户业务无算子报错、无数据异常、无硬件资源瓶颈,结合业务代码特征排查发现,业务核心链路存在大量多线程并发操作,初步判定存在 Python 多线程 GIL 锁抢占异常导致的性能瓶颈。 | 11 | 初步业务排查确认,客户业务无算子报错、无数据异常、无硬件资源瓶颈,结合业务代码特征排查发现,业务核心链路存在大量多线程并发操作,初步判定存在 Python 多线程 GIL 锁抢占异常导致的性能瓶颈。 |
| 12 | 12 | ||
| 13 | -## 定位过程 | 13 | +## 3. 定位过程 |
| 14 | 14 | ||
| 15 | 为精准定位 GIL 锁抢占、持有、释放的异常代码位点及线程行为,本次采用自研 gil_tracer 工具开展专项数据分析,完整定位流程如下: | 15 | 为精准定位 GIL 锁抢占、持有、释放的异常代码位点及线程行为,本次采用自研 gil_tracer 工具开展专项数据分析,完整定位流程如下: |
| 16 | 16 | ||
| @@ -18,13 +18,13 @@ Python 语言存在全局解释器锁(GIL)核心机制,该机制限制同 | |||
| 18 | 2. 数据联合分析:将 gil_trace 锁行为数据与业务 Profiler 性能数据进行交叉比对、关联分析,匹配线程运行耗时、CPU 占用、任务阻塞时段与 GIL 锁状态的对应关系。 | 18 | 2. 数据联合分析:将 gil_trace 锁行为数据与业务 Profiler 性能数据进行交叉比对、关联分析,匹配线程运行耗时、CPU 占用、任务阻塞时段与 GIL 锁状态的对应关系。 |
| 19 | 3. 异常位点锁定:通过数据分析精准识别异常行为:部分业务线程执行逻辑中,长时间占用 GIL 锁未主动释放,导致其余就绪线程持续处于锁等待阻塞状态,无法正常调度执行,形成严重的线程调度瓶颈,最终定位出引发性能问题的核心代码逻辑。 | 19 | 3. 异常位点锁定:通过数据分析精准识别异常行为:部分业务线程执行逻辑中,长时间占用 GIL 锁未主动释放,导致其余就绪线程持续处于锁等待阻塞状态,无法正常调度执行,形成严重的线程调度瓶颈,最终定位出引发性能问题的核心代码逻辑。 |
| 20 | 20 | ||
| 21 | -## 问题根因 | 21 | +## 4. 问题根因 |
| 22 | 22 | ||
| 23 | 1. 机制层面固有瓶颈:Python GIL 锁单时刻单线程执行的特性,决定了纯 Python 多线程无法利用多核并行算力,高并发多线程场景下天然存在锁竞争开销。 | 23 | 1. 机制层面固有瓶颈:Python GIL 锁单时刻单线程执行的特性,决定了纯 Python 多线程无法利用多核并行算力,高并发多线程场景下天然存在锁竞争开销。 |
| 24 | 2. 业务代码实现缺陷(核心根因):客户业务多线程逻辑设计存在不合理性,部分工作线程在执行耗时逻辑期间,长期占用 GIL 锁不主动释放,无合理的锁释放、线程让出机制。 | 24 | 2. 业务代码实现缺陷(核心根因):客户业务多线程逻辑设计存在不合理性,部分工作线程在执行耗时逻辑期间,长期占用 GIL 锁不主动释放,无合理的锁释放、线程让出机制。 |
| 25 | 3. 连锁性能影响:异常持锁行为导致其他业务线程持续抢锁失败、长时间阻塞等待,线程调度优先级失衡、上下文切换频繁,大量算力浪费在锁竞争与线程等待中,最终造成模型整体运行效率大幅下降,迁移后性能不达标。 | 25 | 3. 连锁性能影响:异常持锁行为导致其他业务线程持续抢锁失败、长时间阻塞等待,线程调度优先级失衡、上下文切换频繁,大量算力浪费在锁竞争与线程等待中,最终造成模型整体运行效率大幅下降,迁移后性能不达标。 |
| 26 | 26 | ||
| 27 | -## 定位方法论总结 | 27 | +## 5. 定位方法论总结 |
| 28 | 28 | ||
| 29 | 针对 Python 多线程架构模型迁移、性能退化、吞吐偏低 的场景,可固化标准化定位流程,快速排查 GIL 锁性能问题: | 29 | 针对 Python 多线程架构模型迁移、性能退化、吞吐偏低 的场景,可固化标准化定位流程,快速排查 GIL 锁性能问题: |
| 30 | 30 | ||
| @@ -33,7 +33,7 @@ Python 语言存在全局解释器锁(GIL)核心机制,该机制限制同 | |||
| 33 | 3. 联合分析:结合 Profiler 性能数据,关联锁行为与耗时瓶颈,区分正常锁竞争与异常持锁、死等待场景; | 33 | 3. 联合分析:结合 Profiler 性能数据,关联锁行为与耗时瓶颈,区分正常锁竞争与异常持锁、死等待场景; |
| 34 | 4. 精准定位:锁定长期持锁、频繁抢锁、线程阻塞严重的异常代码片段,指导业务代码优化。 | 34 | 4. 精准定位:锁定长期持锁、频繁抢锁、线程阻塞严重的异常代码片段,指导业务代码优化。 |
| 35 | 35 | ||
| 36 | -## 对工具的改进建议 | 36 | +## 6. 对工具的改进建议 |
| 37 | 37 | ||
| 38 | 当前 gil_tracer 工具可完整采集 GIL 锁行为数据,但线程识别维度不足,为进一步提升问题定位效率,提出优化建议: | 38 | 当前 gil_tracer 工具可完整采集 GIL 锁行为数据,但线程识别维度不足,为进一步提升问题定位效率,提出优化建议: |
| 39 | 39 | ||
| @@ -1,16 +1,16 @@ | |||
| 1 | -# IR中断打断问题分析 | 1 | +# IRQ中断打断问题分析 |
| 2 | 2 | ||
| 3 | -## 问题背景 | 3 | +## 1. 问题背景 |
| 4 | 4 | ||
| 5 | 中断是Linux系统核心异步响应机制,可强制打断当前CPU正在执行的进程任务,优先处理硬件设备紧急事件,是系统响应外设请求、完成设备交互、实现任务调度的基础能力。正常频次的中断处理不会影响业务稳态运行,但若中断触发过于频繁、处理耗时不合理,会持续抢占业务CPU时间片,破坏任务执行连续性。 | 5 | 中断是Linux系统核心异步响应机制,可强制打断当前CPU正在执行的进程任务,优先处理硬件设备紧急事件,是系统响应外设请求、完成设备交互、实现任务调度的基础能力。正常频次的中断处理不会影响业务稳态运行,但若中断触发过于频繁、处理耗时不合理,会持续抢占业务CPU时间片,破坏任务执行连续性。 |
| 6 | 在Ascend平台模型推理、训练业务场景中,Host侧负责算子队列管理与任务下发,NPU负责计算任务执行。业务运行过程中,底层硬件驱动会通过专属中断信号同步任务状态:算子入队下发时触发sq_send_trigger_irq中断,算子执行完成、队列状态更新时触发cq_update_irq中断。两类中断由系统内核调度处理,若中断触发频次过高、CPU中断负载不均衡,会持续打断模型算子下发、数据搬运等核心业务线程,造成下发流程卡顿、流水线空泡、任务堆积,最终拖累整机及集群业务性能。 | 6 | 在Ascend平台模型推理、训练业务场景中,Host侧负责算子队列管理与任务下发,NPU负责计算任务执行。业务运行过程中,底层硬件驱动会通过专属中断信号同步任务状态:算子入队下发时触发sq_send_trigger_irq中断,算子执行完成、队列状态更新时触发cq_update_irq中断。两类中断由系统内核调度处理,若中断触发频次过高、CPU中断负载不均衡,会持续打断模型算子下发、数据搬运等核心业务线程,造成下发流程卡顿、流水线空泡、任务堆积,最终拖累整机及集群业务性能。 |
| 7 | 7 | ||
| 8 | -## 问题现象 | 8 | +## 2. 问题现象 |
| 9 | 9 | ||
| 10 | 客户业务基于 Ascend+Kunpeng(A+K) 平台部署运行,对标 Ascend+X86(A+X) 平台,业务整体吞吐、延迟等核心性能指标存在明显劣化,无法达到预期性能标准。 | 10 | 客户业务基于 Ascend+Kunpeng(A+K) 平台部署运行,对标 Ascend+X86(A+X) 平台,业务整体吞吐、延迟等核心性能指标存在明显劣化,无法达到预期性能标准。 |
| 11 | 经初步全维度排查,排除算子执行异常、NPU计算瓶颈、内存泄漏、网络通信异常、环境配置错误、驱动故障等常规问题。通过系统资源监控与内核状态观测发现:A+K平台部分CPU核心中断次数异常偏高,大量系统资源消耗在硬件中断处理流程中,持续抢占业务算力资源。该异常导致单节点算子下发调度受阻、出现明显慢卡节点,在多卡集群场景下形成“快等慢”的短板效应,拖累整体集群吞吐性能,最终造成A+K平台整体性能显著弱于A+X平台。 | 11 | 经初步全维度排查,排除算子执行异常、NPU计算瓶颈、内存泄漏、网络通信异常、环境配置错误、驱动故障等常规问题。通过系统资源监控与内核状态观测发现:A+K平台部分CPU核心中断次数异常偏高,大量系统资源消耗在硬件中断处理流程中,持续抢占业务算力资源。该异常导致单节点算子下发调度受阻、出现明显慢卡节点,在多卡集群场景下形成“快等慢”的短板效应,拖累整体集群吞吐性能,最终造成A+K平台整体性能显著弱于A+X平台。 |
| 12 | 12 | ||
| 13 | -## 定位过程 | 13 | +## 3. 定位过程 |
| 14 | 14 | ||
| 15 | 为精准定位高频中断的触发类型、负载分布、耗时时段及对业务的影响,本次采用内核调度采集工具联合业务性能剖析工具,开展多维度数据关联分析,逐层收敛问题根因,完整定位流程如下: | 15 | 为精准定位高频中断的触发类型、负载分布、耗时时段及对业务的影响,本次采用内核调度采集工具联合业务性能剖析工具,开展多维度数据关联分析,逐层收敛问题根因,完整定位流程如下: |
| 16 | 16 | ||
| @@ -26,7 +26,7 @@ | |||
| 26 | 针对本次定位的CPU中断负载不均、单核心中断过载、业务线程被频繁打断的核心问题,采用CPU绑核优化方案,工具详情参考:[绑核脚本](../../../misc/host_analyzer/README.md)。 | 26 | 针对本次定位的CPU中断负载不均、单核心中断过载、业务线程被频繁打断的核心问题,采用CPU绑核优化方案,工具详情参考:[绑核脚本](../../../misc/host_analyzer/README.md)。 |
| 27 | 通过绑核工具配置CPU亲和性,实现业务进程与中断任务的核隔离:将模型算子下发、数据搬运等核心业务线程绑定至指定空闲CPU核心,同时将高频硬件中断(sq_send_trigger_irq、cq_update_irq)进行中断亲和性配置,分散至其他CPU核心处理。彻底解决单CPU核心同时承载大量中断任务与核心业务任务导致的资源抢占问题,避免业务线程被高频中断频繁打断,保障算子下发流程的连续性。 | 27 | 通过绑核工具配置CPU亲和性,实现业务进程与中断任务的核隔离:将模型算子下发、数据搬运等核心业务线程绑定至指定空闲CPU核心,同时将高频硬件中断(sq_send_trigger_irq、cq_update_irq)进行中断亲和性配置,分散至其他CPU核心处理。彻底解决单CPU核心同时承载大量中断任务与核心业务任务导致的资源抢占问题,避免业务线程被高频中断频繁打断,保障算子下发流程的连续性。 |
| 28 | 28 | ||
| 29 | -## 问题根因 | 29 | +## 4. 问题根因 |
| 30 | 30 | ||
| 31 | 1. 硬件交互固有中断机制 | 31 | 1. 硬件交互固有中断机制 |
| 32 | Ascend平台Host与NPU通过中断机制完成任务下发、状态同步,sq_send_trigger_irq、cq_update_irq为模型运行必备的硬件交互中断,业务高并发下发场景下,中断触发频次会天然升高,存在固有调度开销。 | 32 | Ascend平台Host与NPU通过中断机制完成任务下发、状态同步,sq_send_trigger_irq、cq_update_irq为模型运行必备的硬件交互中断,业务高并发下发场景下,中断触发频次会天然升高,存在固有调度开销。 |
| @@ -37,7 +37,7 @@ A+K平台默认中断调度策略未做针对性优化,两类核心业务中 | |||
| 37 | 4. 连锁集群性能劣化 | 37 | 4. 连锁集群性能劣化 |
| 38 | 单点CPU中断过载引发节点下发卡顿、慢卡问题,在多卡集群并行场景下,形成全局性能短板,所有正常Rank需等待慢卡节点完成任务同步,大幅拉高集群整体通信等待耗时与推理延迟,降低业务吞吐能力。 | 38 | 单点CPU中断过载引发节点下发卡顿、慢卡问题,在多卡集群并行场景下,形成全局性能短板,所有正常Rank需等待慢卡节点完成任务同步,大幅拉高集群整体通信等待耗时与推理延迟,降低业务吞吐能力。 |
| 39 | 39 | ||
| 40 | -## 定位方法论总结 | 40 | +## 5. 定位方法论总结 |
| 41 | 41 | ||
| 42 | 针对Ascend平台模型业务出现的性能对标劣化、集群快慢卡差异、算子下发卡顿、CPU内核开销偏高等疑似中断干扰问题,可固化标准化定位流程,快速排查IR中断异常瓶颈: | 42 | 针对Ascend平台模型业务出现的性能对标劣化、集群快慢卡差异、算子下发卡顿、CPU内核开销偏高等疑似中断干扰问题,可固化标准化定位流程,快速排查IR中断异常瓶颈: |
| 43 | 43 | ||
| @@ -50,7 +50,7 @@ A+K平台默认中断调度策略未做针对性优化,两类核心业务中 | |||
| 50 | 4. 精准定位优化方向 | 50 | 4. 精准定位优化方向 |
| 51 | 锁定中断过载的CPU热点核心、高频异常中断类型,确认是否存在负载不均衡、调度策略不适配等问题,针对性开展中断亲和性、绑核、调度参数调优。 | 51 | 锁定中断过载的CPU热点核心、高频异常中断类型,确认是否存在负载不均衡、调度策略不适配等问题,针对性开展中断亲和性、绑核、调度参数调优。 |
| 52 | 52 | ||
| 53 | -## 对工具的改进建议 | 53 | +## 6. 对工具的改进建议 |
| 54 | 54 | ||
| 55 | 当前ftrace工具可完整采集中断触发、CPU调度基础数据,但针对昇腾平台业务中断的专项分析能力不足,人工筛选、关联成本较高,为提升同类问题定位效率,提出以下优化建议: | 55 | 当前ftrace工具可完整采集中断触发、CPU调度基础数据,但针对昇腾平台业务中断的专项分析能力不足,人工筛选、关联成本较高,为提升同类问题定位效率,提出以下优化建议: |
| 56 | 56 | ||
| @@ -1,16 +1,16 @@ | |||
| 1 | -# 内核进程频繁切换问题分析 | 1 | +# 内核进程频繁切换 |
| 2 | 2 | ||
| 3 | -## 问题背景 | 3 | +## 1. 问题背景 |
| 4 | 4 | ||
| 5 | Linux操作系统基于时间片轮转、进程优先级调度机制实现线程调度,系统内核会根据CPU时间片耗尽、任务唤醒、资源竞争、中断触发等场景主动触发线程上下文切换。正常合理的线程切换是系统多任务并发运行的基础,切换频次处于合理区间时不会影响业务稳态性能。 | 5 | Linux操作系统基于时间片轮转、进程优先级调度机制实现线程调度,系统内核会根据CPU时间片耗尽、任务唤醒、资源竞争、中断触发等场景主动触发线程上下文切换。正常合理的线程切换是系统多任务并发运行的基础,切换频次处于合理区间时不会影响业务稳态性能。 |
| 6 | 本次客户业务模型基于Linux系统+昇腾平台部署运行,业务核心包含海量轻量任务调度、高频短时计算、多线程轮询监听、数据异步处理等高并发业务场景。业务运行过程中,系统存在大量内核态、用户态线程频繁抢占调度行为,引发超高频率的线程上下文切换。尤其存在时间片分配过小、线程数量过载、任务频繁唤醒与休眠、调度优先级不合理等异常场景时,会极大消耗CPU算力在上下文保存、寄存器读写、调度队列更新等冗余操作上,大幅挤占业务有效计算算力,造成系统调度开销激增、业务执行连续性断裂,最终导致模型整体运行性能严重损耗。 | 6 | 本次客户业务模型基于Linux系统+昇腾平台部署运行,业务核心包含海量轻量任务调度、高频短时计算、多线程轮询监听、数据异步处理等高并发业务场景。业务运行过程中,系统存在大量内核态、用户态线程频繁抢占调度行为,引发超高频率的线程上下文切换。尤其存在时间片分配过小、线程数量过载、任务频繁唤醒与休眠、调度优先级不合理等异常场景时,会极大消耗CPU算力在上下文保存、寄存器读写、调度队列更新等冗余操作上,大幅挤占业务有效计算算力,造成系统调度开销激增、业务执行连续性断裂,最终导致模型整体运行性能严重损耗。 |
| 7 | 7 | ||
| 8 | -## 问题现象 | 8 | +## 2. 问题现象 |
| 9 | 9 | ||
| 10 | 客户核心业务服务部署至服务器硬件及昇腾平台运行后,出现运行延迟波动大、任务吞吐不稳定、实时响应超时、CPU有效算力利用率偏低、系统sys开销偏高等性能不达标问题。 | 10 | 客户核心业务服务部署至服务器硬件及昇腾平台运行后,出现运行延迟波动大、任务吞吐不稳定、实时响应超时、CPU有效算力利用率偏低、系统sys开销偏高等性能不达标问题。 |
| 11 | 经过初步业务排查,确认业务无代码报错、无算子执行异常、无内存泄漏、无硬件资源满载瓶颈,排除业务逻辑、数据链路、环境配置、驱动适配、硬件故障等常规性能问题。结合系统运行监控特征分析,发现系统全局线程上下文切换次数异常暴涨、内核态CPU占用占比过高、任务就绪队列堆积,初步判定为内核线程频繁切换引发的业务性能瓶颈。 | 11 | 经过初步业务排查,确认业务无代码报错、无算子执行异常、无内存泄漏、无硬件资源满载瓶颈,排除业务逻辑、数据链路、环境配置、驱动适配、硬件故障等常规性能问题。结合系统运行监控特征分析,发现系统全局线程上下文切换次数异常暴涨、内核态CPU占用占比过高、任务就绪队列堆积,初步判定为内核线程频繁切换引发的业务性能瓶颈。 |
| 12 | 12 | ||
| 13 | -## 定位过程 | 13 | +## 3. 定位过程 |
| 14 | 14 | ||
| 15 | 为精准定位线程频繁切换的触发场景、切换频次、耗时开销及异常线程点位,本次采用系统调度监控工具、内核调度探针、业务性能剖析工具开展专项数据分析,完整定位流程如下: | 15 | 为精准定位线程频繁切换的触发场景、切换频次、耗时开销及异常线程点位,本次采用系统调度监控工具、内核调度探针、业务性能剖析工具开展专项数据分析,完整定位流程如下: |
| 16 | 16 | ||
| @@ -21,14 +21,14 @@ Linux操作系统基于时间片轮转、进程优先级调度机制实现线程 | |||
| 21 | 3. 异常位点锁定 | 21 | 3. 异常位点锁定 |
| 22 | 通过多维度数据分析精准识别异常行为:业务进程内存在大量轻量短时线程,线程频繁唤醒、休眠、抢占、让出CPU,单秒上下文切换次数远超合理阈值,内核调度开销持续走高,频繁打断业务任务连续执行,导致业务有效计算时间被严重压缩,任务执行碎片化,最终定位出引发性能问题的核心异常线程及调度逻辑。 | 22 | 通过多维度数据分析精准识别异常行为:业务进程内存在大量轻量短时线程,线程频繁唤醒、休眠、抢占、让出CPU,单秒上下文切换次数远超合理阈值,内核调度开销持续走高,频繁打断业务任务连续执行,导致业务有效计算时间被严重压缩,任务执行碎片化,最终定位出引发性能问题的核心异常线程及调度逻辑。 |
| 23 | 23 | ||
| 24 | -## 问题根因 | 24 | +## 4. 问题根因 |
| 25 | 25 | ||
| 26 | 1. 系统调度机制固有特性:Linux系统为保障多任务公平调度,默认采用时间片轮转抢占机制,多线程并发场景下天然存在线程上下文切换开销,高并发短时任务场景下该开销会被持续放大。 | 26 | 1. 系统调度机制固有特性:Linux系统为保障多任务公平调度,默认采用时间片轮转抢占机制,多线程并发场景下天然存在线程上下文切换开销,高并发短时任务场景下该开销会被持续放大。 |
| 27 | 2. 业务线程设计缺陷(核心根因):客户业务多线程架构设计不合理,业务创建大量轻量短时工作线程,单线程任务执行耗时极短、频繁退出与重建,或线程长期处于“唤醒-执行-休眠”循环状态,无批量任务处理机制,持续触发内核线程调度切换。 | 27 | 2. 业务线程设计缺陷(核心根因):客户业务多线程架构设计不合理,业务创建大量轻量短时工作线程,单线程任务执行耗时极短、频繁退出与重建,或线程长期处于“唤醒-执行-休眠”循环状态,无批量任务处理机制,持续触发内核线程调度切换。 |
| 28 | 3. 系统调度配置不合理:系统默认时间片配置、调度优先级、nice值、调度策略适配性不足,大量业务线程采用普通分时调度策略,高并发场景下线程抢占无序,加剧频繁切换问题;同时未做线程CPU亲和性绑定,线程频繁跨核调度,进一步放大切换开销。 | 28 | 3. 系统调度配置不合理:系统默认时间片配置、调度优先级、nice值、调度策略适配性不足,大量业务线程采用普通分时调度策略,高并发场景下线程抢占无序,加剧频繁切换问题;同时未做线程CPU亲和性绑定,线程频繁跨核调度,进一步放大切换开销。 |
| 29 | 4. 连锁性能影响:超高频率的线程上下文切换导致系统内核调度开销激增,大量CPU算力消耗在上下文保存恢复、调度队列遍历、线程状态切换等无效操作中,业务有效计算算力被严重挤占,任务执行连续性断裂,最终造成业务延迟抖动、吞吐下降、算力利用率偏低,整体运行性能不达标。 | 29 | 4. 连锁性能影响:超高频率的线程上下文切换导致系统内核调度开销激增,大量CPU算力消耗在上下文保存恢复、调度队列遍历、线程状态切换等无效操作中,业务有效计算算力被严重挤占,任务执行连续性断裂,最终造成业务延迟抖动、吞吐下降、算力利用率偏低,整体运行性能不达标。 |
| 30 | 30 | ||
| 31 | -## 定位方法论总结 | 31 | +## 5. 定位方法论总结 |
| 32 | 32 | ||
| 33 | 针对Linux系统业务部署后出现的调度开销高、性能抖动大、吞吐不稳、CPU有效利用率低的场景,可固化标准化定位流程,快速排查内核线程频繁切换类性能问题: | 33 | 针对Linux系统业务部署后出现的调度开销高、性能抖动大、吞吐不稳、CPU有效利用率低的场景,可固化标准化定位流程,快速排查内核线程频繁切换类性能问题: |
| 34 | 34 | ||
| @@ -37,7 +37,7 @@ Linux操作系统基于时间片轮转、进程优先级调度机制实现线程 | |||
| 37 | 3. 联合分析:结合业务Profiler性能数据、任务耗时数据、CPU资源占用数据,关联线程高频切换高峰与业务性能劣化时段,区分正常调度开销与异常高频切换瓶颈。 | 37 | 3. 联合分析:结合业务Profiler性能数据、任务耗时数据、CPU资源占用数据,关联线程高频切换高峰与业务性能劣化时段,区分正常调度开销与异常高频切换瓶颈。 |
| 38 | 4. 精准定位:锁定切换频次最高、频繁唤醒休眠、短时执行的异常线程,明确业务代码中不合理的线程创建、任务调度逻辑,指导业务代码优化与系统调度参数调优。 | 38 | 4. 精准定位:锁定切换频次最高、频繁唤醒休眠、短时执行的异常线程,明确业务代码中不合理的线程创建、任务调度逻辑,指导业务代码优化与系统调度参数调优。 |
| 39 | 39 | ||
| 40 | -## 对工具的改进建议 | 40 | +## 6. 对工具的改进建议 |
| 41 | 41 | ||
| 42 | 当前内核调度排查工具可完整采集线程切换基础行为数据,但业务关联定位能力不足,为进一步提升问题定位效率,降低人工分析成本,提出优化建议: | 42 | 当前内核调度排查工具可完整采集线程切换基础行为数据,但业务关联定位能力不足,为进一步提升问题定位效率,降低人工分析成本,提出优化建议: |
| 43 | 43 | ||
| @@ -1,93 +0,0 @@ | |||
| 1 | -# KV Block数量不足 | ||
| 2 | - | ||
| 3 | -## 问题背景 | ||
| 4 | - | ||
| 5 | -KV Block用于承载请求的KVCache。请求进入prefill和decode阶段后,调度器需要持续申请KV Block;如果可用Block不足,请求即使算力还有空闲,也可能因为拿不到KVCache资源而排队、抢占或重算。 | ||
| 6 | - | ||
| 7 | -## 问题来源 | ||
| 8 | - | ||
| 9 | -推理 | ||
| 10 | - | ||
| 11 | -## 问题现象 | ||
| 12 | - | ||
| 13 | -用户通常先看到的是性能劣化,而不是直接看到“KV Block不足”: | ||
| 14 | - | ||
| 15 | -- 压测并发继续增加时,吞吐不再提升,首Token时延和端到端时延明显升高。 | ||
| 16 | -- 服务端存在较多waiting/pending请求,部分请求长时间不进入decode。 | ||
| 17 | -- NPU利用率不一定持续打满,但请求排队时间持续升高。 | ||
| 18 | -- 监控中KVCache使用率长期高位,`free_kvcache_blocks`长期接近0,或出现抢占/分配失败增长。 | ||
| 19 | - | ||
| 20 | - | ||
| 21 | - | ||
| 22 | -## 定位过程 | ||
| 23 | - | ||
| 24 | -### 步骤 1:先确认问题是不是“排队变长” | ||
| 25 | - | ||
| 26 | -在Grafana服务总览或请求时延面板中查看时延拆分,先确认时延增长主要发生在哪个阶段: | ||
| 27 | - | ||
| 28 | -- 首Token时延是否升高。 | ||
| 29 | -- 请求queue/waiting时间是否升高。 | ||
| 30 | -- running请求没有明显增加,但waiting/pending请求持续堆积。 | ||
| 31 | - | ||
| 32 | -如果时延主要涨在模型执行阶段,并且NPU长期满载,应优先排查计算瓶颈;如果时延主要涨在等待阶段,才继续往调度和KVCache方向定位。 | ||
| 33 | - | ||
| 34 | -### 步骤 2:确认等待是否由KV Block不足导致 | ||
| 35 | - | ||
| 36 | -在Grafana的KVCache、请求状态和调度状态面板中,重点观察同一个时间窗口内是否同时出现以下现象: | ||
| 37 | - | ||
| 38 | -- `free_kvcache_blocks`长期低位,KVCache使用率接近上限。 | ||
| 39 | -- waiting/pending请求、队列等待时间或首Token时延同步升高。 | ||
| 40 | -- 抢占、重算或分配失败类指标在同一时间段增长。 | ||
| 41 | - | ||
| 42 | -如果这三类信号对齐,可初步判断请求被KVCache容量卡住,而不是单纯计算慢。 | ||
| 43 | - | ||
| 44 | -### 步骤 3:确认容量压力来源 | ||
| 45 | - | ||
| 46 | -KVCache水位只能表明实例已经接近容量上限;具体是并发、请求长度、流量分配还是KVCache配置导致,需要结合压测配置、服务启动参数、请求日志和Grafana监控一起判断: | ||
| 47 | - | ||
| 48 | -- 从压测配置、服务启动参数或变更记录确认是否提高了并发、`max_num_seqs`、`max_model_len`、最大输出长度或batch相关配置。 | ||
| 49 | -- 从请求日志、压测数据集或请求长度统计确认是否存在长上下文、长输出请求集中进入实例。 | ||
| 50 | -- 从Grafana实例维度监控确认是否只有部分实例承接了更多请求或token,其他实例仍有空闲。 | ||
| 51 | -- 从服务启动参数、显存配置和Grafana中的total/free KV Block水位确认KVCache可用Block总量是否偏小。 | ||
| 52 | - | ||
| 53 | -如果压测流量固定,但长输入/长输出比例升高,通常是请求长度占用Block过多;如果请求长度稳定但并发升高,通常是单实例并发超过当前KVCache容量;如果只有部分实例耗尽Block,则还需要排查多实例负载不均。 | ||
| 54 | - | ||
| 55 | -### 步骤 4:用离线Profiler验证具体卡在哪些请求和batch | ||
| 56 | - | ||
| 57 | -当在线监控已经指向KV Block不足后,再使用msServiceProfiler采集`Schedule`、`KVCache`、`Request`相关数据,重点看三个文件: | ||
| 58 | - | ||
| 59 | -- `request.csv`:看`queue_wait_time(ms)`、`first_token_latency(ms)`是否主要变长,并找到等待时间最长的请求。 | ||
| 60 | -- `batch.csv`:看`used_blocks`、`free_blocks`、`kvcache_usage_rate`是否在连续batch中长期高位,以及`decode_batch_size`是否因为Block不足无法稳定扩大。 | ||
| 61 | -- `kvcache.csv`:看`blocks_allocated`和`blocks_freed`。如果多个时间窗口内申请持续大于释放,最后`free_blocks`被打空,就能把根因收敛到KVCache容量不足。 | ||
| 62 | - | ||
| 63 | -通过Profiler需要回答两个问题:哪些请求占用了最多Block,以及Block耗尽后调度器在哪些batch开始排队或抢占。 | ||
| 64 | - | ||
| 65 | -## 问题根因 | ||
| 66 | - | ||
| 67 | -KVCache可用Block数量不足,导致请求无法及时获得KVCache资源。常见根因是单实例并发过高、输入输出长度过长、KVCache预留显存不足、长请求集中到少数实例,或调度参数允许过多请求同时进入。 | ||
| 68 | - | ||
| 69 | -## 解决方法 | ||
| 70 | - | ||
| 71 | -根据定位结果选择处理方式: | ||
| 72 | - | ||
| 73 | -- 并发过高:降低单实例并发、`max_num_seqs`或入口限流阈值,避免一次放入过多请求。 | ||
| 74 | -- 请求太长:限制最大输入长度、最大输出长度,或将长上下文请求单独路由到更大KVCache容量的实例。 | ||
| 75 | -- 单实例Block总量不足:调整KVCache相关显存配置或提高可用于KVCache的显存比例;如果单卡显存已无余量,需要增加实例、增加卡数或换更大显存规格。 | ||
| 76 | -- 流量分配不均:先处理多实例负载不均,让请求按实例容量和队列状态分配,避免少数实例先耗尽KV Block。 | ||
| 77 | -- 抢占/重算明显:降低进入调度器的请求数量,或调整调度策略,避免频繁把已进入decode的请求换出。 | ||
| 78 | - | ||
| 79 | -处理后需要回看同一组信号:`free_kvcache_blocks`是否恢复到稳定水位,waiting/pending是否下降,首Token时延是否回落,吞吐是否随并发恢复增长。 | ||
| 80 | - | ||
| 81 | -## 定位方法论总结 | ||
| 82 | - | ||
| 83 | -针对KV Block数量不足场景,需要优先使用ms-service-metric确认时延是否主要增加在排队和首Token阶段,并观察KVCache水位、`free_kvcache_blocks`和waiting/pending请求是否在同一时间窗口异常;确认在线指标指向KVCache容量压力后,再使用msServiceProfiler采集`request.csv`、`batch.csv`和`kvcache.csv`,定位具体是请求长度、并发、batch调度还是Block分配释放不平衡导致。 | ||
| 84 | - | ||
| 85 | -## 对工具的改进建议 | ||
| 86 | - | ||
| 87 | -### ms-service-metric | ||
| 88 | - | ||
| 89 | -当前在线监控已能查看KVCache水位、`free_kvcache_blocks`、waiting/pending请求数和首Token时延。建议在现有面板中增加KV Block不足关联诊断提示,把这些指标在同一时间窗口内自动关联展示,辅助判断是否已经由KVCache容量压力导致排队。 | ||
| 90 | - | ||
| 91 | -### msServiceProfiler | ||
| 92 | - | ||
| 93 | -当前Profiler已能通过`request.csv`、`batch.csv`、`kvcache.csv`分析请求等待、batch调度和KVCache分配释放情况。建议在离线报告中增加KV Block不足摘要,自动标记`free_blocks`持续低位、`decode_batch_size`无法扩大、`blocks_allocated`持续大于`blocks_freed`的时间窗口。 | ||
| @@ -1,121 +0,0 @@ | |||
| 1 | -# KVCache传输影响模型性能 | ||
| 2 | - | ||
| 3 | -## 问题背景 | ||
| 4 | - | ||
| 5 | -在PD分离(Prefill-Decode分离)部署场景下,Prefill节点完成输入序列的KV Cache计算后,需要将KV Cache传输到Decode节点进行后续的逐Token生成。KV Cache的跨节点传输是PD分离架构的关键路径,传输延迟直接影响Decode节点的首Token生成时间和整体请求延迟。在分布式KV Cache池化场景中,跨节点的KV Cache加载和写入同样涉及大量数据传输。昇腾通过HIXL单边通信库和MemFabric跨节点内存统一编址技术优化KV Cache传输路径,但在实际部署中,网络带宽不足、传输协议开销大、内存拷贝次数多、传输与计算未充分重叠等问题仍可能导致KV Cache传输成为性能瓶颈。 | ||
| 6 | - | ||
| 7 | -## 问题来源 | ||
| 8 | - | ||
| 9 | -推理 | ||
| 10 | - | ||
| 11 | -## 问题现象 | ||
| 12 | - | ||
| 13 | -用户通常先看到PD分离场景下Decode节点的请求等待时间(`queue_wait_time`)显著偏高,首Token时延(TTFT)中Prefill执行完成后到Decode开始生成之间的间隔时间过长。进一步观察PD分离相关指标时,可能出现: | ||
| 14 | - | ||
| 15 | -- 在`pd_split_communication.csv`中,`prefill_res_time`到`request_end_time`之间的时间差过大,说明KV Cache传输占用了大量时间。 | ||
| 16 | -- 在`pd_split_kvcache.csv`中,`during_time(ms)`(KV Cache从P节点传输到D节点的耗时)偏高,且与请求的`seq_len`(序列长度)呈正相关。序列越长,KV Cache数据量越大,传输耗时越长。 | ||
| 17 | -- 在Timeline视图中,可观察到Prefill节点的ModelExecute色块结束后,Decode节点存在明显的等待间隙,直到KV Cache传输完成后才开始Decode执行。如果传输与计算未重叠,这个等待间隙直接转化为端到端延迟的增加。 | ||
| 18 | -- 在分布式KV Cache池化场景中,跨节点缓存加载的耗时导致请求的Prefill阶段耗时增加,即使本地已有部分缓存,远程加载的延迟仍可能抵消缓存命中带来的收益。 | ||
| 19 | - | ||
| 20 | -## 定位过程 | ||
| 21 | - | ||
| 22 | -### 步骤 1:用Profiler采集PD分离场景的通信和KVCache数据 | ||
| 23 | - | ||
| 24 | -在PD分离部署的多机多卡场景中,需要在各节点统一配置`ms_service_profiler_config.json`,设置`domain`为`"Request; KVCache; Communication; Schedule; ModelExecute"`,确保采集Communication和KVCache domain数据。采集完成后执行解析: | ||
| 25 | - | ||
| 26 | -```bash | ||
| 27 | -python3 -m ms_service_profiler.parse --input-path ${PATH}/prof_dir/ | ||
| 28 | -``` | ||
| 29 | - | ||
| 30 | -解析生成`pd_split_communication.csv`、`pd_split_kvcache.csv`、`request.csv`、`batch.csv`、`chrome_tracing.json`等文件。 | ||
| 31 | - | ||
| 32 | -### 步骤 2:分析pd_split_kvcache.csv中的KV Cache传输耗时 | ||
| 33 | - | ||
| 34 | -在`pd_split_kvcache.csv`中查看每条请求的KV Cache传输数据。关键字段包括: | ||
| 35 | - | ||
| 36 | -- `seq_len`:请求序列长度,决定KV Cache数据量 | ||
| 37 | -- `during_time(ms)`:KV Cache从P节点传输到D节点的实际耗时 | ||
| 38 | -- `block_tables`:传输的block信息 | ||
| 39 | - | ||
| 40 | -按`seq_len`分组统计`during_time(ms)`的分布(平均值、P90、P99)。计算传输带宽(`seq_len * 模型KV维度 * 层数 * 数据类型字节数 / during_time`),与理论网络带宽对比。如果实际传输带宽远低于理论带宽,说明传输效率存在问题。 | ||
| 41 | - | ||
| 42 | -按`rank`(设备ID)分组统计,判断是否存在特定设备或链路的传输慢问题。 | ||
| 43 | - | ||
| 44 | -### 步骤 3:分析pd_split_communication.csv中的端到端通信时序 | ||
| 45 | - | ||
| 46 | -在`pd_split_communication.csv`中查看关键时间节点: | ||
| 47 | - | ||
| 48 | -- `http_req_time(ms)`:请求到达时间 | ||
| 49 | -- `send_request_time(ms)`:P节点开始向D节点发送请求时间 | ||
| 50 | -- `send_request_succ_time(ms)`:请求发送成功时间 | ||
| 51 | -- `prefill_res_time(ms)`:Prefill执行完成时间 | ||
| 52 | -- `request_end_time(ms)`:请求执行完毕时间 | ||
| 53 | - | ||
| 54 | -计算各阶段耗时: | ||
| 55 | - | ||
| 56 | -- 请求转发耗时 = `send_request_succ_time` - `send_request_time` | ||
| 57 | -- Prefill执行耗时 = `prefill_res_time` - `send_request_succ_time` | ||
| 58 | -- KV Cache传输+Decode执行耗时 = `request_end_time` - `prefill_res_time` | ||
| 59 | - | ||
| 60 | -如果KV Cache传输+Decode执行耗时在总耗时中占比过高,且与`seq_len`强相关,可确认KV Cache传输是瓶颈。 | ||
| 61 | - | ||
| 62 | -### 步骤 4:通过Timeline视图确认传输与计算的重叠情况 | ||
| 63 | - | ||
| 64 | -打开`chrome_tracing.json`,在Timeline视图中定位PD分离场景的KV Cache传输过程。观察Prefill节点的ModelExecute色块结束时间与Decode节点开始执行时间之间的间隙。如果这个间隙与`pd_split_kvcache.csv`中的`during_time(ms)`吻合,可确认KV Cache传输是Decode等待的直接原因。 | ||
| 65 | - | ||
| 66 | -在Timeline中观察是否存在KV Cache传输与计算重叠的情况。如果传输完全串行在Prefill之后、Decode之前,说明传输与计算未重叠,存在优化空间。 | ||
| 67 | - | ||
| 68 | -### 步骤 5:在Grafana中观察PD分离场景指标 | ||
| 69 | - | ||
| 70 | -在PD分离部署场景中,分别观察Prefill节点和Decode节点的指标。如果Decode节点的`waiting_batch_size`持续偏高而`batch_size`偏低,且Prefill节点负载正常,说明Decode节点在等待KV Cache传输。观察`request_status.csv`中Decode节点的waiting/running状态变化,判断等待时间是否与KV Cache传输相关。 | ||
| 71 | - | ||
| 72 | -### 步骤 6:用多维度解析工具获取请求维度统计 | ||
| 73 | - | ||
| 74 | -```bash | ||
| 75 | -msserviceprofiler analyze --input-path=/path/to/input | ||
| 76 | -``` | ||
| 77 | - | ||
| 78 | -查看`request_summary.csv`中`first_token_latency(ms)`和`waiting_time(ms)`的统计,判断TTFT中等待时间的占比。 | ||
| 79 | - | ||
| 80 | -## 问题根因 | ||
| 81 | - | ||
| 82 | -KVCache传输影响模型性能的常见根因包括: | ||
| 83 | - | ||
| 84 | -1. **通信协议开销大**:使用传统双边通信协议(如HCCL集合通信)进行KV Cache传输时,发送方和接收方需要多次握手确认,协议开销在高频、小包、单向的PD分离通信模式下被放大。 | ||
| 85 | - | ||
| 86 | -2. **内存拷贝次数多**:KV Cache从Prefill侧计算缓冲区到网络传输再到Decode侧工作内存,经历多次内存拷贝,每次拷贝消耗DMA带宽和内存总线资源。昇腾HIXL单边通信库通过零拷贝(RDMA直写远程内存)可消除中间拷贝,但若未启用HIXL或配置不当,仍使用传统路径。 | ||
| 87 | - | ||
| 88 | -3. **网络带宽不足或链路拥塞**:PD分离场景下KV Cache传输对网络带宽要求高,如果网络带宽不足或存在多流竞争,传输延迟显著增加。跨节点KV Cache池化场景中,多节点同时读写远程内存可能造成网络拥塞。 | ||
| 89 | - | ||
| 90 | -4. **传输与计算未重叠**:KV Cache传输串行在Prefill执行之后、Decode执行之前,未与计算阶段重叠。理想情况下,KV Cache传输应与Prefill的后续计算或Decode的初始化过程并行,隐藏传输延迟。 | ||
| 91 | - | ||
| 92 | -5. **序列长度过大导致传输数据量激增**:长序列场景下KV Cache数据量与序列长度成正比,百万级Token上下文的KV Cache可达数十GB,单次传输耗时可能超过数秒。 | ||
| 93 | - | ||
| 94 | -6. **分布式缓存池化架构中数据路径过长**:使用Mooncake等方案时,调用链冗长,每层引入额外延迟。昇腾通过KV Connector直接对接后端、HIXL零拷贝传输、MemFabric统一内存编址等优化缩短数据路径。 | ||
| 95 | - | ||
| 96 | -## 解决方法 | ||
| 97 | - | ||
| 98 | -- 通信协议开销大:启用昇腾HIXL单边通信库替代传统双边通信协议。 | ||
| 99 | -- 内存拷贝多:使用MemFabric跨节点内存统一编址减少数据搬运,启用HIXL零拷贝传输。 | ||
| 100 | -- 网络带宽不足:增加网络带宽或使用RDMA高速网络。 | ||
| 101 | -- 传输与计算未重叠:优化传输与计算的重叠(如Pipeline并行),让传输与Prefill后续计算或Decode初始化并行。 | ||
| 102 | -- 数据量过大:对KV Cache进行量化压缩减少传输数据量。 | ||
| 103 | -- 数据路径过长:在分布式缓存池化场景中使用KV Connector直接对接后端缩短调用链。 | ||
| 104 | - | ||
| 105 | -处理后需要回看`pd_split_kvcache.csv`中`during_time(ms)`是否下降、Decode节点等待时间是否减少、TTFT是否恢复。 | ||
| 106 | - | ||
| 107 | -## 定位方法论总结 | ||
| 108 | - | ||
| 109 | -该场景的完整判断链是:先确认是否为PD分离或分布式KV Cache池化部署场景;再用msServiceProfiler采集Communication和KVCache domain数据,通过`pd_split_kvcache.csv`直接获取KV Cache传输耗时;然后通过`pd_split_communication.csv`分析端到端时序,计算传输阶段在总耗时中的占比;最后通过Timeline视图确认传输与计算的重叠情况。 | ||
| 110 | - | ||
| 111 | -核心判断逻辑:如果`pd_split_kvcache.csv`中`during_time(ms)`偏高且与`seq_len`强相关,同时`pd_split_communication.csv`中`request_end_time - prefill_res_time`占比过高,则KV Cache传输是瓶颈。进一步判断:如果实际传输带宽远低于理论带宽,则是网络或协议效率问题;如果传输带宽正常但总耗时长,则是数据量过大问题。 | ||
| 112 | - | ||
| 113 | -## 对工具的改进建议 | ||
| 114 | - | ||
| 115 | -### msServiceProfiler | ||
| 116 | - | ||
| 117 | -当前Profiler已能通过`pd_split_kvcache.csv`和`pd_split_communication.csv`分析KV Cache传输耗时。建议在`pd_split_kvcache.csv`中增加传输带宽字段,自动计算实际传输带宽,便于与理论带宽对比。在`pd_split_kvcache.csv`中增加传输路径标识字段(如HIXL/MemFabric/HCCL/TCP),帮助判断当前使用的传输方式。在`pd_split_communication.csv`中增加更细粒度的通信阶段拆解,如"KV Cache序列化耗时"、"网络传输耗时"、"KV Cache反序列化耗时"、"内存拷贝耗时"等。在Timeline视图中增加KV Cache传输泳道,将传输过程独立展示,便于观察传输与计算的重叠情况。 | ||
| 118 | - | ||
| 119 | -### ms-service-metric | ||
| 120 | - | ||
| 121 | -当前在线监控已能按节点观察PD分离场景指标。建议增加PD分离场景的Decode节点等待时间监控指标,区分"等待KV Cache传输"和"等待调度"两种等待类型。增加KV Cache传输延迟的在线监控指标,便于实时观察传输性能。 | ||
| @@ -1,6 +1,6 @@ | |||
| 1 | -# 内存碎片问题分析 | 1 | +# 内存碎片 |
| 2 | 2 | ||
| 3 | -## 问题背景 | 3 | +## 1. 问题背景 |
| 4 | 4 | ||
| 5 | 服务化推理场景中,显存往往不是瞬时暴涨,而是长时间缓慢增长。这类问题既可能是代码层面的内存泄漏,也可能是框架侧或 GE 侧碎片累积导致的显存持续上涨。 | 5 | 服务化推理场景中,显存往往不是瞬时暴涨,而是长时间缓慢增长。这类问题既可能是代码层面的内存泄漏,也可能是框架侧或 GE 侧碎片累积导致的显存持续上涨。 |
| 6 | 6 | ||
| @@ -9,15 +9,15 @@ | |||
| 9 | <div align="center"><img src="../figures/profiler_case_frag_overview.png" /></div> | 9 | <div align="center"><img src="../figures/profiler_case_frag_overview.png" /></div> |
| 10 | <div align="center"><b>图1:显存缓慢增长定位流程总览</b></div> | 10 | <div align="center"><b>图1:显存缓慢增长定位流程总览</b></div> |
| 11 | 11 | ||
| 12 | -## 问题现象 | 12 | +## 2. 问题现象 |
| 13 | 13 | ||
| 14 | `qwen cosyvoice2` 推理过程中,经过几次图推后显存开始缓慢增长,每次上涨十几 MB,最终约 10小时后 OOM。该问题在 GPU 上未复现,仅在 NPU 上出现。 | 14 | `qwen cosyvoice2` 推理过程中,经过几次图推后显存开始缓慢增长,每次上涨十几 MB,最终约 10小时后 OOM。该问题在 GPU 上未复现,仅在 NPU 上出现。 |
| 15 | 15 | ||
| 16 | 从现象看更接近长时间运行后的显存泄漏,但用户反馈即使开启 `empty_cache`,显存仍持续上涨。 | 16 | 从现象看更接近长时间运行后的显存泄漏,但用户反馈即使开启 `empty_cache`,显存仍持续上涨。 |
| 17 | 17 | ||
| 18 | -## 定位过程 | 18 | +## 3. 定位过程 |
| 19 | 19 | ||
| 20 | -### 1. 采集跨 step profiling,查看 allocated 与 reserved 趋势 | 20 | +### 3.1 采集跨 step profiling,查看 allocated 与 reserved 趋势 |
| 21 | 21 | ||
| 22 | 首轮 profiling 仅覆盖单个 step 时,无法判断增长是发生在 step 内还是跨 step 累积。因此需要扩大采集范围,覆盖多个连续推理 step,并开启内存统计能力。 | 22 | 首轮 profiling 仅覆盖单个 step 时,无法判断增长是发生在 step 内还是跨 step 累积。因此需要扩大采集范围,覆盖多个连续推理 step,并开启内存统计能力。 |
| 23 | 23 | ||
| @@ -52,7 +52,7 @@ with torch_npu.profiler.profile( | |||
| 52 | 52 | ||
| 53 | > `allocated`(算子实际使用)保持平稳,排除算子侧的持续泄漏;`reserved`(内存池持有的物理内存)持续上涨,说明分配器持有越来越多的内存却无法归还——这是**内存碎片的典型特征**。 | 53 | > `allocated`(算子实际使用)保持平稳,排除算子侧的持续泄漏;`reserved`(内存池持有的物理内存)持续上涨,说明分配器持有越来越多的内存却无法归还——这是**内存碎片的典型特征**。 |
| 54 | 54 | ||
| 55 | -### 2. 筛选 operator_memory.csv,区分 GE 侧与框架侧来源 | 55 | +### 3.2 筛选 operator_memory.csv,区分 GE 侧与框架侧来源 |
| 56 | 56 | ||
| 57 | 确认是碎片问题后,进一步通过 `operator_memory.csv` 定位碎片来自哪一侧: | 57 | 确认是碎片问题后,进一步通过 `operator_memory.csv` 定位碎片来自哪一侧: |
| 58 | 58 | ||
| @@ -62,7 +62,7 @@ with torch_npu.profiler.profile( | |||
| 62 | <div align="center"><img src="../figures/profiler_case_frag_filter.png" /></div> | 62 | <div align="center"><img src="../figures/profiler_case_frag_filter.png" /></div> |
| 63 | <div align="center"><b>图3:operator_memory.csv 关键字筛选 GE 侧与框架侧来源</b></div> | 63 | <div align="center"><b>图3:operator_memory.csv 关键字筛选 GE 侧与框架侧来源</b></div> |
| 64 | 64 | ||
| 65 | -### 3. 环境变量验证碎片特征 | 65 | +### 3.3 环境变量验证碎片特征 |
| 66 | 66 | ||
| 67 | 针对 GE 侧和框架侧分别开启碎片缓解环境变量验证: | 67 | 针对 GE 侧和框架侧分别开启碎片缓解环境变量验证: |
| 68 | 68 | ||
| @@ -78,14 +78,14 @@ export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True | |||
| 78 | 78 | ||
| 79 | > 开启两个环境变量后,`reserved` 的增长趋势明显被抑制,涨幅从 ~600MB 降至 ~75MB。 | 79 | > 开启两个环境变量后,`reserved` 的增长趋势明显被抑制,涨幅从 ~600MB 降至 ~75MB。 |
| 80 | 80 | ||
| 81 | -## 问题结论 | 81 | +## 4. 问题结论 |
| 82 | 82 | ||
| 83 | 1. 短序列场景下,问题主要是内存碎片持续累积,而非典型代码泄漏。 | 83 | 1. 短序列场景下,问题主要是内存碎片持续累积,而非典型代码泄漏。 |
| 84 | 2. 当 `operators allocated` 基本不涨但 `reserved` 持续上涨时,应优先怀疑碎片问题。 | 84 | 2. 当 `operators allocated` 基本不涨但 `reserved` 持续上涨时,应优先怀疑碎片问题。 |
| 85 | 3. 通过筛选 `operator_memory.csv`,可以快速区分 GE 侧和框架侧的上涨来源。 | 85 | 3. 通过筛选 `operator_memory.csv`,可以快速区分 GE 侧和框架侧的上涨来源。 |
| 86 | 4. 开启 `GE_USE_STATIC_MEMORY=3` 和 `PYTORCH_NPU_ALLOC_CONF=expandable_segments:True` 后,短序列场景的上涨可明显缓解。 | 86 | 4. 开启 `GE_USE_STATIC_MEMORY=3` 和 `PYTORCH_NPU_ALLOC_CONF=expandable_segments:True` 后,短序列场景的上涨可明显缓解。 |
| 87 | 87 | ||
| 88 | -## 定位方法论总结 | 88 | +## 5. 定位方法论总结 |
| 89 | 89 | ||
| 90 | <div align="center"><img src="../figures/profiler_case_frag_methodology.png" /></div> | 90 | <div align="center"><img src="../figures/profiler_case_frag_methodology.png" /></div> |
| 91 | <div align="center"><b>图5:碎片问题定位方法论决策流程</b></div> | 91 | <div align="center"><b>图5:碎片问题定位方法论决策流程</b></div> |
| @@ -95,7 +95,7 @@ export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True | |||
| 95 | 3. 结合 `operator_memory.csv` 的关键字筛选,区分 GE 侧与框架侧来源。 | 95 | 3. 结合 `operator_memory.csv` 的关键字筛选,区分 GE 侧与框架侧来源。 |
| 96 | 4. 通过环境变量验证,可快速判断问题是否具备碎片缓解特征。 | 96 | 4. 通过环境变量验证,可快速判断问题是否具备碎片缓解特征。 |
| 97 | 97 | ||
| 98 | -## 对工具的改进建议 | 98 | +## 6. 对工具的改进建议 |
| 99 | 99 | ||
| 100 | - 增加 GE 侧碎片问题的专项定位能力 | 100 | - 增加 GE 侧碎片问题的专项定位能力 |
| 101 | - 更直观地区分 `allocated` 上涨和 `reserved` 上涨的原因 | 101 | - 更直观地区分 `allocated` 上涨和 `reserved` 上涨的原因 |
| @@ -1,6 +1,6 @@ | |||
| 1 | -# 内存泄漏问题分析 | 1 | +# 内存泄漏 |
| 2 | 2 | ||
| 3 | -## 问题背景 | 3 | +## 1. 问题背景 |
| 4 | 4 | ||
| 5 | 【问题来源】 | 5 | 【问题来源】 |
| 6 | CANN 包版本升级(A版本 → B版本),推理场景。 | 6 | CANN 包版本升级(A版本 → B版本),推理场景。 |
| @@ -8,7 +8,7 @@ CANN 包版本升级(A版本 → B版本),推理场景。 | |||
| 8 | 【问题现象】 | 8 | 【问题现象】 |
| 9 | 稳定复现。B版本运行约 12 小时后,在第 471 个 step 出现 OOM。该问题在 A 版本上未复现,且在 GPU 上同样未出现,仅在 NPU B 版本上复现。已确认开启了虚拟内存。 | 9 | 稳定复现。B版本运行约 12 小时后,在第 471 个 step 出现 OOM。该问题在 A 版本上未复现,且在 GPU 上同样未出现,仅在 NPU B 版本上复现。已确认开启了虚拟内存。 |
| 10 | 10 | ||
| 11 | -## 定位过程 | 11 | +## 2. 定位过程 |
| 12 | 12 | ||
| 13 | ### 第一步:对比两个版本单 step 的 profiling 内存数据 | 13 | ### 第一步:对比两个版本单 step 的 profiling 内存数据 |
| 14 | 14 | ||
| @@ -83,13 +83,13 @@ with torch_npu.profiler.profile( | |||
| 83 | 83 | ||
| 84 | 进一步代码审查发现,B版本中 `custom_attention_forward` 的 KV-cache 实现存在引用计数问题:中间 tensor 被 cache 内部引用后,Python 侧引用计数未正确递减,导致 step 结束后 tensor 不会被 GC 回收,累积在内存池中。 | 84 | 进一步代码审查发现,B版本中 `custom_attention_forward` 的 KV-cache 实现存在引用计数问题:中间 tensor 被 cache 内部引用后,Python 侧引用计数未正确递减,导致 step 结束后 tensor 不会被 GC 回收,累积在内存池中。 |
| 85 | 85 | ||
| 86 | -## 问题根因 | 86 | +## 3. 问题根因 |
| 87 | 87 | ||
| 88 | B版本 `custom_attention_forward` 算子的 KV-cache 实现存在引用计数错误,导致每 step 产生的中间 tensor(约 47MB)无法被垃圾回收,持续累积在显存中。经过 471 个 step 后,累积泄漏量达到 ~22GB,触发 OOM。 | 88 | B版本 `custom_attention_forward` 算子的 KV-cache 实现存在引用计数错误,导致每 step 产生的中间 tensor(约 47MB)无法被垃圾回收,持续累积在显存中。经过 471 个 step 后,累积泄漏量达到 ~22GB,触发 OOM。 |
| 89 | 89 | ||
| 90 | 该问题属于算子 bug:KV-cache 内部对中间 tensor 的引用管理不当。该故障模式需补充至故障模式库。 | 90 | 该问题属于算子 bug:KV-cache 内部对中间 tensor 的引用管理不当。该故障模式需补充至故障模式库。 |
| 91 | 91 | ||
| 92 | -## 定位方法论总结 | 92 | +## 4. 定位方法论总结 |
| 93 | 93 | ||
| 94 | <div align="center"><img src="../figures/profiler_case_leak_methodology.png" /></div> | 94 | <div align="center"><img src="../figures/profiler_case_leak_methodology.png" /></div> |
| 95 | <div align="center"><b>图3:内存泄漏问题定位方法论</b></div> | 95 | <div align="center"><b>图3:内存泄漏问题定位方法论</b></div> |
| @@ -98,7 +98,7 @@ B版本 `custom_attention_forward` 算子的 KV-cache 实现存在引用计数 | |||
| 98 | 2. 确认单 step 存在泄漏后,扩大 profiling 范围验证跨 step 累积趋势,排除单次异常。 | 98 | 2. 确认单 step 存在泄漏后,扩大 profiling 范围验证跨 step 累积趋势,排除单次异常。 |
| 99 | 3. 利用 `operator_memory.csv` 筛选申请/释放不匹配的算子,结合 `with_stack` 调用栈定位到具体代码路径。 | 99 | 3. 利用 `operator_memory.csv` 筛选申请/释放不匹配的算子,结合 `with_stack` 调用栈定位到具体代码路径。 |
| 100 | 100 | ||
| 101 | -## 对工具的改进建议 | 101 | +## 5. 对工具的改进建议 |
| 102 | 102 | ||
| 103 | - `operator_memory.csv` 目前需要手动对比申请和释放记录来识别泄漏算子,建议增加"未释放算子"的自动标注能力 | 103 | - `operator_memory.csv` 目前需要手动对比申请和释放记录来识别泄漏算子,建议增加"未释放算子"的自动标注能力 |
| 104 | - profiling 工具可增加跨 step 的 `allocated` 趋势图自动生成,降低泄漏累积的识别门槛 | 104 | - profiling 工具可增加跨 step 的 `allocated` 趋势图自动生成,降低泄漏累积的识别门槛 |
| @@ -1,155 +0,0 @@ | |||
| 1 | -# 模型性能劣化导致SLO劣化 | ||
| 2 | - | ||
| 3 | -## 问题背景 | ||
| 4 | - | ||
| 5 | -在服务化推理场景中,SLO(Service Level Objective,服务等级目标)是衡量服务质量的核心指标,通常包括首Token时延(TTFT)、Token生成速度(TPS)、请求端到端时延(E2E Latency)、吞吐量(Throughput)等。当模型执行侧出现性能劣化时,会直接导致SLO指标恶化,影响用户体验和业务SLA。模型性能劣化可能由多种因素引起:算子执行效率下降、模型计算图编译优化失效、NPU显存不足导致Swap、模型版本升级引入性能回退、CANN版本变更导致算子性能变化、动态shape场景下编译缓存未命中、MoE模型专家负载不均等。昇腾NPU上,模型从GPU迁移后可能因算子适配差异、图编译策略不同、内存管理机制差异等原因出现性能劣化,需要通过系统化的定位手段逐层排查。 | ||
| 6 | - | ||
| 7 | -## 问题来源 | ||
| 8 | - | ||
| 9 | -推理 | ||
| 10 | - | ||
| 11 | -## 问题现象 | ||
| 12 | - | ||
| 13 | -用户通常先看到推理服务SLO指标全面恶化:TTFT升高、TPS下降、P95/P99端到端时延升高、整体吞吐下降。在Grafana中按指标拆开后,常见现象是: | ||
| 14 | - | ||
| 15 | -- `first_token_latency`指标P50/P90/P99均升高。 | ||
| 16 | -- `generate_token_speed`(Token生成速度)下降。 | ||
| 17 | -- `request_latency`(请求端到端时延)升高。 | ||
| 18 | -- `batch_size`可能正常但`during_time(ms)`(模型执行耗时)增加。 | ||
| 19 | -- NPU利用率可能正常甚至偏高(说明NPU在忙于执行低效算子)。 | ||
| 20 | - | ||
| 21 | -在`batch.csv`中,`name`为`modelExec`的行的`during_time(ms)`显著增加,而`batch_size`和`total_scheduled_tokens`与劣化前相近,说明相同计算量下模型执行耗时变长。在`forward.csv`中,`during_time(ms)`(forward执行时间)增加,`bubble_time(ms)`(空泡时间)可能正常,说明瓶颈在模型前向计算本身而非调度。在`request.csv`中,`execution_time(ms)`和`first_token_latency(ms)`均升高,而`queue_wait_time(ms)`可能正常,说明请求在队列中的等待时间未增加,瓶颈在执行阶段。 | ||
| 22 | - | ||
| 23 | -典型场景包括:模型版本升级后性能回退、CANN版本升级后算子性能变化、模型从GPU迁移到昇腾NPU后性能不达预期、MoE模型专家负载不均导致部分卡成为短板、动态shape场景下编译缓存未命中导致重复编译。 | ||
| 24 | - | ||
| 25 | -## 定位过程 | ||
| 26 | - | ||
| 27 | -### 步骤 1:先确认SLO劣化范围和劣化幅度 | ||
| 28 | - | ||
| 29 | -在Grafana中查看`first_token_latency`、`generate_token_speed`、`request_latency`等SLO指标的时序变化,确认劣化开始时间点和劣化幅度。对比劣化前后的`batch_size`、`total_scheduled_tokens`、NPU利用率等指标,判断劣化是否与负载变化相关。如果负载未变但SLO恶化,可初步判断为模型执行侧性能劣化。 | ||
| 30 | - | ||
| 31 | -### 步骤 2:用Profiler采集模型执行阶段数据 | ||
| 32 | - | ||
| 33 | -配置`ms_service_profiler_config.json`,设置`domain`为`"Schedule; ModelExecute; Request; KVCache"`,开启数据采集。如果怀疑算子级别性能问题,可设置`acl_task_time`为1或2,开启算子耗时采集(注意:开启算子采集会引入额外性能开销,建议在模型执行耗时异常时开启)。采集完成后执行解析: | ||
| 34 | - | ||
| 35 | -```bash | ||
| 36 | -python3 -m ms_service_profiler.parse --input-path ${PATH}/prof_dir/ | ||
| 37 | -``` | ||
| 38 | - | ||
| 39 | -解析生成`batch.csv`、`forward.csv`、`request.csv`、`chrome_tracing.json`等文件。 | ||
| 40 | - | ||
| 41 | -### 步骤 3:分析batch.csv和forward.csv中的模型执行耗时 | ||
| 42 | - | ||
| 43 | -在`batch.csv`中筛选`name`为`modelExec`的行,按时间序列观察`during_time(ms)`的变化趋势。如果模型执行耗时在某个时间点后突然增加,可能是配置变更或环境变化导致。 | ||
| 44 | - | ||
| 45 | -按`dp_rank`分组统计各DP域的模型执行耗时。如果特定DP域的执行耗时明显高于其他DP域,可能是该DP域对应的设备或进程存在异常。 | ||
| 46 | - | ||
| 47 | -按`batch_type`(prefill/decode)分别统计。如果Prefill执行耗时增加,可能是输入处理或注意力计算变慢;如果Decode执行耗时增加,可能是逐Token生成效率下降。 | ||
| 48 | - | ||
| 49 | -在`forward.csv`中按`dp_rank`和`forward_iter`观察`during_time(ms)`和`bubble_time(ms)`。如果`during_time(ms)`增加而`bubble_time(ms)`正常,说明瓶颈在模型前向计算;如果`bubble_time(ms)`也增加,可能是调度或通信问题。 | ||
| 50 | - | ||
| 51 | -### 步骤 4:用服务化拆解工具细粒度拆解模型执行阶段 | ||
| 52 | - | ||
| 53 | -```bash | ||
| 54 | -msserviceprofiler split --input-path /path/to/input --prefill-batch-size 1 --prefill-number 50 | ||
| 55 | -msserviceprofiler split --input-path /path/to/input --decode-batch-size 1 --decode-number 50 | ||
| 56 | -``` | ||
| 57 | - | ||
| 58 | -查看`prefill.csv`和`decode.csv`中各子阶段的耗时分布,定位模型执行的具体瓶颈子环节(如数据下发、算子执行、数据接收等)。 | ||
| 59 | - | ||
| 60 | -### 步骤 5:通过Timeline视图定位瓶颈算子 | ||
| 61 | - | ||
| 62 | -打开`chrome_tracing.json`,在Timeline视图中放大模型执行阶段,观察各算子的执行耗时。如果开启了`acl_task_time`采集,可在Timeline中看到算子级别的执行时序,定位耗时最长的算子。 | ||
| 63 | - | ||
| 64 | -对比劣化前后的Timeline(如果有历史数据),观察哪些算子的执行耗时发生了变化。使用服务化性能数据比对工具: | ||
| 65 | - | ||
| 66 | -```bash | ||
| 67 | -msserviceprofiler compare ./profiling_data/before ./profiling_data/after | ||
| 68 | -``` | ||
| 69 | - | ||
| 70 | -对比两个采集时间点的性能数据差异。 | ||
| 71 | - | ||
| 72 | -### 步骤 6:用多维度解析工具获取整体统计 | ||
| 73 | - | ||
| 74 | -```bash | ||
| 75 | -msserviceprofiler analyze --input-path=/path/to/input | ||
| 76 | -``` | ||
| 77 | - | ||
| 78 | -查看`batch_summary.csv`中prefill和decode执行时间的P50/P90/P99分位数,判断是否存在长尾。查看`request_summary.csv`中`first_token_latency(ms)`和`exec_time(ms)`的分布。查看`service_summary.csv`中`generate_token_speed`和`generate_all_token_speed`,确认整体吞吐是否下降。 | ||
| 79 | - | ||
| 80 | -### 步骤 7:如果怀疑算子级别问题,用msprof工具进行算子级性能分析 | ||
| 81 | - | ||
| 82 | -在采集时配置`acl_task_time`参数值为3,确保采集的性能数据文件目录中包含以`_ascend_pt`为后缀的算子数据文件。解析完成后使用msprof导出算子数据: | ||
| 83 | - | ||
| 84 | -```bash | ||
| 85 | -msprof --export=on --output=/path/to/output | ||
| 86 | -``` | ||
| 87 | - | ||
| 88 | -使用MindStudio Insight打开解析后的性能数据,在"算子耗时"面板中查看TOP耗时算子,定位性能瓶颈算子。 | ||
| 89 | - | ||
| 90 | -### 步骤 8:如果怀疑MoE模型专家负载不均,采集eplb_observe domain数据 | ||
| 91 | - | ||
| 92 | -配置`domain`为`"eplb_observe"`,采集专家热点信息。解析后查看专家热点热力图和负载不均折线图,判断是否存在专家负载不均导致的性能劣化。 | ||
| 93 | - | ||
| 94 | -## 问题根因 | ||
| 95 | - | ||
| 96 | -模型性能劣化导致SLO劣化的常见根因包括: | ||
| 97 | - | ||
| 98 | -1. **算子性能回退**:CANN版本升级后,某些算子的实现发生变化导致性能下降;模型版本升级后计算图结构变化引入低效算子;算子融合策略变化导致融合失效。 | ||
| 99 | - | ||
| 100 | -2. **模型从GPU迁移到昇腾NPU后适配不足**:模型中存在大量Pad、Strided_Slice等算子在昇腾上实现效率较低(涉及数组重排);部分算子在昇腾上不支持导致模型切分为多个子图,子图间数据传输增加耗时;模型未真正调用昇腾后端而自动切换到CPU执行。 | ||
| 101 | - | ||
| 102 | -3. **动态shape场景下编译缓存未命中**:每次推理的输入shape不同导致图编译缓存失效,触发重复编译,首次推理或shape变化时耗时显著增加。 | ||
| 103 | - | ||
| 104 | -4. **NPU显存不足导致Swap**:KVCache占用过高或模型权重占用过大导致NPU显存不足,触发request Swap(将请求的KV Cache换出到CPU内存),Swap和恢复操作引入大量延迟。 | ||
| 105 | - | ||
| 106 | -5. **MoE模型专家负载不均**:DeepSeek等MoE模型中,不同专家被调用的频率差异大,部分专家所在设备成为计算热点,其他设备空闲等待,形成快慢卡现象。 | ||
| 107 | - | ||
| 108 | -6. **Host Bound导致Device空闲**:小模型或Decode阶段,Host下发Task的速度跟不上Device执行速度,Device出现间歇性空闲。可通过CANN图模式调度或模型下沉解决。 | ||
| 109 | - | ||
| 110 | -7. **通信瓶颈**:多卡推理场景中,AllReduce/AllGather等集合通信耗时占比过高;PD分离场景中KV Cache传输延迟大;EP(专家并行)场景中Dispatch-Combine通信成为瓶颈。 | ||
| 111 | - | ||
| 112 | -8. **模型量化或精度设置不当**:量化模型推理时精度损失导致需要更多计算步骤;或量化配置不当导致部分算子回退到高精度计算。 | ||
| 113 | - | ||
| 114 | -## 解决方法 | ||
| 115 | - | ||
| 116 | -- 算子性能回退:使用AOE自动调优优化模型计算图,或回退CANN版本。 | ||
| 117 | -- GPU迁移适配不足:使用昇腾亲和算子替换低效算子,确认模型已调用昇腾后端。 | ||
| 118 | -- 动态shape编译缓存未命中:固定输入shape或启用编译缓存。 | ||
| 119 | -- NPU显存不足Swap:调整KVCache配置避免Swap,降低单实例并发或增加显存。 | ||
| 120 | -- MoE专家负载不均:启用专家负载均衡(EPLB),调整专家放置策略。 | ||
| 121 | -- Host Bound:启用CANN图模式调度或模型下沉。 | ||
| 122 | -- 通信瓶颈:优化通信策略(如使用HIXL替代HCCL),调整并行配置。 | ||
| 123 | -- 量化精度问题:调整量化配置,确保量化参数正确。 | ||
| 124 | - | ||
| 125 | -处理后需要回看SLO指标是否恢复、模型执行耗时是否下降、NPU利用率是否正常。 | ||
| 126 | - | ||
| 127 | -## 定位方法论总结 | ||
| 128 | - | ||
| 129 | -该场景的完整判断链是:先用ms-service-metric确认SLO劣化的具体指标和劣化幅度;再用msServiceProfiler采集ModelExecute domain数据,通过`batch.csv`和`forward.csv`确认模型执行耗时是否增加;然后用服务化拆解工具细粒度定位模型执行的瓶颈子阶段;接着通过Timeline视图和算子级Profiling定位具体瓶颈算子;最后根据瓶颈类型(算子/通信/调度/内存)采取针对性优化。 | ||
| 130 | - | ||
| 131 | -核心判断逻辑: | ||
| 132 | - | ||
| 133 | -- 如果`modelExec`的`during_time(ms)`增加而`batch_size`未变 → 模型执行效率下降 | ||
| 134 | -- 如果`forward.csv`中`bubble_time(ms)`也增加 → 可能是调度或通信问题 | ||
| 135 | -- 如果特定`dp_rank`的执行耗时偏高 → 设备或进程异常 | ||
| 136 | -- 如果`request.csv`中`queue_wait_time(ms)`正常但`execution_time(ms)`高 → 瓶颈在执行阶段而非排队 | ||
| 137 | -- 如果`request_status.csv`中`swapped`请求数>0 → NPU显存不足触发Swap | ||
| 138 | - | ||
| 139 | -## 对工具的改进建议 | ||
| 140 | - | ||
| 141 | -### ms-service-metric | ||
| 142 | - | ||
| 143 | -当前在线监控已能查看TTFT、TPS、E2E Latency等SLO指标。建议增加SLO劣化自动告警能力,当TTFT、TPS、E2E Latency等指标连续超过基线阈值时自动输出告警。增加模型执行耗时与调度耗时的比值监控,便于快速区分执行瓶颈和调度瓶颈。增加Swap请求数监控指标,当出现Swap时及时告警。 | ||
| 144 | - | ||
| 145 | -### msServiceProfiler | ||
| 146 | - | ||
| 147 | -当前Profiler已能通过`batch.csv`和`forward.csv`分析模型执行耗时。建议在`batch.csv`中增加模型执行阶段的子阶段拆解字段(如"数据下发耗时"、"算子执行耗时"、"数据接收耗时"),便于直接定位执行瓶颈子环节。增加与历史数据的自动对比能力,当检测到模型执行耗时显著增加时,自动提示可能的劣化原因。在解析结果中增加SLO影响评估面板,自动计算模型执行耗时增加对TTFT、TPS等SLO指标的量化影响。 | ||
| 148 | - | ||
| 149 | -### 服务化拆解工具 | ||
| 150 | - | ||
| 151 | -当前拆解工具需要手动指定`batch_size`或`rid`。建议增加模型执行阶段的自动拆解能力,无需手动指定参数,自动选取耗时异常的Batch进行拆解。在拆解结果中增加与基线数据的对比,标注各子阶段耗时的变化幅度。 | ||
| 152 | - | ||
| 153 | -### 服务化专家建议工具 | ||
| 154 | - | ||
| 155 | -当前专家建议工具已能基于benchmark结果给出调参建议。建议增加基于性能劣化数据的自动调参建议,当检测到模型执行耗时增加时,自动分析是否可通过调整`maxBatchSize`、`maxPrefillBatchSize`等参数缓解。 | ||
| @@ -1,86 +0,0 @@ | |||
| 1 | -# 模型前后处理耗时过长问题分析 | ||
| 2 | - | ||
| 3 | -## 问题背景 | ||
| 4 | - | ||
| 5 | -大模型推理服务的一条请求可拆分为三个阶段:前处理(Tokenizer 编码)、模型推理(Prefill + Decode)、后处理(Detokenizer 解码)。其中前/后处理在 CPU 侧执行,涉及文本编码/解码、特殊 token 处理、chat template 渲染等操作。当输入 prompt 较长(>10000 tokens)或服务处于多轮对话场景时,前后处理的 CPU 耗时可能超过模型推理耗时,成为端到端延迟的主要瓶颈。 | ||
| 6 | - | ||
| 7 | -用户反馈在A2上部署对话模型服务,TTFT(首令牌生成时间)约 450ms,其中模型 Prefill 仅占约 180ms,怀疑前处理耗时过长,需通过服务化 profiling 定位具体环节。 | ||
| 8 | - | ||
| 9 | -## 问题现象 | ||
| 10 | - | ||
| 11 | -稳定复现。以单条 8000 token 的 prompt 为例: | ||
| 12 | - | ||
| 13 | -- TTFT 约 450ms,远超预期的 ~200ms | ||
| 14 | -- NPU 在请求到达后有明显的空闲等待期(约 250ms),期间无任何计算活动 | ||
| 15 | -- prompt 越长,TTFT 中的空闲占比越高:2000 prompt 时空闲约 60ms,8000 prompt 时空闲约 250ms | ||
| 16 | -- 并发请求下,前后处理排队等待现象明显——后续请求的前处理需等待前序请求完成后处理才能开始 | ||
| 17 | - | ||
| 18 | -<div align="center"><img src="../figures/profiler_model_time_consume.png" /></div> | ||
| 19 | - | ||
| 20 | -> 实际 TTFT 450ms,其中模型 Prefill 仅 180ms,前处理占用约 250ms,后处理占用约 20ms。前后处理合计占 TTFT 的 60%。 | ||
| 21 | - | ||
| 22 | -## 定位过程 | ||
| 23 | - | ||
| 24 | -### 1. 全局性能数据采集 —— msServiceProfiler | ||
| 25 | - | ||
| 26 | -使用**msServiceProfiler**工具对服务端进行完整的性能数据采集,获取端到端各阶段的耗时分布。 | ||
| 27 | - | ||
| 28 | -### 2. 可视化分析 | ||
| 29 | - | ||
| 30 | -使用 `MindStudio Insight` 导入解析后的性能数据。 | ||
| 31 | - | ||
| 32 | -关键分析步骤: | ||
| 33 | - | ||
| 34 | -#### 1. 查看单请求全链路 timeline | ||
| 35 | - | ||
| 36 | -以时间线方式呈现从请求到达到首 token 输出的完整过程。可观察到模型 Prefill 之前存在一段 CPU 前处理区间,包含以下操作: | ||
| 37 | - | ||
| 38 | -- Chat template 渲染:将原始文本套入对话模板 | ||
| 39 | -- Tokenizer encode:将文本转为 token id 序列 | ||
| 40 | -- 输入 tensor 构造与传输:将 token ids 拷贝到 Device 侧 | ||
| 41 | - | ||
| 42 | -Prefill 完成后同样存在一段 CPU 后处理区间: | ||
| 43 | - | ||
| 44 | -- Detokenizer decode:将首个 output token id 转为文本 | ||
| 45 | - | ||
| 46 | -<div align="center"><img src="../figures/profiler_model_request_link.png" /></div> | ||
| 47 | - | ||
| 48 | -> 前处理耗时 250ms 占据 TTFT 的 55.6%,期间 NPU 完全空闲。后处理 20ms 占比不大,但在流式输出场景下每 token 都需 detokenize,累积开销可观。 | ||
| 49 | - | ||
| 50 | -#### 2. 分析前处理各环节耗时 | ||
| 51 | - | ||
| 52 | -从导出 CSV 中筛选前处理相关函数,按耗时排序。 | ||
| 53 | - | ||
| 54 | -<div align="center"><img src="../figures/profiler_model_time_usage.png" /></div> | ||
| 55 | - | ||
| 56 | -关键发现: | ||
| 57 | - | ||
| 58 | -- Tokenizer encode 耗时占比最高(约 60%),8000 prompt 需约 150ms 逐字符编码 | ||
| 59 | -- Chat template 渲染耗时约 55ms(22%),涉及字符串拼接和特殊 token 插入 | ||
| 60 | -- Tensor 构造与 Host→Device 传输耗时约 30ms(12%) | ||
| 61 | -- 其他(参数校验、memory pinning 等)约 15ms(6%) | ||
| 62 | - | ||
| 63 | -进一步分析不同 prompt 长度下的前处理耗时变化: | ||
| 64 | -<div align="center"><img src="../figures/profiler_model_prompt_length_trend.png" /></div> | ||
| 65 | - | ||
| 66 | -> 前处理耗时与 prompt 长度呈近似线性关系,说明 Tokenizer encode 是主要瓶颈,且未采用并行分词或缓存优化。 | ||
| 67 | - | ||
| 68 | -## 问题根因 | ||
| 69 | - | ||
| 70 | -前处理中 Tokenizer encode 对 prompt 全量文本逐字符编码,未启用缓存机制。在多轮对话场景下,固定的 system prompt 每次请求都被重新编码,导致前处理耗时与 prompt 长度线性增长。8000 prompt 下前处理耗时约 250ms,占 TTFT 的 55.6%,NPU 在此期间完全空闲。 | ||
| 71 | - | ||
| 72 | -该问题属于**服务化管线配置问题**:Tokenizer 缓存未启用,且前后处理与模型推理共享 CPU 线程,阻塞 NPU 调度。该故障模式需补充至故障模式库。 | ||
| 73 | - | ||
| 74 | -## 问题结论 | ||
| 75 | - | ||
| 76 | -1. 前处理耗时过长的根因是 Tokenizer encode 未启用缓存,每次请求对全量 prompt 重新编码,8000 prompt 下耗时约 150ms。 | ||
| 77 | -2. 前后处理全流程在 CPU 侧执行,NPU 空闲等待约 270ms(前处理 250ms + 后处理 20ms),占 TTFT 的 60%。 | ||
| 78 | -3. 前处理耗时与 prompt 长度呈线性增长,16000 prompt 下前处理约 480ms,几乎与 Prefill 耗时持平。 | ||
| 79 | -4. 优化方向:启用 Tokenizer 缓存(system prompt 仅编码一次)、使用 Rust/C++ 层 Tokenizer 绕过 Python GIL、将前后处理与模型推理部署到不同线程/进程以避免阻塞 NPU 调度。 | ||
| 80 | - | ||
| 81 | -## 定位方法论总结 | ||
| 82 | - | ||
| 83 | -1. TTFT 异常偏高时,先通过 `msServiceProfiler` 采集全链路 timeline,确认 Prefill 前是否存在 CPU 空闲区间。 | ||
| 84 | -2. 通过 MindStudio Insight 定位前处理中各环节(Tokenizer encode、chat template、tensor 传输)的耗时占比。 | ||
| 85 | -3. 对比不同 prompt 长度下的前处理耗时,判断是否存在线性增长特征。 | ||
| 86 | -4. 对比冷热请求的前处理耗时,判断 Tokenizer 缓存是否生效。 | ||
| @@ -1,104 +0,0 @@ | |||
| 1 | -# 多实例负载不均 | ||
| 2 | - | ||
| 3 | -## 问题背景 | ||
| 4 | - | ||
| 5 | -推理服务通常由多个实例共同承接流量。理想情况下,请求量、token量、队列长度和KVCache水位应在实例间大致均衡;如果入口路由、实例权重、健康状态或请求长度分布异常,少数实例会成为热点,其他实例仍有空闲,整体吞吐和时延都会被热点实例限制。 | ||
| 6 | - | ||
| 7 | -## 问题来源 | ||
| 8 | - | ||
| 9 | -推理 | ||
| 10 | - | ||
| 11 | -## 问题现象 | ||
| 12 | - | ||
| 13 | -用户通常先看到整体吞吐低于多实例容量预期,或者P95/P99时延明显高于平均时延。按实例拆开后,常见现象是: | ||
| 14 | - | ||
| 15 | -- 少数实例请求数、token吞吐或batch大小持续高于其他实例。 | ||
| 16 | -- 热点实例waiting/pending请求更多,首Token时延和队列等待时间更高。 | ||
| 17 | -- 热点实例KVCache使用率更高,`free_kvcache_blocks`更低。 | ||
| 18 | -- 其他实例仍有空闲,但整体服务已经出现时延长尾。 | ||
| 19 | - | ||
| 20 | - | ||
| 21 | - | ||
| 22 | -## 定位过程 | ||
| 23 | - | ||
| 24 | -### 步骤 1:先确认是否存在热点实例 | ||
| 25 | - | ||
| 26 | -在Grafana实例维度面板中选择同一压测窗口或同一线上时间窗口,按实例比较: | ||
| 27 | - | ||
| 28 | -- 请求QPS、running/waiting请求数。 | ||
| 29 | -- prompt token、generation token和总token吞吐。 | ||
| 30 | -- 首Token时延、端到端时延和队列等待时间。 | ||
| 31 | -- batch大小、KVCache使用率、`free_kvcache_blocks`。 | ||
| 32 | - | ||
| 33 | -如果只有短时波动,不一定是故障;如果少数实例在多个连续窗口内持续更高,而其他实例持续偏低,可初步判断存在实例间负载偏斜。 | ||
| 34 | - | ||
| 35 | -### 步骤 2:判断偏斜来自请求数量还是请求重量 | ||
| 36 | - | ||
| 37 | -把“请求数”和“token数”分开看: | ||
| 38 | - | ||
| 39 | -- 请求数更多,token数也更多:结合网关日志、负载均衡配置、服务发现状态和连接复用情况,优先排查入口路由、实例权重或连接粘滞。 | ||
| 40 | -- 请求数接近,但token数更多、平均输入输出长度更长:结合请求日志、压测数据集或请求长度统计确认是否存在长请求集中到热点实例的情况。 | ||
| 41 | -- 请求数和token数都接近,但热点实例时延更高:结合服务启动参数、设备监控、进程日志和Profiler排查实例配置、设备状态、进程状态或本地资源竞争。 | ||
| 42 | - | ||
| 43 | -通过这一步先判断不均类型,再选择对应的排查方向。 | ||
| 44 | - | ||
| 45 | -### 步骤 3:检查入口路由和实例状态 | ||
| 46 | - | ||
| 47 | -如果判断为请求数量偏斜,需要结合网关、服务发现或负载均衡侧信息检查入口侧: | ||
| 48 | - | ||
| 49 | -- 各实例流量权重是否一致。 | ||
| 50 | -- 是否有实例健康检查异常,导致没有被分配流量。 | ||
| 51 | -- 长连接、连接池或会话粘滞是否让请求固定落到少数实例。 | ||
| 52 | -- 灰度、扩缩容或重启后,部分实例是否没有正常加入负载均衡。 | ||
| 53 | - | ||
| 54 | -如果判断为请求重量偏斜,需要结合请求长度统计和负载均衡策略,确认当前策略是否只按请求数分发,而没有感知输入长度、输出长度、队列状态或KVCache水位。 | ||
| 55 | - | ||
| 56 | -### 步骤 4:确认热点实例是否已经被资源卡住 | ||
| 57 | - | ||
| 58 | -继续看热点实例内部状态: | ||
| 59 | - | ||
| 60 | -- waiting/pending是否持续增加。 | ||
| 61 | -- KVCache使用率是否高位,空闲Block是否接近耗尽。 | ||
| 62 | -- NPU是否打满;如果NPU不满但队列变长,更可能是KVCache或调度资源卡住。 | ||
| 63 | -- 端到端时延升高是否主要来自排队等待或首Token阶段。 | ||
| 64 | - | ||
| 65 | -如果热点实例同时出现排队和KVCache高水位,需要结合“KV Block数量不足”场景继续下钻。 | ||
| 66 | - | ||
| 67 | -### 步骤 5:用Profiler对比热点实例和空闲实例 | ||
| 68 | - | ||
| 69 | -分别采集热点实例和空闲实例的`Schedule`、`Request`、`KVCache`数据,重点做对比: | ||
| 70 | - | ||
| 71 | -- `request.csv`:比较请求数量、输入长度、输出长度、`queue_wait_time(ms)`、`first_token_latency(ms)`。 | ||
| 72 | -- `batch.csv`:比较`batch_size`、`prefill_batch_size`、`decode_batch_size`、`total_scheduled_tokens`和`during_time(ms)`。 | ||
| 73 | -- `kvcache.csv`:比较`used_blocks`、`free_blocks`和`kvcache_usage_rate`。 | ||
| 74 | - | ||
| 75 | -如果热点实例请求更多或token更重,并且Profiler中排队、batch规模和KVCache水位都更高,可将问题闭环到实例间负载不均。 | ||
| 76 | - | ||
| 77 | -## 问题根因 | ||
| 78 | - | ||
| 79 | -多实例间承接的请求数量、请求长度或实例能力不一致。常见根因包括负载均衡权重错误、健康检查或服务发现异常、长连接/会话粘滞、长请求集中到少数实例、实例配置不一致,以及负载均衡策略未感知token量、队列长度或KVCache水位。 | ||
| 80 | - | ||
| 81 | -## 解决方法 | ||
| 82 | - | ||
| 83 | -- 路由权重错误:修正实例权重,确保所有健康实例都进入负载均衡。 | ||
| 84 | -- 健康检查异常:恢复异常实例或从负载均衡中移除不可用实例,避免流量只打到部分实例。 | ||
| 85 | -- 长连接或会话粘滞:调整连接池、网关策略或负载均衡算法,减少请求固定落点。 | ||
| 86 | -- 长请求集中:按输入/输出token量、队列长度或KVCache水位做调度,必要时隔离长短请求。 | ||
| 87 | -- 实例能力不一致:统一模型版本、启动参数、并行配置、显存配置和硬件规格。 | ||
| 88 | -- 热点实例KVCache耗尽:先限流或迁移流量,再按KV Block不足场景调整并发、长度或KVCache容量。 | ||
| 89 | - | ||
| 90 | -处理后需要回看实例间请求数、token数、waiting请求数、KVCache水位和P99时延是否收敛。 | ||
| 91 | - | ||
| 92 | -## 定位方法论总结 | ||
| 93 | - | ||
| 94 | -针对多实例负载不均场景,需要优先使用ms-service-metric按实例比较请求数、token吞吐、waiting请求数、时延和KVCache水位,先判断是否只有少数实例持续成为热点;确认存在实例间偏斜后,再使用msServiceProfiler分别采集热点实例和空闲实例的`request.csv`、`batch.csv`和`kvcache.csv`进行对比,区分入口路由/实例权重异常、请求长度分布偏斜、实例能力不一致或热点实例内部资源耗尽。 | ||
| 95 | - | ||
| 96 | -## 对工具的改进建议 | ||
| 97 | - | ||
| 98 | -### ms-service-metric | ||
| 99 | - | ||
| 100 | -当前在线监控已能按实例比较请求量、token量、时延、队列和KVCache水位。建议增加多实例负载偏斜提示,自动区分“请求数偏斜”和“请求长度/token重量偏斜”,并提示检查入口路由、实例权重或请求长度分布。 | ||
| 101 | - | ||
| 102 | -### msServiceProfiler | ||
| 103 | - | ||
| 104 | -当前Profiler已能分别采集热点实例和空闲实例的`request.csv`、`batch.csv`、`kvcache.csv`并进行人工对比。建议支持多实例采集结果合并分析,直接输出热点实例与空闲实例的请求量、token重量、batch规模、排队时间和KVCache水位差异。 | ||
| @@ -1,12 +1,14 @@ | |||
| 1 | -# 一、问题背景 | 1 | +# 算子编译高耗时 |
| 2 | + | ||
| 3 | +## 1. 问题背景 | ||
| 2 | 4 | ||
| 3 | 在NPU业务执行过程中,业务执行时间不及预期,通过采集profiling数据确认,存在较多算子编译耗时长问题,急需问题定位和性能优化。 | 5 | 在NPU业务执行过程中,业务执行时间不及预期,通过采集profiling数据确认,存在较多算子编译耗时长问题,急需问题定位和性能优化。 |
| 4 | 6 | ||
| 5 | -# 二、问题来源 | 7 | +## 2. 问题来源 |
| 6 | 8 | ||
| 7 | 性能调优 | 9 | 性能调优 |
| 8 | 10 | ||
| 9 | -# 三、问题现象 | 11 | +## 3. 问题现象 |
| 10 | 12 | ||
| 11 | 如图所示,典型算子编译接口建议锁定关键字“aclopCompile”。 | 13 | 如图所示,典型算子编译接口建议锁定关键字“aclopCompile”。 |
| 12 | 14 | ||
| @@ -20,7 +22,7 @@ | |||
| 20 | 22 | ||
| 21 |  | 23 |  |
| 22 | 24 | ||
| 23 | -# 四、问题根因 | 25 | +## 4. 问题根因 |
| 24 | 26 | ||
| 25 | 要想解决由于算子编译而引入的Host Bound问题,首先得先明确,在何种场景会触发算子编译行为。以此为依据来审视业务整体的算子调用,以及方便后续定位。 | 27 | 要想解决由于算子编译而引入的Host Bound问题,首先得先明确,在何种场景会触发算子编译行为。以此为依据来审视业务整体的算子调用,以及方便后续定位。 |
| 26 | 28 | ||
| @@ -32,7 +34,7 @@ | |||
| 32 | 34 | ||
| 33 | 而在非常情况下,在旧版本CANN包上、或未安装ops包时、或处于误用设置torch_npu.npu.set_compile_mode(jit_compile=True)的情况下,由于设置了不走二进制,会导致默认强制走算子编译。导致了大量编译行为。 | 35 | 而在非常情况下,在旧版本CANN包上、或未安装ops包时、或处于误用设置torch_npu.npu.set_compile_mode(jit_compile=True)的情况下,由于设置了不走二进制,会导致默认强制走算子编译。导致了大量编译行为。 |
| 34 | 36 | ||
| 35 | -# 五、定位过程 | 37 | +## 5. 定位过程 |
| 36 | 38 | ||
| 37 | 通过insight打开msprof.json或者trace_view.json。通过连线能力,找到compile api和实际执行算子的关系,找到对应算子。 | 39 | 通过insight打开msprof.json或者trace_view.json。通过连线能力,找到compile api和实际执行算子的关系,找到对应算子。 |
| 38 | 40 | ||
| @@ -46,7 +48,7 @@ | |||
| 46 | 48 | ||
| 47 |  | 49 |  |
| 48 | 50 | ||
| 49 | -# 六、定位方法总结 | 51 | +## 6. 定位方法总结 |
| 50 | 52 | ||
| 51 | 1、通过可视化工具,从timeline角度发现compile api,以及对应的算子关系 | 53 | 1、通过可视化工具,从timeline角度发现compile api,以及对应的算子关系 |
| 52 | 54 | ||
| @@ -58,6 +60,6 @@ | |||
| 58 | 60 | ||
| 59 |  | 61 |  |
| 60 | 62 | ||
| 61 | -# 七、对工具的改进建议 | 63 | +## 7. 对工具的改进建议 |
| 62 | 64 | ||
| 63 | 暂无 | 65 | 暂无 |
| @@ -1,102 +0,0 @@ | |||
| 1 | -# PrefixCache未命中 | ||
| 2 | - | ||
| 3 | -## 问题背景 | ||
| 4 | - | ||
| 5 | -在LLM推理应用中,长system prompt场景和多轮对话场景非常普遍。长system prompt场景下,不同请求的system prompt相同,对应的KV Cache计算也相同;多轮对话场景中,每一轮对话依赖所有历史轮次的上下文,历史轮次的KV Cache在后续每一轮中都要被重新计算。Prefix Caching(前缀缓存)通过缓存和复用已计算的公共前缀KV Cache,可以显著降低首Token时延(TTFT)和Prefill阶段计算量。Ascend-vLLM默认开启Prefix Caching特性,但在实际使用中,由于缓存命中条件不满足、缓存容量不足被淘汰、跨请求公共前缀token数不足block size等原因,可能出现PrefixCache未命中,导致TTFT升高、Prefill耗时增加。 | ||
| 6 | - | ||
| 7 | -## 问题来源 | ||
| 8 | - | ||
| 9 | -推理 | ||
| 10 | - | ||
| 11 | -## 问题现象 | ||
| 12 | - | ||
| 13 | -用户通常先看到推理服务的首Token时延(TTFT)出现波动性升高,部分请求的TTFT明显高于同类请求。进一步观察KVCache和请求相关指标时,可能出现: | ||
| 14 | - | ||
| 15 | -- 在`request.csv`中可观察到`cache_hit_rate`字段值偏低,`first_token_latency(ms)`偏高。 | ||
| 16 | -- 在`batch.csv`中,Prefill类型Batch的`during_time(ms)`和`prefill_scheduled_tokens`均偏高,说明大量前缀token被重新计算而非复用缓存。 | ||
| 17 | -- 在KVCache相关指标中,`kvcache_usage_rate`波动较大,`free_blocks`频繁变化,说明缓存在不断被分配和释放,而非稳定复用。 | ||
| 18 | -- 在`kvcache.csv`中可观察到频繁的block分配(`blocks_allocated`)和释放(`blocks_freed`)操作,且`blocks_allocated`的值接近请求的完整前缀token数,说明缓存未命中导致全量前缀重新分配。 | ||
| 19 | - | ||
| 20 | -典型场景:多轮对话中,第二轮及之后的请求TTFT与首轮请求TTFT几乎相同,未体现出PrefixCache应有的加速效果;长system prompt场景下,相同system prompt的不同请求之间TTFT无差异。 | ||
| 21 | - | ||
| 22 | -## 定位过程 | ||
| 23 | - | ||
| 24 | -### 步骤 1:先确认KVCache使用情况和TTFT变化 | ||
| 25 | - | ||
| 26 | -在Grafana中查看`free_kvcache_blocks`、`allocated_kvcache_blocks`、`kvcache_usage_rate`等KVCache相关指标。如果`kvcache_usage_rate`长期处于低位但`allocated_kvcache_blocks`频繁波动,说明缓存在被反复分配释放而非复用。同时观察TTFT指标(`first_token_latency`),如果TTFT波动大且与KVCache使用率变化相关,可初步怀疑PrefixCache命中率问题。 | ||
| 27 | - | ||
| 28 | -### 步骤 2:用Profiler采集请求和KVCache数据 | ||
| 29 | - | ||
| 30 | -配置`ms_service_profiler_config.json`,设置`domain`为`"Request; KVCache; Schedule"`,开启数据采集。采集完成后执行解析: | ||
| 31 | - | ||
| 32 | -```bash | ||
| 33 | -python3 -m ms_service_profiler.parse --input-path ${PATH}/prof_dir/ | ||
| 34 | -``` | ||
| 35 | - | ||
| 36 | -解析生成`request.csv`、`kvcache.csv`、`batch.csv`等文件。 | ||
| 37 | - | ||
| 38 | -### 步骤 3:分析request.csv中的缓存命中率和TTFT | ||
| 39 | - | ||
| 40 | -在`request.csv`中查看每条请求的`cache_hit_rate`字段。统计整体缓存命中率分布(平均值、P50、P90)。如果命中率普遍偏低,说明PrefixCache未有效工作。 | ||
| 41 | - | ||
| 42 | -按请求到达时间排序,观察`cache_hit_rate`的时间序列变化。如果命中率随时间波动大,可能是缓存容量不足导致频繁淘汰。对比相同`recv_token_size`(输入长度)的请求,如果输入长度相近但`first_token_latency(ms)`差异大,且低时延请求对应高`cache_hit_rate`,可确认PrefixCache命中率是TTFT的关键影响因素。 | ||
| 43 | - | ||
| 44 | -### 步骤 4:分析kvcache.csv中的缓存分配模式 | ||
| 45 | - | ||
| 46 | -在`kvcache.csv`中按时间序列观察`blocks_allocated`和`blocks_freed`的变化。如果每次新请求到达时`blocks_allocated`接近请求的完整前缀token数(而非仅增量部分),说明缓存未命中,全量前缀被重新分配。 | ||
| 47 | - | ||
| 48 | -统计`total_blocks`和`free_blocks`的变化趋势。如果`total_blocks`配置充足但`free_blocks`频繁大幅波动,说明缓存管理策略存在问题,可能是LRU淘汰策略过于激进或缓存容量配置不足。 | ||
| 49 | - | ||
| 50 | -### 步骤 5:分析batch.csv中的Prefill调度情况 | ||
| 51 | - | ||
| 52 | -筛选`batch_type`为`prefill`的行,查看`prefill_scheduled_tokens`和`during_time(ms)`。如果Prefill调度的token数接近请求的完整输入长度(而非增量),说明前缀未被缓存复用。对比相同输入长度的请求在不同时间的Prefill耗时,如果差异大且与缓存命中率相关,可确认根因。 | ||
| 53 | - | ||
| 54 | -### 步骤 6:用多维度解析工具获取请求维度统计 | ||
| 55 | - | ||
| 56 | -```bash | ||
| 57 | -msserviceprofiler analyze --input-path=/path/to/input | ||
| 58 | -``` | ||
| 59 | - | ||
| 60 | -查看`request_summary.csv`中`first_token_latency(ms)`的P50/P90/P99分位数和`input_token_num`分布,判断TTFT是否存在长尾。 | ||
| 61 | - | ||
| 62 | -## 问题根因 | ||
| 63 | - | ||
| 64 | -PrefixCache未命中的常见根因包括: | ||
| 65 | - | ||
| 66 | -1. **跨请求公共前缀token数不足block size**:Ascend-vLLM的Prefix Caching基于PagedAttention的block机制,仅当跨请求公共前缀token数大于等于block size时,才会复用公共前缀的KV Cache。如果公共前缀较短(如简短的system prompt),无法触发缓存复用。 | ||
| 67 | - | ||
| 68 | -2. **缓存容量不足导致频繁淘汰**:KVCache总block数(`total_blocks`)配置不足,或并发请求数过多导致缓存被快速占满。当新请求到达时,LRU策略淘汰了本可复用的前缀缓存,导致后续相同前缀请求无法命中。 | ||
| 69 | - | ||
| 70 | -3. **Prefix Caching特性未正确启用**:虽然Ascend-vLLM默认开启Prefix Caching,但如果同时配置了`ascend_scheduler_config`,两者存在冲突,Prefix Caching会被禁用。此外,多模态模型当前不支持Prefix Caching。 | ||
| 71 | - | ||
| 72 | -4. **请求前缀哈希冲突或缓存索引失效**:在分布式部署或多实例场景下,不同实例的缓存相互隔离,请求被路由到不同实例时无法复用其他实例的缓存。PD分离场景下,Prefill节点和Decode节点的缓存独立管理,跨节点缓存共享机制未启用。 | ||
| 73 | - | ||
| 74 | -5. **模型限制**:当前仅Qwen2.5和Qwen3系列模型支持Prefix Caching特性,其他模型使用该特性可能无效。 | ||
| 75 | - | ||
| 76 | -6. **Chunked Prefill与Prefix Caching的交互**:Prefix Caching生效时Chunked Prefill也同时生效,分块Prefill可能导致缓存块边界与请求前缀边界不对齐,影响缓存命中。 | ||
| 77 | - | ||
| 78 | -## 解决方法 | ||
| 79 | - | ||
| 80 | -- 公共前缀不足block size:确保system prompt或对话历史长度大于block size,或调整block size配置。 | ||
| 81 | -- 缓存容量不足:增加KVCache总block数配置,或降低单实例并发。 | ||
| 82 | -- Prefix Caching未启用:检查是否同时配置了`ascend_scheduler_config`,如有冲突则移除;确认模型在支持列表中。 | ||
| 83 | -- 分布式缓存隔离:在分布式场景启用跨节点KV Cache池化(如HIXL+MemFabric方案),实现缓存共享。 | ||
| 84 | -- Chunked Prefill交互:调整Chunked Prefill的分块大小,使其与block size对齐。 | ||
| 85 | - | ||
| 86 | -处理后需要回看`cache_hit_rate`是否提升、TTFT是否下降、`blocks_allocated`是否从全量分配变为增量分配。 | ||
| 87 | - | ||
| 88 | -## 定位方法论总结 | ||
| 89 | - | ||
| 90 | -该场景的完整判断链是:先用ms-service-metric观察KVCache使用率波动和TTFT变化趋势;再用msServiceProfiler采集Request和KVCache domain数据,通过`request.csv`的`cache_hit_rate`字段直接确认缓存命中率;然后通过`kvcache.csv`分析缓存分配释放模式,判断是容量不足还是命中条件不满足;最后结合`batch.csv`的Prefill调度token数确认前缀是否被重新计算。 | ||
| 91 | - | ||
| 92 | -核心判断逻辑:如果`cache_hit_rate`低且`blocks_allocated`接近完整前缀token数,则PrefixCache未命中。进一步判断:如果`free_blocks`长期接近0,则是容量不足;如果`free_blocks`充足但命中率仍低,则需检查公共前缀长度是否满足block size要求、Prefix Caching是否被正确启用、模型是否支持该特性。 | ||
| 93 | - | ||
| 94 | -## 对工具的改进建议 | ||
| 95 | - | ||
| 96 | -### ms-service-metric | ||
| 97 | - | ||
| 98 | -当前在线监控已能查看KVCache水位和TTFT指标。建议增加PrefixCache命中率在线监控指标,直接展示`cache_hit_rate`的时间序列,便于实时观察缓存效果。增加PrefixCache未命中告警,当命中率持续偏低时自动输出风险提示。增加公共前缀长度分布统计,帮助用户判断请求前缀是否满足block size要求。 | ||
| 99 | - | ||
| 100 | -### msServiceProfiler | ||
| 101 | - | ||
| 102 | -当前Profiler已能通过`request.csv`的`cache_hit_rate`字段确认缓存命中率。建议在`request.csv`中增加`cache_hit_blocks`和`cache_miss_blocks`字段,区分命中block数和未命中block数,便于精确分析缓存效果。在`kvcache.csv`中增加缓存淘汰原因字段(如LRU淘汰、请求结束释放、手动失效等),帮助分析缓存未命中的具体原因。在解析结果中增加PrefixCache诊断报告,自动检测公共前缀长度是否满足block size、是否存在`ascend_scheduler_config`冲突等常见配置问题。 | ||
| @@ -1,16 +1,16 @@ | |||
| 1 | # Pthread线程锁等待 | 1 | # Pthread线程锁等待 |
| 2 | 2 | ||
| 3 | -## 【问题背景】 | 3 | +## 1. 问题背景 |
| 4 | 4 | ||
| 5 | 在 PyTorch 大模型分布式训练场景中,[DataLoader、pin_memory](https://docs.pytorch.org/docs/2.12/data.html#torch.utils.data.DataLoader) 模块采用多线程生产者 - 消费者模型,使用 pthread 互斥锁(pthread_mutex_t)保护共享队列的并发访问。 | 5 | 在 PyTorch 大模型分布式训练场景中,[DataLoader、pin_memory](https://docs.pytorch.org/docs/2.12/data.html#torch.utils.data.DataLoader) 模块采用多线程生产者 - 消费者模型,使用 pthread 互斥锁(pthread_mutex_t)保护共享队列的并发访问。 |
| 6 | 6 | ||
| 7 | 训练运行在多卡 NPU 服务器上,数据加载线程池配置为 16 个 worker 线程,主线程负责从队列中取数据喂给 NPU 计算。随着 batch size 增大和数据预处理逻辑复杂化,训练性能出现下降。 | 7 | 训练运行在多卡 NPU 服务器上,数据加载线程池配置为 16 个 worker 线程,主线程负责从队列中取数据喂给 NPU 计算。随着 batch size 增大和数据预处理逻辑复杂化,训练性能出现下降。 |
| 8 | 8 | ||
| 9 | -## 【问题来源】 | 9 | +## 2. 问题来源 |
| 10 | 10 | ||
| 11 | 训练。 | 11 | 训练。 |
| 12 | 12 | ||
| 13 | -## 【问题现象】 | 13 | +## 3. 问题现象 |
| 14 | 14 | ||
| 15 | 稳定复现。 | 15 | 稳定复现。 |
| 16 | 16 | ||
| @@ -33,7 +33,7 @@ | |||
| 33 | 33 | ||
| 34 |  | 34 |  |
| 35 | 35 | ||
| 36 | -## 【定位过程】 | 36 | +## 4. 定位过程 |
| 37 | 37 | ||
| 38 | 1. 使用 perf 工具做进程级性能采样 | 38 | 1. 使用 perf 工具做进程级性能采样 |
| 39 | 39 | ||
| @@ -97,7 +97,7 @@ | |||
| 97 | 97 | ||
| 98 | 可以从检测结果中观察到,`pthread_cond_wait` 函数占比较高,这是锁等待的主要原因。同时,`read`、`ioctl` 等函数也占比较高,这是数据预处理逻辑耗时的主要原因。根据这些信息,我们可以定位到数据预处理逻辑的性能瓶颈。 | 98 | 可以从检测结果中观察到,`pthread_cond_wait` 函数占比较高,这是锁等待的主要原因。同时,`read`、`ioctl` 等函数也占比较高,这是数据预处理逻辑耗时的主要原因。根据这些信息,我们可以定位到数据预处理逻辑的性能瓶颈。 |
| 99 | 99 | ||
| 100 | -## 【问题根因】 | 100 | +## 5. 问题根因 |
| 101 | 101 | ||
| 102 | 1. 锁粒度设计错误: | 102 | 1. 锁粒度设计错误: |
| 103 | 103 | ||
| @@ -109,7 +109,7 @@ | |||
| 109 | - 使用默认的 `PTHREAD_MUTEX_TIMED_NP` 类型,在高竞争下性能退化严重。 | 109 | - 使用默认的 `PTHREAD_MUTEX_TIMED_NP` 类型,在高竞争下性能退化严重。 |
| 110 | - 未启用 `PTHREAD_MUTEX_ADAPTIVE_NP` 自适应锁,导致内核态 futex 等待过多。 | 110 | - 未启用 `PTHREAD_MUTEX_ADAPTIVE_NP` 自适应锁,导致内核态 futex 等待过多。 |
| 111 | 111 | ||
| 112 | -## 【定位方法论总结】 | 112 | +## 6. 定位方法论总结 |
| 113 | 113 | ||
| 114 | 针对线程锁等待场景,需要优先执行以下定位步骤: | 114 | 针对线程锁等待场景,需要优先执行以下定位步骤: |
| 115 | 115 | ||
| @@ -123,7 +123,7 @@ | |||
| 123 | - 从 `MSOSRT` 检测结果中,定位到 `pthread_cond_wait` 函数占比较高,这是锁等待的主要原因。 | 123 | - 从 `MSOSRT` 检测结果中,定位到 `pthread_cond_wait` 函数占比较高,这是锁等待的主要原因。 |
| 124 | - 分析 `read`、`ioctl` 等函数占比较高,这是数据预处理逻辑耗时的主要原因。 | 124 | - 分析 `read`、`ioctl` 等函数占比较高,这是数据预处理逻辑耗时的主要原因。 |
| 125 | 125 | ||
| 126 | -## 【对工具的改进建议】 | 126 | +## 7. 对工具的改进建议 |
| 127 | 127 | ||
| 128 | 1. msprof 集成 perf 工具增强: | 128 | 1. msprof 集成 perf 工具增强: |
| 129 | 129 | ||
| @@ -1,20 +1,20 @@ | |||
| 1 | # Python GC回收高耗时 | 1 | # Python GC回收高耗时 |
| 2 | 2 | ||
| 3 | -## 【问题背景】 | 3 | +## 1. 问题背景 |
| 4 | 4 | ||
| 5 | 客户在多机分布式环境下进行类 GPT 大模型训练时,观测到训练过程中出现频繁的性能抖动现象。 | 5 | 客户在多机分布式环境下进行类 GPT 大模型训练时,观测到训练过程中出现频繁的性能抖动现象。 |
| 6 | 6 | ||
| 7 | -## 【问题来源】 | 7 | +## 2. 问题来源 |
| 8 | 8 | ||
| 9 | 训练。 | 9 | 训练。 |
| 10 | 10 | ||
| 11 | -## 【问题现象】 | 11 | +## 3. 问题现象 |
| 12 | 12 | ||
| 13 | 稳定复现,通过长跑分析发现,各节点的训练单步(step)耗时在抖动趋势与发生频率上呈现出高度一致性,单步 step 耗时周期性从 2770ms 左右抖动到 2900ms 左右,现象如下: | 13 | 稳定复现,通过长跑分析发现,各节点的训练单步(step)耗时在抖动趋势与发生频率上呈现出高度一致性,单步 step 耗时周期性从 2770ms 左右抖动到 2900ms 左右,现象如下: |
| 14 | 14 | ||
| 15 |  | 15 |  |
| 16 | 16 | ||
| 17 | -## 【定位过程】 | 17 | +## 4. 定位过程 |
| 18 | 18 | ||
| 19 | 1. 通过 Ascend PyTorch Profiler 工具,打开 GC 检测选项,对模型性能进行采集与深度分析后发现,在训练耗时出现抖动的异常 step 中,对应的 Timeline 时间线上存在一段显著的 free 耗时。该 free 发生在框架侧的 Python 函数调用栈中,与 NPU 硬件执行及 HCCL 通信算子无直接关联。经过多轮重复采集与交叉验证后可确认,这段耗时异常的 free 均出现在同一个 nn.Module 模块的执行路径中,并在同一时间段内检测到了 GC 事件。 | 19 | 1. 通过 Ascend PyTorch Profiler 工具,打开 GC 检测选项,对模型性能进行采集与深度分析后发现,在训练耗时出现抖动的异常 step 中,对应的 Timeline 时间线上存在一段显著的 free 耗时。该 free 发生在框架侧的 Python 函数调用栈中,与 NPU 硬件执行及 HCCL 通信算子无直接关联。经过多轮重复采集与交叉验证后可确认,这段耗时异常的 free 均出现在同一个 nn.Module 模块的执行路径中,并在同一时间段内检测到了 GC 事件。 |
| 20 | 20 | ||
| @@ -86,7 +86,7 @@ | |||
| 86 | 86 | ||
| 87 | 实验结果:抖动仍然存在,但发生频次减少。 | 87 | 实验结果:抖动仍然存在,但发生频次减少。 |
| 88 | 88 | ||
| 89 | -## 【问题根因】 | 89 | +## 5. 问题根因 |
| 90 | 90 | ||
| 91 | Python 作为解释型语言,其底层通过 C 语言实现的解释器逐条解析并执行字节码指令。在 Python 的内存管理机制中,每个对象都维护着一个引用计数器,用于实时追踪对象的被引用状态。当对象的引用计数降至 0 时,表明该对象已不再被任何地方引用,Python 会立即自动回收该对象所占用的内存空间。 | 91 | Python 作为解释型语言,其底层通过 C 语言实现的解释器逐条解析并执行字节码指令。在 Python 的内存管理机制中,每个对象都维护着一个引用计数器,用于实时追踪对象的被引用状态。当对象的引用计数降至 0 时,表明该对象已不再被任何地方引用,Python 会立即自动回收该对象所占用的内存空间。 |
| 92 | 92 | ||
| @@ -94,10 +94,10 @@ Python 作为解释型语言,其底层通过 C 语言实现的解释器逐条 | |||
| 94 | 94 | ||
| 95 | 需要特别注意的是,GC 垃圾回收操作是一项计算密集型任务,执行耗时较长,且执行过程中会阻塞整个 Python 进程(Stop-The-World 特性)。对于大模型训练这类对性能稳定性要求极高的场景而言,GC 被触发时最典型的外部表现就是:单个训练 Step 耗时突然异常升高,整体训练过程呈现出明显的周期性性能抖动。 | 95 | 需要特别注意的是,GC 垃圾回收操作是一项计算密集型任务,执行耗时较长,且执行过程中会阻塞整个 Python 进程(Stop-The-World 特性)。对于大模型训练这类对性能稳定性要求极高的场景而言,GC 被触发时最典型的外部表现就是:单个训练 Step 耗时突然异常升高,整体训练过程呈现出明显的周期性性能抖动。 |
| 96 | 96 | ||
| 97 | -## 【定位方法论总结】 | 97 | +## 6. 定位方法论总结 |
| 98 | 98 | ||
| 99 | 针对于该场景需要优先使用 Ascend PyTorch Profiler 工具,获取模型性能数据分析,查看 Timeline 中是否有 GC 事件发生,若存在,需要分析 GC 事件的触发条件、影响范围及耗时,并调整 Python GC 回收阈值,避免 GC 事件频繁触发。 | 99 | 针对于该场景需要优先使用 Ascend PyTorch Profiler 工具,获取模型性能数据分析,查看 Timeline 中是否有 GC 事件发生,若存在,需要分析 GC 事件的触发条件、影响范围及耗时,并调整 Python GC 回收阈值,避免 GC 事件频繁触发。 |
| 100 | 100 | ||
| 101 | -## 【对工具的改进建议】 | 101 | +## 7. 对工具的改进建议 |
| 102 | 102 | ||
| 103 | 暂无。 | 103 | 暂无。 |
| @@ -1,253 +0,0 @@ | |||
| 1 | -# 模型推理请求等待时间过长问题调优指导实例 | ||
| 2 | - | ||
| 3 | -## 场景说明 | ||
| 4 | - | ||
| 5 | -在大模型推理服务化场景中,请求从进入服务到开始执行模型推理之间,通常会经过网关转发、请求入队、批处理组batch、Prefill执行、Decode调度、结果回传等阶段。若请求等待时间过长,用户侧会表现为首Token时延升高、端到端时延P99变差、低负载下响应不稳定或高负载下排队持续堆积。 | ||
| 6 | - | ||
| 7 | -本文以推理请求等待时间过长为例,介绍如何使用msServiceProfiler采集Request和BatchSchedule数据,定位等待时间主要发生在入口排队、组batch等待、Prefill/Decode资源竞争、外部依赖阻塞还是系统资源瓶颈,并给出批处理、调度、资源、缓存和监控方向的优化方案。 | ||
| 8 | - | ||
| 9 | -## 问题现象 | ||
| 10 | - | ||
| 11 | -**典型表现** | ||
| 12 | - | ||
| 13 | -- Request_Status_curve中waiting状态请求数持续升高,长时间无法回落。 | ||
| 14 | -- First_Token_Latency_curve的P90/P99明显偏高,但模型单次执行耗时并未同比升高。 | ||
| 15 | -- Request_Latency_curve端到端时延抖动大,高峰流量下尾延迟快速放大。 | ||
| 16 | -- Batch_Size_curve显示batch长期偏小或等待时间过长,说明组batch策略与请求负载不匹配。 | ||
| 17 | -- Prefill请求和Decode请求互相抢占资源,短请求被长请求阻塞。 | ||
| 18 | -- 服务进程CPU繁忙但NPU利用率低,说明请求可能阻塞在I/O、调度或预处理阶段。 | ||
| 19 | - | ||
| 20 | -**影响范围** | ||
| 21 | - | ||
| 22 | -| 影响项 | 表现 | | ||
| 23 | -| --- | --- | | ||
| 24 | -| 首Token时延 | 请求长时间等待组batch或Prefill资源,TTFT升高。 | | ||
| 25 | -| 端到端时延 | 排队时间被放大,Request Latency P90/P99恶化。 | | ||
| 26 | -| 吞吐 | batch未打满或调度过于保守,NPU利用率不足。 | | ||
| 27 | -| 稳定性 | 高峰流量下队列持续堆积,出现超时或请求失败。 | | ||
| 28 | -| 资源利用率 | CPU、内存、KVCache或NPU资源分配不均,导致局部瓶颈。 | | ||
| 29 | - | ||
| 30 | -## 数据采集 | ||
| 31 | - | ||
| 32 | -### 功能说明 | ||
| 33 | - | ||
| 34 | -使用msServiceProfiler采集Request、BatchSchedule、ModelExecute、KVCache和Communication域数据,结合batch.csv、request.csv、BatchSchedule.csv、forward.csv以及可视化曲线,拆解请求等待时间来源。 | ||
| 35 | - | ||
| 36 | -### 注意事项 | ||
| 37 | - | ||
| 38 | -- 建议在稳定复现的压测场景下采集,记录并发、输入输出长度、maxBatchSize和max_wait_time等关键参数。 | ||
| 39 | -- 若等待时间主要出现在服务入口或外部依赖,需要同时采集业务网关、数据库、缓存和后处理链路日志。 | ||
| 40 | -- 多实例或分布式集群场景需保证各节点时间同步,避免Timeline分析出现偏差。 | ||
| 41 | -- 开启更多domain会增加采集数据量,建议先采集Request和BatchSchedule,再按需增加ModelExecute、KVCache和Communication。 | ||
| 42 | - | ||
| 43 | -### 配置示例 | ||
| 44 | - | ||
| 45 | -创建ms_service_profiler_config.json,采集请求状态、批处理调度和模型执行数据。 | ||
| 46 | - | ||
| 47 | -```json | ||
| 48 | -{ | ||
| 49 | - "enable": 1, | ||
| 50 | - "prof_dir": "${HOME}/.ms_server_profiler", | ||
| 51 | - "profiler_level": "INFO", | ||
| 52 | - "domain": "Request;BatchSchedule;ModelExecute;KVCache;Communication" | ||
| 53 | -} | ||
| 54 | -``` | ||
| 55 | - | ||
| 56 | -启动服务前设置配置文件路径。 | ||
| 57 | - | ||
| 58 | -```bash | ||
| 59 | -export SERVICE_PROF_CONFIG_PATH=/path/to/ms_service_profiler_config.json | ||
| 60 | -``` | ||
| 61 | - | ||
| 62 | -解析时建议导出默认Span数据,重点查看forward.csv和BatchSchedule.csv。 | ||
| 63 | - | ||
| 64 | -```bash | ||
| 65 | -ms_service_profiler_parse --input-path ${PROF_DIR} --output-path ${OUTPUT_DIR} --span | ||
| 66 | -``` | ||
| 67 | - | ||
| 68 | -### 插桩建议 | ||
| 69 | - | ||
| 70 | -若框架中已有自定义调度逻辑,可增加请求排队、组batch、外部依赖和模型执行前后的Span与Metric。 | ||
| 71 | - | ||
| 72 | -```C++ | ||
| 73 | -auto enqueueSpan = PROF(INFO, SpanStart("RequestEnqueue")); | ||
| 74 | - | ||
| 75 | -// 请求入队、鉴权、参数解析等逻辑 | ||
| 76 | - | ||
| 77 | -PROF(enqueueSpan.SpanEnd()); | ||
| 78 | - | ||
| 79 | -auto batchWaitSpan = PROF(INFO, SpanStart("BatchWait")); | ||
| 80 | - | ||
| 81 | -// 等待组batch或等待max_wait_time触发 | ||
| 82 | - | ||
| 83 | -PROF(batchWaitSpan.SpanEnd()); | ||
| 84 | - | ||
| 85 | -auto modelReadySpan = PROF(INFO, SpanStart("ModelReady")); | ||
| 86 | - | ||
| 87 | -// Prefill/Decode调度完成,准备进入模型执行 | ||
| 88 | - | ||
| 89 | -PROF(modelReadySpan.SpanEnd()); | ||
| 90 | -``` | ||
| 91 | - | ||
| 92 | -采集队列长度、组batch等待时间和外部依赖耗时。 | ||
| 93 | - | ||
| 94 | -```C++ | ||
| 95 | -PROF(INFO, Metric("requestQueueSize", requestQueueSize).MetricScope("scheduler", instanceId).Launch()); | ||
| 96 | -PROF(INFO, Metric("batchWaitMs", batchWaitMs).MetricScope("batch", batchId).Launch()); | ||
| 97 | -PROF(INFO, Metric("externalIOMs", externalIOMs).MetricScope("request", reqId).Launch()); | ||
| 98 | -``` | ||
| 99 | - | ||
| 100 | -## 定位方法 | ||
| 101 | - | ||
| 102 | -1. 查看Request_Status_curve。 | ||
| 103 | - - waiting请求数持续升高:入口流量超过服务消费能力,需检查batch策略、实例数量和资源瓶颈。 | ||
| 104 | - - waiting周期性升高后回落:可能是max_wait_time过长或批处理窗口过大导致。 | ||
| 105 | - - running请求数很低但waiting很高:请求可能阻塞在调度、I/O或线程池阶段。 | ||
| 106 | - | ||
| 107 | -2. 查看Batch_Size_curve和batch.csv。 | ||
| 108 | - - batch size长期低于maxBatchSize:可能是max_wait_time过短、并发不足或调度条件过严。 | ||
| 109 | - - batch size接近maxBatchSize但等待仍高:可能是模型执行能力不足,需扩容或优化Prefill/Decode调度。 | ||
| 110 | - - prefill_batch_size和decode_batch_size波动大:可能是Prefill和Decode资源竞争,需调整优先级策略。 | ||
| 111 | - | ||
| 112 | -3. 查看First_Token_Latency_curve。 | ||
| 113 | - - TTFT升高且Prefill执行耗时正常:等待主要发生在请求入队到Prefill开始之间。 | ||
| 114 | - - TTFT升高且Prefill执行耗时也升高:需检查maxPrefillBatchSize、maxSeqLen、KVCache和Prefill算子性能。 | ||
| 115 | - | ||
| 116 | -4. 查看Request_Latency_curve。 | ||
| 117 | - - 端到端P99升高但平均值变化小:说明少量请求被长队列、长上下文或外部依赖拖慢。 | ||
| 118 | - - 平均值和P99同时升高:说明服务整体消费能力不足,应优先扩容或降低单请求计算成本。 | ||
| 119 | - | ||
| 120 | -## 原因分析与解决方案 | ||
| 121 | - | ||
| 122 | -### 批处理参数不匹配 | ||
| 123 | - | ||
| 124 | -**原因** | ||
| 125 | - | ||
| 126 | -maxBatchSize过小会限制吞吐,max_wait_time过长会让请求在低负载下等待过久,max_wait_time过短又会导致batch难以打满。若参数与实际并发和请求长度不匹配,会同时影响等待时间和吞吐。 | ||
| 127 | - | ||
| 128 | -**解决方案** | ||
| 129 | - | ||
| 130 | -- 根据硬件资源逐步增大maxBatchSize,例如将voc_inference_max_bs从4调整为8,并观察NPU利用率和Request Latency。 | ||
| 131 | -- 缩短最大等待时间,例如将voc_inference_max_wait_ms调整到20ms,降低低负载下的组batch等待。 | ||
| 132 | -- 建立动态批处理策略:低负载时适当等待以提升batch利用率,高负载时缩短等待窗口以降低尾延迟。 | ||
| 133 | -- 每次调整后对比Batch_Size_curve、Request_Status_curve、First_Token_Latency和吞吐,避免只优化单一指标。 | ||
| 134 | - | ||
| 135 | -### Prefill/Decode调度策略不合理 | ||
| 136 | - | ||
| 137 | -**原因** | ||
| 138 | - | ||
| 139 | -Prefill阶段通常计算量大,Decode阶段需要持续迭代。如果调度策略固定或只按到达顺序处理,长Prefill请求可能阻塞Decode,Decode持续占用也可能导致新请求首Token等待过长。 | ||
| 140 | - | ||
| 141 | -**解决方案** | ||
| 142 | - | ||
| 143 | -- 启用Prefill/Decode优先级调度,根据prefillTimeMsPerReq与decodeTimeMsPerReq动态选择调度策略。 | ||
| 144 | -- 对短请求设置更高调度优先级,减少短请求被长上下文请求阻塞的概率。 | ||
| 145 | -- 在高并发下限制单轮Prefill占用,避免Decode被长期饿死。 | ||
| 146 | -- 对长上下文或超长输出请求单独分桶,避免拖慢普通请求队列。 | ||
| 147 | -- 结合BatchSchedule.csv观察prefill和decode batch的时间分布,确认调度调整是否降低排队时间。 | ||
| 148 | - | ||
| 149 | -### 同步阻塞或外部依赖拖慢主线程 | ||
| 150 | - | ||
| 151 | -**原因** | ||
| 152 | - | ||
| 153 | -服务化链路中可能存在鉴权、数据库查询、向量检索、日志落盘、网络调用或后处理逻辑。如果这些操作在主线程或调度线程中同步执行,会导致请求无法及时入队或组batch。 | ||
| 154 | - | ||
| 155 | -**解决方案** | ||
| 156 | - | ||
| 157 | -- 引入异步非阻塞架构,例如使用FastAPI等异步框架处理I/O操作。 | ||
| 158 | -- 将数据库查询、缓存访问、日志落盘和后处理从调度关键路径移出。 | ||
| 159 | -- 为外部依赖设置超时和降级策略,避免单个慢依赖拖住整个请求。 | ||
| 160 | -- 使用Metric记录externalIOMs和requestQueueSize,确认等待是否来自外部I/O。 | ||
| 161 | - | ||
| 162 | -### 实例资源不足或负载不均 | ||
| 163 | - | ||
| 164 | -**原因** | ||
| 165 | - | ||
| 166 | -单实例承接过多请求时,队列会持续堆积。多实例部署中若路由策略粗糙,可能出现部分实例过载、部分实例空闲,导致整体P99升高。 | ||
| 167 | - | ||
| 168 | -**解决方案** | ||
| 169 | - | ||
| 170 | -- 部署分布式推理集群,通过Kubernetes Service或网关进行多实例负载均衡。 | ||
| 171 | -- 使用HPA基于QPS、队列长度、NPU利用率或P99延迟自动扩缩容。 | ||
| 172 | -- 建立智能请求路由,采用“网关粗分桶 + 实例细预测”的两阶段调度策略。 | ||
| 173 | -- 将不同长度、不同业务优先级或不同模型版本的请求分流到对应实例池。 | ||
| 174 | -- 对过载实例设置熔断和排队上限,避免尾延迟无限放大。 | ||
| 175 | - | ||
| 176 | -### Prefill与Decode资源竞争 | ||
| 177 | - | ||
| 178 | -**原因** | ||
| 179 | - | ||
| 180 | -Prefill阶段和Decode阶段对计算、显存和KVCache的需求不同。若二者部署在同一资源池中,在长上下文或高并发场景下容易互相抢占,导致请求等待和Decode抖动。 | ||
| 181 | - | ||
| 182 | -**解决方案** | ||
| 183 | - | ||
| 184 | -- 采用PD分离架构,将Prefill和Decode部署在不同节点或实例池中。 | ||
| 185 | -- 通过高性能KV Cache传输降低Prefill到Decode切换成本。 | ||
| 186 | -- 分别为Prefill实例和Decode实例设置不同的batch、并发和扩缩容策略。 | ||
| 187 | -- 对PD分离链路采集Communication域数据,确认KV Cache传输没有成为新的瓶颈。 | ||
| 188 | - | ||
| 189 | -### 缓存与预处理缺失 | ||
| 190 | - | ||
| 191 | -**原因** | ||
| 192 | - | ||
| 193 | -重复请求、相似查询、固定系统Prompt和长历史上下文如果每次都完整计算,会增加Prefill阶段负载和请求等待时间。 | ||
| 194 | - | ||
| 195 | -**解决方案** | ||
| 196 | - | ||
| 197 | -- 构建向量缓存层,例如使用Redis缓存热门问题的Embedding或检索结果,减少重复Embedding模型调用。 | ||
| 198 | -- 对高频固定前缀启用Prefix Cache,复用历史上下文的KV Cache,降低Prefill计算开销。 | ||
| 199 | -- 对请求预处理结果进行缓存,例如模板拼接、分词或路由判定结果。 | ||
| 200 | -- 监控缓存命中率,并将命中率与TTFT、Prefill耗时关联分析。 | ||
| 201 | - | ||
| 202 | -### 系统级性能抖动 | ||
| 203 | - | ||
| 204 | -**原因** | ||
| 205 | - | ||
| 206 | -CPU调度抖动、内存页抖动、线程迁移或KVCache显存碎片化,可能导致请求等待时间不稳定。流式输入或语音模型场景中,内存页和CPU调度影响会更明显。 | ||
| 207 | - | ||
| 208 | -**解决方案** | ||
| 209 | - | ||
| 210 | -- 对关键线程开启CPU绑核,减少线程迁移。 | ||
| 211 | -- 根据系统要求评估透明大页配置,降低内存管理抖动。 | ||
| 212 | -- 使用PagedAttention类技术对KV Cache进行分块管理,提高显存利用率并降低碎片化。 | ||
| 213 | -- 对语音流式输入场景,优化内存页和缓冲区大小,减少小块数据频繁拷贝。 | ||
| 214 | - | ||
| 215 | -## 优化验证 | ||
| 216 | - | ||
| 217 | -建议按“批处理参数 -> 调度策略 -> 异步链路 -> 资源扩容 -> 缓存与系统优化”的顺序逐项验证。 | ||
| 218 | - | ||
| 219 | -| 优化项 | 观察指标 | 期望结果 | | ||
| 220 | -| --- | --- | --- | | ||
| 221 | -| 调整maxBatchSize | Batch_Size_curve、吞吐 | batch更接近目标大小,NPU利用率提升。 | | ||
| 222 | -| 调整max_wait_time | First_Token_Latency、Request_Status_curve | TTFT下降,waiting队列更快回落。 | | ||
| 223 | -| Prefill/Decode优先级 | BatchSchedule.csv、Decode时延 | Prefill和Decode互相阻塞减少。 | | ||
| 224 | -| 异步I/O | externalIOMs、requestQueueSize | 主线程阻塞降低,请求入队更稳定。 | | ||
| 225 | -| 分布式扩容 | P99延迟、实例负载 | 高峰期waiting队列不再持续堆积。 | | ||
| 226 | -| Prefix Cache | Prefill耗时、TTFT | 重复前缀请求首Token时延下降。 | | ||
| 227 | -| PagedAttention | KVCache使用率、并发 | 显存利用率提升,可承接更多请求。 | | ||
| 228 | - | ||
| 229 | -优化有效时,通常会看到以下结果: | ||
| 230 | - | ||
| 231 | -- Request_Status_curve中waiting队列峰值下降,回落速度变快。 | ||
| 232 | -- First_Token_Latency的P90/P99下降。 | ||
| 233 | -- Request_Latency的P99更稳定,高峰期超时减少。 | ||
| 234 | -- Batch_Size_curve更符合预期,低负载不过度等待,高负载不过度堆积。 | ||
| 235 | -- NPU利用率提升,CPU或I/O阻塞时间下降。 | ||
| 236 | - | ||
| 237 | -在批处理拼接推理生效的场景中,总耗时可由串行的多次单请求耗时降低到接近一次批处理执行时间,NPU利用率也会明显提升。若动态批处理和异步架构同时生效,应重点观察TTFT、非首Token平均延迟和tokens/s是否同时改善。 | ||
| 238 | - | ||
| 239 | -## 推荐处理策略 | ||
| 240 | - | ||
| 241 | -| 问题类型 | 推荐方案 | | ||
| 242 | -| --- | --- | | ||
| 243 | -| 低负载下等待高 | 缩短max_wait_time,降低组batch等待窗口。 | | ||
| 244 | -| 高负载下队列堆积 | 增大maxBatchSize或扩容实例,启用动态批处理。 | | ||
| 245 | -| TTFT高但模型执行正常 | 优先排查请求入队、组batch等待、外部I/O和Prefill调度。 | | ||
| 246 | -| Decode抖动明显 | 优化Prefill/Decode优先级,评估PD分离和通信优化。 | | ||
| 247 | -| 重复请求占比高 | 启用向量缓存、结果缓存或Prefix Cache。 | | ||
| 248 | -| KVCache接近上限 | 调整maxSeqLen、限制并发或启用PagedAttention类管理能力。 | | ||
| 249 | -| 多实例P99高 | 优化请求路由,使用HPA和实例细粒度负载预测。 | | ||
| 250 | - | ||
| 251 | -## 总结 | ||
| 252 | - | ||
| 253 | -模型推理请求等待时间过长的核心原因通常不只在模型执行本身,而是出现在请求入队、组batch等待、Prefill/Decode调度、外部I/O、资源竞争和缓存缺失等服务化链路中。定位时应先使用msServiceProfiler采集Request和BatchSchedule数据,通过Request_Status_curve、Batch_Size_curve、First_Token_Latency和Request_Latency判断等待发生位置。优化时建议优先调整maxBatchSize和max_wait_time,再引入Prefill/Decode优先级调度、异步I/O、分布式扩容、PD分离、Prefix Cache和PagedAttention等能力,逐步降低TTFT和端到端P99。 | ||
| @@ -1,95 +0,0 @@ | |||
| 1 | -# sampler执行耗时过长问题分析 | ||
| 2 | - | ||
| 3 | -## 【问题背景】 | ||
| 4 | - | ||
| 5 | -在大模型推理服务化场景中,Sampler(采样器)是生成阶段的核心组件之一,负责在模型完成单次前向推理后,根据logits计算概率分布并采样得到下一个Token。Sampler的执行逻辑包含Softmax归一化、Top-K/Top-P筛选、温度缩放、随机采样或贪心选择等多个环节。当Sampler执行耗时过长时,会直接拖慢整个Decode阶段的端到端延迟,尤其是在每轮迭代都会触发的高频Decode阶段,影响将被持续放大。 | ||
| 6 | - | ||
| 7 | -## 【问题来源】 | ||
| 8 | - | ||
| 9 | -推理 | ||
| 10 | - | ||
| 11 | -## 【问题现象】 | ||
| 12 | - | ||
| 13 | -稳定复现(在高并发或长序列场景下)。 | ||
| 14 | -**问题类型:** 计算瓶颈 / Host-NPU交互开销。 | ||
| 15 | - | ||
| 16 | -1. **Timeline中sampler阶段耗时异常**:在MindStudio Insight时间线中,观察到一个请求的模型执行周期内,`modelExec`(模型前向)结束后,`sampler`相关操作占用了一段明显的时间条,其耗时与模型计算本身相当甚至更长。 | ||
| 17 | -2. **卡死在采样步骤**:在日志或调试中发现执行卡在`sampled_token_ids = sampler_output.sampled_token_ids`等类似代码行,程序在此处长时间无响应。 | ||
| 18 | -3. **高并发下延迟突增**:随着并发请求数增加,每个Token的生成延迟显著上升,但模型前向计算时间保持相对稳定,瓶颈集中在Sampler阶段。 | ||
| 19 | -4. **NPU利用率与CPU利用率倒挂**:NPU利用率不高,但CPU侧采样器所在核心的负载较高,存在明显的Host侧计算或同步开销。 | ||
| 20 | - | ||
| 21 | -## 【定位过程】 | ||
| 22 | - | ||
| 23 | -### 第一步:服务化时序采集 —— msServiceProfiler | ||
| 24 | - | ||
| 25 | -使用**msServiceProfiler**工具采集请求粒度的时序数据,重点关注Sampler阶段的执行时长。该工具专门针对MindIE Service推理服务化场景设计,可采集关键过程的开始和结束时间点。 | ||
| 26 | - | ||
| 27 | -1. **准备配置**:创建`ms_service_profiler_config.json`,开启细粒度事件采集。 | ||
| 28 | - | ||
| 29 | - ```json | ||
| 30 | - { | ||
| 31 | - "enable": 1, | ||
| 32 | - "prof_dir": "/path/to/profile_output", | ||
| 33 | - "record_op_detail": true | ||
| 34 | - } | ||
| 35 | - ``` | ||
| 36 | - | ||
| 37 | -2. **启动采集**: | ||
| 38 | - | ||
| 39 | - ```bash | ||
| 40 | - export SERVICE_PROF_CONFIG_PATH=/path/to/ms_service_profiler_config.json | ||
| 41 | - # 启动MindIE Service服务 | ||
| 42 | - ``` | ||
| 43 | - | ||
| 44 | -3. **复现压力**:使用业务并发请求压测,模拟Sampler耗时异常的场景。 | ||
| 45 | -4. **解析数据**: | ||
| 46 | - | ||
| 47 | - ```bash | ||
| 48 | - python3 -m ms_service_profiler.parse --input-path=/path/to/profile_output | ||
| 49 | - ``` | ||
| 50 | - | ||
| 51 | -### 第二步:Timeline细粒度分析 —— MindStudio Insight | ||
| 52 | - | ||
| 53 | -将解析生成的`chrome_tracing.json`导入**MindStudio Insight**进行可视化分析。MindStudio Insight以Timeline方式呈现全流程运行情况,可对推理过程进行细粒度分析。 | ||
| 54 | - | ||
| 55 | -1. **定位Sampler阶段**:在Timeline树状图中找到Sampler相关泳道(如`Sampler`、`PostProcess`或`Sampling`线程)。 | ||
| 56 | -2. **观察执行序列**:重点关注`modelExec`与`sampler`之间的间隔,以及sampler内部的执行条长度。 | ||
| 57 | -3. **识别隐式同步**:如果Sampler阶段存在明显的空闲间隙或等待标记,可能存在Host与Device之间的隐式同步。vLLM社区的经验表明,`sampler_output.sampled_token_ids`涉及GPU张量到CPU的同步或数据拷贝,高并发下此开销会被放大。 | ||
| 58 | -4. **对比分析**:对比不同batch_size或不同序列长度下的Sampler耗时差异,观察是否存在线性增长关系。 | ||
| 59 | - | ||
| 60 | -### 第三步:采样参数与配置排查 | ||
| 61 | - | ||
| 62 | -通过检查请求参数和服务端配置,排除参数配置导致的采样器计算开销过大问题。 | ||
| 63 | - | ||
| 64 | -1. **检查采样参数**:确认请求中是否携带了复杂的采样参数组合,如`top_k`、`top_p`、`temperature`、`repetition_penalty`同时生效,或使用了`logprobs`、`best_of`等需要额外计算的后处理参数。 | ||
| 65 | -2. **检查Vocabulary规模**:确认模型词表大小,大词表(如50k+)场景下Softmax计算量本身较大。 | ||
| 66 | -3. **检查量化配置**:确认Sampler相关算子是否在正确的数据类型下运行,混合精度可能引入额外转换开销。 | ||
| 67 | - | ||
| 68 | -## 【问题根因】 | ||
| 69 | - | ||
| 70 | -**Host与Device间的隐式同步 / Sampler实现存在串行瓶颈** | ||
| 71 | -(属于**框架适配问题**及**调度实现缺陷**范畴) | ||
| 72 | - | ||
| 73 | -**详细解释:** | ||
| 74 | - | ||
| 75 | -1. **GPU->CPU数据同步是主要诱因**:vLLM社区的定位经验表明,`sampled_token_ids = sampler_output.sampled_token_ids`这一行看似简单的赋值,实际上可能触发GPU张量到CPU的隐式同步或数据拷贝。在高并发或显存紧张时,PCIe带宽成为瓶颈,导致采样步骤长时间阻塞。 | ||
| 76 | - | ||
| 77 | -2. **大词表Softmax计算开销**:当词表规模较大(如50k-100k)时,对logits执行Softmax + Top-K/Top-P筛选的计算量不可忽视。若采样器在CPU侧完成这部分计算,则涉及大块数据从Device到Host的拷贝;若在NPU侧完成,则占用了本可用于下一轮Decode的算力。 | ||
| 78 | - | ||
| 79 | -3. **采样参数过于复杂**:同时启用多个采样参数(如Top-K、Top-P、Temperature、Repetition Penalty等)会显著增加采样器的计算复杂度,部分处理逻辑可能是串行的。 | ||
| 80 | - | ||
| 81 | -4. **调度参数配置不当**:根据vLLM社区的排查经验,`max_num_batched_tokens`设置过小会导致调度频率增加,采样步骤被更频繁地触发,放大了单次采样开销的影响。同时,`max_num_seqs`过大时单次batch内需要采样大量序列,采样时间与batch_size呈线性关系。 | ||
| 82 | - | ||
| 83 | -## 【定位方法论总结】 | ||
| 84 | - | ||
| 85 | -针对**“Sampler执行耗时过长”**的场景,定位的关键在于**区分“真正的采样计算耗时”与“隐式的数据传输/同步耗时”**,避免将同步开销误判为计算瓶颈。 | ||
| 86 | - | ||
| 87 | -1. **切忌只看平均耗时,忽略Timeline形态**:如果只看平均数据,Sampler耗时长可能被误判为采样算法效率问题。必须通过MindStudio Insight观察Timeline中的具体形态——如果Sampler阶段有明显间隙或等待标记,应优先排查Host-Device同步问题。 | ||
| 88 | - | ||
| 89 | -2. **用纯模型测试隔离调度干扰**:根据MindStudio官方调优指南,应先通过纯模型测试评估推理上限,识别瓶颈所在,再分析服务化调度问题。可以在不经过服务化框架的情况下直接调用模型执行单次推理,对比Sampler耗时是否依然存在,从而判断问题是出自Sampler实现本身还是服务化调度层。 | ||
| 90 | - | ||
| 91 | -3. **检查日志中的采样参数**:部分异常耗时的场景可能是请求参数引起的(如某次请求携带了极高的`top_k`值)。建议在服务端增加采样参数的日志记录,便于回溯分析。 | ||
| 92 | - | ||
| 93 | -4. **调整调度参数验证**:如果怀疑是调度频率过高导致采样开销被放大,可以尝试增大`max_num_batched_tokens`参数,观察P99延迟是否改善。如果改善,说明原始配置下采样步骤被过度频繁触发。 | ||
| 94 | - | ||
| 95 | -5. **利用msprof进行算子级分析**:如果需要进一步定位到Sampler内部的哪个具体算子(如Softmax、TopK)耗时最高,可以使用msprof工具采集算子级别的Profiling数据,再通过MindStudio Insight的算子耗时面板定位TOP耗时算子。 | ||
| @@ -1,107 +0,0 @@ | |||
| 1 | -# scheduler耗时过长 | ||
| 2 | - | ||
| 3 | -## 问题背景 | ||
| 4 | - | ||
| 5 | -在服务化推理场景中,调度器(Scheduler)负责将到达的推理请求按一定策略组Batch并下发到NPU执行。当调度器自身耗时占比过高时,会导致NPU设备空闲等待,整体吞吐下降、请求排队时间增加。尤其在Host Bound场景下(如小模型推理、Decode阶段),单个算子的Host下发时间可能超过Device执行时间,调度开销成为系统瓶颈。昇腾CANN通过图模式调度和模型下沉调度技术可优化此问题,但在实际部署中,调度策略配置不当、动态调度优先级切换、组Batch逻辑复杂等因素仍可能导致scheduler耗时过长。 | ||
| 6 | - | ||
| 7 | -## 问题来源 | ||
| 8 | - | ||
| 9 | -推理 | ||
| 10 | - | ||
| 11 | -## 问题现象 | ||
| 12 | - | ||
| 13 | -用户通常先看到推理服务整体吞吐低于预期,NPU利用率偏低但请求排队(waiting)数量持续增长。在Grafana中按调度指标拆开后,常见现象是: | ||
| 14 | - | ||
| 15 | -- `waiting_batch_size`指标持续处于高位,而`batch_size`(running请求数)未达到配置的`maxBatchSize`上限。 | ||
| 16 | -- 从`request_status.csv`中可观察到大量请求长期处于waiting状态,running状态请求数波动较大。 | ||
| 17 | -- NPU执行流上出现间歇性空闲,Timeline视图中连续的Schedule色块之间存在明显的空闲间隙(bubble)。 | ||
| 18 | - | ||
| 19 | -使用msServiceProfiler采集数据后,在`batch.csv`中观察到`name`为`batchFrameworkProcessing`(组Batch阶段)的`during_time(ms)`显著偏高,与`modelExec`(模型执行阶段)耗时之比异常。典型表现为:组Batch耗时占总Batch耗时的比例偏高,而正常场景下该比例通常较低。在Host Bound模型(如小参数量的Encoder模型或Decode阶段的小Batch场景)中尤为明显。 | ||
| 20 | - | ||
| 21 | -## 定位过程 | ||
| 22 | - | ||
| 23 | -### 步骤 1:先确认调度瓶颈是否存在 | ||
| 24 | - | ||
| 25 | -在Grafana中查看`batch_size`、`waiting_batch_size`、`num_running_reqs`、`num_waiting_reqs`等调度相关指标。如果`waiting_batch_size`持续增长而`batch_size`未达到上限,说明调度器未能及时将等待请求组Batch下发。同时观察NPU利用率指标,若NPU利用率低但等待队列长,可初步判断存在调度瓶颈。 | ||
| 26 | - | ||
| 27 | -### 步骤 2:用Profiler采集调度阶段数据 | ||
| 28 | - | ||
| 29 | -配置`ms_service_profiler_config.json`,设置`domain`为`"Schedule; Request; ModelExecute"`,开启数据采集。采集完成后执行解析命令: | ||
| 30 | - | ||
| 31 | -```bash | ||
| 32 | -python3 -m ms_service_profiler.parse --input-path ${PATH}/prof_dir/ | ||
| 33 | -``` | ||
| 34 | - | ||
| 35 | -解析生成`batch.csv`、`request.csv`、`forward.csv`、`chrome_tracing.json`等文件。 | ||
| 36 | - | ||
| 37 | -### 步骤 3:分析batch.csv中的调度耗时 | ||
| 38 | - | ||
| 39 | -在`batch.csv`中筛选`name`为`batchFrameworkProcessing`的行,统计其`during_time(ms)`的分布(平均值、P90、P99)。同时筛选`name`为`modelExec`的行,计算组Batch耗时与模型执行耗时的比值。如果组Batch耗时占比偏高,说明调度阶段存在瓶颈。 | ||
| 40 | - | ||
| 41 | -按`dp_rank`维度分别统计各DP域的调度耗时,判断是否为特定DP域调度慢。按`batch_type`(prefill/decode)分别统计,判断是Prefill调度慢还是Decode调度慢。 | ||
| 42 | - | ||
| 43 | -### 步骤 4:用服务化拆解工具细粒度拆解Batch执行阶段 | ||
| 44 | - | ||
| 45 | -```bash | ||
| 46 | -msserviceprofiler split --input-path /path/to/input --decode-batch-size 1 --decode-number 100 | ||
| 47 | -``` | ||
| 48 | - | ||
| 49 | -拆解后查看`decode.csv`中各子阶段(如数据下发、模型执行、数据接收等)的耗时分布,确认调度阶段的具体耗时瓶颈在哪个子环节。 | ||
| 50 | - | ||
| 51 | -### 步骤 5:通过Timeline视图确认bubble位置 | ||
| 52 | - | ||
| 53 | -打开`chrome_tracing.json`,在Timeline视图中观察Schedule色块与ModelExecute色块之间的时序关系。如果存在大量bubble(空闲间隙),且bubble出现在组Batch阶段而非模型执行阶段,可确认调度器是瓶颈。 | ||
| 54 | - | ||
| 55 | -结合`forward.csv`中的`bubble_time(ms)`字段,统计forward之间的空泡时间。如果空泡时间占比较高,说明调度下发不及时导致NPU等待。 | ||
| 56 | - | ||
| 57 | -### 步骤 6:用多维度解析工具获取整体统计 | ||
| 58 | - | ||
| 59 | -```bash | ||
| 60 | -msserviceprofiler analyze --input-path=/path/to/input | ||
| 61 | -``` | ||
| 62 | - | ||
| 63 | -查看`batch_summary.csv`中prefill和decode的batch数量和执行时间统计,从服务整体维度判断调度效率。 | ||
| 64 | - | ||
| 65 | -## 问题根因 | ||
| 66 | - | ||
| 67 | -调度器耗时过长的常见根因包括: | ||
| 68 | - | ||
| 69 | -1. **Host Bound场景**:小模型或Decode阶段单算子执行时间极短,但Host调度每个算子的下发流程耗时相对较长,导致Device频繁空闲等待。这是昇腾NPU上Host调度模式的固有问题,可通过CANN的图模式调度或模型下沉调度解决。 | ||
| 70 | - | ||
| 71 | -2. **调度策略配置不当**:`maxBatchSize`设置过小导致频繁组Batch;动态调度优先级在单并发场景下引入额外的策略切换开销;`maxPrefillBatchSize`与`maxBatchSize`配比不合理导致Prefill和Decode调度互相阻塞。 | ||
| 72 | - | ||
| 73 | -3. **组Batch逻辑复杂度过高**:请求数量大、请求长度差异大时,调度器需要遍历大量候选请求进行组Batch匹配,匹配算法复杂度随请求数增长。 | ||
| 74 | - | ||
| 75 | -4. **框架适配问题**:调度器与昇腾NPU的Task下发机制未充分优化,未启用图模式调度或模型下沉,仍使用单算子模式逐算子下发。 | ||
| 76 | - | ||
| 77 | -5. **资源竞争**:调度器线程与其它服务线程竞争CPU资源,导致调度延迟抖动。 | ||
| 78 | - | ||
| 79 | -## 解决方法 | ||
| 80 | - | ||
| 81 | -- Host Bound:启用CANN图模式调度或模型下沉,减少Host下发开销。 | ||
| 82 | -- 调度策略不当:调整`maxBatchSize`和`maxPrefillBatchSize`配比,关闭不必要的动态调度优先级。 | ||
| 83 | -- 组Batch逻辑复杂:优化组Batch算法,减少候选请求遍历范围。 | ||
| 84 | -- 框架适配:确认已启用图模式调度或模型下沉,避免单算子模式。 | ||
| 85 | -- 资源竞争:确保调度线程有足够CPU资源,避免与其它服务线程竞争。 | ||
| 86 | - | ||
| 87 | -处理后需要回看`waiting_batch_size`是否下降、`batch_size`是否接近上限、组Batch耗时占比是否降低、NPU利用率是否提升。 | ||
| 88 | - | ||
| 89 | -## 定位方法论总结 | ||
| 90 | - | ||
| 91 | -该场景的完整判断链是:先用ms-service-metric确认`waiting_batch_size`高、`batch_size`未达上限、NPU利用率低的现象;再用msServiceProfiler采集Schedule和ModelExecute domain数据,通过`batch.csv`对比组Batch耗时与模型执行耗时;然后用服务化拆解工具细粒度拆解Batch各子阶段耗时;最后通过Timeline视图确认bubble位置和持续时间。 | ||
| 92 | - | ||
| 93 | -核心判断逻辑:如果组Batch耗时占比高且Timeline上存在大量调度间隙,则瓶颈在调度器;如果模型执行耗时占比高,则瓶颈在模型侧。 | ||
| 94 | - | ||
| 95 | -## 对工具的改进建议 | ||
| 96 | - | ||
| 97 | -### ms-service-metric | ||
| 98 | - | ||
| 99 | -当前在线监控已能查看`waiting_batch_size`、`batch_size`等调度指标。建议增加调度效率指标,如"调度耗时/模型执行耗时"比值、"平均组Batch延迟"等,便于在线快速识别调度瓶颈。增加Host Bound风险提示,当检测到小模型或Decode阶段NPU利用率持续偏低时,自动提示可能存在Host Bound。 | ||
| 100 | - | ||
| 101 | -### msServiceProfiler | ||
| 102 | - | ||
| 103 | -当前Profiler已能通过`batch.csv`对比组Batch耗时与模型执行耗时。建议在`batch.csv`中增加调度子阶段拆解字段,如"请求匹配耗时"、"Token分配耗时"、"Task下发耗时"等,便于直接定位调度瓶颈子环节。在Timeline视图中增加调度效率面板,自动计算并展示组Batch耗时占比、bubble占比等关键指标。 | ||
| 104 | - | ||
| 105 | -### 服务化拆解工具 | ||
| 106 | - | ||
| 107 | -当前拆解工具需要手动指定`batch_size`或`rid`。建议增加自动识别耗时异常Batch的能力,自动选取耗时最长的Top N个Batch进行拆解分析。 | ||
| @@ -1,241 +0,0 @@ | |||
| 1 | -# 服务化与纯模型性能差异过大问题调优指导实例 | ||
| 2 | - | ||
| 3 | -## 场景说明 | ||
| 4 | - | ||
| 5 | -在大模型推理调优中,通常会先使用纯模型方式获取模型在固定输入输出长度、固定batch size下的性能基准,再将模型部署到服务化框架中承接真实请求。若服务化场景的吞吐、首Token时延或Decode时延与纯模型基准差异过大,常见原因包括服务化参数未对齐、资源分配不足、通信配置异常、负载不均或序列长度配置过大。 | ||
| 6 | - | ||
| 7 | -本文以服务化推理性能低于纯模型基准为例,介绍如何使用msServiceProfiler采集服务化链路数据,定位性能差异来源,并给出参数、资源、通信和负载均衡方向的调优方案。 | ||
| 8 | - | ||
| 9 | -## 问题现象 | ||
| 10 | - | ||
| 11 | -**典型表现** | ||
| 12 | - | ||
| 13 | -- 纯模型测试中吞吐正常,例如输入/输出长度为256/256、bs=128时可达到1132.24 tokens/s,但服务化部署后吞吐明显下降。 | ||
| 14 | -- 服务化场景中Batch_Size_curve长期低于maxBatchSize或maxPrefillBatchSize配置上限。 | ||
| 15 | -- Prefill_Generate_Speed_Latency_curve、Decode_Generate_Speed_Latency_curve相较纯模型基准明显变差。 | ||
| 16 | -- First_Token_Latency_curve或Request_Latency_curve的P90/P99偏高,且随并发增加快速放大。 | ||
| 17 | -- 启动阶段出现HCCL通信超时、rank连接失败、模型加载卡死或服务进程被杀。 | ||
| 18 | -- MoE模型多卡部署时,部分Device耗时明显偏高,moe_analysis或专家热点图呈现负载不均。 | ||
| 19 | - | ||
| 20 | -**影响范围** | ||
| 21 | - | ||
| 22 | -| 影响项 | 表现 | | ||
| 23 | -| --- | --- | | ||
| 24 | -| 吞吐 | 服务化tokens/s明显低于纯模型基准。 | | ||
| 25 | -| 首Token时延 | Prefill阶段排队、组batch或执行耗时增加。 | | ||
| 26 | -| Decode时延 | 通信等待、通算未融合或负载不均导致单步耗时升高。 | | ||
| 27 | -| 稳定性 | 内存不足、权限不足或通信超时导致服务启动失败。 | | ||
| 28 | -| 资源利用率 | batch未打满、KVCache配置过大或热点专家集中导致Device利用率下降。 | | ||
| 29 | - | ||
| 30 | -## 数据采集 | ||
| 31 | - | ||
| 32 | -### 功能说明 | ||
| 33 | - | ||
| 34 | -使用msServiceProfiler采集服务化推理过程中的Request、BatchSchedule、ModelExecute、Communication、KVCache和专家负载相关数据。通过batch.csv、request.csv、forward.csv、BatchSchedule.csv以及可视化曲线,对比纯模型基准和服务化链路中的差异。 | ||
| 35 | - | ||
| 36 | -### 注意事项 | ||
| 37 | - | ||
| 38 | -- 调优前需先完成纯模型基准测试,明确在固定输入输出长度和固定batch size下的最大性能。 | ||
| 39 | -- 服务化压测应尽量复用纯模型基准的输入输出长度、并发规模和模型配置,避免基准不可比。 | ||
| 40 | -- 多机多卡场景采集前需确认各节点时间同步,避免Timeline和负载均衡图出现时间偏差。 | ||
| 41 | -- 若需要分析通信、任务下发或算子执行耗时,可开启acl任务耗时相关采集,但需评估额外开销。 | ||
| 42 | -- 专家热点信息建议单独配置eplb_observe domain域,避免采集数据过大。 | ||
| 43 | - | ||
| 44 | -### 配置示例 | ||
| 45 | - | ||
| 46 | -创建ms_service_profiler_config.json,按需采集Request、BatchSchedule、ModelExecute、Communication和KVCache域。 | ||
| 47 | - | ||
| 48 | -```json | ||
| 49 | -{ | ||
| 50 | - "enable": 1, | ||
| 51 | - "prof_dir": "${HOME}/.ms_server_profiler", | ||
| 52 | - "profiler_level": "INFO", | ||
| 53 | - "domain": "Request;BatchSchedule;ModelExecute;Communication;KVCache", | ||
| 54 | - "acl_task_time": 1, | ||
| 55 | - "acl_prof_task_time_level": "L0" | ||
| 56 | -} | ||
| 57 | -``` | ||
| 58 | - | ||
| 59 | -若需要采集MoE专家热点信息,可单独开启eplb_observe域,并配置MindIE专家热点采集环境变量。 | ||
| 60 | - | ||
| 61 | -```json | ||
| 62 | -{ | ||
| 63 | - "enable": 1, | ||
| 64 | - "prof_dir": "${HOME}/.ms_server_profiler", | ||
| 65 | - "profiler_level": "INFO", | ||
| 66 | - "domain": "eplb_observe" | ||
| 67 | -} | ||
| 68 | -``` | ||
| 69 | - | ||
| 70 | -启动服务前设置采集配置路径。 | ||
| 71 | - | ||
| 72 | -```bash | ||
| 73 | -export SERVICE_PROF_CONFIG_PATH=/path/to/ms_service_profiler_config.json | ||
| 74 | -``` | ||
| 75 | - | ||
| 76 | -## 基准对齐 | ||
| 77 | - | ||
| 78 | -服务化性能低于纯模型基准时,应先确认两类测试是否具备可比性。 | ||
| 79 | - | ||
| 80 | -| 检查项 | 说明 | | ||
| 81 | -| --- | --- | | ||
| 82 | -| 输入输出长度 | 纯模型与服务化压测的输入、输出长度应一致,例如256/256。 | | ||
| 83 | -| batch与并发 | 纯模型bs应与服务化maxBatchSize、maxPrefillBatchSize、concurrency建立对应关系。 | | ||
| 84 | -| 模型权重 | 模型版本、量化方式、并行策略和rank配置应一致。 | | ||
| 85 | -| 精度与算子 | 纯模型和服务化使用的精度、算子库和图优化开关应一致。 | | ||
| 86 | -| 硬件资源 | NPU数量、机器数量、CPU和内存资源应一致或可换算。 | | ||
| 87 | - | ||
| 88 | -若基准未对齐,不应直接判断服务化框架存在瓶颈。建议先记录纯模型最大性能,再在服务化侧逐项打开调优开关,确认每一步收益。 | ||
| 89 | - | ||
| 90 | -## 定位方法 | ||
| 91 | - | ||
| 92 | -1. 查看Batch_Size_curve和batch.csv。 | ||
| 93 | - - 若prefill_batch_size或decode_batch_size长期偏小,说明服务化组batch未打满,需检查concurrency、maxPrefillBatchSize、maxBatchSize、请求分布和supportSelectBatch。 | ||
| 94 | - - 若batch size已接近上限但吞吐仍低,需继续检查ModelExecute、Communication和Device利用率。 | ||
| 95 | - | ||
| 96 | -2. 查看Request_Status_curve。 | ||
| 97 | - - 若waiting队列持续堆积,说明服务入口、组batch或执行阶段消费能力不足。 | ||
| 98 | - - 若running队列较少但吞吐低,说明调度策略可能过于保守,或服务化参数限制了有效batch。 | ||
| 99 | - | ||
| 100 | -3. 查看Prefill和Decode相关曲线。 | ||
| 101 | - - Prefill_Generate_Speed_Latency偏高,优先检查maxPrefillBatchSize、maxSeqLen、KVCache预留和输入长度分布。 | ||
| 102 | - - Decode_Generate_Speed_Latency偏高,优先检查通信配置、LCCL、通算融合、MoE负载均衡和跨卡同步等待。 | ||
| 103 | - | ||
| 104 | -4. 查看Kvcache_usage_percent_curve。 | ||
| 105 | - - 若KVCache使用率长期较低但maxSeqLen配置很大,说明预留过多,可能限制batch和并发。 | ||
| 106 | - - 若KVCache使用率接近上限,说明并发或序列长度已触及内存瓶颈,需降低maxSeqLen或增加资源。 | ||
| 107 | - | ||
| 108 | -## 原因分析与解决方案 | ||
| 109 | - | ||
| 110 | -### 参数配置与纯模型基准不一致 | ||
| 111 | - | ||
| 112 | -**原因** | ||
| 113 | - | ||
| 114 | -服务化场景中的maxPrefillBatchSize、maxBatchSize、concurrency、prefillBatchSize等参数若未按实际负载配置,可能导致组batch不足、队列调度保守或Prefill/Decode资源分配不合理,最终表现为吞吐低于纯模型。 | ||
| 115 | - | ||
| 116 | -**解决方案** | ||
| 117 | - | ||
| 118 | -- 以纯模型基准为目标,建立bs与服务化并发、maxBatchSize的对应关系。 | ||
| 119 | -- 根据请求长度分布调整maxPrefillBatchSize和prefillBatchSize,避免Prefill阶段batch过小。 | ||
| 120 | -- 根据压测并发逐步提高concurrency,观察Batch_Size_curve是否接近配置上限。 | ||
| 121 | -- 吞吐优先场景建议开启supportSelectBatch,使调度优先选择更有利于吞吐的batch组合。 | ||
| 122 | -- 分别记录调优前后的Batch_Size_curve、Prefill_Generate_Speed_Latency和Request_Latency,避免只看单次吞吐结果。 | ||
| 123 | - | ||
| 124 | -### 资源分配与内存不足 | ||
| 125 | - | ||
| 126 | -**原因** | ||
| 127 | - | ||
| 128 | -服务化部署相比纯模型通常需要额外的框架进程、队列、KVCache、通信缓存和监控组件。若机器内存不足,可能出现模型加载卡死、进程被杀或首轮请求时延异常。 | ||
| 129 | - | ||
| 130 | -**解决方案** | ||
| 131 | - | ||
| 132 | -- 启动前确认可用内存满足基本要求,建议free_mem不低于`(权重大小 / 机器数) * 1.3`。 | ||
| 133 | -- 在测试环境中可释放系统缓存后再启动服务。 | ||
| 134 | - | ||
| 135 | -```bash | ||
| 136 | -sync | ||
| 137 | -echo 3 > /proc/sys/vm/drop_caches | ||
| 138 | -``` | ||
| 139 | - | ||
| 140 | -- 容器化部署时确认特权模式和路径权限,避免模型、rank table、共享内存或设备文件访问失败。 | ||
| 141 | - | ||
| 142 | -```bash | ||
| 143 | -docker run --privileged=true | ||
| 144 | -``` | ||
| 145 | - | ||
| 146 | -- 若KVCache使用率长期偏低且内存占用高,检查maxSeqLen是否远大于真实数据集最大序列长度。 | ||
| 147 | -- 若服务进程停止,优先检查系统日志、容器内存限制和权重加载阶段内存峰值。 | ||
| 148 | - | ||
| 149 | -### 通信与环境变量配置不足 | ||
| 150 | - | ||
| 151 | -**原因** | ||
| 152 | - | ||
| 153 | -多机多卡服务化部署依赖HCCL或LCCL通信。若主从节点环境变量不一致、rank table路径错误、容器IP设置错误或通信超时配置过小,可能导致启动失败、Decode等待增加或跨卡同步耗时偏高。 | ||
| 154 | - | ||
| 155 | -**解决方案** | ||
| 156 | - | ||
| 157 | -在主节点和从节点分别设置本机IP、rank table和确定性通信相关环境变量。 | ||
| 158 | - | ||
| 159 | -```bash | ||
| 160 | -export MIES_CONTAINER_IP=本机IP | ||
| 161 | -export RANKTABLEFILE=/path/to/rank_table.json | ||
| 162 | -export HCCL_DETERMINISTIC=true | ||
| 163 | -``` | ||
| 164 | - | ||
| 165 | -大规模部署或网络初始化较慢时,可增大通信连接超时时间,并确认WORLD_SIZE与实际rank数量一致。 | ||
| 166 | - | ||
| 167 | -```bash | ||
| 168 | -export HCCL_CONNECT_TIMEOUT=7200 | ||
| 169 | -export WORLD_SIZE=32 | ||
| 170 | -``` | ||
| 171 | - | ||
| 172 | -Decode时延偏高时,建议评估启用LCCL通信库和通算融合。 | ||
| 173 | - | ||
| 174 | -```bash | ||
| 175 | -export ATB_LLM_LCOC_ENABLE=1 | ||
| 176 | -``` | ||
| 177 | - | ||
| 178 | -验证时重点对比Communication域Span、Decode_Generate_Speed_Latency和Request_Latency的P90/P99。 | ||
| 179 | - | ||
| 180 | -### MoE负载不均 | ||
| 181 | - | ||
| 182 | -**原因** | ||
| 183 | - | ||
| 184 | -MoE模型中,不同专家的访问热度可能差异很大。如果热点专家集中部署在少数Device或rank上,会导致部分快卡等待慢卡,服务化吞吐低于纯模型理想基准。 | ||
| 185 | - | ||
| 186 | -**解决方案** | ||
| 187 | - | ||
| 188 | -- 使用msServiceProfiler采集eplb_observe域,观察专家热点和负载不均曲线。 | ||
| 189 | -- 使用msit elb工具生成专家部署表expert_map_file。 | ||
| 190 | -- 在config.json中配置专家负载均衡参数,例如设置`"level": 1`启用静态负载均衡。 | ||
| 191 | -- 调整后重新采集moe_analysis.csv和专家负载不均折线图,确认不同Device耗时差距缩小。 | ||
| 192 | - | ||
| 193 | -### 序列长度配置过大 | ||
| 194 | - | ||
| 195 | -**原因** | ||
| 196 | - | ||
| 197 | -maxSeqLen若按极端上限配置,例如设置为10000,但实际数据集最大长度只有698,会导致KVCache和内存预留过大,限制可用batch和并发,进而降低服务化吞吐。 | ||
| 198 | - | ||
| 199 | -**解决方案** | ||
| 200 | - | ||
| 201 | -- 统计线上或压测数据集的真实输入输出长度分布,使用P99或实际最大值作为maxSeqLen配置依据。 | ||
| 202 | -- 将maxSeqLen从过大的保守值调整为贴近真实负载的值,例如从10000调整为698。 | ||
| 203 | -- 调整后观察Kvcache_usage_percent_curve、Batch_Size_curve和服务吞吐是否改善。 | ||
| 204 | -- 若业务存在少量超长请求,可对超长请求单独路由或降级处理,避免拖累主服务实例。 | ||
| 205 | - | ||
| 206 | -## 优化验证 | ||
| 207 | - | ||
| 208 | -每次只调整一个方向,并在相同压测条件下重新采集数据。建议按以下顺序验证。 | ||
| 209 | - | ||
| 210 | -| 步骤 | 验证目标 | 观察指标 | | ||
| 211 | -| --- | --- | --- | | ||
| 212 | -| 纯模型基准 | 确认模型理论上限 | tokens/s、bs、输入输出长度 | | ||
| 213 | -| 参数调优 | 确认服务化batch是否打满 | Batch_Size_curve、batch.csv | | ||
| 214 | -| 内存调优 | 确认资源是否足够 | Kvcache_usage_percent、进程RSS、系统free_mem | | ||
| 215 | -| 通信调优 | 确认Decode等待是否下降 | Communication Span、Decode_Generate_Speed_Latency | | ||
| 216 | -| 负载均衡 | 确认快慢卡是否收敛 | moe_analysis.csv、专家热点图 | | ||
| 217 | -| 端到端验证 | 确认用户侧收益 | First_Token_Latency、Request_Latency、吞吐 | | ||
| 218 | - | ||
| 219 | -优化有效时,通常会看到以下结果: | ||
| 220 | - | ||
| 221 | -- Batch_Size_curve更接近maxBatchSize或maxPrefillBatchSize配置上限。 | ||
| 222 | -- Prefill和Decode阶段token平均时延下降。 | ||
| 223 | -- Request_Latency_curve的avg、P90和P99下降。 | ||
| 224 | -- KVCache使用率更贴近真实负载,内存浪费减少。 | ||
| 225 | -- MoE场景中不同Device耗时差距缩小,快慢卡现象减弱。 | ||
| 226 | -- 服务化吞吐逐步接近纯模型基准。 | ||
| 227 | - | ||
| 228 | -## 推荐处理策略 | ||
| 229 | - | ||
| 230 | -| 问题类型 | 推荐方案 | | ||
| 231 | -| --- | --- | | ||
| 232 | -| 服务化batch长期偏小 | 调整concurrency、maxBatchSize、maxPrefillBatchSize,开启supportSelectBatch。 | | ||
| 233 | -| Prefill时延偏高 | 调整prefillBatchSize、maxSeqLen,检查KVCache预留和输入长度分布。 | | ||
| 234 | -| Decode时延偏高 | 优化HCCL/LCCL配置,开启通算融合,检查跨卡通信等待。 | | ||
| 235 | -| 启动失败或进程被杀 | 检查free_mem、容器特权模式、路径权限和内存限制。 | | ||
| 236 | -| 多卡负载不均 | 使用msit elb生成expert_map_file,启用静态或动态专家负载均衡。 | | ||
| 237 | -| 与纯模型差异仍大 | 回到基准对齐,确认模型版本、并行策略、输入输出长度和硬件资源一致。 | | ||
| 238 | - | ||
| 239 | -## 总结 | ||
| 240 | - | ||
| 241 | -服务化与纯模型性能差异过大的核心在于基准对齐、参数配置、资源分配和通信优化。调优时应先用纯模型测试获取最大性能基准,再通过msServiceProfiler拆解服务化链路,重点观察BatchSchedule、Request、KVCache、Communication和MoE负载均衡数据。若业务追求吞吐,应优先打满batch并开启吞吐优先策略;若Decode尾时延偏高,应优先检查通信库、通算融合和专家负载均衡;若资源不足,应先解决内存、容器权限和序列长度配置问题,再继续做服务化参数优化。 | ||
| @@ -1,19 +1,21 @@ | |||
| 1 | -# 一、问题背景 | 1 | +# 同步接口频繁调用 |
| 2 | + | ||
| 3 | +## 1. 问题背景 | ||
| 2 | 4 | ||
| 3 | 在NPU业务执行过程中,业务执行时间不及预期,通过采集profiling数据确认,发现有较多处的流同步之类的等待行为,急需问题定位和性能优化。 | 5 | 在NPU业务执行过程中,业务执行时间不及预期,通过采集profiling数据确认,发现有较多处的流同步之类的等待行为,急需问题定位和性能优化。 |
| 4 | 6 | ||
| 5 | -# 二、问题来源 | 7 | +## 2. 问题来源 |
| 6 | 8 | ||
| 7 | 性能调优 | 9 | 性能调优 |
| 8 | 10 | ||
| 9 | -# 三、问题现象 | 11 | +## 3. 问题现象 |
| 10 | 12 | ||
| 11 | 通过可视化工具打开msprof.json或trace_view.json文件,发现有较多算子执行,往往伴随aclrtSynchronizeStreamWithTimeout等同步接口。 | 13 | 通过可视化工具打开msprof.json或trace_view.json文件,发现有较多算子执行,往往伴随aclrtSynchronizeStreamWithTimeout等同步接口。 |
| 12 | 而在同步接口调用时,则没有任何其他算子下发,即该算子阻塞了其余算子的下发行为,导致NPU整体利用率较低,性能较差。对于整体业务而言,异步下发方式需要长时间下发算子,并使device侧业务处于繁忙执行状态,充分利用硬件资源。但大量的同步接口调用,会将异步行为转变为同步行为,进而导致业务的不连贯性,降低硬件资源利用率。 | 14 | 而在同步接口调用时,则没有任何其他算子下发,即该算子阻塞了其余算子的下发行为,导致NPU整体利用率较低,性能较差。对于整体业务而言,异步下发方式需要长时间下发算子,并使device侧业务处于繁忙执行状态,充分利用硬件资源。但大量的同步接口调用,会将异步行为转变为同步行为,进而导致业务的不连贯性,降低硬件资源利用率。 |
| 13 | 15 | ||
| 14 |  | 16 |  |
| 15 | 17 | ||
| 16 | -# 四、定位过程 | 18 | +## 4. 定位过程 |
| 17 | 19 | ||
| 18 | 通过insight打开msprof.json或者trace_view.json。可观察到有大量的类似名为“Synchronize”等同步API。 | 20 | 通过insight打开msprof.json或者trace_view.json。可观察到有大量的类似名为“Synchronize”等同步API。 |
| 19 | 21 | ||
| @@ -25,16 +27,16 @@ | |||
| 25 | 27 | ||
| 26 | 因此,可基于profiler的stack调用栈功能,额外采集一份带有堆栈信息的数据,从时间角度确认相关同步动作是从哪些位置引入的。 | 28 | 因此,可基于profiler的stack调用栈功能,额外采集一份带有堆栈信息的数据,从时间角度确认相关同步动作是从哪些位置引入的。 |
| 27 | 29 | ||
| 28 | -# 五、问题根因 | 30 | +## 5. 问题根因 |
| 29 | 31 | ||
| 30 | 1、大多流同步动作都是人为或业务引入的。因此相关操作优先确认业务代码,从业务逻辑角度对接口调用必要性进行评估和处理。酌情删除不必要的同步接口。 | 32 | 1、大多流同步动作都是人为或业务引入的。因此相关操作优先确认业务代码,从业务逻辑角度对接口调用必要性进行评估和处理。酌情删除不必要的同步接口。 |
| 31 | 33 | ||
| 32 | 2、除此以外,部分流同步业务可能是环境变量引入,例如 | 34 | 2、除此以外,部分流同步业务可能是环境变量引入,例如 |
| 33 | 35 | ||
| 34 | -[ASCEND_LAUNCH_BLOCKING](https://gitcode.com/Ascend/pytorch/blob/v2.7.1/docs/zh/environment_variable_reference/ASCEND_LAUNCH_BLOCKING.md) | 36 | +[ASCEND_LAUNCH_BLOCKING](https://gitcode.com/Ascend/pytorch/blob/master/docs/zh/api/environment_variable/op_execution/ASCEND_LAUNCH_BLOCKING.md) |
| 35 | 就会对每个算子进行流同步,用以定位问题。 | 37 | 就会对每个算子进行流同步,用以定位问题。 |
| 36 | 38 | ||
| 37 | -# 六、定位方法总结 | 39 | +## 6. 定位方法总结 |
| 38 | 40 | ||
| 39 | 1、通过insight打开msprof.json或者trace_view.json,明确流同步现象。 | 41 | 1、通过insight打开msprof.json或者trace_view.json,明确流同步现象。 |
| 40 | 42 | ||
| @@ -46,6 +48,6 @@ | |||
| 46 | 48 | ||
| 47 |  | 49 |  |
| 48 | 50 | ||
| 49 | -# 七、对工具的改进建议 | 51 | +## 7. 对工具的改进建议 |
| 50 | 52 | ||
| 51 | 暂无 | 53 | 暂无 |
| @@ -1,14 +1,14 @@ | |||
| 1 | # 系统调用高耗时函数 | 1 | # 系统调用高耗时函数 |
| 2 | 2 | ||
| 3 | -## 【问题背景】 | 3 | +## 1. 问题背景 |
| 4 | 4 | ||
| 5 | 在大模型分布式训练场景下,某客户 3000 卡 NPU 服务器进行多机多卡模型训练。训练初期性能正常,当迭代到第 500 步左右时,保存 Checkpoint,之后训练 step 耗时突然增加,经过 5-6 个 step 后,耗时逐渐恢复正常。该问题在相同配置的其他集群上也可复现,影响训练效率。 | 5 | 在大模型分布式训练场景下,某客户 3000 卡 NPU 服务器进行多机多卡模型训练。训练初期性能正常,当迭代到第 500 步左右时,保存 Checkpoint,之后训练 step 耗时突然增加,经过 5-6 个 step 后,耗时逐渐恢复正常。该问题在相同配置的其他集群上也可复现,影响训练效率。 |
| 6 | 6 | ||
| 7 | -## 【问题来源】 | 7 | +## 2. 问题来源 |
| 8 | 8 | ||
| 9 | 训练。 | 9 | 训练。 |
| 10 | 10 | ||
| 11 | -## 【问题现象】 | 11 | +## 3. 问题现象 |
| 12 | 12 | ||
| 13 | 稳定复现。 | 13 | 稳定复现。 |
| 14 | 14 | ||
| @@ -26,7 +26,7 @@ | |||
| 26 | 26 | ||
| 27 |  | 27 |  |
| 28 | 28 | ||
| 29 | -## 【定位过程】 | 29 | +## 4. 定位过程 |
| 30 | 30 | ||
| 31 | 1. 使用 strace 工具做了系统调用追踪。 | 31 | 1. 使用 strace 工具做了系统调用追踪。 |
| 32 | 32 | ||
| @@ -100,7 +100,7 @@ | |||
| 100 | 100 | ||
| 101 | 可以看到 futex、ioctl、pthread_mutex_unlock 等系统调用耗时较长,需要进行进一步分析。 | 101 | 可以看到 futex、ioctl、pthread_mutex_unlock 等系统调用耗时较长,需要进行进一步分析。 |
| 102 | 102 | ||
| 103 | -## 【问题根因】 | 103 | +## 5. 问题根因 |
| 104 | 104 | ||
| 105 | 在 Checkpoint 保存阶段,模型执行 30GB 量级的 D2H 数据拷贝并长期占用 Host 内存,触发内核内存回收与重整机制,导致 malloc、free 系统调用耗时显著增长,最终拖慢训练性能。 | 105 | 在 Checkpoint 保存阶段,模型执行 30GB 量级的 D2H 数据拷贝并长期占用 Host 内存,触发内核内存回收与重整机制,导致 malloc、free 系统调用耗时显著增长,最终拖慢训练性能。 |
| 106 | 106 | ||
| @@ -108,11 +108,11 @@ Linux 透明大页(THP)通过自动合并小内存页为大页,减少 TLB | |||
| 108 | 108 | ||
| 109 | 对于大模型集群训练这类大内存使用场景,若系统默认页尺寸已较大,开启透明大页的性能收益将小于后台线程抢占带来的负面影响,建议关闭透明大页功能。 | 109 | 对于大模型集群训练这类大内存使用场景,若系统默认页尺寸已较大,开启透明大页的性能收益将小于后台线程抢占带来的负面影响,建议关闭透明大页功能。 |
| 110 | 110 | ||
| 111 | -## 【定位方法论总结】 | 111 | +## 6. 定位方法论总结 |
| 112 | 112 | ||
| 113 | 优先使用全链路性能分析工具 msprof 能力,获取 NPU-OS-CPU 三层性能数据,进行端到端耗时分解分析。若确认在系统调用层,使用 OS 内核工具 strace、perf 等进行系统调用追踪和采样分析。 | 113 | 优先使用全链路性能分析工具 msprof 能力,获取 NPU-OS-CPU 三层性能数据,进行端到端耗时分解分析。若确认在系统调用层,使用 OS 内核工具 strace、perf 等进行系统调用追踪和采样分析。 |
| 114 | 114 | ||
| 115 | -## 【对工具的改进建议】 | 115 | +## 7. 对工具的改进建议 |
| 116 | 116 | ||
| 117 | 1. 数据整合与联动分析 | 117 | 1. 数据整合与联动分析 |
| 118 | 118 | ||
| @@ -340,7 +340,7 @@ docker load -i cann.tar | |||
| 340 | docker images | grep cann | 340 | docker images | grep cann |
| 341 | ``` | 341 | ``` |
| 342 | 342 | ||
| 343 | -加载完成后,继续完成 [第 3.2 节](#32-传输容器启动脚本),再返回 [第 2.1.5 节](#215-宿主机启动容器),然后启动容器。如果已切换宿主机 shell,请重新执行第 [第 2.1.2 节](#212-宿主机自动识别并配置镜像环境变量) 中的命令以恢复镜像环境变量。 | 343 | +加载完成后,继续完成 [第 3.2 节](#32-传输容器启动脚本),再返回 [第 2.1.5 节](#215-宿主机启动容器),然后启动容器。如果已切换宿主机 shell,请重新执行 [第 2.1.2 节](#212-宿主机自动识别并配置镜像环境变量) 中的命令以恢复镜像环境变量。 |
| 344 | 344 | ||
| 345 | ### 3.2 传输容器启动脚本 | 345 | ### 3.2 传输容器启动脚本 |
| 346 | 346 | ||