剖析数据生成
在仿真框架内,AI 引擎仿真器可以为完整应用生成剖析报告。此报告是使用 –profile
标志生成的。
aiesimulator –pkg-dir=Work –profile
文本文件和 .xml 文件都是在 aiesimulator_output
目录中生成的。对于位于 C 列和 R 行中的拼块,会生成两种类型的文件。*_funct
用于报告每个函数的调用次数和周期数。*_instr
则是深入汇编代码的报告。使用 Vitis 分析器即可直观显示此报告。
vitis_analyzer aiesimulator_output/default.aierun_summary
- Summary(汇总)
- 报告总周期计数、总指令计数和存储器中的程序大小。
- Function Reports(函数报告)
- 在表格和图示中显示逐个函数的多项关键指示符。
- 调用次数
- 函数总时间(周期数和 %)
- 函数总时间 + 后代时间(周期数和 %)
- 最小/平均/最大函数时间(周期数)
- 最小/平均/最大函数时间 + 后代时间(周期数)
- 程序计数器低位/高位
- 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() 和所有函数)内执行该指令期间,等待状态所使用的相对周期 |
使用剖析数据进行性能调试
要改善设计的性能,应首先从最优化占用周期数最多的函数开始。完成后即可对占用周期数和比例略少的函数进行最优化。为达成此目的,函数总时间 graph 将帮助您选择这些函数。
对于最优化本身,您可使用编译指示(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 上(所有读取都来自源代码中的相同窗口)。