本文描述DSP单核编程并行计算的处理:
1)Instruction Level Parallelism (ILP):指令集并行。
(1)实现方式:VLIW(超长指令字)。
(2)VLIW优缺点:优点:充分利用core内的计算单元,VLIW是通过编译器实现一个cycle多个指令的执行,减少了硬件的复杂度。缺点:增加了编译器的复杂度,需要一个强大的编译器。
(3)dependency:(1)计算单元类型及个数;(2)指令集;(3)软件流水;(4)指令读取的带宽。(5)编译器的关键字。
(4)学习目的:(1)对内核架构进行充分的了解;(2)一个cycle执行多个指令C语言的书写方式。
(5)瓶颈:(1)依赖;(2)资源限制。
2)SIMD:单指令多数据。
目前我个人认为VLIW架构的处理器,SIMD是VLIW针对数据并行的扩展。
(1)实现方式:基于SIMD指令完成算法编程。
(2)学习目的:提高算法的运行效率。
1. ILP解析
本节的以C6678的C66x为例进行说明:
ILP通过汇编语言进行体现。
(1)VLIW指令描述
VLIW是一种乱序执行技术,CPU并没有按Code的编写顺序进行执行,而是通过编译器的指令的执行速度,最大的利用CPU的资源。
图1 指令描述
p-bit(bit-0)控制指令的执行顺序,如果A instruction的p-bit=1,则B instruction 与 A instruction在同一个cycle中执行。
- 串行执行
- 并行执行
- 部分并行
下图表示汇编语言描述指令执行的概述。
(2)IPL实现
VLIW是由编译器完成的,则我们要告知编译器更多的信息,这样保证IPL功能更好的实现。
- 内存依赖
add(int *s32_in1, int *s32_in2, int *s32_out)
add函数进行编译的时候,编译器会判定*s32_in1、*s32_in2是否只想同一个地址,则可通过restrict关键进行限定,告知编译器,指针是独立的。
add(int *restrict s32_in1, int *restrict s32_in2, int *s32_out)
- unroll loop
循环展开是为了均衡功能单元的。
void add(int *restrict s32_in1, int *restrict s32_in2, int *s32_out, int data_num)
{
int i;
for (i = 0; i < data_num; i++)
{
*(s32_out+i) = *(s32_in1+i) + *(s32_in2+i);
}
}
*(s32_out+i) = *(s32_in1+i) + *(s32_in2+i); 包含两个LOAD指令,一个相加的指令,是奇数,
空闲出来一个功能单元。
void add(int *restrict s32_in1, int *restrict s32_in2, int *s32_out, int data_num)
{
int i;
for (i = 0; i < (data_num/2); i+=2)
{
*(s32_out+i) = *(s32_in1+i) + *(s32_in2+i);
*(s32_out+i+1) = *(s32_in1+i+1) + *(s32_in2+i+1);
}
}
3)#pragma
数字信号处理多数为loop,告知编译器执行的最大最小次数。
```c
#pragma MUST_ITERATE(lower_bound, upper_bound, factor)
```c
可通过MUST_ITERATE完成展开的效果。
void add(int *restrict s32_in1, int *restrict s32_in2, int *s32_out, int data_num)
{
int i;
#pragma MUST_ITERATE(2, , 2)
for (i = 0; i < data_num; i++)
{
*(s32_out+i) = *(s32_in1+i) + *(s32_in2+i);
}
}
注意处理数据的长度要是2的整数倍。
- 判断语句的处理
Loop中函数的调用,(1)if等判断语句;(2)函数的调用(inline关键字的使用)
2. 软件流水
DSP代码中一般循环是比较耗时的,则通过软件流水技术优化DSP代码。软件流水技术是基于VLIW架构,对指令的执行顺序进行排序。