{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# **算子仿真调优**\n",
"\n",
"本节为算子仿真调优章节,完成本章节内容的学习可以掌握如何使用msProf工具采集仿真性能数据,并分析算子仿真性能瓶颈。我们将按照以下结构,带你学习算子仿真调优流程:\n",
"- 环境准备\n",
"- 如何使用msProf工具采集仿真性能数据\n",
"- 如何分析仿真性能数据\n",
"- 针对性优化\n",
"- 课后实践\n",
"\n",
"---"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## **1环境准备**\n",
"本文所有内容均存放于Sources文件夹。\n",
"在开始创建算子工程前,先要对jupyter环境进行初始化。以下代码完成了初始化并将环境中的变量导入jupyter环境,并完成代码目录的创建。保证能正常导入代码以及正常使用工具。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!mkdir -p Sources/04.04\n",
"\n",
"\n",
"import os\n",
"import subprocess\n",
"from pathlib import Path\n",
"\n",
"set_env = os.environ.get(\"ASCEND_TOOLKIT_HOME\", \"/usr/local/Ascend/cann\") + \"/set_env.sh\"\n",
"\n",
"result = subprocess.run(\n",
" [\"bash\", \"-lc\", f\"source {set_env} && env\"],\n",
" capture_output=True,\n",
" text=True,\n",
" check=True,\n",
")\n",
"for line in result.stdout.strip().split(\"\\n\"):\n",
" if \"=\" in line and not line.startswith((\"#\", \" \")):\n",
" key, value = line.split(\"=\", 1)\n",
" os.environ[key] = value\n",
"\n",
"print(\"Environment initialization process completed successfully.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## **2如何使用msProf工具采集仿真性能数据**\n",
"\n",
"上一节已经介绍了如何使用msProf采集上板性能数据。相对于上板模式,仿真模式多了 `simulator` 参数,并且需要指定仿真的产品型号。对于本节使用的自包含Add算子样例,可在CMake配置阶段通过 `CMAKE_ASC_RUN_MODE=sim` 开启仿真编译,并通过 `CMAKE_ASC_ARCHITECTURES=dav-2201` 指定NPU架构版本。同时,为了让仿真trace能够正常显示源码代码行,需要在运行目录的 `CMakeLists.txt` 中为Ascend C编译添加 `-g`。\n",
"\n",
"所以仿真性能采集分为3步: \n",
"\n",
"1. 准备测试程序并添加源码行信息编译选项\n",
"2. 使用仿真编译参数编译测试程序\n",
"3. 采集仿真数据\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"这里继续使用 `./src/04.03` 中的自包含Add算子测试程序,复制到 `Sources/04.04` 后用于仿真采集。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 清理并准备测试程序目录\n",
"!rm -rf Sources/04.04\n",
"!mkdir -p Sources/04.04\n",
"\n",
"# 复制已准备好的自包含 Add 算子样例\n",
"!cp ./src/04.03/add_custom.asc Sources/04.04/add_custom.asc\n",
"!cp ./src/04.03/CMakeLists.txt Sources/04.04/CMakeLists.txt\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"测试程序目录结构为:\n",
"\n",
"```\n",
"Sources/04.04/\n",
"├── add_custom.asc // 包含Kernel实现、Host侧调用代码和main函数\n",
"└── CMakeLists.txt // 使用Ascend C CMake工具链编译demo可执行程序\n",
"```\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"复制得到的 `CMakeLists.txt` 来自共享测试程序目录。为了让仿真trace能够显示源码代码行,本节只在运行目录 `Sources/04.04/CMakeLists.txt` 中增加 `-g` 编译选项;仿真编译所需配置仍通过CMake配置命令传入:\n",
"\n",
"```shell\n",
"cmake -B build -DCMAKE_ASC_RUN_MODE=sim -DCMAKE_ASC_ARCHITECTURES=dav-2201\n",
"```\n",
"\n",
"其中 `CMAKE_ASC_RUN_MODE=sim` 表示开启仿真编译,`CMAKE_ASC_ARCHITECTURES=dav-2201` 表示本节样例使用的NPU架构版本。\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%writefile Sources/04.04/CMakeLists.txt\n",
"\n",
"cmake_minimum_required(VERSION 3.16)\n",
"\n",
"find_package(ASC REQUIRED)\n",
"\n",
"project(kernel_samples LANGUAGES ASC CXX)\n",
"\n",
"add_executable(demo\n",
" add_custom.asc\n",
")\n",
"\n",
"target_compile_options(demo PRIVATE\n",
" $<$<COMPILE_LANGUAGE:ASC>:--npu-arch=dav-2201>\n",
" $<$<COMPILE_LANGUAGE:ASC>:-g>\n",
")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"然后根据仿真产品型号设置仿真相关的环境变量,这里以仿真Atlas A2训练产品为例,应设置环境变量为:\n",
"\n",
"```shell\n",
"export LD_LIBRARY_PATH=${ASCEND_TOOLKIT_HOME}/tools/simulator/Ascend910B1/lib:$LD_LIBRARY_PATH\n",
"```\n",
"\n",
"设置环境变量后,即可使用 `msprof op simulator` 抓取可执行程序执行的仿真性能,命令为:\n",
"\n",
"```shell\n",
"msprof op simulator --output=./output_data ./xxxx\n",
"```\n",
"\n",
"如果不设置 `LD_LIBRARY_PATH`,也可通过增加 `--soc-version` 指定要仿真的产品型号,命令为:\n",
"\n",
"```shell\n",
"msprof op simulator --soc-version=Ascend910B1 --output=./output_data ./xxxx\n",
"```\n",
"\n",
"如果确认核间数据为均匀分布,或者只想获取指定核的仿真数据,可以通过 `--core-id` 来指定核。以采集id为0的核的仿真性能为例,命令为:\n",
"\n",
"```shell\n",
"msprof op simulator --soc-version=Ascend910B1 --output=./output_data --core-id=0 ./xxxx\n",
"```\n",
"\n",
"让我们执行以下命令编译测试程序,尝试采集id为0的仿真性能数据。\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 清除可能存在的性能文件\n",
"!rm -rf Sources/04.04/prof\n",
"# 创建性能文件存放目录\n",
"!mkdir -p Sources/04.04/prof\n",
"# 编译测试程序\n",
"!cd Sources/04.04 && cmake -B build -DCMAKE_ASC_RUN_MODE=sim -DCMAKE_ASC_ARCHITECTURES=dav-2201 && cmake --build build\n",
"# 采集仿真性能数据\n",
"!msprof op simulator --soc-version=Ascend910B1 --output=./Sources/04.04/prof --core-id=0 ./Sources/04.04/build/demo\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"命令执行后,Sources/04.04/prof目录下会生成性能数据文件,目录结构如下:\n",
"\n",
"```\n",
"OPPROF_20260310020803_BJNTOKUSUZMIESZL/\n",
"├── simulator/\n",
"│ ├── core0.veccore0/ // 按照core*.veccore*或core*.cubecore*目录存放各核的数据文件\n",
"│ ├── trace.json // 全部核或指定核的仿真指令流水图文件\n",
"│ └── visualize_data.bin // 全部核或指定核的仿真指令流水图文件\n",
"└── dump/ // 存放过程件的文件夹,无需关注\n",
" ├── aicore_binary.o\n",
" ├── object_dump.txt\n",
" └── pc_start_addr.txt\n",
"```\n",
"\n",
"\n",
"执行以下命令查看Sources/04.04/prof查看到采集的性能数据文件。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!cd Sources/04.04/prof; find . -maxdepth 3 -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## **3如何分析仿真性能数据**\n",
"\n",
"已抓取的仿真数据文件trace.json、visualize_data.bin通常不能直接分析性能,这里我们需要借助Chrome浏览器的chrome://tracing打开trace.json或者使用[MindStudio Insight工具](https://www.hiascend.com/document/detail/zh/mindstudio/840/GUI_baseddevelopmenttool/msascendinsightug/Insight_userguide_0027.html)打开trace.json、visualize_data.bin。 \n",
"\n",
"### **3.1 Chrome浏览器打开**\n",
"在Chrome浏览器中输入“chrome://tracing”地址,并将通过msprof op simulator生成指令流水图文件(trace.json)拖到空白处打开,键盘上输入快捷键(**W:放大,S:缩小,A:左移,D:右移**)可进行查看看各个流水任务耗时的信息。例如刚刚我们抓取的Add算子样例性能文件打开会如下: \n",
"\n",
"<img src=\"./images/trace_info.png\" alt=\"trace\" width=\"1920px\"> \n",
"\n",
"我们可以比较直观的看到算子整体耗时中MTE2、VECTOR、MET3耗时均很短,而SCALAR运算耗时很长,点击右侧SCALAR可在下方看到该流水任务对应的具体代码行数。\n",
"执行以下代码下载我们抓取到的trace.json文件,尝试使用Chrome浏览器查看一下吧。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import glob,base64;from IPython.display import display,HTML\n",
"f=glob.glob(\"Sources/04.04/prof/OPPROF_*/simulator/trace.json\")\n",
"if f:\n",
" b64=base64.b64encode(open(f[0],'rb').read()).decode()\n",
" display(HTML(f'<a href=\"data:application/json;base64,{b64}\" download=\"trace.json\" style=\"color:white;background:#007bff;padding:5px 10px;text-decoration:none;border-radius:3px;\">📥 下载</a>'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"也可以直接执行下面代码查看性能文件,该代码简单生成了一个图表模拟了chrome://tracing的展示效果,但是不可以缩放和拖动。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt, warnings, json, pandas as pd, os, glob\n",
"plt.set_loglevel(\"error\"); warnings.filterwarnings('ignore', category=UserWarning)\n",
"\n",
"BASE_DIR = \"Sources/04.04/prof\"\n",
"try:\n",
" trace_path = f\"{sorted(glob.glob(f'{BASE_DIR}/OPPROF*'), key=os.path.getctime)[-1]}/simulator/trace.json\"\n",
"except:\n",
" trace_path = \"Sources/04.04/prof/OPPROF_20260310110753_XXSVYUAHKSEHAZXS/simulator/trace.json\"\n",
"\n",
"df = pd.DataFrame([{\"name\":e.get(\"name\",\"unknown\"),\"start\":e[\"ts\"]/1e6,\"dur\":e[\"dur\"]/1e6,\"thread\":f\"Thread-{e.get('tid',0)}\"} \n",
" for e in json.load(open(trace_path))[\"traceEvents\"] if \"ts\" in e and \"dur\" in e])\n",
"plt.figure(figsize=(12, 5))\n",
"\n",
"for thread in df[\"thread\"].unique():\n",
" t_df = df[df[\"thread\"] == thread]\n",
" plt.barh(thread, t_df[\"dur\"], left=t_df[\"start\"], label=t_df[\"name\"].iloc[0], alpha=0.7)\n",
"\n",
"thread_names = [th.replace(\"Thread-\", \"\") for th in df[\"thread\"].unique()]\n",
"plt.yticks(ticks=df[\"thread\"].unique(), labels=thread_names)\n",
"\n",
"plt.xlabel(\"Time (ms)\"); plt.title(\"Trace.json\")\n",
"plt.legend(loc=\"upper right\", bbox_to_anchor=(1.2, 1)); plt.grid(axis='x', alpha=0.3)\n",
"plt.tight_layout(); plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### **3.2使用MindStudio Insight打开**\n",
"若要使用MindStudio Insight进行查看时,需要单独安装MindStudio Insight软件包,具体下载链接请参见[安装与卸载](https://www.hiascend.com/document/detail/zh/mindstudio/840/GUI_baseddevelopmenttool/msascendinsightug/Insight_userguide_0006.html)。 \n",
"安装好MindStudio Insight软件包后,我们可以在工具中导入刚刚抓取到的性能数据文件。 \n",
"\n",
"<img src=\"./images/chose_file.png\" alt=\"chose_file\" width=\"700px\">"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"导入后,时间线界面与Chrome浏览器中打开效果一致,如图: \n",
"\n",
"<img src=\"./images/timeline.png\" alt=\"timeline\" width=\"700px\">"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"切换到源码界面,我们在设置好对应源码后,即可查看每行代码对应的时钟周期,可以更直观的看到耗时较多的代码或代码块。 \n",
"\n",
"<img src=\"./images/code_info.png\" alt=\"code_info\" width=\"1920px\">"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## **4针对性优化**\n",
"\n",
"根据trace图或者源码时钟周期我们可以看出耗时主要集中在`printf`打印,所以推测将`printf`打印屏蔽后,算子的性能会有较大提升。这里通过CMake编译定义`ASCENDC_DUMP=0`屏蔽打印,并重新采集仿真性能数据进行对比。\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%writefile Sources/04.04/CMakeLists.txt\n",
"\n",
"cmake_minimum_required(VERSION 3.16)\n",
"\n",
"find_package(ASC REQUIRED)\n",
"\n",
"project(kernel_samples LANGUAGES ASC CXX)\n",
"\n",
"add_executable(demo\n",
" add_custom.asc\n",
")\n",
"\n",
"target_compile_options(demo PRIVATE\n",
" $<$<COMPILE_LANGUAGE:ASC>:--npu-arch=dav-2201>\n",
" $<$<COMPILE_LANGUAGE:ASC>:-g>\n",
")\n",
"\n",
"target_compile_definitions(demo PRIVATE ASCENDC_DUMP=0)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"修改完成后重新部署算子并抓取性能:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 清理旧构建目录并重新编译\n",
"!rm -rf Sources/04.04/build\n",
"!cd Sources/04.04 && cmake -B build -DCMAKE_ASC_RUN_MODE=sim -DCMAKE_ASC_ARCHITECTURES=dav-2201 && cmake --build build\n",
"\n",
"# 清除可能存在的性能文件\n",
"!rm -rf Sources/04.04/prof2\n",
"# 创建性能文件存放目录\n",
"!mkdir -p Sources/04.04/prof2\n",
"# 采集屏蔽打印后的仿真性能数据\n",
"!msprof op simulator --soc-version=Ascend910B1 --output=./Sources/04.04/prof2 --core-id=0 ./Sources/04.04/build/demo\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"抓取仿真性能后,使用Chrome浏览器读取性能数据与之前对比,观察是否符合预期,减少了scalar运算耗时。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import glob,base64;from IPython.display import display,HTML\n",
"f=glob.glob(\"Sources/04.04/prof2/OPPROF_*/simulator/trace.json\")\n",
"if f:\n",
" b64=base64.b64encode(open(f[0],'rb').read()).decode()\n",
" display(HTML(f'<a href=\"data:application/json;base64,{b64}\" download=\"trace.json\" style=\"color:white;background:#007bff;padding:5px 10px;text-decoration:none;border-radius:3px;\">📥 下载</a>'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"预期如图: \n",
"\n",
"<img src=\"./images/no_print_trace.png\" alt=\"no_print_trace\" width=\"1920px\">\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"或执行下面代码简单查看"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt, warnings, json, pandas as pd, os, glob\n",
"plt.set_loglevel(\"error\"); warnings.filterwarnings('ignore', category=UserWarning)\n",
"\n",
"BASE_DIR = \"Sources/04.04/prof2\"\n",
"try:\n",
" trace_path = f\"{sorted(glob.glob(f'{BASE_DIR}/OPPROF*'), key=os.path.getctime)[-1]}/simulator/trace.json\"\n",
"except:\n",
" trace_path = \"Sources/04.04/prof2/OPPROF_20260310110753_XXSVYUAHKSEHAZXS/simulator/trace.json\"\n",
"\n",
"df = pd.DataFrame([{\"name\":e.get(\"name\",\"unknown\"),\"start\":e[\"ts\"]/1e6,\"dur\":e[\"dur\"]/1e6,\"thread\":f\"Thread-{e.get('tid',0)}\"} \n",
" for e in json.load(open(trace_path))[\"traceEvents\"] if \"ts\" in e and \"dur\" in e])\n",
"plt.figure(figsize=(12, 5))\n",
"\n",
"for thread in df[\"thread\"].unique():\n",
" t_df = df[df[\"thread\"] == thread]\n",
" plt.barh(thread, t_df[\"dur\"], left=t_df[\"start\"], label=t_df[\"name\"].iloc[0], alpha=0.7)\n",
"\n",
"thread_names = [th.replace(\"Thread-\", \"\") for th in df[\"thread\"].unique()]\n",
"plt.yticks(ticks=df[\"thread\"].unique(), labels=thread_names)\n",
"\n",
"plt.xlabel(\"Time (ms)\"); plt.title(\"Trace.json\")\n",
"plt.legend(loc=\"upper right\", bbox_to_anchor=(1.2, 1)); plt.grid(axis='x', alpha=0.3)\n",
"plt.tight_layout(); plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## **课后实践**\n",
"请根据本节课程学习内容完成以下题目进行自测。\n",
"\n",
"1. (单选题)在AscendC算子仿真调优环节,原文档中提到,开展算子性能仿真验证、获取性能数据的前置条件是? \n",
" A. 完成算子开发并能正常调用 \n",
" B. 完成算子Kerne实现逻辑即可采集性能数据 \n",
" C. 仅通过编译器静态分析代码逻辑,即可分析出性能数据,不需要借助工具 \n",
" D. 手动计算理论性能值,不需要借助工具 \n",
"\n",
"2. (单选题)Ascend C算子仿真数据抓取完成后,主要通过查看哪类核心文件来获取详细的性能耗时、单元利用率等关键性能数据? \n",
" A. 源码编译生成的.o目标文件 \n",
" B. 仿真运行生成的性能统计trace.json和visualize_data.bin文件 \n",
" C. 算子定义头文件 \n",
" D. 系统通用日志文件 \n",
"\n",
"3. (单选题)AscendC算子仿真性能分析时,重点关注的核心性能指标不包含以下哪一项? \n",
" A. 算子整体执行耗时 \n",
" B. AI Core计算单元利用率 \n",
" C. 数据搬运带宽与搬运耗时占比 \n",
" D. 操作系统版本号 \n",
"\n",
"4. (单选题)Ascend C算子仿真调优中的性能瓶颈定位,可行的方法是? \n",
" A. 随机修改代码尝试优化 \n",
" B. 对比仿真报告中计算模块、搬运模块、同步等待的耗时占比,定位核心瓶颈 \n",
" C. 仅查看代码行数判断效率 \n",
" D. 依赖硬件自带的自动瓶颈提示 \n",
"\n",
"5. (单选题)Ascend C算子仿真调优相比硬件实测,在算子性能优化阶段的核心优势是? \n",
" A. 无需依赖算子实际运行的实体昇腾硬件,借助仿真模拟实际硬件行为完成性能验证与瓶颈定位,缩短优化周期 \n",
" B. 性能数据比硬件实测更精准 \n",
" C. 可以直接修改硬件底层参数 \n",
" D. 不需要编写任何算子代码 "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"执行以下代码查看答案:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!cat ./answer/04.04_answer.txt"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "py312",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.13"
}
},
"nbformat": 4,
"nbformat_minor": 2
}