剖析数据生成
在仿真框架内,AI 引擎仿真器可以为完整应用生成剖析报告。此报告是使用 –-profile
标志生成的。
aiesimulator –pkg-dir=Work –-profile
文本文件和 XML 文件都是在 aiesimulator_output
目录中生成的。对于位于 C 列和 R 行中的拼块,会生成两种类型的文件。*_funct
用于报告每个函数的调用次数和周期数。*_instr
则是深入汇编代码的报告。要直观显示此报告,可使用 Vitis Unified IDE 的“Analysis”(分析)视图。
vitis -a aiesimulator_output/default.aierun_summary
Profile(剖析)选项卡会打开“Profile”报告,其中显示了含信息的各节菜单。
- “Summary”(汇总)
- 报告总周期计数、总指令计数和存储器中的程序大小。
- “Function Reports”(函数报告)
- 显示计算图中函数的几个关键指标。
- “Number of calls”(调用次数)
- 报告函数的执行次数
- “Total function time”(函数总时间,以周期数和 % 表示)
- 报告函数执行时间(以周期数和 % 来表示)。这是执行函数内的代码所需的时间,不包括对其后代的任何调用。
- “Total function + descendant time”(函数总时间 + 后代时间,以周期数和 % 表示)
- 报告函数执行时间以及后代函数的执行时间(由当前报告的剖析信息对应的函数所调用的函数即为后代函数)。“Total Function+descendant time”表示执行某个函数中的代码及该函数所调用的任何函数中的代码所需的总时间,包括其后代函数中耗费的时间。请务必注意,此时间既包含函数本身内所耗费的时间,也包含该函数直接或间接调用的所有函数内所耗费的时间。
- “Min/Avg/Max function time”(最短/平均/最长函数时间,以周期数来表示)
- 报告最短、平均、最长函数执行时间(以周期数和 % 来表示)。
- “Min/Avg/Max function + descendant time”(最短/平均/最长函数时间 + 后代时间,以周期数来表示)
- 报告最短、平均、最长函数执行时间以及后代函数的执行时间(由当前报告的剖析信息对应的函数所调用的函数即为后代函数)。
- “Program counter Low/High”(程序计数器低位/高位)
- 报告特定函数的最低和最高程序计数器值。
- “Profile Details”(剖析详情)
- 显示逐个函数的汇编代码(含实用的精度)。各列如下表所示。
列名 | 内容 |
---|---|
PC | 程序计数器 |
Instruction(指令) | 每行最多 16 字节 |
Assembly(汇编) | 汇编代码助记符,含完整的 7 路指令字 |
Exe-count(执行计数) | 处理器执行该行的次数 |
Cycles(周期数) | 所需的周期数 |
User Count(用户计数) | |
Wait States(等待状态) | 对于部分指令,可能会出现存储器冲突,导致多次进入等待状态 |
Relative cycle use within function(函数内的相对周期使用情况) | 显示为“*”行,其中相对长度会直观显示该指令在函数内的相对周期使用情况 |
Relative cycle use within simulation(仿真内的相对周期使用情况) | 显示为“*”行,其中相对长度会直观显示该指令在仿真(包括 main() 和所有函数)内的相对周期使用情况 |
Relative wait-state use within function(函数内的相对等待状态使用情况) | 显示为“W”行,其中相对长度会直观显示在函数内执行该指令期间,等待状态所使用的相对周期 |
Relative wait state use within simulation(仿真内的相对等待状态使用情况) | 显示为“*”行,其中相对长度会直观显示在仿真(包括 main() 和所有函数)内执行该指令期间,等待状态所使用的相对周期 |
使用剖析数据进行性能调试
要改善设计的性能,应首先从最优化占用周期数最多的函数开始。完成后即可对占用周期数和比例略少的函数进行最优化。为达成此目的,函数总时间计算图将帮助您选择这些函数。
对于最优化本身,您可使用编译指示(chess_prepare_for_pipelining 和 chess_loop_range)来执行寻常的循环流水打拍和展开。Profile Details选项卡提供了有关等待状态的洞察。即使内层循环完美完成最优化,仍可能由于等待状态而浪费几个周期。当资源访问中存在冲突时,这些等待状态就会出现。
- 在本地 AI 引擎内或者两个连续 AI 引擎内的同一个存储体中执行两次读取或者执行一次读取和一次写入。
- 本地 AI 引擎会尝试访问存储体(读取或写入),而存储体 DMA 同时也在访问该存储体以执行某些数据传输。
以下是剖析详情的示例。
在此截屏中,内层循环首先使用 ls 和 le(即循环开始和循环结束 PC)进行本地化。此内层循环显示在蓝色矩形中。这看似正确,因为这些行上的 Exe-Count 远比其他行高。
在第二步中,由于等待状态已本地化,一条指令会持续耗用两个时钟周期,而不是一个时钟周期:
- Exe-count = 56
- Cycles = 112
VMUL 指令会提取寄存器 yd 中的数据和 wc0 中的系数。加载耗时 7 个时钟周期,随后数据才能有效加载到该寄存器中。第三步是对第一次迭代 (3) 的 7 个时钟周期之间的代码进行分析,或者对前一次迭代 (3') 上的循环内的代码进行分析。此处可以看到,每一种情况下都有 2 次加载,且发生在同一个 bank 上(所有读取都来自源代码中的相同窗口)。