awd*_*nld 15 c c++ algorithm performance assembly
在现代(SSE2 +)x86处理器上合并多达4096个32位浮点数的数组的排序子集的快速方法是什么?
请假设以下内容:
可行性的主要标准:比in-L1 LSD基数排序更快.
考虑到上述参数,我很想知道是否有人知道这样做的合理方法!:)
这是一种非常天真的方式.(请原谅任何凌晨4点谵妄引起的伪代码错误;)
//4x sorted subsets
data[4][4] = {
{3, 4, 5, INF},
{2, 7, 8, INF},
{1, 4, 4, INF},
{5, 8, 9, INF}
}
data_offset[4] = {0, 0, 0, 0}
n = 4*3
for(i=0, i<n, i++):
sub = 0
sub = 1 * (data[sub][data_offset[sub]] > data[1][data_offset[1]])
sub = 2 * (data[sub][data_offset[sub]] > data[2][data_offset[2]])
sub = 3 * (data[sub][data_offset[sub]] > data[3][data_offset[3]])
out[i] = data[sub][data_offset[sub]]
data_offset[sub]++
Run Code Online (Sandbox Code Playgroud)
编辑:
使用AVX2及其聚集支持,我们可以同时比较多达8个子集.
编辑2:
根据类型转换,有可能在Nehalem上每次迭代削减3个额外的时钟周期(mul:5,shift + sub:4)
//Assuming 'sub' is uint32_t
sub = ... << ((data[sub][data_offset[sub]] > data[...][data_offset[...]]) - 1)
Run Code Online (Sandbox Code Playgroud)
编辑3:
有可能在某种程度上利用无序执行,特别是当K变大时,使用两个或更多max值:
max1 = 0
max2 = 1
max1 = 2 * (data[max1][data_offset[max1]] > data[2][data_offset[2]])
max2 = 3 * (data[max2][data_offset[max2]] > data[3][data_offset[3]])
...
max1 = 6 * (data[max1][data_offset[max1]] > data[6][data_offset[6]])
max2 = 7 * (data[max2][data_offset[max2]] > data[7][data_offset[7]])
q = data[max1][data_offset[max1]] < data[max2][data_offset[max2]]
sub = max1*q + ((~max2)&1)*q
Run Code Online (Sandbox Code Playgroud)
编辑4:
根据编译器的智能,我们可以使用三元运算符完全删除乘法:
sub = (data[sub][data_offset[sub]] > data[x][data_offset[x]]) ? x : sub
Run Code Online (Sandbox Code Playgroud)
编辑5:
为了避免代价高昂的浮点比较,我们可以简单地reinterpret_cast<uint32_t*>()使用数据,因为这会导致整数比较.
另一种可能性是利用SSE寄存器,因为它们不是键入的,并且明确地使用整数比较指令.
这是因为操作符< > ==在解释二进制级别的浮点时产生相同的结果.
编辑6:
如果我们充分展开循环以使值的数量与SSE寄存器的数量相匹配,我们就可以对正在进行比较的数据进行分级.
在迭代结束时,我们将重新传输包含所选最大/最小值的寄存器,并将其移位.
虽然这需要稍微重新编写索引,但它可能比使用LEAs 乱丢循环更有效.
| 归档时间: |
|
| 查看次数: |
1338 次 |
| 最近记录: |