概述
Hexagon_DSP_User_Guide. (3)
- 4.2.2.2 Resourcecontentiononthesharedscalarresources
- 4.2.2.3 Understandandoptimizememoryaccesses
- 4.2.3 Software pipelining
- 4.3 HVX-specificoptimizations
- 4.3.1 WhentouseHVX
- 4.3.2 64-byte mode deprecation
- 4.3.3 RearrangeelementswithinHVXvectors
- 4.3.4 VTCM/lookup
- 4.3.5 Emulatefloating-point
- 4.3.6 Convertfloattofix
(3))
4.2.2.2 Resourcecontentiononthesharedscalarresources
V6x上的另一个停顿来源是多个线程使用所有硬件线程共享的以下资源。
1. 浮点单元(仅V65和早期版本) 乘法器单元(仅V65和早期版本)。
1. L1缓存
如第2.2.2节所述,在V66之前,浮点单元和乘法器单元是所有线程共享的。这意味着在比V66更早的版本中,在任何处理器周期内,只有两个浮点操作在执行。换句话说,如果四个线程要执行一连串的数据包,每个数据包包含两个浮点运算,那么每个线程每隔一个线程周期就会停滞。
此外,L1高速缓存也是一种共享资源。因此,尽可能不频繁地加载数据,并利用寄存器的优势在本地存储数值,然后再重新使用它们,这一点很重要。
4.2.2.3 Understandandoptimizememoryaccesses
正如第2.2.4节所讨论的,标量数据存储器的访问要经过一个两级的高速缓存层次结构,而HVX存储器的访问只经过二级存储器。
缓存的大小取决于具体的芯片变体。
1. L1缓存大小为16至32KB
2. L2缓存大小在aDSP变体上为128至1024KB,在cDSP变体上为512至2048KB。
HVX数据存储器访问绕过L1。
在编写优化的应用程序时,为了避免缓存丢失,减少数据存储器的吞吐量并最大限度地提高数据定位性是至关重要的。常见的利用数据定位的数据优化技术包括以下这些技术。
3. 寄存器数据再利用
应用程序将数值存储到寄存器中供以后使用。例如,同时在多条线路上应用一个过滤器,可以将系数保存到寄存器中,从而减少整个数据带宽。
*4. 瓦片
一个瓦片定义了一个图像的一个小区域。应用程序一次处理一个图像,或一次处理几个瓦片。当使用标量指令而不是HVX指令时,这种方法可能是合适的,因为它允许在L1内保存数据,从而最大化标量处理的吞吐量。较大的缓冲区,如图像线组,对于L1来说通常太大。使用平铺方法通常要付出更大的编程复杂性和更多的非线性数据寻址的代价。
行处理
应用程序一次处理几行图像。这是HVX实现中最常见的方法,因为它允许加载整个HVX向量并利用大的二级内存缓存大小。
另一种缓存优化包括通过预取数据到缓存的方式明确地管理缓存内容,更少的情况下,使缓存行内容失效。这种优化应该留到最后,一旦你已经在他们的代码中确保了最大的数据位置性。
Hexagon V66程序员参考手册(80-N2040-42)详细介绍了二级缓存预取机制。在Hexagon SDK的example/common目录下包含的downscaleBy2项目实例中,对各种形式的L1和L2缓存管理技术进行了很好的说明,SDK在线文档中也有讨论。
通常情况下,先在单线程上优化应用程序,然后再对代码进行多线程优化。当采用这种方法时,从单线程性能推断多线程性能有时会产生误导:当只有一个线程运行时,内存带宽可能不是瓶颈,但当更多线程并行运行时,内存带宽就成为限制性资源之一。因此,无论单线程代码的性能如何,在内存带宽使用方面尽可能保守地编写应用程序是一个好的做法。
尽管数据内存延迟取决于许多参数和架构变体,但在计划优化应用程序时,了解内存访问成本的一阶是有用的。下面的数字是对内存访问预期的粗略估计。
DDR内存访问。~250 ns
L2读取延迟:6个线程周期
在HVX上,实现了一种机制,将HVX指令推入一个叫做V FIFO的队列。只要没有错误预测的分支发生,这个队列就会保持满员,由VMEM指令触发的L2读取就会提前发生,以至于VMEM加载的结果可以在下一个周期内得到,而不会停滞。
换句话说,在HVX上,L2读取有1个周期的延迟,只要最近没有错误预测的分支发生,以下指令序列就不会停滞。
{ v0 = vmem(r0++) }
{ v1 = vadd(v0,v1) } // 如果最近没有发生错误预测的分支就不会停滞。
在没有银行冲突的情况下,最大的可持续读写二级带宽。每个处理器周期128字节 使用www.DeepL.com/Translator翻译(免费版)
4.2.3 Software pipelining
Hexagon指令集允许在一个数据包内有多个不相关的指令。这种灵活性为代码的并行化提供了很好的机会,通常通过做软件流水线来最好地利用这些机会。软件流水线包括并行处理一个循环的几个连续实例,以减少数据的依赖性,并提供更多的机会来并行执行操作。
这种方法的代价是为序幕和尾声代码提供单独的代码。例如,如果一个循环处理为迭代n+2加载数据,为迭代n和n+1执行一些计算,并存储迭代n的结果,序幕和尾声代码有可能必须分别处理第一个和最后两个或三个循环迭代,并处理循环迭代次数少的情况。
Hexagon指令集通过支持流水线硬件循环,可以降低序幕和尾声代码的复杂性。管道式硬件循环在循环迭代特定次数后设置谓词寄存器,从而允许一些操作–通常是存储–仅在几个循环迭代后执行。有关这种方法的更多信息,请参阅《Hexagon V66程序员参考手册》(80-N2040-42)中的管道硬件循环部分。
Hexagon编译器会自动对适当的循环进行软件管道化。
4.3 HVX-specificoptimizations
HVX增加了一套强大的指令,可以非常有效地处理大型向量。
Hexagon V66 HVX程序员参考手册(80-N2040-44)是任何给定版本的HVX指令语法和行为的权威来源。在下面的章节中,我们强调了其中的一些指令。
4.3.1 WhentouseHVX
HVX向量是128字节宽。因此,HVX很适合对连续的32位、16位或8位元素进行相同的操作序列。
此外,HVX只支持对整数的原始操作。
这两个特点使得HVX非常适用于某些应用空间,比如图像处理,其中许多整数操作要独立应用于连续像素。然而,这并不意味着HVX被限制在只对内存中的连续元素进行整数操作,如下文所述。
尽管HVX内存的加载和存储都是访问内存中的连续元素,但HVX提供了许多强大的指令,用于在HVX向量之间和内部进行元素的洗牌和交错。这些指令使HVX能够有效地处理遵循一些可预测模式的非连续元素,比如奇数和偶数元素,或者垂直线。第4.3.3节更详细地讨论了这些指令。
HVX没有对浮点的本地支持。但是,如果代码的某些部分被转换为使用定点运算,或者不需要严格遵守IEEE浮点格式,那么在浮点代码上使用HVX仍然值得考虑。4.3.5和4.3.6节详细讨论了将浮点代码移植到HVX的技术。
对于只能按顺序操作的部分代码,一次一个元素,并且没有发现并行的机会,使用V6x指令代替,让其他线程使用HVX资源往往是最好的方法。
4.3.2 64-byte mode deprecation
在大多数架构变体上,工具仍然支持早期的模式,允许开发者将HVX寄存器长度设置为64字节而不是128字节。然而,不要使用这种模式,因为它在V66和更新的设备上不被支持。
用-mhvx编译的文件假定应该使用64字节模式。因此,用-mhvx-double编译代码时,必须假定使用128字节模式。在你的hexagon.min中添加以下一行,以确保编译器以128字节模式为目标:
CC_FLAGS += $(MHVX_DOUBLE_FLAG)
4.3.3 RearrangeelementswithinHVXvectors
根据在HVX上移植的算法的性质,可能需要以各种方式重新排列HVX向量或一对HVX向量中的元素。一些HVX指令可以解决这一难题。图4-2描述了这些指令并提供了这些指令的可视化摘要。
1. valign,vlalign,vror
这三条指令很简单。
2. valign和vlalign创建一个HVX向量,由一个向量的最低字节和另一个向量的最高字节组成。
3. vror对一个HVX向量进行任意字节数的循环旋转。
4. vpacke, vpacko, vpack, vunpack, vunpacko, vdeal
vpacke和vpacko将两个HVX向量的偶数或奇数32位或16位元素打包成一个。
vpack执行元素大小缩减,将两个HVX向量的内容在饱和后缩减为一个。
vunpack和vunpacko是与vpack相反的形式,分别将偶数和奇数的8位或16位元素解包成两倍大的元素。
vdeal(消耗一个输入寄存器的味道)的操作方式与vpacke和vpacko结合在一起的方式相同,但对一半的元素进行操作:它将输入寄存器的偶数元素打包到输出寄存器的下半部分,将奇数元素打包到上半部分。
*5. vshuffe, vshuffo, vshuffoe, vshuff
vshuffe和vshuffo与它们的对应物vpacke和vpacko相似,它们将两个HVX的偶数或奇数元素移入一个HVX向量。与vpack对应函数的不同之处在于,来自两个输入HVX向量的元素是交错的(两个输入寄存器的内容都被洗进一个寄存器)。
vshuff和vpack的变体在不同的使用情况下都很方便。例如,如果一个HVX寄存器包含成对的(x,y)坐标,vpacke和vpacko对于分离不同向量中的x和y元素很有用。另一方面,vshuffo或vshuffe可能最适合在HVX指令之后使用,这些指令以双精度产生HVX向量,并将连续操作的结果存储在一对寄存器的上部和下部。
vshuffoe同时执行vshuffe和vshuffo,并生成一个寄存器对,其中的两个寄存器是vshuffo和vshuffe指令的输出。
vshuff(消耗一个输入寄存器的味道)将一个寄存器的上下部分的元素交织到另一个寄存器中。
vasr
一个缩小的移位:它接收两个输入HVX向量,并返回一个输出HVX向量。缩小移位是交替应用于两个输入HVX寄存器的每个元素,因此产生的输出与vshuffe或vshuffo指令的顺序相同。
*6. Crosslane vshuff, vdeal
这些指令非常强大,但理解起来并不简单。它们在寄存器组之间进行多级转置操作。vshuff和vdeal最常用的配置是用于2的正负幂。
vshuff的元素大小为Rt=2N字节,在输出的低寄存器中放置
对来自两个输入向量的2N字节的偶数元素,以及高位寄存器中的2N字节的奇数元素。这个操作本质上是vshuffoe对更大元素大小的概括。
vshuff的元素大小为Rt=-2N字节,将两个输入向量的2N字节的元素交织到输出寄存器。这个操作本质上是vshuff的非交叉线变体对更大元素尺寸的概括。
元素大小为Rt=2N字节的vdeal与vshuff相同。
元素大小为Rt=-2N字节的vdeal将两个输入向量的2N字节的偶数元素打包到低输出寄存器对中,将奇数元素打包到高输出寄存器对中。对于N=0,这条指令因此与同时执行packo和packe相同。
vdelta,vrdelta
vdelta和vrdelta使用一个开关盒网络在HVX向量中对字节进行排列或复制。当你需要一些上面列出的各种操作中没有涵盖的不规则模式的变换时,请考虑使用这些指令。
vdelta和vrdelta是用一个HVX向量配置的。最简单和最安全的方法是
确定这个寄存器的配置值的最简单和最安全的方法是使用一个配置工具
下的SDK工具提供。
{HEXAGON_SDK_ROOT}/tools/HEXAGON_Tools//Examples/libcore/Vdelta_Helper/General_permute_network.htm下提供的配置工具。
在这个页面的底部,你可以指定一个模式,输入向量的字节应该被重新排序。例如,如果要将字节1和5从输入向量中删除,在TPERM[N]控制框中指定一个以0、2、3、4、6…开头的字节序列。
一旦完全指定了输出模式,单击 "提交贝恩斯 "或 "提交德尔塔 "检索配置(如果存在的话),以使用vrdelta和vdelta指令序列(贝恩斯方法)或一个vrdelta指令实现模式转换。
4.3.4 VTCM/lookup
从V65开始,增加了对散射/聚集的支持。有了这个新增的支持,你现在可以执行矢量随机访问内存查找,而不像所有DSP变体上的vlut指令那样,限制在256个条目。
关于该指令的更多细节,请参见《Hexagon V66 HVX程序员参考手册》(80-N2040-44)。
散射/聚集操作是非常密集的内存,所以当内存冲突发生时,它们很容易停滞。有关如何避免散射/聚集停顿的信息,请参见《Hexagon V66 HVX程序员参考手册》(80-N2040-44)中的避免散射/聚集停顿部分。
4.3.5 Emulatefloating-point
HVX没有本地浮点支持。然而,Hexagon SDK提供的qmath库引入了一种伪浮点格式,支持类似于IEEE浮点的精度和动态范围。在这种格式下,使用qmath提供的库,可以进行所有基本的算术操作(加、子、多、大、除、平方)。此外,qmath库提供了一组函数,允许将IEEE浮点值阵列转换成这种伪浮点格式,反之亦然。
使用qmath浮点库是加快HVX浮点代码的最简单方法,只要数据处理是并行的。关于这个库的更多细节,请参见{HEXAGON_SDK_ROOT}/libs/common/qmath中的库包及其文档(Qualcomm Math (qmath) Library,80-VB419-105)。关于如何使用该库的例子,请参见{HEXAGON_SDK_ROOT}/examples/compute/qmath_sample中的代码例子。
4.3.6 Convertfloattofix
将浮点代码移植到HVX实现中的另一种方法是将算术转换为定点。高通公司提供了一个库来帮助完成这一过程。该库可以帮助你描述所有浮点变量的行为,提供如何用定点表示浮点变量的提示,以最大限度地提高精度并保证没有溢出,并提供各种定点实现的精确位模拟,帮助你在精度和计算效率之间取得适当的平衡,而不需要首先编写任何实际的HVX代码。只有当你对定点模型的行为感到满意时,你才需要编写相应的HVX实现,从而节省大量的开发工作。
关于这个库的更多细节,请参阅{HEXAGON_SDK_ROOT}/libs/common/qfxp中的库包及其文档(Qualcomm定点(qfxp)库,80-VB419-69)。关于如何使用该库的例子,请参阅{HEXAGON_SDK_ROOT}/examples/compute/qfxp_sample中的代码例子。
最后
以上就是勤恳戒指为你收集整理的Hexagon_DSP_User_Guide(3)的全部内容,希望文章能够帮你解决Hexagon_DSP_User_Guide(3)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复