基础案例
1. 内存泄漏检测
1.1 操作步骤
-
参考《msMemScope 安装指南》完成相关环境变量的配置。
-
进入仓库目录,准备一个简单的 PyTorch 训练脚本。以
example_api.py为例,脚本内容如下:import torch import torch_npu import msmemscope msmemscope.config( events="alloc,free,launch", level="op", analysis="leaks", output="./output" ) msmemscope.start() # 用户代码:简单的模型训练 device = torch.device("npu:0") model = torch.nn.Linear(1024, 1024).to(device) optimizer = torch.optim.SGD(model.parameters(), lr=0.01) leak_tensors = [] for step in range(10): data = torch.randn(64, 1024).to(device) output = model(data) loss = output.sum() loss.backward() optimizer.step() msmemscope.step() msmemscope.stop() -
在上述脚本中构造一个内存泄漏场景:在训练循环中,每次迭代申请一个 Tensor 但不释放,模拟内存持续增长。
# 在 for step in range(10): 循环内部添加以下代码,构造泄漏 leak_tensors.append(torch.randn(1024, 1024).to(device)) # 每次迭代申请,不释放 -
执行脚本:
python example_api.py -
执行完成后,工具会输出内存泄漏分析结果。请参考《msMemScope 使用指南》中的"内存泄漏分析功能介绍"分析异常行为。
1.2 内存泄漏示例说明
- 在操作步骤中,构造了一个典型的泄漏场景:每个 Step 内申请了 4MB(1024×1024×4 bytes)的显存但未释放。
- 工具会检测到内存持续增长,并在输出中报告泄漏的地址、泄漏大小以及关联的 Step 信息,与构造的异常场景对应。
2. 内存对比分析
2.1 操作步骤
-
准备一个 PyTorch 训练脚本,使用 msmemscope 命令行方式采集两个不同 Step 的内存数据。
-
采集第一个 Step 的数据(以 Step 2 为例):
msmemscope --events=alloc,free --level=kernel --steps=2 --output=./output/step2 python train.py -
采集第二个 Step 的数据(以 Step 5 为例):
msmemscope --events=alloc,free --level=kernel --steps=5 --output=./output/step5 python train.py -
执行对比命令,比较两个 Step 的内存使用差异:
msmemscope --compare --input=./output/step2,./output/step5 --level=kernel -
对比结果会输出到
memscopeDumpResults/compare/目录下,生成memory_compare_{timestamp}.csv文件。请参考《msMemScope 使用指南》中的"内存对比分析功能介绍"分析差异。
2.2 内存对比示例说明
- 在上述操作中,如果 Step 2 和 Step 5 的训练逻辑存在差异(例如 Step 5 多申请了一块临时缓冲区),对比报告中会显示两个 Step 之间新增或减少的内存分配记录。
- 通过对比文件可快速定位到具体哪个算子或模块在两个 Step 间产生了内存差异,为 OOM 问题排查提供依据。
3. 内存块监测
3.1 操作步骤
-
关闭多任务下发,保证算子按序执行:
export ASCEND_LAUNCH_BLOCKING=1 -
在用户脚本中引入 watcher 模块,指定需要监测的 Tensor:
import torch import torch_npu import msmemscope torch.npu.synchronize() test_tensor = torch.randn(256, 256).to('npu:0') # 监测该 Tensor,dump_nums=3 表示最多落盘 3 次 msmemscope.watcher.watch(test_tensor, name="test_tensor", dump_nums=3) # 执行一些算子操作,可能发生内存踩踏 result = test_tensor + 1 result = result * 2 torch.npu.synchronize() msmemscope.watcher.remove(test_tensor) -
使用命令行开启内存块监测功能,拉起用户脚本:
msmemscope --watch=start:op0,end:op1,full-content python user_script.py -
命令执行完成后,结果会输出到
memscopeDumpResults/watch_dump/目录。请参考《msMemScope 使用指南》中的"内存块监测功能介绍"分析监测结果。
3.2 内存块监测示例说明
- 在上述操作中,
msmemscope.watcher.watch监测了test_tensor对应的内存块。 - 构造一个内存踩踏场景:在
watch和remove之间,某个算子越界写入了test_tensor相邻的内存区域。 - 通过对比算子执行前后的 bin 文件或哈希值,可以精确定位是哪个算子导致了内存数据的变化。
4. 内存拆解
4.1 操作步骤
-
在 PyTorch 训练脚本中导入 msmemscope,使用 describe 接口对代码段进行标记:
import torch import torch_npu import msmemscope import msmemscope.describe as describe msmemscope.config( events="alloc,free", analysis="decompose", data_format="csv", output="./output" ) msmemscope.start() device = torch.device("npu:0") # 方式一:使用装饰器标记函数 @describe.describer(owner="model_init") def init_model(): model = torch.nn.Linear(4096, 4096).to(device) return model # 方式二:使用 with 语句标记代码块 with describe.describer(owner="forward_pass"): model = init_model() data = torch.randn(64, 4096).to(device) output = model(data) msmemscope.stop() -
执行脚本:
python train_decompose.py -
执行完成后,落盘的
memscope_dump_{timestamp}.csv文件中会包含owner字段,标记各内存分配所属的组件。请参考《msMemScope 使用指南》中的"内存拆解功能介绍"分析拆解结果。
4.2 内存拆解示例说明
- 在上述操作中,通过
@describe.describer(owner="model_init")装饰器标记了模型初始化函数,通过with describe.describer(owner="forward_pass")标记了前向传播代码块。 - 工具会根据标记将内存分配事件归类,输出中
owner字段分别显示model_init和forward_pass,帮助用户了解各部分的内存占用情况。
5. 低效内存识别
5.1 操作步骤
-
准备一个 PyTorch 单算子调用脚本,使用命令行方式开启低效内存识别:
msmemscope --events=alloc,free,access,launch --analysis=inefficient --level=op python inefficient_demo.py -
构造一个存在低效内存使用的脚本
inefficient_demo.py,示例如下:import torch import torch_npu device = torch.device("npu:0") # 过早申请:提前申请但很久之后才使用 early_tensor = torch.randn(1024, 1024).to(device) # 中间穿插其他操作 temp1 = torch.randn(512, 512).to(device) temp2 = torch.randn(512, 512).to(device) del temp1 del temp2 # 此时才使用 early_tensor result = early_tensor + 1 # 过迟释放:使用完毕后未及时释放 used_tensor = torch.randn(2048, 2048).to(device) _ = used_tensor * 2 # 最后一次使用 # 中间穿插其他操作 temp3 = torch.randn(1024, 1024).to(device) del temp3 # 此时才释放 used_tensor del used_tensor -
执行完成后,工具会在输出文件中标记低效内存事件。请参考《msMemScope 使用指南》中的"低效内存识别功能介绍"分析结果。
5.2 低效内存识别示例说明
- 上述脚本构造了两类低效内存场景:
- 过早申请:
early_tensor申请后,中间穿插了temp1、temp2的申请和释放,之后才首次使用early_tensor,工具会将其识别为"过早申请"。 - 过迟释放:
used_tensor最后一次使用后,中间穿插了temp3的申请和释放,之后才释放used_tensor,工具会将其识别为"过迟释放"。
- 过早申请:
- 工具报告会指明低效内存的类型、地址和大小,帮助用户优化内存使用策略。
6. OOM 场景内存快照采集
6.1 操作步骤
-
使用 Python 接口配置采集参数,并启用快照采集:
import torch import torch_npu import msmemscope msmemscope.config( events="alloc,free", data_format="csv", output="./output" ) msmemscope.start() device = torch.device("npu:0") try: # 模拟大内存申请,可能触发 OOM tensors = [] for i in range(100): tensors.append(torch.randn(1024, 1024, 128).to(device)) except RuntimeError as e: # OOM 发生时,工具会自动落盘快照信息 print(f"OOM detected: {e}") msmemscope.stop() -
执行脚本:
python oom_demo.py -
OOM 发生时,工具会自动落盘快照信息到
memscope_dump_{timestamp}.csv文件中。请参考《msMemScope 使用指南》中的"Python接口采集功能介绍"和《输出文件说明》分析快照数据。
6.2 OOM 快照示例说明
- 上述脚本在循环中不断申请大块显存,直到触发 OOM。
- msMemScope 工具在 OOM 发生时自动采集当前显存快照,记录各内存块的分配信息。
- 通过分析快照文件,可以快速识别出哪些内存分配导致了 OOM,从而定位问题根因。