OpenCL for-loop делает странные вещи

#for-loop #opencl #noise

#для цикла #opencl #шум

Вопрос:

В настоящее время я внедряю генерацию ландшафта в OpenCL, используя многоуровневые октавы шума, и я наткнулся на эту проблему:

 float multinoise2d(float2 position, float scale, int octaves, float persistence)
{
    float result = 0.0f;
    float sample = 0.0f;
    float coefficient = 1.0f;

    for(int i = 0; i < octaves; i  ){
        // get a sample of a simple signed perlin noise
        sample = sgnoise2d(position/scale);

        if(i > 0){
            // Here is the problem:

            // Implementation A, this works correctly.
            coefficient = pown(persistence, i);

            // Implementation B, using this only the first
            // noise octave is visible in the terrain.
            coefficient = persistence;
            persistence = persistence*persistence;
        }

        result  = coefficient * sample;
        scale /= 2.0f;
    }
    return resu<
}
  

OpenCL распараллеливает for-циклы, что приводит к проблемам синхронизации здесь, или я что-то еще упускаю?

Любая помощь приветствуется!

Комментарии:

1. где этот код использует OpenCL? OpenCL не распараллеливает for-циклы. Вам нужно написать код, используя поток / блоки.

2. @Vivek G: некоторые компиляторы OpenCL могут автоматически изменять вектор для циклов.

3. @Anselm: Вы предполагаете, что разделение pown на два отдельных оператора является потенциальной угрозой синхронизации? Но pown — это не атомарная функция; у нее тоже могут быть проблемы с синхронизацией. Но, как сказал Джеймс ниже, вся ваша память является частной для рабочего элемента, поэтому это спорный вопрос.

Ответ №1:

проблема вашего кода в строках

 coefficient = persistence;
persistence = persistence*persistence;
  

Это должно быть изменено на

 coefficient = coefficient *persistence;
  

в противном случае на каждой итерации

первый коэффициент увеличивается только за счет постоянства

 pow(persistence, 1) ; pow(persistence, 2); pow(persistence, 3) ....
  

Однако вторая реализация идет

 pow(persistence, 1); pow(persistence, 2); pow(persistence, 4); pow(persistence, 8) ......
  

вскоре «постоянство» превысит предел для float, и вы получите нули (или неопределенное поведение) в своем ответе.

ОТРЕДАКТИРУЙТЕ еще две вещи

  1. Накопление (реализация 2) — не очень хорошая идея, особенно с действительными числами и алгоритмами, которые требуют точности. Возможно, вы теряете небольшую часть вашей информации каждый раз, когда вы накапливаете «постоянство» (например, из-за округления). Предпочитайте прямое вычисление (1-я реализация), а не накопление, когда можете. (плюс, если это было последовательным, 2-я реализация будет легко распараллеливаемой.)
  2. Если вы работаете с AMD OpenCL, обратите внимание на функции pow(). У меня неоднократно возникали проблемы с ними на нескольких машинах. Функции, кажется, иногда зависают без причины. Просто К вашему сведению.

Комментарии:

1. Базовая математика снова терпит неудачу. Спасибо и за советы!

Ответ №2:

Я предполагаю, что это какой-то служебный метод, который вызывается в вашем ядре CL. Вивек прав в своем комментарии выше: OpenCL не распараллеливает ваш код за вас. Вы должны использовать возможности OpenCL для разделения вашей проблемы на фрагменты, параллельные данным.

Кроме того, я не вижу потенциальной проблемы синхронизации в приведенном выше коде. Все ваши переменные находятся в личном пространстве памяти рабочего элемента.

Комментарии:

1. хорошо, тогда все в порядке, поскольку я не хочу распараллеливать эту часть кода (и не могу, поскольку постоянные обратные связи). Есть идеи, почему итеративная мощность не работает, но работает pown?