Skip to main content
欢迎来到PAWPAW技术文档网站了解更多信息

第4A部分:多线程BFP

到目前为止,之前的所有阶段都在单个硬件线程中执行其滤波计算。xcore XS3设备上的每个 Tile 都有8个可用的硬件线程,而迄今为止大部分这些线程都未被使用。在第4A部分中,将并行化应用程序,以便滤波计算跨越多个线程以减少延迟。

第4A部分将采用与第3B部分最相似的块浮点方法。之所以将此阶段建模为第3B部分而不是第3C部分,是因为lib_xcore_math的高级BFP API与这种并行性不兼容。对于这种高级用法,需要使用较低级别的API。

来自lib_xcore_math

本页引用了lib_xcore_math中的以下操作:

实现

第4A部分的实现分为两个文件,part4A.cstage9.xc。在stage9.xc中,只实现了filter_frame()函数,这是因为在XC中编写它可以利用XC语言的便捷语法,使用par块进行同步并行操作。

实际上,在第4A部分中,唯一与第3B部分不同的函数是filter_frame()

src/part4A/part4A.c
// 计算整个输出帧
// 在stage9.xc中定义
void filter_frame(
int32_t frame_out[FRAME_SIZE],
exponent_t* frame_out_exp,
headroom_t* frame_out_hr,
const int32_t history_in[HISTORY_SIZE],
const exponent_t history_in_exp,
const headroom_t history_in_hr);

第4A部分filter_frame()的内部与第3B部分非常相似。在第4A部分,所有的并行性都发生在par块内部。从语义和概念上讲,这与for循环的工作方式非常相似。不同之处在于,当然,每个“迭代”不是按顺序进行,而是在par块中每个“迭代”同时进行。

通常情况下,有多种方法可以引入并行性。例如,一个选项是将并行性下移到filter_sample()中。在这种情况下,每个线程可以计算内积的一部分,然后由主(调用)线程将部分结果相加。

相反,因为我们处理的是数据帧,第4A部分选择让每个工作线程计算不同的输出样本。具体而言,在每次for循环的迭代中,下一个THREADS个输出样本将被计算(注意每次迭代s增加THREADS)。在每次迭代中,par块启动THREADS(4)个线程,每个线程计算一个不同的输出样本。每个线程计算的输出样本的索引基于它获取的tid的值。

请注意,实现并行性的另一种方式是为每个工作线程分配一组输出样本的_范围_,每个线程在其分配的输出样本范围内进行内部迭代。实际上,这种方式很可能更好,因为启动和同步线程组的开销较小(每帧执行一次而不是64次)。然而,timer_start()timer_stop()不是线程安全的,所以这会破坏我们的性能信息。

结果

信息

下面的示例计时信息是每四个样本的计时

计时

计时类型测量时间
每个滤波器系数15.05 ns
每个输出样本15413.09 ns
每帧1033652.88 ns

输出波形

第4A部分的输出