我有这个功能,英特尔顾问强烈建议它进行矢量化:
void SIFTDescriptor::samplePatch(float *vec)
{
for (int r = 0; r < par.patchSize; ++r)
{
const int br0 = par.spatialBins * bin0[r]; const float wr0 = w0[r];
const int br1 = par.spatialBins * bin1[r]; const float wr1 = w1[r];
for (int c = 0; c < par.patchSize; ++c)
{
const float val = mask.at<float>(r,c) * grad.at<float>(r,c);
const int bc0 = bin0[c];
const float wc0 = w0[c]*val;
const int bc1 = bin1[c];
const float wc1 = w1[c]*val;
// ori from atan2 is in range <-pi,pi> so add 2*pi to be surely above zero
const float o = float(par.orientationBins)*(ori.at<float>(r,c) + 2*M_PI)/(2*M_PI);
int bo0 = (int)o;
const float wo1 = o - bo0;
bo0 %= par.orientationBins;
int bo1 = (bo0+1) % par.orientationBins;
const float wo0 = 1.0f - wo1;
// add to corresponding 8 vec...
if (wr0*wc0>0) {
vec[br0+bc0+bo0] += wr0*wc0 * wo0;
vec[br0+bc0+bo1] += wr0*wc0 * wo1;
}
if (wr0*wc1>0) {
vec[br0+bc1+bo0] += wr0*wc1 * wo0;
vec[br0+bc1+bo1] += wr0*wc1 * wo1;
}
if (wr1*wc0>0) {
vec[br1+bc0+bo0] += wr1*wc0 * wo0;
vec[br1+bc0+bo1] += wr1*wc0 * wo1;
}
if (wr1*wc0>0) {
vec[br1+bc1+bo0] += wr1*wc0 * wo0;
vec[br1+bc1+bo1] += wr1*wc0 * wo1;
}
}
}
}
我使用带有以下选项的intel编译器:
INTEL_OPT=-O3 -ipo -simd -xCORE-AVX2 -parallel -qopenmp -fargument-noalias -ansi-alias -no-prec-div -fp-model fast=2 -fma -align -finline-functions
INTEL_PROFILE=-g -qopt-report=5 -Bdynamic -shared-intel -debug inline-debug-info -qopenmp-link dynamic -parallel-source-info -ldl
但是,英特尔顾问告诉我,在:
中有两个Read-After-Write依赖项 vec[br0+bc0+bo0] += wr0*wc0 * wo0;
和
vec[br1+bc0+bo0] += wr1*wc0 * wo0;
现在,我是一个非常初学的simd,根据我的理解,我必须编写SSE / AVX2 / AVX-512指令来解决这种依赖。例如,我发现了this问题,其中解释了如何在阵列单元格中保存累积总和。这与this有所不同,因为我想将累积结果的结果保存在数组的元素(vec[something]
而不是像result
这样的标量变量中。)
然而,在第二个问题的答案中,它解释了为了使用该代码,我们需要对齐数据。由于vec
是指向cv::Mat
对象的指针,因此我并不认为数据是对齐的。
在this回答中有人争辩说询问对齐数据是否对我的问题是必要的。换句话说,我担心自己陷入了XY问题,在那里我专注于将数据对齐在哪里(也许)实际上并不需要(特别是因为我&#39 ; ma simd初学者,我害怕过度思考)。
注意:我正在使用兼容AVX2的机器,我计划将其移至AVX-512机器。