Почему умножение int матрицы Eigen C++ в 10 раз медленнее, чем умножение с плавающей запятой (даже медленнее, чем наивныC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Почему умножение int матрицы Eigen C++ в 10 раз медленнее, чем умножение с плавающей запятой (даже медленнее, чем наивны

Сообщение Anonymous »

Я тестирую умножение матриц int, но обнаружил, что оно везде очень медленное (python numpy с использованием бэкэнда BLAS также работает так же медленно). Понятно, что int matmul медленнее, чем float matmul, но почему-то он в 3-5 раз медленнее, чем наивный 5-строчный matmul.
Что здесь не так? Приветствуются результаты тестирования с использованием другой матричной библиотеки.
Спецификация теста:
  • 48-ядерный процессор AMD EPYC 7643, четырехканальная ОЗУ 128 ГБ. Но этот вопрос проверяет один поток
  • Ubuntu 22.04, g++ 13.3
  • Команда установки:
!apt-get update -qq
!apt-get install -y -qq libopenblas-dev g++ make
!sudo apt-get update -y
!sudo apt-get install -y libeigen3-dev
!sudo apt-get update
!sudo apt-get install -y libopenblas-dev
!g++ --version

Eigen version: 3.4.0
CBLAS provider: /usr/lib/x86_64-linux-gnu/libopenblas.so.0
OpenBLAS (compile-time): OpenBLAS 0.3.26
OpenBLAS config (runtime): OpenBLAS 0.3.26 NO_LAPACKE DYNAMIC_ARCH NO_AFFINITY Zen MAX_THREADS=64
OpenBLAS core (runtime): Zen

Выполнить команду:
rm bench_eigen
g++ -std=c++20 -O3 -march=native -mavx2 -mfma -I /usr/include/eigen3 -DEIGEN_USE_BLAS -DNDEBUG -DEIGEN_DONT_PARALLELIZE bench_eigen.cpp -o bench_eigen -lopenblas -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

Результат
Testing M = 1
A (naive u32) = 0.00469
E (Eigen u32) = 0.00048
F (Eigen float) = 0.00103
Testing M = 2
A (naive u32) = 0.00032
E (Eigen u32) = 0.00025
F (Eigen float) = 0.00066
Testing M = 4
A (naive u32) = 0.00044
E (Eigen u32) = 0.00035
F (Eigen float) = 0.00486
Testing M = 8
A (naive u32) = 0.0006
E (Eigen u32) = 0.00463
F (Eigen float) = 0.04194
Testing M = 16
A (naive u32) = 0.00135
E (Eigen u32) = 0.00416
F (Eigen float) = 0.00671
Testing M = 32
A (naive u32) = 0.00528
E (Eigen u32) = 0.03033
F (Eigen float) = 0.01717
Testing M = 64
A (naive u32) = 0.05397
E (Eigen u32) = 0.20641
F (Eigen float) = 0.082491
Testing M = 128
A (naive u32) = 0.247691
E (Eigen u32) = 1.63561
F (Eigen float) = 0.481171
Testing M = 256
A (naive u32) = 1.80377
E (Eigen u32) = 13.0081
F (Eigen float) = 1.97049
Testing M = 512
A (naive u32) = 17.8799
E (Eigen u32) = 46.5605
F (Eigen float) = 4.99723
Testing M = 1024
A (naive u32) = 56.7417
E (Eigen u32) = 323.462
F (Eigen float) = 33.8333
Testing M = 2048
A (naive u32) = 487.233
E (Eigen u32) = 2545.22
F (Eigen float) = 234.984
Testing M = 4096
A (naive u32) = 7373.18
E (Eigen u32) = 20315.3
F (Eigen float) = 1574.43
Testing M = 8192
A (naive u32) = 64366.7
E (Eigen u32) = 162164
F (Eigen float) = 11347.4
Testing M = 16384

Код:
#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
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»