Реализация пользовательского atomic_add (), который работает с плавающей точкой - PullRequest
1 голос
/ 23 марта 2019

Я пытаюсь следовать разделу B.12 https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html для атомарного добавления, которое работает с плавающей точкой. Простое копирование и вставка кода оттуда и изменение типов на плавающие не работает, потому что я не могу выполнить приведение указателя приведения из GLOBAL в PRIVATE, требуемый для операции atomicCAS. Чтобы преодолеть это, я решил использовать atomic_xchg (), потому что он работает с плавающей точкой, с дополнительным оператором if для достижения той же функциональности, что и atomicCAS. Тем не менее, при каждом сложении с большим вектором с плавающей запятой каждый раз я получаю разные ответы.

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

kernel void atomicAdd_2(volatile global float* address, float value)
{
    float old = *address, assumed;

    do {
        assumed = old;
        if (*address == assumed) {
            old = atomic_xchg(address, value + assumed);
        }
        else{
            old = *address;
        }
        // Note: uses integer comparison to avoid hang in case of NaN (since NaN != NaN)
    } while (assumed != old);
}

Это моя реализация atomicAdd для чисел с плавающей запятой.

kernel void reduce_add(global const float* input, global float* output) {
         float temp = 242.23f;
         atomicAdd_floats(&output[0], temp);
         printf(" %f ", output[0]);

}

Это функция, в которой я предоставляю аргументы для atomicAdd_floats. Обратите внимание, что мой входной аргумент содержит вектор с плавающей точкой, а выходной аргумент - это просто место, где я хочу сохранить результат, в частности, в первом элементе выходного вектора output [0]; но вместо этого, когда я printf ("% f", output [0]); он показывает мое значение инициализации по умолчанию 0.

Comparison of serially computed ground truth sum against parallel output B

1 Ответ

0 голосов
/ 26 марта 2019

Прежде всего, я бы предложил удалить ключевое слово "kernel" в функции atomicAdd_2. «Ядро» следует использовать только для тех функций, которые вы собираетесь ставить в очередь с хоста. Во-вторых, в сети есть OpenCL-реализации atomic-add-float .

Тогда я немного озадачен тем, что вы пытаетесь сделать. Вы пытаетесь суммировать вектор и имея сумму в закрытой переменной? если это так, то нет смысла использовать atomicAdd. Личная память всегда атомарна, потому что она личная. Атомарность требуется только для глобальных и локальных воспоминаний, потому что они являются общими. В противном случае я не уверен, почему вы упоминаете об изменении адреса или ГЛОБАЛЬНОГО на ЧАСТНЫЙ.

В любом случае код по ссылке должен работать, хотя он относительно медленный. Если вектор для суммирования велик, вам может быть лучше использовать другой алгоритм (весовые частичные суммы). Попробуйте поискать "параллельная сумма opencl" или что-то подобное.

...