Нет ускорения с бесполезными printf с использованием OpenMP - PullRequest
3 голосов
/ 26 апреля 2010

Я только что написал свою первую программу OpenMP, которая распараллеливает простой цикл for. Я запустил код на моей двухъядерной машине и увидел, что при переходе с 1 потока на 2 потока наблюдается некоторое ускорение. Тем не менее, я запустил тот же код на школьном сервере Linux и не увидел ускорения. Попробовав разные вещи, я наконец понял, что удаление некоторых бесполезных операторов printf привело к значительному ускорению кода. Ниже приведена основная часть кода, который я распараллелил:

#pragma omp parallel for private(i)
for(i = 2; i <= n; i++)
{
  printf("useless statement");
  prime[i-2] = is_prime(i);
}

Я предполагаю, что реализация printf имеет значительные накладные расходы, которые OpenMP должен дублировать с каждым потоком. Что вызывает эти издержки и почему OpenMP не может их преодолеть?

Ответы [ 4 ]

6 голосов
/ 26 апреля 2010

Предположим, но, может быть, stdout защищен замком?

В общем случае printf - это дорогостоящая операция, поскольку она взаимодействует с другими ресурсами (такими как файлы, консоль и т. Д.).

Мой опыт показывает, что printf очень медленный на консоли Windows, сравнительно намного быстрее на консоли Linux, но быстрее всего при перенаправлении в файл или /dev/null.

Я обнаружил, что отладка printf может серьезно повлиять на производительность моих приложений, и я использую ее редко.

Попробуйте запустить приложение, перенаправленное в файл или в / dev / null, чтобы увидеть, насколько это заметно; это поможет сузить суть проблемы.

Конечно, если printfs бесполезны, почему они вообще в цикле?

3 голосов
/ 26 апреля 2010

Чтобы немного расширить ответ @ Уилла ...

Я не знаю, защищен ли stdout блокировкой, но я почти уверен, что запись в него сериализуется в какой-то момент в программном стеке. С включенными операторами printf OP, вероятно, синхронизирует выполнение большого количества последовательных записей в stdout, а не параллельное выполнение цикла.

Я полагаю, что OP изменяет оператор printf для включения i, посмотрим, что произойдет.

Что касается очевидного ускорения на двухъядерном компьютере - было ли оно статистически значимым?

1 голос
/ 29 декабря 2010

Здесь у вас есть параллель для цикла, но планирование не определено.

#pragma omp parallel for private(i)
for(i = 2; i <= n; i++)

В стандарте OpenMP 3.0 определены некоторые типы планирования. Их можно изменить, установив OMP_SCHEDULE переменную окружения на type[,chunk], где

  • тип является одним из статический , динамический , управляемый или авто
  • chunk - необязательное положительное целое число, которое определяет размер куска

Другим способом изменения вида расписания является вызов функции openmp omp_set_schedule

Функция is_prime может быть довольно быстрой. / Предлагаю /

  prime[i-2] = is_prime(i);

Таким образом, проблема может возникать из-за неправильного режима планирования, когда выполняется небольшое число перед барьером от планирования.

И у printf есть 2 части внутри / я считаю glibc популярной реализацией Linux libc /

  1. Разобрать строку формата и поместить все параметры в буфер
  2. Запись буфера в файловый дескриптор (в буфер FILE, так как стандартный вывод буферизируется glibc по умолчанию)

Первая часть printf может выполняться параллельно, но вторая часть является критической и блокируется с помощью _IO_flockfile.

0 голосов
/ 26 декабря 2010

Какие у вас были сроки - было намного медленнее с printf? В некоторых узких циклах printf может занимать большую долю общего вычислительного времени; например, если is_prime () довольно быстро, и, следовательно, производительность определяется в большей степени числом вызовов функции printf, чем числом (распараллеленных) вызовов функции is_prime ()

...