l - hpcource

advertisement
В программе реализуется ниже приведенный алгоритм из статьи
Дворцова В. И.
В процессе разработки оказалось, что этот алгоритм не самый удачный для
распараллеливания на CUDA:
 алгоритм рекурсивный, а CUDA не поддерживает рекурсии, поэтому
распараллеливанию подверглась лишь часть (деление точек на правое
и левое множества);
 рекурсия производилась на CPU с последующим вызовом GPU на
каждой итерации;
 выигрыш CUDA дает на больших множествах точек, по мере
уменьшения размера преимущество нивелируется, а так как
множество на каждом этапе рекурсии уменьшается, что сказывается на
производительности;
 так как изначально неизвестно в какое место записать координаты в
результирующий массив, то массив блокируется и запись происходит
последовательно, но запись в левую и в правую сторону происходит
параллельно.
Особенности реализации:
 множество точек генерируется так, чтобы не было повторяющихся,
первая и последняя точка заведомо задаются на краю множества.
 все множество точек (массив координат) единожды загружается на
GPU, так как загрузка на GPU слабое место CUDA, GPU передаются
лишь параметры (начало, конец текущего массива, граница и т. д.);
 количество блоков регулируется размером данных;
 в каждой блоке выделяется две нити, которые записывают данные в
результирующий массив (левое, правое множества);
 запись левых и правых координат в результирующий массив
производится одновременно (левые записываются слева, правые –
справа);
 условие выхода из рекурсии является размер массива равный 3, а не 2
как в алгоритме, так как при таком размере координаты лежат в
нужном порядке.
 на выходе получаем отсортированный массив;
 количество нитей в блоке задается вручную глобальной переменной (в
текущей программе 1024).
В итоге для реализации наиболее эффективной работы необходимо
написание гибридной модели алгоритма, которая в зависимости от
размера на текущем шаге рекурсии массива, вычислялась либо на CUDA,
либо на CPU, но при этом варианте необходимо продумать эффективное
хранение текущего массива.
3.2.3. АЛГОРИТМ ПОСТРОЕНИЯ ПРОСТОГО МНОГОУГОЛЬНИКА МЕТОДОМ
РАЗДЕЛЕНИЯ ПРОСТРАНСТВА
Алгоритм
строит
произвольный
простой
многоугольник
за
оптимальное количество операций и принадлежит к классу рекурсивных
алгоритмов. Он рекурсивно делит множество точек, пока в подмножестве не
окажется всего две точки (или одна), а потом строит отрезок и рекурсивно
соединяет отрезки в цепь [37][40] (рисунок 9).
Рис. 9. Разделение множества S '
Алгоритм рекурсивно разделяет исходное множество точек на
подмножества, которые имеют разные выпуклые оболочки. Пусть S ' будет
таким подмножеством S. (Тогда, CH( S ' ) (выпуклая оболочка S ' ) не содержит
не одной точки из S\ S ' .) Когда генерируется многоугольник Р гарантируется,
что пересечение Р с CH( S ' ) состоит из единственной цепи. Первая точка этой
цепи обозначается s 'f , а ее последняя точка обозначается s l' . Заметим, что и
s 'f , и s l' находятся на границе CH( S ' ).
Во время фазы инициализации алгоритма выбирается s 'f и s l' из S
случайно. Тогда оставшиеся точки разделяются на левое и правое
подмножество линией l( s 'f , s l' ). Для общего вызова рекурсии алгоритма
рассмотрим подмножество S ' созданное этим рекурсивным разделением и
пусть s 'f будет его первой точкой, а s l' будет его последней точкой. Если s 'f и
s l' это последние точки в S ' , тогда выходом является отрезок соединяющий
эти две точки и рекурсия останавливается. Иначе, S ' расщепляется в два
подмножества S ' ' и S ' ' ' следующим образом:
1. Выбирается случайно точка s ' из S ' .
2. Проводится случайная линия l через
s'
такая что l пересекает
отрезок s 'f s l' . Линия l разделяет S ' в два подмножества S ' ' и S ' ' ' ,
где S ' ' имеет s 'f в качестве начала и s ' в качестве конца.
Аналогично, S ' ' ' имеет s ' в качестве начала и s l' в качестве конечной
точки (рисунок 9)
Procedure CreatePartion(S, size, e)
Begin
If size > 2 then
Begin
S1 = подмножество S левее е;
S2 = подмножество S правее е;
e0 = отрезок проходящий через середину е;
е1 = (e0, конец точки е);
е2 = (начало точки е, e0);
CreatePartion(S1, size(S1), e1);
CreatePartion(S2, size(S2), e2);
End;
If size = 2 then InsertPointInPolygon(); конец рекурсии
End.
Download