Что здесь не так? Результаты тестов с использованием другой библиотеки матриц приветствуются.
РЕДАКТИРОВАТЬ: Я нашел кое-что более странное. Компиляция с использованием -march=skylake (то есть без AVX512) делает код в 4 раза медленнее по сравнению с использованием AVX512 (-march=native -mavx512f -mavx512vl -mavx512bw -mavx512dq -mavx2 -mfma). В обоих случаях Float matmul имеет одинаковую скорость. Похоже на сбой компилятора (векторизация кода при компиляции с помощью AVX512).
-march=skylake -mavx2 -mfma
Testing M = 8192
A (naive u32) = 125991
E (Eigen u32) = 34135.3
F (Eigen float) = 46756.6
-march=native -mavx512f -mavx512vl -mavx512bw -mavx512dq -mavx2 -mfma
Testing M = 8192
A (naive u32) = 106590
E (Eigen u32) = 169307
F (Eigen float) = 45510.9
Новая тестовая спецификация:
- ЦП i5 11400F, двухканальная оперативная память
- Ubuntu 20.04
- g++ 13.1
- Eigen версии 5.0 (в коде C++ отображается как 3.5.0)
OpenBLAS config (runtime): OpenBLAS 0.3.8 NO_LAPACKE DYNAMIC_ARCH NO_AFFINITY USE_OPENMP Prescott MAX_THREADS=64
OpenBLAS core (runtime): Prescott
Команда установки
sudo apt update
sudo apt install -y build-essential cmake git
git clone --depth=1 --branch 5.0.0 https://gitlab.com/libeigen/eigen.git
cmake -S eigen -B build -DCMAKE_BUILD_TYPE=Release -DEIGEN_BUILD_TESTING=OFF
sudo cmake --install build
sudo apt install -y libopenblas-openmp-dev
Компилируем команду для версии AVX512:
g++ -std=c++17 -O3 bench_eigen.cpp -march=native -mavx512f -mavx512vl -mavx512bw -mavx512dq -mavx2 -mfma -I/usr/local/include/eigen3 -DEIGEN_USE_BLAS -DNDEBUG -DEIGEN_DONT_PARALLELIZE -o bench_eigen -lopenblas -ldl -lpthread
Команда компиляции для версии AVX2:
g++ -std=c++17 -O3 bench_eigen.cpp -march=skylake -mavx2 -mfma -I/usr/local/include/eigen3 -DEIGEN_USE_BLAS -DNDEBUG -DEIGEN_DONT_PARALLELIZE -o bench_eigen -lopenblas -ldl -lpthread
Команда «Выполнить» (принудительно выполнить один поток):
OMP_NUM_THREADS=1 \
OPENBLAS_NUM_THREADS=1 \
MKL_NUM_THREADS=1 \
BLIS_NUM_THREADS=1 \
VECLIB_MAXIMUM_THREADS=1 \
NUMEXPR_MAX_THREADS=1 \
TBB_NUM_THREADS=1 \
taskset -c 0 ./bench_eigen
Результат AVX2:
Testing M = 1
A (naive u32) = 0.001543
E (Eigen u32) = 0.0004
F (Eigen float) = 0.000749
Testing M = 2
A (naive u32) = 0.000216
E (Eigen u32) = 0.000192
F (Eigen float) = 0.002067
Testing M = 4
A (naive u32) = 0.000242
E (Eigen u32) = 0.000251
F (Eigen float) = 0.000134
Testing M = 8
A (naive u32) = 0.00041
E (Eigen u32) = 0.011007
F (Eigen float) = 0.025273
Testing M = 16
A (naive u32) = 0.001032
E (Eigen u32) = 0.001554
F (Eigen float) = 0.002024
Testing M = 32
A (naive u32) = 0.004202
E (Eigen u32) = 0.005868
F (Eigen float) = 0.008759
Testing M = 64
A (naive u32) = 0.027771
E (Eigen u32) = 0.027779
F (Eigen float) = 0.040187
Testing M = 128
A (naive u32) = 0.195786
E (Eigen u32) = 0.230665
F (Eigen float) = 0.343123
Testing M = 256
A (naive u32) = 2.53591
E (Eigen u32) = 2.43643
F (Eigen float) = 2.55185
Testing M = 512
A (naive u32) = 21.0246
E (Eigen u32) = 12.9793
F (Eigen float) = 10.7131
Testing M = 1024
A (naive u32) = 99.9402
E (Eigen u32) = 60.1828
F (Eigen float) = 92.6357
Testing M = 2048
A (naive u32) = 1752.68
E (Eigen u32) = 602.128
F (Eigen float) = 790.347
Testing M = 4096
A (naive u32) = 15556.7
E (Eigen u32) = 4897.88
F (Eigen float) = 6155.12
Testing M = 8192
A (naive u32) = 125991
E (Eigen u32) = 34135.3
F (Eigen float) = 46756.6
Результат AVX512:
Testing M = 1
A (naive u32) = 0.003368
E (Eigen u32) = 0.000611
F (Eigen float) = 0.000263
Testing M = 2
A (naive u32) = 0.000333
E (Eigen u32) = 0.004817
F (Eigen float) = 0.000229
Testing M = 4
A (naive u32) = 0.000516
E (Eigen u32) = 0.000491
F (Eigen float) = 0.00023
Testing M = 8
A (naive u32) = 0.000877
E (Eigen u32) = 0.013735
F (Eigen float) = 0.036483
Testing M = 16
A (naive u32) = 0.00193
E (Eigen u32) = 0.004418
F (Eigen float) = 0.003246
Testing M = 32
A (naive u32) = 0.006337
E (Eigen u32) = 0.018598
F (Eigen float) = 0.011729
Testing M = 64
A (naive u32) = 0.04339
E (Eigen u32) = 0.128536
F (Eigen float) = 0.075315
Testing M = 128
A (naive u32) = 0.221819
E (Eigen u32) = 0.810674
F (Eigen float) = 0.202773
Testing M = 256
A (naive u32) = 1.12003
E (Eigen u32) = 8.39073
F (Eigen float) = 1.56858
Testing M = 512
A (naive u32) = 15.7097
E (Eigen u32) = 38.1472
F (Eigen float) = 10.2836
Testing M = 1024
A (naive u32) = 82.0125
E (Eigen u32) = 311.277
F (Eigen float) = 74.7194
Testing M = 2048
A (naive u32) = 1430.89
E (Eigen u32) = 2392.62
F (Eigen float) = 628.108
Testing M = 4096
A (naive u32) = 12446
E (Eigen u32) = 18972
F (Eigen float) = 5581.78
Testing M = 8192
A (naive u32) = 106590
E (Eigen u32) = 169307
F (Eigen float) = 45510.9
Код:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using std::cout;
constexpr bool DEBUG = 1;
class MyTimer {
std::chrono::time_point start;
public:
void startCounter() {
if constexpr(DEBUG) start = std::chrono::system_clock::now();
}
int64_t getCounterNs() {
if constexpr(DEBUG) return std::chrono::duration_cast(std::chrono::system_clock::now() - start).count();
else return 0;
}
int64_t getCounterMs() {
if constexpr(DEBUG) return std::chrono::duration_cast(std::chrono::system_clock::now() - start).count();
else return 0;
}
double getCounterMsPrecise() {
if constexpr(DEBUG) return std::chrono::duration_cast(std::chrono::system_clock::now() - start).count()
/ 1000000.0;
else return 0;
}
};
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
using u32 = uint32_t;
using u64 = uint64_t;
constexpr int BLK = 32;
const long long MAXM = 1 u32* {
return static_cast(::operator new[](n * sizeof(u32), std::align_val_t(align)));
};
using f32 = float;
static inline bool feq(f32 x, f32 y, f32 eps = 1e-3f)
{
f32 ax = std::fabs(x), ay = std::fabs(y);
f32 tol = eps * std::max(1.0f, std::max(ax, ay));
return std::fabs(x - y)
Подробнее здесь: https://stackoverflow.com/questions/798 ... iplication
Мобильная версия