我正在尝试优化一些代码,以尽可能减少执行时间。 这是代码:
int shifter=0;
// now iterate through all the pairings
UINT32_ALIAS* ptr2=(UINT32_ALIAS*)ptr;
const BriskShortPair* max=shortPairs_+noShortPairs_;
for(BriskShortPair* iter=shortPairs_; iter<max;++iter){
t1=*(_values+iter->i);
t2=*(_values+iter->j);
if(t1>t2){
*ptr2|=((1)<<shifter);
} // else already initialized with zero
// take care of the iterators:
++shifter;
if(shifter==32){
shifter=0;
++ptr2;
}
}
我想知道是否有可能以某种方式使用NEON并行化。 可能吗? 谢谢
编辑:此代码的上下文是BRISK功能检测器(http://www.asl.ethz.ch/people/lestefan/personal/BRISK) 我正在尝试为ARM体系结构优化此代码。 我所指的那段代码具有以下结构:
- 扫描一定数量的点的循环外部
- 对于这些点中的每一个,其周围都有一定数量的其他点(固定数字),并且每个点都具有相关的强度值。
- 在内部循环固定的点对基于它们的强度值进行比较,并且该比较的结果可以是0或1,并且该值被放在矢量中。
我在这里发布的代码是循环内部。
答案 0 :(得分:3)
虽然它不像下面的初始版本那么简单,但是NEON可以非常好地处理这个问题,与原始的C实现相比,性能提升了。
通过正确的调整,您可以获得额外的性能提升(少于50次循环/迭代)。然而,可读性会受到严重影响。
玩得开心!
AREA BRISK_ASM_NEON, CODE, READNOLY
EXPORT yourFunction
CODE32
yourFunction FUNCTION
loop
pld [r0, #192]
vld2.32 {q8, q9}, [r0]!
vld2.32 {q10, q11}, [r0]!
pld [r0, #192]
vld2.32 {q12, q13}, [r0]!
vld2.32 {q14, q15}, [r0]!
vcgt.u32 q8, q8, q9
vcgt.u32 q9, q10, q11
vcgt.u32 q10, q12, q13
vcgt.u32 q11, q14, q15
pld [r0, #192]
vld2.32 {q12, q13}, [r0]!
vld2.32 {q14, q15}, [r0]!
pld [r0, #192]
vld2.32 {q0, q1}, [r0]!
vld2.32 {q2, q3}, [r0]!
vcgt.u32 q12, q12, q13
vcgt.u32 q13, q14, q15
vcgt.u32 q14, q0, q1
vcgt.u32 q15, q2, q3
vsli.32 q8, q10, #8
vsli.32 q9, q11, #8
vsli.32 q8, q12, #16
vsli.32 q9, q13, #16
vsli.32 q8, q14, #24
vsli.32 q9, q15, #24
vsli.8 d16, d17, #2
vsli.8 d18, d19, #2
vsli.8 d16, d18, #4
vbic.i8 d16, #0xaa
vshr.u64 d17, d16, #31
vorr d16, d16, d17
vst1.32 {d16[0]}, [r1]!
subs r2, r2, #32
bgt loop
bx lr
ENDFUNC
END
=============================================== ==============================
=============================================== ==============================
与NEON相比,这是一块蛋糕。
这是你的“奇迹”:
原型: void yourFunc(unsigned int * pPair,unsigned int * ptr2,unsigned int count);
AREA BRISK_ASM_NEON, CODE, READNOLY
EXPORT yourFunction
CODE32
yourFunction FUNCTION
adr r12, shifter_table
vpush {q4-q7}
vldmia r12, {q0-q7}
loop
vld1.32 {q8, q9}, [r1]
vorr q10, q8, q0
vorr q11, q9, q1
vld2.32 {q12, q13}, [r0]!
vld2.32 {q14, q15}, [r0]!
vcgt.u32 q12, q12, q13
vcgt.u32 q13, q14, q15
vbsl q12, q10, q8
vbsl q13, q11, q9
vst1.32 {q12, q13}, [r1]!
vld1.32 {q8, q9}, [r1]
vorr q10, q8, q2
vorr q11, q9, q3
vld2.32 {q12, q13}, [r0]!
vld2.32 {q14, q15}, [r0]!
vcgt.u32 q12, q12, q13
vcgt.u32 q13, q14, q15
vbsl q12, q10, q8
vbsl q13, q11, q9
vst1.32 {q12, q13}, [r1]!
vld1.32 {q8, q9}, [r1]
vorr q10, q8, q4
vorr q11, q9, q5
vld2.32 {q12, q13}, [r0]!
vld2.32 {q14, q15}, [r0]!
vcgt.u32 q12, q12, q13
vcgt.u32 q13, q14, q15
vbsl q12, q10, q8
vbsl q13, q11, q9
vst1.32 {q12, q13}, [r1]!
vld1.32 {q8, q9}, [r1]
vorr q10, q8, q6
vorr q11, q9, q7
vld2.32 {q12, q13}, [r0]!
vld2.32 {q14, q15}, [r0]!
vcgt.u32 q12, q12, q13
vcgt.u32 q13, q14, q15
vbsl q12, q10, q8
vbsl q13, q11, q9
vst1.32 {q12, q13}, [r1]!
subs r2, #32
bgt loop
vpop {q4-q7}
bx lr
ENDFUNC
shifter_table
DCD (1<<00), (1<<01), (1<<02), (1<<03), (1<<04), (1<<05), (1<<06), (1<<07), (1<<08), (1<<09), (1<<10), (1<<11), (1<<12), (1<<13), (1<<14), (1<<15)
DCD (1<<16), (1<<17), (1<<18), (1<<19), (1<<20), (1<<21), (1<<22), (1<<23), (1<<24), (1<<25), (1<<26), (1<<27), (1<<28), (1<<29), (1<<30), (1<<31)
END
上面的代码只是适度优化(此处和那里互锁),仅当count是32的倍数时才有效。
这就是我管理可读性以及“非专业”工作的时候。
47次循环/迭代也不错。其余的由你决定。
祝你好运!