I'm using cv::norm()
to compute the L2 distance between row vectors in thousands of dimensions (at least 4096 dimensions). I'm using an AVX2 machine and icpc
version 2017.
Since I'm computing this function millions of times, I need the possible most efficient version for this function and I highly doubt that cv::norm()
exploits vectorization properly.
So I implemnted this function:
#include <opencv2/opencv.hpp>
float euclDist (const cv::Mat1f &first, const cv::Mat1f &second){
float dist = 0;
const float *firstp = first.ptr<float>(0);
const float *secondp = second.ptr<float>(0);
#pragma omp simd reduction(+:dist)
for(size_t i=0; i<first.cols; i++)
dist += std::pow(firstp[i]-secondp[i],2);
return std::sqrt(dist);
}
int main (int argc, const char *argv[]){
int codeSize = 4096;
cv::Mat1f mat(1, codeSize);
float low = 0;
float high = 2.0;
srand (0);
cv::theRNG().state = cv::getTickCount() ;
randu(mat, cv::Scalar(low), cv::Scalar(high));
euclDist(mat, mat);
return 0;
}
The example above is similar what the actually program does: it generates a row vector and it computes the distance with itself (i.e. 0). In the actual program generates a matrix and it randomly compute the distance between some rows. I don't think that I can get only that part of the code easily.
I already noticed an improvement w.r.t. cv::norm()
, but scales badly when computing multiple distances in parallel. According to Intel VTune I fully use all the processors, but I get poor memory performance, as it shown from this general exploration analysis:
This is the result from: sudo lshw -short -C memory
H/W path Device Class Description
=====================================================
/0/0 memory 128KiB BIOS
/0/4/b memory 32KiB L1 cache
/0/4/c memory 256KiB L2 cache
/0/4/d memory 6MiB L3 cache
/0/a memory 32KiB L1 cache
/0/2a memory 12GiB System Memory
/0/2a/0 memory 4GiB SODIMM DDR3 Synchronous 1600 MHz (0.6 ns)
/0/2a/1 memory DIMM [empty]
/0/2a/2 memory 8GiB SODIMM DDR3 Synchronous 1600 MHz (0.6 ns)
/0/2a/3 memory DIMM [empty]
What I could do?
std::pow(x, 2)
- did you compare againstfor(size_t i=0; i<first.cols; i++) { auto d = firstp[i]-secondp[i]; dist += d * d; }
? \$\endgroup\$