GCC 8.1.0 / MinGW64-скомпилированная программа OpenMP вылетает в поисках cygwin.s? - PullRequest
0 голосов
/ 24 января 2019
  • Я изучаю OpenMP на C ++, используя gcc 8.1.0 и MinGW64 (последняя версия этого месяца), и сталкиваюсь со странной ошибкой отладки, когда моя программа сталкивается с ошибкой сегментации.

  • Я знаю причину сбоя, пытаясь создать слишком много потоков OpenMP (50000), но сама ошибка меня озадачила.Я не компилировал gcc или MinGW64 из исходных кодов, я просто использовал установщики, и я на Windows.

  • Почему он ищет cygwin.s и зачем использовать эту файловую структуру в Windows?Мой код и сообщение об ошибке от GDB ниже закрытия.

  • Я изучаю OpenMP в процессе программирования трассировщика пути, и я думаю, что у меня есть обходной путь для ограничения потока (используя while (потоки <прогоны) и позволяя OpenMP установитьподсчет потоков автоматически), но я озадачен относительно ошибки.Есть ли обходной путь или решение для этого?</p>

  • Отлично работает с ~ 10000 потоков.Я знаю, что на самом деле он не создает одновременно 10 000 потоков, но это то, чем я занимался до того, как подумал об обходном пути.

Спасибо за советы по поводу rand () и безопасности потоков.Я закончил тем, что заменил свой код RNG на код, который, кажется, работает нормально в OpenMP, и визуально это разница между днем ​​и ночью.Я попробую другие изменения и сообщу.Спасибо!

ВАУ!Он работает намного быстрее и изображение не содержит артефактов!Спасибо!

Jadan Bliss

Финальный код:

#pragma omp parellel
for (j = options.height - 1; j >= 0; j--){
    for (i=0; i < options.width; i++) {
            #pragma omp parallel for reduction(Vector3Add:col)
            for (int s=0; s < options.samples; s++)
            {
                float u = (float(i) + scene_drand()) / float(options.width);
                float v = (float(j) + scene_drand()) / float(options.height);
                Ray r = cam.get_ray(u, v); // was: origin, lower_left_corner + u*horizontal + v*vertical);

                col +=  color(r, world, 0);
            }

            col /= real(options.samples);
            render.set(i,j, col);
            col = Vector3(0.0);
    }
}

Ошибка:

Запуск программы: C: \ Users \ Jadan \Документы \ CBProjects \ learnOMP \ bin \ Debug \ learnOMP.exe [Новая тема 22136.0x6620] [Новая тема 22136.0x80a8] [Новая тема 22136.0x8008] [Новая тема 22136.0x5428]

Тема 1 получила сигнал SIGSEGV, сегментациянеисправность.___chkstk_ms () в ../../../../../src/gcc-8.1.0/libgcc/config/i386/cygwin.S:126 126
../../ ../../../src/gcc-8.1.0/libgcc/config/i386/cygwin.S: Нет такого файла или каталога.

1 Ответ

0 голосов
/ 24 января 2019

Вот некоторые замечания по вашему коду.

Использование огромного количества потоков не принесет вам никакой выгоды и является вероятной причиной ваших проблем. Создание потока требует затрат времени и ресурсов. Из-за временных затрат это, вероятно, будет основным временем в вашей программе, и ваша параллельная программа будет намного длиннее, чем ее последовательная версия. Что касается стоимости ресурсов, каждый поток имеет свой собственный сегмент стека. Его размер зависит от системы, но типичные значения измеряются в МБ. Я не знаю характеристик вашей системы, но с 100000 потоков это, вероятно, причина сбоя вашего кода. У меня нет объяснения для сообщения о cygwin.s, но после переполнения стека поведение может быть странным.

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

Кроме того, есть и другие проблемы.

rand() не является поточно-безопасным , поскольку использует глобальное состояние, которое будет изменяться одновременно потоками. rand_r(), поскольку состояние генератора случайных чисел не является глобальным и может храниться в каждом потоке.

Не следует изменять общую переменную, например result, без атомарного доступа , поскольку одновременный доступ к потокам может привести к неожиданным результатам. Хотя использование атомной модификации для каждого значения безопасно, это не очень эффективное решение. Атомный доступ очень дорог, и лучше использовать сокращение, которое делает локальное накопление в каждом потоке, и уникальный атомарный доступ в конце.

#include <omp.h>
#include <iostream>
#include <random>
#include <time.h>

int main()
{
    int runs = 100000;
    double result = 0.0;
#pragma omp parallel
    {
      // per thread initialisation of rand_r seed.
      unsigned int rand_state=omp_get_thread_num()*time(NULL);
                     // or whatever thread dependent seed
#pragma omp for reduction(+:result)
      for(int i=0; i<runs; i++) 
        {
          double d = double(rand_r(&rand_state))/double(RAND_MAX);
          result += d;
        }
    }
    result /= double(runs);
    std::cout << "The computed average over " << runs << " runs was " 
           << result << std::endl;
    return 0;
}
...