以列主要顺序重新排序 3D 矢量三元组很慢

Posted

技术标签:

【中文标题】以列主要顺序重新排序 3D 矢量三元组很慢【英文标题】:reordering 3D vector triplets in column major order is slow 【发布时间】: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]; 【参考方案1】:

首先,您不应该创建 3 个临时矢量对象。 而不是:

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

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

使用 3 个变量会运行很多非常缓慢的构造函数。出于同样的原因,第二种方式(来自评论)也好不到哪里去。

【讨论】:

让我想知道您正在使用哪些编译器以及哪些标志。我认为打开适当的优化后,代码应该在某种程度上呈现相同的效果。

以上是关于以列主要顺序重新排序 3D 矢量三元组很慢的主要内容,如果未能解决你的问题,请参考以下文章

数据结构期末复习

r 按字母顺序排序矢量

Python 基础三元组

在 C# 中对整数三元组数组进行排序

Python语法之元组

Python编写代码实现指定下标值顺序进行正序和倒序排序算法编程