Почему вычисление матрицы броненосца намного медленнее, чем Фортран

Aristotle0 спросил: 26 ноября 2017 в 05:30 в: c++

Я пытаюсь переписать коды с Фортрана на C ++ с помощью матрицы, реализуемой через библиотеку Armadillo. Результат одинаков для обоих кодов, но код C ++ намного медленнее, чем Fortran (> 10x). Коды включают в себя обратную матрицу (2x2, 4x4), умножение и сложение. Я поместил здесь часть похожего кода для тестирования.

===========================

clang++ cplusplus.cc -o cplusplus --std=c++14 -larmadillo -O2ifort fort.f90 -o fort -O2

время кода C ++: 0,39404 с

время кода Фортрана: 0,068 с

============= ===============

код C ++:

#include <armadillo>
#include <iostream>int main()
{
  const int niter = 1580000;
  const int ns = 3;
  arma::cx_cube m1(2, 2, ns), m2(2, 2, ns), m3(2, 2, ns);
  arma::wall_clock timer;
  timer.tic();
  for (auto i=0; i<niter; ++i) {
    for (auto j=0; j<ns; ++j)
      m1.slice(j) += m2.slice(j) * m3.slice(j);
  }
  double n = timer.toc();
  std::cout << "time: " << n << "s" << std::endl;
  return 0;
}

код Фортрана:

program main
  implicit none
  integer, parameter :: ns = 3, niter = 1580000
  complex*16 m1(2, 2, ns), m2(2, 2, ns), m3(2, 2, ns)
  integer i, j
  real :: start, finish
  call cpu_time(start)
  do i = 1, niter
     do j = 1, ns
        m1(1, 1, j) = m1(1, 1, j) + m2(1, 1, j) * m3(1, 1, j) + m2(1, 2, j) * m3(2, 1, j)
        m1(1, 2, j) = m1(1, 2, j) + m2(1, 1, j) * m3(1, 2, j) + m2(1, 2, j) * m3(2, 2, j)
        m1(2, 1, j) = m1(2, 1, j) + m2(2, 1, j) * m3(1, 1, j) + m2(2, 2, j) * m3(2, 1, j)
        m1(2, 2, j) = m1(2, 2, j) + m2(2, 1, j) * m3(1, 2, j) + m2(2, 2, j) * m3(2, 2, j)
     end do
  end do
  call cpu_time(finish)
  print *, "time: ", finish-start, " s"end program main

============================================ ========================

после @ewcz @ user5713492 совета

====== ======================

clang++ cplusplus.cc -o cplusplus --std=c++14 -larmadillo -O2ifort fort.f90 -o fort -O2ifort fort2.f90 -o fort2 -O2

код C ++ (cplusplus.cc) время: 0,39650 с

Код Фортрана (fort.f90) (явно операция) время: 0,020 с

Код Фортрана (fort2.f90) (матрица) время: 0,064 с

=== =========================

код C ++ (cplusplus.cc):

#include <armadillo>
#include <iostream>
#include <complex>int main()
{
  const int niter = 1580000;
  const int ns = 3;
  arma::cx_cube m1(2, 2, ns, arma::fill::ones),
    m2(2, 2, ns, arma::fill::ones),
    m3(2, 2, ns,arma::fill::ones);
  std::complex<double> result;
  arma::wall_clock timer;
  timer.tic();
  for (auto i=0; i<niter; ++i) {
    for (auto j=0; j<ns; ++j)
      m1.slice(j) += m2.slice(j) * m3.slice(j);
  }  double n = timer.toc();
  std::cout << "time: " << n << "s" << std::endl;
  result = arma::accu(m1);
  std::cout << result << std::endl;
  return 0;
}

Код Фортрана (fort.f90):

program main
  implicit none
  integer, parameter :: ns = 3, niter = 1580000
  complex*16 m1(2, 2, ns), m2(2, 2, ns), m3(2, 2, ns)
  integer i, j
  complex*16 result
  real :: start, finish
  m1 = 1
  m2 = 1
  m3 = 1
  call cpu_time(start)
  do i = 1, niter
     do j = 1, ns
        m1(1, 1, j) = m1(1, 1, j) + m2(1, 1, j) * m3(1, 1, j) + m2(1, 2, j) * m3(2, 1, j)
        m1(1, 2, j) = m1(1, 2, j) + m2(1, 1, j) * m3(1, 2, j) + m2(1, 2, j) * m3(2, 2, j)
        m1(2, 1, j) = m1(2, 1, j) + m2(2, 1, j) * m3(1, 1, j) + m2(2, 2, j) * m3(2, 1, j)
        m1(2, 2, j) = m1(2, 2, j) + m2(2, 1, j) * m3(1, 2, j) + m2(2, 2, j) * m3(2, 2, j)
     end do
  end do
  call cpu_time(finish)
  result = sum(m1)
  print *, "time: ", finish-start, " s"
  print *, resultend program main

Код Фортрана (fort2.f90):

program main
  implicit none
  integer, parameter :: ns = 3, niter = 1580000
  complex*16 m1(2, 2, ns), m2(2, 2, ns), m3(2, 2, ns)
  integer i, j
  complex*16 result
  real :: start, finish
  m1 = 1
  m2 = 1
  m3 = 1
  call cpu_time(start)
  do i = 1, niter
     do j = 1, ns
        m1(:,:,j) = m1(:,:,j)+matmul(m2(:,:,j),m3(:,:,j))
     end do
  end do
  call cpu_time(finish)
  result = sum(m1)
  print *, "time: ", finish-start, " s"
  print *, resultend program main

== ================================================== ==================

Комплексное число может быть одной из причин того, что броненосец такой медленный. Если я использую arma::cube вместо arma::cx_cube в C ++ и использую real*8 в Fortran, время:

C ++ время кода: 0,08 с

Код Фортрана (fort.f90) (явно операция) время: 0,012 с

Код Фортрана (fort2.f90) (матрица) время: 0,028 с

Тем не менее, комплексное число необходимо для моего вычисления. Странно, что время вычислений очень сильно увеличивается для библиотеки броненосцев, но немного для Фортрана.

0 ответов