快速单精度矩阵时间向量积

时间:2016-07-14 11:46:46

标签: c++ optimization matrix-multiplication blas

考虑一个矩阵 A 的大小为48x16的浮点数和一个大小为1x48的浮点数 b

请建议在普通桌面处理器(i5 / i7)上尽快计算 b × A

背景 上述产品处于紧密循环中,因此其快速计算至关重要。目前我正在使用以下天真算法:

inline void Critical(const float A[48][16], const float b[48], float x[16] ) const {
    for (int u = 0; u < 48; ++u) {
        for (int i = 0; i < 16; ++i) {
            x[i] += A[u][i] * b[u];
        }
    }
}

我试图将乘法卸载到MKL的SGEMV,然后卸载到SGEMM,但无济于事。在i7 4800MQ上,天真的实现仍然可以更快地运行。

EDIT1

静态分配的特征与初始算法一样快。

我尝试打开优化的GCC5,ICC和VC2015U3(/ O3,快速数学,mtune = native等)。 ICC似乎在Linux和Windows上产生了最快的代码。

EDIT2

A 的元素很小,max(| A _ui |)= 256.同样max(| b _u |)= 1.0。只要算法比天真算法快,合理的近似解也是可以接受的。

1 个答案:

答案 0 :(得分:2)

MKL通常具有较大的开销,因此对于小矩阵而言性能较差。另一方面,Eigen具有固定大小的矩阵优化,在小矩阵上表现良好。您还需要正确的编译选项以获得Eigen的最大性能。

#include <iostream>
#include <Eigen/Eigen>
#include <omp.h>

inline void Critical(const float A[48][16], const float b[48], float x[16]) {
  for (int i = 0; i < 16; ++i) {
    x[i] = 0;
  }
  for (int u = 0; u < 48; ++u) {
    for (int i = 0; i < 16; ++i) {
      x[i] += A[u][i] * b[u];
    }
  }
}

int main() {
  float a[48][16] = { 0 };
  float b[48] = { 0 };
  float x[16] = { 0 };
  Eigen::Matrix<float, 48, 16> ma;
  Eigen::Matrix<float, 1, 48> mb;
  Eigen::Matrix<float, 1, 16> mx;

  ma.setRandom();
  mb.setRandom();
  for (int i = 0; i < 48; ++i) {
    for (int j = 0; j < 16; ++j) {
      a[i][j] = ma(i, j);
    }
    b[i] = mb(i);
  }

  double t;
  int n = 10000000;

  t = omp_get_wtime();
  for (int i = 0; i < n; ++i) {
    Critical(a, b, x);
  }
  t = omp_get_wtime() - t;
  std::cout << "for-loop time: " << t << std::endl;

  t = omp_get_wtime();
  for (int i = 0; i < n; ++i) {
    mx = mb * ma;
  }
  t = omp_get_wtime() - t;
  std::cout << "eigen time: " << t << std::endl;

  Eigen::Map < Eigen::Matrix<float, 1, 16> > native_x(x);
  std::cout << "error: " << (mx - native_x).norm() << std::endl;

  return 0;
}

使用g ++ 5.2.1进行编译时

$ g++ -fopenmp -O3 -DNDEBUG -I~/program/include/eigen3 -o test/gemv test/gemv.cpp && test/gemv
for-loop time: 2.53004
eigen time: 1.17458
error: 1.49636e-06

使用icpc 16.0.2进行编译时

$ icpc -fopenmp -fast -DNDEBUG -I~/program/include/eigen3 -o test/gemv test/gemv.cpp && test/gemv
for-loop time: 1.03432
eigen time: 1.01054
error: 1.40769e-06

icpc在fop-loop上使用自动矢量化,因此性能与Eigen相同。