Почему два процесса, которые выполняют умножение матриц, работают параллельно медленнее, чем последовательно? - PullRequest
0 голосов
/ 13 февраля 2019

У меня есть программа, которая выполняет эксперимент по линейной алгебре (с использованием библиотеки Armadillo в C ++).Мне нужно было запускать эту программу много раз, поэтому собирался выполнять несколько процессов параллельно (вплоть до моих доступных ресурсов).Однако даже при параллельном запуске только двух экспериментов оба процесса замедляют непропорционально - по крайней мере, в 10 раз медленнее, чем при последовательном выполнении.

Мне удалось сократить свой код до места возникновения проблемыи, кажется, я умножаю матрицу на вектор.Вот воспроизводимый пример.Это выполняется бесконечно и печатает истекшее количество секунд каждую 1000-ю итерацию умножения матрицы на вектор.

test.cpp

#include <iostream>
#include <armadillo>
#include <chrono>

using namespace std;
using namespace arma;

int main(int argc, char** argv) {
  chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();

  mat A = randn(1500,1500);
  vec y = randn(1500);
  vec values;

  long its = 0;
  while (true) {

    values = A*y;

    // print time once in a while
    if (++its % 1000 == 0) {
      long secondsElapsed = chrono::duration_cast<chrono::seconds>(chrono::steady_clock::now() - begin).count();
      cout << "secs elapsed by iteration " << its << ": " << secondsElapsed << endl;
    }
  }
  return 0;
}

Я скомпилировал / связал с:

$ g++ test.cpp -larmadillo -std=c++11

При запуске одного процесса этой программы в терминале вывод:

secs elapsed by iteration 1000: 1
secs elapsed by iteration 2000: 2
secs elapsed by iteration 3000: 3
...

При запуске двух процессов этой программы (в двух разных терминалах) вывод для процесса 1:

secs elapsed by iteration 1000: 24
secs elapsed by iteration 2000: 48
secs elapsed by iteration 3000: 74
...

и вывод процесса 2 аналогичен.Процесс работает в 24 раза медленнее, когда работает второй процесс.

Утилита top в Linux показывает 400% ЦП для каждого из двух процессов, таким образом, 800% в общей сложности (у меня 4 ядра8 потоков).0,3% моей памяти занято каждым из двух процессов.

Почему это может происходить и как я могу это исправить?Я не уверен, как отлаживать это сам, но хочу учиться, поэтому было бы здорово, если бы кто-то мог дать несколько советов о том, как отладить ситуацию, подобную этой, в своем ответе!

Детали платформы: Linux 3.10.0-693.11.1.el7.x86_64, 4 ядра / 8 потоков, 8 ГБ ОЗУ.g ++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36).Версия ARMA: 8.300.2 (тропический шенаниган).

1 Ответ

0 голосов
/ 13 февраля 2019

Вот несколько вещей.

Вы не компилируете с оптимизацией.Используйте -O2 и -march=native

Похоже, что Армадилло использует BLAS для умножения векторной матрицы.Секрет может лежать там.Похоже, библиотека уже настроена на использование всех ядер;вы не сможете выжать больше производительности из-за многопроцессорности.Хорошо ... хорошо, как вы сказали, у вас есть гиперпоточный четырехъядерный процессор x86_64 и вы хотите использовать 8 логических ядер вместо просто 4. Но помните, что гиперпоточность работает, позволяя двум потокам использовать процессор одновременно,Это может удвоить производительность, так как обычно есть много оставшихся арифметических единиц.Но если ядро ​​BLAS использует все блоки SIMD (или просто по-настоящему хорошо использует доступные арифметические единицы) на всех 4 ядрах, у второго экземпляра, работающего одновременно, не останется никакого аппаратного обеспечения, и он может оказаться только вчерез переключение контекста, которое портит аппаратные конвейеры и вызывает ошибки в кэше.

Я пытаюсь придумать, как можно это проверить.Если у вас есть доступ к другим машинам с разным количеством физических ядер, вы можете увидеть шаблон.Идеальным элементом управления отладкой была бы возможность сообщить BLAS, сколько ядер использовать, но я не уверен, что это доступно.

Арку ЦП было бы полезно узнать здесь, а также версию BLAS (если выдействительно используя BLAS).

Вы не упомянули профилирование, которое вы сделали.Если вы еще не выполнили профилирование, сейчас самое время!Если этот раздел является узким местом для многих, вы могли бы выиграть от некоторого ускорения графического процессора.Или, если это узкое место, но ненадолго, вы можете передать другие части программы, чтобы этот раздел был наполнен данными.Или вы всегда можете довольствоваться текущей скоростью, если время выполнения разумно.

...