Вот вопрос об алгоритмах графического процессора, относящийся к проблеме, которую я пытаюсь ускорить:
Предположим, у меня концептуально есть поле данных, подобное следующему, где 512 - количество потоков в блоке:
bool is_a_foo[131072][512];
bool
в этой структуре представляют, являются ли данные в другом месте (которые имеют схожие измерения ... но это не имеет значения) как foo
.Для простоты, давайте предположим, что я просто работаю на одном блоке графического процессора, с каждым разрывающимся потоком (на шаге блокировки через __syncwarp()
... но, пожалуйста, не позволяйте этому быть слишком отвлекающим, как на практике я делаючто-то более чувственное) локации 0
-> 131071
.Другими словами, код каждого потока выглядит примерно так:
// assume is_a_foo is initialized earlier to 0's by some sort of memset call
// assume that the values for is_a_foo can go from false->true but never from true->false
for (int i = 0; i < 131072; ++i) {
if (something_kind_of_expensive_but_not_the_bottleneck()) {
is_a_foo[ i ][thread] = true;
}
}
Если каждый bool
представлен как 8 битов, данные не теряются.Тем не менее, давайте предположим, что я хотел бы уменьшить объем занимаемой памяти / кеша и потребление пропускной способности.Вместо этого мы могли бы представить вышеупомянутую структуру данных как:
unsigned int is_a_foo[131072][512 / (sizeof(unsigned int) * 8)];
И мы можем выполнить битовую арифметику, чтобы установить интересующий бит равным 1.
Проблема в том, что без какой-либо специальной обработки,записи в is_a_foo
будут разбивать друг друга, и не каждый бит, который должен быть установлен в 1, обязательно будет установлен в 1.
В случае, если мы хотим сделать что-то особенное, мыможно использовать atomicCAS
, чтобы гарантировать, что никакие записи не будут потеряны.К сожалению, это кажется довольно дорогим.Действительно, в моем приложении, где запуск ядра занимает около 30 миллисекунд, время выполнения ядра увеличивается на ~ 33%.В настоящее время неясно, связано ли дополнительное время с атомной операцией или дополнительными инструкциями, но я подозреваю, что это атомная операция.
Одна вещь, которая смогла бы смягчить ущерб, была бы, если бы я мог работать на unsigned char
с вместо unsigned int
с.К сожалению, CUDA не предоставляет такого интерфейса.И, когда я работаю на unsigned short
s, я получаю ошибку компилятора о том, что функция недоступна для unsigned short
s (подробности доступны по запросу).
Все это спрашивать, Существуют ли алгоритмы / структуры данных, которые хорошо подходят для этого типа операций на графическом процессоре ?