Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top
>
>
Холодный Tachyon

Холодный Tachyon

08 Дек 2009

Чуть более месяца назад состоялся первый русскоязычный онлайн-семинар от Intel "Intel Parallel Studio workflow". На нем Кирилл Мавродиев продемонстрировал, как можно распараллелить приложение, рассматривая его как черный ящик. Другими словами, была рассмотрена типичная ситуация, когда у разработчика имеется незнакомый ему код, которые необходимо модернизировать.

Поддержка OpenMP была прекращена в PVS-Studio после версии 5.20. По всем возникшим вопросам вы можете обратиться в нашу поддержку.

Например, распараллелить. В качестве демонстрационного примера была выбрана программа Tachyon, реализующая алгоритм трассировки лучей и рисующая на экране трехмерный фрактал. В качестве инструментария был выбрана технология параллельного программирования OpenMP, компилятор Intel C++, профилировщик многопоточных приложений Parallel Amplifier и инструмент для поиска параллельных ошибок Parallel Inspector. После семинара появилась еще одна запись " По теплым следам онлайн семинара "Intel(R) Parallel Studio workflow""

Мы подумали и решили, раз был пост "по теплым следам", то этот текст уже следует назвать холодным. Есть и еще одна причина. Динамический анализ на этапе исполнения программы, осуществляемый Parallel Inspector, почему-то ассоциируется со словом "горячий". А альтернативный подход, который здесь будет продемонстрирован, основан на статическом анализе исходного кода и скорее ассоциируется со словом "холодный".

Давно было желание привести новый пример использования анализатора VivaMP, входящего в состав PVS-Studio для выявления ошибок в параллельном коде. Оказалось, что этот альтернативный подход к анализу очень хорошо можно продемонстрировать на примере Tachyon. Напомню, что в вебинаре для поиска параллельных ошибок использовался инструмент Parallel Inspector. Диагностика ошибок происходила в несколько этапов. Мы продемонстрируем на этих этапах работу инструмента VivaMP.

В начале, мы имеем последовательный код:

TachyonStep1\trace.serial.cpp
unsigned int serial = 1;
unsigned int mboxsize = sizeof(unsigned int)*(max_objectid() + 20);
unsigned int * local_mbox = (unsigned int *) alloca(mboxsize);
memset(local_mbox,0,mboxsize);
for (int y = starty; y < stopy; y++) { {
    drawing_area drawing(startx, totaly-y, stopx-startx, 1);
    for (int x = startx; x < stopx; x++) {
       color_t c = render_one_pixel (x, y,
               local_mbox, serial, startx, stopx, starty, stopy);
       drawing.put_pixel(c);
   } }
   if(!video->next_frame()) return;
}

Код совершенно корректен и не вызывает подозрений ни у Parallel Inspector, ни у VivaMP.

Далее код был модифицирован следующим образом:

TachyonStep2\trace.par1.cpp
unsigned int serial = 1;
int ison=1;
unsigned int mboxsize = sizeof(unsigned int)*(max_objectid() + 20);
unsigned int * local_mbox = (unsigned int *) alloca(mboxsize);
memset(local_mbox,0,mboxsize);
#pragma omp parallel for
for(int y = starty; y < stopy*ison; y++) { {
    drawing_area drawing(startx, totaly-y, stopx-startx, 1);
    for (int x = startx; x < stopx; x++) {
      color_t c = render_one_pixel (x, y,
                local_mbox, serial, startx, stopx, starty, stopy);
        drawing.put_pixel(c);
    } }
    if(!video->next_frame()) ison=0;
 }

Такое смелое распараллеливание привело к ошибке и построению некорректного изображения на экране. С помощью Parallel Inspector, было выяснено, что в коде возникает несколько ошибок состояния гонки (race condition). Результатом изучения диагностических сообщений Parallel Inspector было решение объявить переменные ison, local_mbox и serial приватными (shared), то есть уникальными для каждого потока. Именно при обращении к этим переменным возникали гонки. Теперь посмотрим, какие предупреждения для этого кода выдает анализатор VivaMP:

1 error V1206: Data race risk. The value of the 'scene' variable can be changed concurrently via the 'camray' function. r:\src\tachyonstep2\trace.par1.cpp 87

2 error V1206: Data race risk. The value of the 'local_mbox' variable can be changed concurrently via the 'render_one_pixel' function. r:\src\tachyonstep2\trace.par1.cpp 157

3 error V1206: Data race risk. The value of the 'serial' variable can be changed concurrently via the 'render_one_pixel' function. r:\src\tachyonstep2\trace.par1.cpp 157

4 error V1205: Data race risk. Unprotected concurrent operation with the 'ison' variable. r:\src\tachyonstep2\trace.par1.cpp 160

Обратите внимания, что анализатор VivaMP предупредил о потенциальных ошибках гонки для тех же трех переменных: ison, local_mbox и serial. Есть еще одна потенциальная ошибка использования переменной 'camray' в другой функции, но этот момент мы рассмотрим позже.

Основываясь на диагностике Parallel Inspector, код был изменен следующим образом:

TachyonStep2\trace.par2.cpp
unsigned int serial = 1;
int ison=1;
unsigned int mboxsize = sizeof(unsigned int)*(max_objectid() + 20);
unsigned int * local_mbox = (unsigned int *) alloca(mboxsize);
memset(local_mbox,0,mboxsize);
#pragma omp parallel for firstprivate(ison,local_mbox,serial)
for(int y = starty; y < stopy*ison; y++) { {
  drawing_area drawing(startx, totaly-y, stopx-startx, 1);
  for (int x = startx; x < stopx; x++) {
    color_t c = render_one_pixel (x, y,
            local_mbox, serial, startx, stopx, starty, stopy);
    drawing.put_pixel(c);
  } }
  if(!video->next_frame()) ison=0
}

Измененная программа по-прежнему продолжает вести себя некорректно, хотя это и выражается иным образом. Повторный анализ с помощью Parallel Inspector выявляет ошибку совместного использования одного массива local_mbox. Директива firstprivate(local_mbox) создает уникальный указатель для каждого из потока. Но сам массив, на который ссылаются эти указатели, по-прежнему общий.

Анализатор VivaMP также смог диагностировать эту проблему (см. второе предупреждение):

1 error V1206: Data race risk. The value of the 'scene' variable can be changed concurrently via the 'camray' function. r:\src\tachyonstep3.1\trace.par2.cpp 87

2 error V1209: Warning: The 'local_mbox' variable of pointer type should not be private. r:\src\tachyonstep3.1\trace.par2.cpp 153

Ниже приведен окончательный вариант функции, в которой устранены все дефекты, и программа корректно строит изображение фрактала:

TachyonStep2\trace.par3.cpp
#pragma omp parallel
{
unsigned int serial = 1;
int ison=1;
unsigned int mboxsize = sizeof(unsigned int)*(max_objectid() + 20);
unsigned int * local_mbox = (unsigned int *) alloca(mboxsize);
memset(local_mbox,0,mboxsize);
#pragma omp for
for(int y = starty; y < stopy*ison; y++) { {
  drawing_area drawing(startx, totaly-y, stopx-startx, 1);
  for (int x = startx; x < stopx; x++) {
    color_t c = render_one_pixel (x, y,
            local_mbox, serial, startx, stopx, starty, stopy);
    drawing.put_pixel(c);
  } }
  if(!video->next_frame()) ison=0
 }
}

Это код уже не вызывает у Parallel Inspector подозрений. А вот VivaMP по-прежнему выдает одно диагностическое сообщение, являющееся ложным:

1 error V1206: Data race risk. The value of the 'scene' variable can be changed concurrently via the 'camray' function. r:\src\tachyonstep3.2\trace.par3.cpp 87

Это сообщение относится к вызываемой параллельно функции render_one_pixel. В ней VivaMP не может разобраться, что объект scene используется в нескольких потоках только для чтения. Можно легко убрать это сообщение, если объявить функцию чуть более изящно. Достаточно сделать параметр функции scenedef константным. То есть заменить

ray  camray(scenedef *, int, int);

на

ray  camray(const scenedef *, int, int);

После этой модификации анализатор VivaMP не выдаст более ни одного предупреждения.

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

Популярные статьи по теме


Комментарии (0)

Следующие комментарии next comments
close comment form
close form

Заполните форму в два простых шага ниже:

Ваши контактные данные:

Шаг 1
Поздравляем! У вас есть промокод!

Тип желаемой лицензии:

Шаг 2
Team license
Enterprise license
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности
close form
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Бесплатная лицензия PVS‑Studio для специалистов Microsoft MVP
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Мне интересно попробовать плагин на:
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
check circle
Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте, отфильтровано ли письмо в одну из следующих стандартных папок:

  • Промоакции
  • Оповещения
  • Спам