Что здесь не так? Результаты тестов с использованием другой библиотеки матриц приветствуются.
РЕДАКТИРОВАТЬ: Я нашел кое-что более странное. Компиляция с использованием -march=skylake (то есть без AVX512) делает код в 4 раза медленнее по сравнению с использованием AVX512 (-march=native -mavx512f -mavx512vl -mavx512bw -mavx512dq -mavx2 -mfma). В обоих случаях Float matmul имеет одинаковую скорость. Это похоже на сбой компилятора (векторизация кода при компиляции с AVX512).
РЕДАКТИРОВАНИЕ 2: Протестировано на другом ПК с i5-11400F, результат -march=skylake намного быстрее и соответствует ожиданиям (последний тест использовал виртуальную машину, поэтому, вероятно, были некоторые проблемы с конфигурацией). Однако int matmul на этом новом ПК по-прежнему работает намного медленнее при компиляции с AVX512. Вы можете видеть, что как в старых, так и в новых результатах компиляция с AVX512 делает Eigen int matmul намного медленнее, в то время как float matmul имеет аналогичную скорость.
EDIT 3: Протестировано на процессоре AMD с поддержкой AVX512 (Ryzen 9 9950X). Та же проблема сохраняется: int matmul работает намного медленнее при компиляции с помощью AVX512
-march=skylake -mavx2 -mfma
Old result i5-11400F (run inside VM)
Testing M = 8192
A (naive u32) = 125991
E (Eigen u32) = 34135.3
F (Eigen float) = 46756.6
New result i5-11400F (physical machine)
Testing M = 8192
A (naive u32) = 90380.7
E (Eigen u32) = 23885.2
F (Eigen float) = 8307.87
AMD 9950X
Testing M = 8192
A (naive u32) = 51796.6
E (Eigen u32) = 14387.8
F (Eigen float) = 3648.81
-march=native -mavx512f -mavx512vl -mavx512bw -mavx512dq -mavx2 -mfma
Old result i5-11400F
Testing M = 8192
A (naive u32) = 106590
E (Eigen u32) = 169307
F (Eigen float) = 45510.9
New result i5-11400F
Testing M = 8192
A (naive u32) = 90707.9
E (Eigen u32) = 131440
F (Eigen float) = 8217.99
AMD 9950X
Testing M = 8192
A (naive u32) = 49783.9
E (Eigen u32) = 78567
F (Eigen float) = 3616.15
Спецификация тестов:
- ЦП i5 11400F и двухканальная оперативная память AMD 9950X
- Ubuntu 20.04
- g++ 13.3
- 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 software-properties-common
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
sudo apt update
sudo apt install -y gcc-13 g++-13
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 130
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 130
sudo update-alternatives --install /usr/bin/cpp cpp /usr/bin/cpp-13 130
# Eigen 5:
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:
Old result i5-11400F (running on VM)
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
New resullt i5-11400F (same CPU but physical machine)
Testing M = 128
A (naive u32) = 0.12163
E (Eigen u32) = 0.116401
F (Eigen float) = 0.075121
Testing M = 256
A (naive u32) = 1.09552
E (Eigen u32) = 0.919345
F (Eigen float) = 0.371853
Testing M = 512
A (naive u32) = 10.6812
E (Eigen u32) = 6.0438
F (Eigen float) = 2.51853
Testing M = 1024
A (naive u32) = 79.6962
E (Eigen u32) = 46.3137
F (Eigen float) = 18.0736
Testing M = 2048
A (naive u32) = 1042.06
E (Eigen u32) = 369.876
F (Eigen float) = 135.139
Testing M = 4096
A (naive u32) = 10479.9
E (Eigen u32) = 2960.94
F (Eigen float) = 1052.21
Testing M = 8192
A (naive u32) = 90380.7
E (Eigen u32) = 23885.2
F (Eigen float) = 8307.87
AMD 9950X
Testing M = 128
A (naive u32) = 0.076725
E (Eigen u32) = 0.06347
F (Eigen float) = 0.047079
Testing M = 256
A (naive u32) = 0.552815
E (Eigen u32) = 0.556001
F (Eigen float) = 0.219865
Testing M = 512
A (naive u32) = 4.25005
E (Eigen u32) = 3.74131
F (Eigen float) = 1.32005
Testing M = 1024
A (naive u32) = 33.7412
E (Eigen u32) = 28.8141
F (Eigen float) = 8.7186
Testing M = 2048
A (naive u32) = 276.306
E (Eigen u32) = 225.863
F (Eigen float) = 62.0906
Testing M = 4096
A (naive u32) = 6166.02
E (Eigen u32) = 1791.01
F (Eigen float) = 463.528
Testing M = 8192
A (naive u32) = 51796.6
E (Eigen u32) = 14387.8
F (Eigen float) = 3648.81
Результат AVX512:
Old result i5-11400F (run inside VM)
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
New result i5-11400F (same CPU, physical machine)
Testing M = 128
A (naive u32) = 0.119588
E (Eigen u32) = 0.553603
F (Eigen float) = 0.116075
Testing M = 256
A (naive u32) = 1.02111
E (Eigen u32) = 4.0471
F (Eigen float) = 0.373552
Testing M = 512
A (naive u32) = 10.8143
E (Eigen u32) = 31.5743
F (Eigen float) = 2.47198
Testing M = 1024
A (naive u32) = 79.4369
E (Eigen u32) = 249.567
F (Eigen float) = 18.0903
Testing M = 2048
A (naive u32) = 1039.77
E (Eigen u32) = 2040.11
F (Eigen float) = 134.361
Testing M = 4096
A (naive u32) = 10571.3
E (Eigen u32) = 16428.7
F (Eigen float) = 1041.24
Testing M = 8192
A (naive u32) = 90707.9
E (Eigen u32) = 131440
F (Eigen float) = 8217.99
AMD 9950X
Testing M = 128
A (naive u32) = 0.069131
E (Eigen u32) = 0.268768
F (Eigen float) = 0.046569
Testing M = 256
A (naive u32) = 0.467504
E (Eigen u32) = 2.14106
F (Eigen float) = 0.200218
Testing M = 512
A (naive u32) = 3.39699
E (Eigen u32) = 17.0184
F (Eigen float) = 1.25278
Testing M = 1024
A (naive u32) = 30.5326
E (Eigen u32) = 136.566
F (Eigen float) = 9.05632
Testing M = 2048
A (naive u32) = 252.328
E (Eigen u32) = 1083.29
F (Eigen float) = 61.8197
Testing M = 4096
A (naive u32) = 5452.87
E (Eigen u32) = 9689
F (Eigen float) = 462.547
Testing M = 8192
A (naive u32) = 49783.9
E (Eigen u32) = 78567
F (Eigen float) = 3616.15
Код:
#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
Мобильная версия