【发布时间】:2011-10-29 01:08:00
【问题描述】:
我有很多 (x1,y1,z1),(x2,y2,z2),(x3,y3,z3) 单精度向量三元组,我想对它们重新排序,所以 (x1,y1,z1),(x2,y2,z2),(x3,y3,z3) 变成 (x1,x2,x3,0,y1,y2,y3,0,z1,z2,z3,0)
目标是为基于 SSE 的计算准备数据集。我有以下代码可以做到这一点:
for (int i=0;i<count;i++)
{
Vect3F p0 = get_first_point(i);
Vect3F p1 = get_second_point(i);
Vect3F p2 = get_third_point(i);
int idx = i*3;
scratch[idx] = Vec4F(p0.x, p1.x, p2.x, 0); // These 3 rows are the slowest
scratch[idx+1] = Vec4F(p0.y, p1.y, p2.y, 0);
scratch[idx+2] = Vec4F(p0.z, p1.z, p2.z, 0);
}
循环的最后 3 行非常慢,它们占用了我整个算法 90% 的时间!
正常吗?我可以让这样的洗牌更快吗? (scratch是静态变量,16位对齐,函数调用频繁,所以我认为scratch的块不应该从缓存中消失。)
【问题讨论】:
-
这里似乎创建了很多临时对象。希望编译器省略了构造函数、赋值等。您是否考虑过将 Vect3F、Vect4F 成员实现为具有对齐 SSE (__m128) 类型的联合?
-
不幸的是,Vect3F 无法对齐,它应该是 12 字节长,所以当我重新排序浮点数时,我无法使用 SSE。完成后,我正在使用 _mm_load_ps 将数据加载到寄存器中(而且速度很快)。现在我扩展了我所有的构造函数和赋值:
float* a = (float*)(cache + i*3); a[0] = p0.x; a[1] = p1.x; a[2] = p2.x; a[4] = p0.y; a[5] = p1.y; a[6] = p2.y; a[8] = p0.z; a[9] = p1.z; a[10] = p2.z;有点帮助,但还是很慢。 -
这个 sn-p 还能编译吗?你声明 Vect3F p0 三次!
-
这本质上是矩阵转置。谷歌 sse transpose,你会得到一些更快的版本。
-
即使编译器优化了p0、p1、p2临时对象的访问,也最好使用:const Vect3F & p0 = points[i];