admin 2026-09-01 11:48:20 攻略指南

写给新手的 profiling-suite:昇腾性能分析套件到底是啥?

之前优化推理性能,我觉得有点慢,但不知道哪慢。兄弟说:“哥,用 profiling-suite 跑一下,看看时间都去哪了。”

好问题。今天一次说清楚。

profiling-suite 是啥?

profiling-suite 是昇腾的性能分析套件。帮你找出性能瓶颈在哪,哪个算子慢,哪个占用内存多。

一句话说清楚:profiling-suite 是昇腾的性能分析套件,帮你分析算子耗时、内存占用、资源利用率,找出性能瓶颈。

你说气人不气人,之前觉得慢但不知道原因,现在跑一下全清楚了。

为什么要用 profiling-suite?

三个字:找瓶颈。

不用 profiling-suite(蒙着跑)

# 跑模型,看结果

for batch in dataloader:

output = model(batch)

print(f"Total time: {time.time() - start:.3f}s")

# 输出:

# Total time: 5.234s

# 问题:不知道哪慢,不知道哪个算子占用时间长

用 profiling-suite(明着跑)

import profiling_suite

# 启用分析

profiler = profiling_suite.Profiler()

profiler.start()

# 跑模型

for batch in dataloader:

output = model(batch)

# 停止分析

profiler.stop()

# 打印报告

profiler.report()

# 输出:

# ========================================

# Performance Report

# ========================================

# Total time: 5.234s

#

# Operator breakdown:

# Conv2d_1 1.234s (23.6%) ████████████████████

# Relu_1 0.123s ( 2.4%) ██

# MaxPool_1 0.456s ( 8.7%) ████████

# Matmul_1 2.345s (44.8%) ██████████████████████████████████████

# Softmax_1 0.876s (16.7%) ████████████

# Other 0.200s ( 3.8%) ███

#

# Memory breakdown:

# Input: 12.3 MB

# Weights: 98.5 MB

# Output: 23.4 MB

# Total: 134.2 MB

#

# Bottleneck: Matmul_1 (44.8% of time)

# Recommendation: Use mixed precision (FP16)

你说气人不气人,一目了然知道该优化哪里。

核心概念就三个

1. 算子分析(Operator Profiling)

分析每个算子的耗时:

import profiling_suite

# 按算子统计

profiler = profiling_suite.Profiler(mode="operator")

profiler.start()

model(input)

profiler.stop()

profiler.print_operator_summary()

# 输出:

# Operator Time(ms) Percentage Calls

# -------- -------- ---------- -----

# Conv2d 12.34 23.5% 10

# Matmul 23.45 44.8% 100

# Relu 1.23 2.4% 50

# Softmax 8.76 16.7% 10

# Add 2.34 4.5% 20

2. 时间线分析(Timeline)

timeline 显示时间顺序:

import profiling_suite

# 时间线模式

profiler = profiling_suite.Profiler(mode="timeline")

profiler.start()

model(input)

profiler.stop()

profiler.save_timeline("timeline.json")

# 可以用 Chrome 的 chrome://tracing 打开看

# 看算子执行的顺序和重叠情况

3. 内存分析(Memory Profiling)

分析内存使用:

import profiling_suite

# 内存模式

profiler = profiling_suite.Profiler(mode="memory")

profiler.start()

model(input)

profiler.stop()

profiler.print_memory_summary()

# 输出:

# ========================================

# Memory Summary

# ========================================

# Peak memory: 234.5 MB

#

# Breakdown:

# Conv2d_1 89.2 MB ( 38.0%)

# Matmul_1 123.4 MB ( 52.6%)

# Relu_1 0.0 KB ( 0.0%)

# Input 12.3 MB ( 5.2%)

# Output 9.6 MB ( 4.1%)

#

# Location:

# Device memory: 234.5 MB (100.0%)

# Host memory: 0.0 KB ( 0.0%)

为什么要用 profiling-suite?

三个理由:

1. 精准定位问题

之前凭感觉优化,现在有数据:

# 凭感觉:我觉得是卷积慢

# 数据:Matmul 占 44.8%

# 凭感觉:可能是内存问题

# 数据:内存 234MB,没问题

# 凭感觉:算子融合能快

# 数据:单算子执行,没有重叠,无法融合

2. 量化优化效果

优化前后对比:

# 优化前

print(profiler_before.report())

# Total time: 5.234s

# 优化后

print(profiler_after.report())

# Total time: 3.456s

# 加速比: 1.51x

3. 指导优化方向

告诉你该优化什么:

# 建议

recommendations = profiler.get_recommendations()

for rec in recommendations:

print(rec)

# 输出:

# 1. Use FP16 for Matmul (expected 2x speedup)

# 2. Fuse Conv2d + Bias + Relu (expected 1.3x speedup)

# 3. Enable memory reuse (save 50MB memory)

# 4. Increase batch size to 16 (better throughput)

怎么用?代码示例

示例 1:基础性能分析

import profiling_suite

import time

import numpy as np

# 创建模型

class SimpleModel:

def __init__(self):

self.conv = np.random.randn(64, 3, 7, 7)

def forward(self, x):

# 模拟卷积

y = np.random.randn(1, 64, 112, 112)

time.sleep(0.1) # 模拟计算

# 模拟 ReLU

y = np.maximum(y, 0)

time.sleep(0.01)

return y

model = SimpleModel()

# 创建分析器

profiler = profiling_suite.Profiler()

# 开始分析

profiler.start()

# 运行模型多次

for i in range(10):

x = np.random.randn(1, 3, 224, 224)

y = model.forward(x)

# 停止分析

profiler.stop()

# 打印报告

profiler.report()

# 输出:

# Total time: 1.100s

#

# Breakdown:

# forward 1.100s (100.0%)

# Conv2d 1.000s (90.9%)

# ReLU 0.100s (9.1%)

示例 2:Timeline 分析

import profiling_suite

import numpy as np

import time

# 设置 timeline 模式

profiler = profiling_suite.Profiler(mode="timeline", trace=True)

# 启动

profiler.start()

# 模型推理

input_data = np.random.randn(1, 3, 224, 224)

# Layer 1

conv1_out = np.random.randn(1, 64, 112, 112)

profiler.add_marker("Conv1 done")

# Activation

relu1_out = np.maximum(conv1_out, 0)

profiler.add_marker("Relu1 done")

# Layer 2

conv2_out = np.random.randn(1, 128, 56, 56)

profiler.add_marker("Conv2 done")

# 停止

profiler.stop()

# 保存 timeline

profiler.save_timeline("model_trace.json")

print("Timeline saved to model_trace.json")

print("Open in Chrome at chrome://tracing")

示例 3:内存分析

import profiling_suite

import numpy as np

# 内存分析模式

profiler = profiling_suite.Profiler(mode="memory")

profiler.start()

# 模拟大模型推理

# Input: 1*3*224*224 * 4 bytes = 0.6 MB

input = np.random.randn(1, 3, 224, 224).astype(np.float32)

profiler.mark("Input allocated")

# Convs: 64 layers

for i in range(64):

# 每个卷积权重: out_ch * in_ch * kH * kW * 4 bytes

pass

profiler.mark("Weights loaded")

# Output: 1*1000 * 4 bytes = 4 KB

output = np.random.randn(1, 1000)

profiler.mark("Inference done")

# Forward 中间激活值:约 100 MB

profiler.mark("Forward intermediate")

# Backward 梯度

profiler.mark("Backward done")

profiler.stop()

# 打印内存报告

profiler.print_memory()

# 输���:

# Memory: 234.5 MB peak

#

# By lifecycle:

# Input: 0.6 MB ( 0.3%)

# Weights: 98.5 MB (42.0%)

# Output: 0.0 MB ( 0.0%)

# Activations: 135.4 MB (57.7%)

示例 4:对比分析

import profiling_suite

import numpy as np

import time

# 对比两种实现

def version_fp32():

"""FP32 版本"""

data = np.random.randn(1024, 1024).astype(np.float32)

weights = np.random.randn(1024, 1024).astype(np.float32)

time.sleep(0.1) # matmul simulation

return np.dot(data, weights)

def version_fp16():

"""FP16 版本"""

data = np.random.randn(1024, 1024).astype(np.float16)

weights = np.random.randn(1024, 1024).astype(np.float16)

time.sleep(0.05) # faster simulation

return np.dot(data, weights)

# 分析 FP32

profiler_fp32 = profiling_suite.Profiler(name="FP32")

profiler_fp32.start()

for _ in range(100):

version_fp32()

profiler_fp32.stop()

# 分析 FP16

profiler_fp16 = profiling_suite.Profiler(name="FP16")

profiler_fp16.start()

for _ in range(100):

version_fp16()

profiler_fp16.stop()

# 对比报告

print("\n=== Comparison ===")

print(f"FP32: {profiler_fp32.get_total_time():.3f}s")

print(f"FP16: {profiler_fp16.get_total_time():.3f}s")

print(f"Speedup: {profiler_fp32.get_total_time() / profiler_fp16.get_total_time():.2f}x")

# 输出:

# === Comparison ===

# FP32: 10.00s

# FP16: 5.00s

# Speedup: 2.00x

性能数据

使用 profiling-suite 的优化效果:

优化前

优化后

加速比

FP32 matmul

FP16 matmul

2.0x

未融合算子

融合算子

1.3x

静态 batch

动态 batch

1.5x

无优化

内存复用

节省 50MB

你说气人不气人,有数据才能精准优化。

跟其他仓库的关系

profiling-suite 在 CANN 架构里属于第 3 层(昇腾计算编译层),是性能分析工具。

依赖关系:

profiling-suite(性能分析)

↓ 分析

ge(图引擎)

↓ 执行

算子库(ops-xxx)

↓ 实现

硬件(昇腾 NPU)

解释一下:

ge:图引擎,调度算子

profiling-suite:分析 ge 的执行

算子库:实际执行

硬件:昇腾 NPU

简单说:profiling-suite 是性能"CT 机"。给模型做体检,哪有问题都能看出来。

profiling-suite 的核心能力

1. Operator Profiling

profiler = profiling_suite.Profiler(mode="operator")

profiler.start()

model()

profiler.stop()

profiler.print_operator_summary()

2. Timeline Profiling

profiler = profiling_suite.Profiler(mode="timeline", trace=True)

profiler.start()

model()

profiler.stop()

profiler.save_timeline("trace.json")

3. Memory Profiling

profiler = profiling_suite.Profiler(mode="memory")

profiler.start()

model()

profiler.stop()

profiler.print_memory_summary()

4. Comparison

baseline = profiler.version1()

optimized = profiler.version2()

comparison = baseline.compare_with(optimized)

print(comparison)

适用场景

什么情况下用 profiling-suite:

性能优化:不知道哪慢

内存优化:内存不够

对比实验:优化前后对比

验���:性能达标

什么情况下不用:

生产环境:会影响性能

简单场景:Run 就完事了

总结

profiling-suite 就是昇腾的"性能 CT 机":

算子分析:精确到每个算子

时间线:看执行顺序

内存:看内存分配

对比:优化前后对比