OpenEM 简介和基于 OpenEM 的大矩阵乘实现
2.3.2 基于 OpenEM 的性能测试结果
基于 OpenEM的演示用例实现过程中,DSP 代码中嵌入了少量测试代码收集运行的 cycle 信息。每个核把自己处理每个 event 的起始和结束时间记录在内存(我们通过一个全局 timer 来保证所有DSP 核记录的时间戳在时间轴上是同步的)。这些时间戳用 CCS 存到主机做后处理分析。通过分析,我们可以得到 8 个 DSP 核并行处理消耗的时间。还可以分析每个 DSP 核的忙/闲区间。
测试结果是,从第一个 event 开始处理到最后一个 event 处理完,总时间是 31,433,438 cycle,也就是 31.4ms。也就是说,通过 OpenEM把单 DSP 核的工作负载平衡到 8 个 DSP 核上能达到的DSP 核利用率是 190,574,214/(31,433,438*8)= 76%。
通过对时间戳的处理我们得到下面的运行图,“-”表示 receiver 函数处理 event 的区间,本文称之为有效时间。“#”表示 receiver 之外的区间(也就是代码在 dispatcher 中执行的区间),本文称之为调度开销。每个“-”和“#”刻度表示 100,000 CPU cycle。
从上面的执行图看,调度开销不小,占了大约 15~20%的时间。但是这只是表面的现象。实际上,调度开销的大部分时间里,Dispatcher 是在查询 hardware queue,等待新的 event。这是因为preload 没能及时完成导致的。因为同时给 8 个核做 preload 需要很大的数据搬移的流量。根据以往的测试结果。使用 QMSS 的 packet DMA 从 DDR3 输入数据到 local L2 的流量大约是 4G bytes 每秒。那么 preload 8 个 event 总的数据量是 4byte * 2048 rows * 16 columns * 8 core = 1M bytes,需要的时间是 1/4 ms。因为每个“-”和“#”刻度表示 100,000 CPU cycle,运行图中红线长度就代表 preload 8 个 event 的时间,它非常接近 250,000 cycle。理论计算和实际值基本吻合,所以我们认为调度延迟是 packet DMA 的传输流量不足导致的。
我们也测试了不使用 pre-load 的场景。观测到 scheduler 调度一个 event 的延迟大约是 1200 个C66 CPU cycle。但是 DSP 核处理一个 event 的耗时增大到原来的 10 倍。所以,pre-load 虽然会导致 QMSS packet DMA 流量不足成为凸显的瓶颈,但是从总体效率来看还是非常必要的。
细心的读者可能会发现 76% + 20% = 96%,并不是 100%。我们分析时间戳发现,8 个 DSP 核同时运行的场景下,每个核处理一个 100*2048 × 2048*16 的矩阵乘的时间比只有一个 DSP 核运行的场景下的时间稍长。原因是: 我们的演示用例中 X 矩阵和 Z 矩阵是存储在 shared L2 的, 8 个核同时运行就会同时读写这两个 buffer,导致产生 shared L2 的 bank 冲突。 所以性能下降了。
3、总结
OpenEM具有使用简单,功能实用,执行高效的特点。能在 KeyStone 多核 DSP 上实现动态的负载平衡。它一方面提供了强大的功能,另一方面也给应用留出了很大的灵活性。例如,通过让应用初始化 free pool 方便了 buffer 的管理。OpenEM 的现有功能已经能够支持基本的应用。随着版本更新功能还将不断完善。
Reference
Ref[1] ti.openem.white.paper.pdf 位于 OpenEM 安装目录
评论