按列主序重新排序3D向量三元组很慢。

7

我有许多单精度向量三元组 (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块不应从缓存中消失。)

2
这里似乎创建了很多临时对象。希望编译器能够省略构造函数、赋值等操作。您是否考虑过将Vect3F、Vect4F成员实现为一个带有对齐SSE(__m128)类型的联合体? - Brett Hale
很遗憾,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; 这有一些帮助,但仍然非常缓慢。 - antonfrv
这段代码能编译通过吗?你声明了三次Vect3F p0! - mloskot
这是原始代码的样子(后来我在编辑器中进行了更改,以使其看起来更简单):int tri = triangles[i];Vect3F p0 = points[indices[tri]]; Vect3F p1 = points[indices[tri+1]];Vect3F p2 = points[indices[tri+2]]; - antonfrv
8
这基本上是矩阵转置。谷歌搜索 SSE 转置,你会得到一些更快的版本。 - Pubby
3
即使编译器优化了p0、p1、p2临时对象的访问,最好还是使用:const Vect3F & p0 = points[i]; - Brett Hale
1个回答

1

首先,你不应该创建三个临时向量对象。 而应该使用:

tri = triangles[i];
Vect3F p0 = points[indices[tri]];
Vect3F p1 = points[indices[tri+1]];
Vect3F p2 = points[indices[tri+2]];

你应该使用memcpy()函数来复制数据;创建一个循环,遍历整个集合并复制原始数据。这是我能想到的最快的方法。

使用3个变量会运行很多构造函数,这些函数非常慢。从评论中提出的第二种方法由于同样的原因也不太好。


让我想知道你使用的编译器和标志是什么。我认为只要打开适当的优化,代码应该会有些相似。 - stefan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接