【发布时间】:2012-08-10 13:16:17
【问题描述】:
首先,在使用 Accelerate 框架调整频率分析函数时,每次迭代的绝对系统时间始终为 225 毫秒。然后昨晚我改变了声明两个数组的顺序,突然它下降到 202ms。仅通过更改申报顺序来增加 10% 似乎很疯狂。有人可以向我解释为什么编译器(设置为优化)还没有找到这个解决方案吗?
附加信息:在循环之前,对循环中使用的数组进行了一些设置,包括将它们从整数转换为浮点数组(用于加速),然后取时间数组的 sin 和 cos(16 行长)。所有的浮点数组(8 个数组 x 1000 个元素)首先在函数中声明(在对参数进行完整性检查之后)。它们总是被声明为相同的大小(由一个常数),否则性能会因占用空间的小幅收缩而受到影响。我测试了将它们设为全局,但我认为编译器已经发现了这一点,因为没有性能变化。循环长 25 行。
---添加---
是的,“-Os”是标志。 (无论如何,Xcode 中的默认值:最快、最小)
(以下来自记忆 - 不要尝试编译它,因为我没有输入步幅(即 1)等内容。但是,所有的 Accelerate 调用都在那里)
传递的参数:inttimearray、intamparray、length、scale1、scale2、amp
float trigarray1[maxsize];
float trigarray2[maxsize];
float trigarray3[maxsize];
float trigarray4[maxsize];
float trigarray5[maxsize];
float temparray[maxsize];
float amparray[maxsize]; //these two make the most change
float timearray[maxsize]; //these two make the most change
vDSP_vfltu32(inttimearray,timearray,length); //convert to float array
vDSP_vflt16(intamparray,amparray,length); //convert to float array
vDSP_vsmul(timearray,scale1,temparray,length); //scale time and store in temp
vvcosf(temparray,trigarray3,length); //cos of temparray
vvsinf(temparray,trigarray4,length); //sin of temparray
vDSP_vneg(trigarray4,trigarray5,length); //negative of trigarray4
vDSP_vsmul(timearray,scale2,temparray,length); //scale time and store in temp
vvcosf(temparray,trigarray1,length); //cos of temparray
vvsinf(temprray,trigarray2,length); //sin of temparray
float ysum;
vDSP_sve(amparray,ysum,length); //sum of amparray
float csum, ssum, ccsum, sssum, cssum, ycsum, yssum;
for (i = 0; i<max; i++) {
vDSP_sve(trigarray1,csum,length); //sum of trigarray1
vDSP_sve(trigarray2,ssum,length); //sum of trigarray2
vDSP_svesq(trigarray1,ccsum,length); //sum of trigarray1^2
vDSP_svesq(trigarray2,sssum,length); //sum of trigarray2^2
vDSP_vmul(trigarray1,trigarray2,temparray,length); //temp = trig1*trig2
vDSP_sve(temparray,cssum,length); //sum of temp array
// 2 more sets of the above 2 lines, for the 2 remaining sums
amp[i] = (arithmetic of sums);
//trig identity to increase the sin/cos by a delta frequency
//vmma is a*b+c*d=result
vDSP_vmma (trigarray1,trigarray3,trigarray2,trigarray4,temparray,length);
vDSP_vmma (trigarray2,trigarray3,trigarray1,trigarray5,trigarray2,length);
memcpy(trigarray1,temparray,length*sizeof(float));
}
---当前解决方案---
我做了如下改动:
数组都被声明为对齐,并被归零(我将在接下来解释)并且 maxsize 现在是 16 的倍数
__attribute__ ((align (16))) float timearray[maxsize] = {0};
我已将所有数组归零,因为现在,当长度小于 maxsize 时,我将长度四舍五入到最接近 16 的倍数,以便所有循环函数在可被 16 整除的宽度上运行,不影响总和。
好处是:
- 性能略有提升
- 无论数组声明的顺序如何,速度几乎都是恒定的(现在在需要它们之前就完成了,而不是全部放在一个大块中)
- 对于任何 16 宽长度(即 241 到 256,或 225 到 240...),速度也几乎恒定,而在此之前,如果长度从 256 变为 255,则该函数将占用 3+%性能受到影响。
在未来(可能使用此代码,因为分析要求仍在不断变化),我意识到我需要更多地考虑堆栈的使用,以及向量的对齐/块。不幸的是,对于这段代码,我不能将这些数组设为静态或全局,因为该函数一次可以被多个对象调用。
【问题讨论】:
-
你能通过交换数组声明顺序回到 225ms 吗?
-
是的,这两个,始终如一。而且我发现如果我切换其他阵列,我最终会得到更差的性能 290+ms 或其他配置 210ms。现在它们都在一行中声明(每行一个,以便更快地测试订单)。但是,我确实尝试在需要之前将每个声明移动到正确的位置,并获得了 290 毫秒。
-
可以给我们看看代码吗?至少对于声明来说,如果它们都在一起的话。
-
会不会是一些缓存的东西?如果数组按一个顺序排列,也许您更有可能在一个操作中提取下一个操作所需的数据。
标签: arrays performance accelerate-framework vdsp