有没有人知道使用SIMD对这样的东西进行矢量化:
for(size_t i = 0; i < refSeq.length() / 4; i++){
for(size_t j = 0; j<otherSeq.length(); j++){
if(refSeq[i] == otherSeq[j]){
if(i == 0 || j == 0)
L[i][j] = 1;
else
L[i][j] = L[i-1][j-1] + 1;
}
else
L[i][j] = 0;
}
}
答案 0 :(得分:1)
这是一个动态编程问题,而且一个前沿实现有太多的数据依赖性,不适合SIMD计算。
但是,如果将算法从逐行迭代更改为对角线迭代,则可以并行计算整个对角线。见下图。
&#34;伪&#34;下面的代码使用一个带有1个额外行/列的矩阵,以简化&#34;内部&#34;计算。在每次对角线迭代之前初始化这个额外的行/列。
int i, j, k;
for (k = 1; ; k++) {
int minI = k > refLen ? k - refLen : 1;
int maxI = k > otherLen ? otherLen : k - 1;
for (i = maxI; i >= minI; ) {
j = k - i;
// vectorized calculation 256 bit (AVX2)
if (i >= 32 && otherLen - j >= 32) {
// calculate 32 values of the diagonal with SIMD
i -= 32;
continue;
}
// vectorized calculation 128 bit (SSE)
if (i >= 16 && otherLen - j >= 16) {
// calculate 16 values of the diagonal with SIMD
i -= 16;
continue;
}
// scalar calculation
if (refSeq[i - 1] == otherSeq[j - 1]) {
L[i][j] = L[i - 1][j - 1] + 1;
} else {
L[i][j] = 0;
}
i--;
}
if (k == otherLen + refLen) {
break;
}
// initialize next j-endpoint in diagonal
if (k <= refLen) {
L[0][k] = 0;
}
// initialize next i-endpoint in diagonal
if (k <= otherLen) {
L[k][0] = 0;
}
}
不确定您是否需要用于计算的实际SIMD指令,或者只是知道如何并行化/向量化计算。
答案 1 :(得分:0)
让我试着提出一个解决方案。最初计算L [i] [0]和L [0] [j]的值。现在开始从i = 1和j = 1迭代。现在可以删除在循环的每次迭代中检查i == 0或j == 0。另外一个优点是,对于行中每次迭代中的每个L [i] [j],L [i-1] [j-1]的值是可用的。现在,假设向量寄存器可以容纳数组的4个元素。现在我们可以加载refSeq,otherSeq,L(前一行)和L(当前行)的4个元素。从理论上讲,我们现在得到了矢量化。我假设自动矢量化器不会识别这个。所以我们必须手动完成它。如果我错了,请纠正我。
for(size_t i=0;i<refSeq.length()/4;i++)
{
if(refSeq[i]==otherSeq[0])
L[i][0]=1;
else
L[i][0]=0;
}
for(size_t j=0; j<otherSeq.length();j++)
{
if(refSeq[0]==otherSeq[j])
L[0][j]=1;
else
L[0][j]=0;
}
for(size_t i=1;i<refSeq.length()/4;i++)
{
for(size_t j=1; j<otherSeq.length();j++)
{
if(refSeq[i]==otherSeq[j])
L[i][j] = L[i-1][j-1] + 1;
else
L[i][j]=0;
}
}
一个缺点是,现在我们正在加载前一行,无论refSeq [i]是否等于otherSeq [j],或者与原始代码一样,只有当序列相等时才访问对角元素。 / p>