2016-02-13 4 views
5

У меня есть программа следующая программа C++, которая не использует никакой связи, и то же тождественны работа делается на всех ядрах, я знаю, что это не использует параллельную обработку на всех:Стоимость OpenMPI в C++

unsigned n = 130000000; 
std::vector<double>vec1(n,1.0); 
std::vector<double>vec2(n,1.0); 
double precision :: t1,t2,dt; 
t1 = MPI_Wtime(); 
for (unsigned i = 0; i < n; i++) 
{ 
    // Do something so it's not a trivial loop 
    vec1[i] = vec2[i]+i; 
} 
t2 = MPI_Wtime(); 
dt = t2-t1; 

Я запускаю эту программу в одном узле с двумя процессором Intel® Xeon® E5-2690 v3, поэтому у меня есть 24 ядра. Это выделенный узел, и никто его не использует. Поскольку нет связи, и каждый процессор выполняет одинаковое количество (одинаковой) работы, запуск его на нескольких процессорах должен давать одинаковое время. Тем не менее, я получаю следующие разы (в среднее время, в течение всех ядер):

1 ядро: 0,237

2 жилы: 0,240

4 ядра: 0,241

8 ядер: 0,261

16 ядер: 0,454

Что Коула d приведет к увеличению времени? Особенно для 16 ядер. У меня есть callgrind, и я получаю примерно одинаковое количество промахов данных/команд на всех ядрах (процент пропусков одинаковый).

Я повторил тот же тест на узле с двумя процессорами Intel® Xeon® E5-2628L v2 (16 ядер вместе), я наблюдаю такое же увеличение времени выполнения. Это как-то связано с реализацией MPI?

+0

Я не совсем понимаю, что вы делаете - вы используете отдельный экземпляр одной и той же программы на каждом ядре отдельно? Кроме того, вы говорите о Cores (24), а затем о процессорах - что это? – MikeMB

+0

Да, я бегу, я запускаю отдельный экземпляр одной программы на каждом ядре. Извините за смешение слов, я отредактировал его. – user302157

ответ

2

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

Вы видите, у вас может быть 24 ядра, но это не означает, что вся ваша система позволяет каждому ядру делать все одновременно. Как упоминалось в комментариях, доступ к памяти - это одна вещь, которая может вызвать задержки (из-за трафика), то же самое для диска.

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


Общее примечание: Вспомним, как Эффективность программы определяется:

Е = S/P, где S является ускорение и р число узлов/процессов/потоков

Теперь возьмите Масштабируемость. Обычно программы слабо масштабируемы, т. Е. Вам необходимо увеличить с той же скоростью размер проблемы и p.Увеличивая только число p, сохраняя при этом размер вашей проблемы (n в вашем случае) постоянный, сохраняя постоянную эффективности, дает сильно масштабируемую программу.

+2

Это может быть так. Я мало знаю о доступе к ОЗУ, но я знаю, что все ядра имеют одинаковую RAM. Я не знаю, возможен ли доступ к этой памяти одновременно. – user302157

+0

Точно @ user302157, вы также видите, что это связано с сетью межсоединений. ;) Отсканируйте ответы и выберите один, чтобы принять (также проверьте мое обновление). – gsamaras

+0

Спасибо! Да, я на самом деле пытаюсь определить причину плохого масштабирования при слабых тестах масштабирования. Перед представленным циклом есть фактически параллельный код, который вставляет разные данные в векторы в зависимости от ранга, но я анализирую каждую часть отдельно, и я был замешан в этой части, которая должна очень хорошо масштабироваться при слабом масштабировании. Но причина плохого масштабирования при переходе на 16 ядер обусловлена ​​проблемами пропускной способности. Я не думал об этом. Еще раз спасибо. – user302157

1

Ваша программа не использует параллельную обработку вообще. Просто потому, что вы скомпилировали его с помощью OpenMP, это не делает его parallel.

Для параллелизации цикла for, например, вам нужно использовать другое предложение OpenMP от # pragma.

unsigned n = 130000000; 
std::vector<double>vec1(n,1.0); 
std::vector<double>vec2(n,1.0); 
double precision :: t1,t2,dt; 
t1 = MPI_Wtime(); 

#pragma omp parallel for 
for (unsigned i = 0; i < n; i++) 
{ 
    // Do something so it's not a trivial loop 
    vec1[i] = vec2[i]+i; 
} 
t2 = MPI_Wtime(); 
dt = t2-t1; 

Однако, примите во внимание, что при больших значениях п, влияние промахов кэша может скрыть Perfomance получило с несколькими ядрами.

+2

Да, я знаю, что параллельной обработки нет. Я заявил, что коммуникации нет, и то же самое делается. Поэтому я не знаю, почему происходит увеличение времени выполнения, даже когда каждое ядро ​​выполняет точно то же самое. Я запускал программу через callgrind, и на всех ядрах было одинаковое количество пропусков команд/данных. – user302157

4

Учитывая, что вы используете ~ 2 гигабайта памяти за ранг, ваш код привязан к памяти. За исключением prefetchers, вы не работаете в кеше, а в основной памяти. Вы просто нажимаете полосу пропускания памяти на определенное количество активных ядер.

Другим аспектом может быть турборежим, если он включен. Режим Turbo может увеличить частоту ядра до более высоких уровней, если используется меньшее количество ядер. Пока пропускная способность памяти не насыщена, более высокая частота от турбо-сердечника увеличит пропускную способность, получаемую каждым ядром. This paper обсуждает доступную совокупную пропускную способность памяти на процессорах Haswell в зависимости от количества активных ядер и частоты (рис. 7./8.)

Обратите внимание, что это не имеет ничего общего с MPI/OpenMPI. Вы также можете запустить ту же программу X раз с помощью любого другого средства.

+0

Спасибо! Это точно. Я просмотрю газету. – user302157

+0

Я просмотрел бумагу. Быстрый вопрос, знаете ли вы, возможно ли изменить частоту процессора на C++? Мне просто интересно, как они собираются менять частоту на рис. 7 и 8, или мне нужен какой-то админ-доступ или какой-то вид. – user302157

+0

@ user302157, по умолчанию для этого требуется root. Это можно разрешить пользователям, установив разрешения для '/ sys/devices/system/cpu/cpu */cpufreq/scaling_ {Governor, setspeed}'. Вы можете либо напрямую записать файлы, либо 'libcpufreq' (немного медленный, потому что он всегда выполняет двойную проверку регулятора). – Zulan