LINUX.ORG.RU

5
Всего сообщений: 31

Параллельный итератор для stencil-вычислений?

пардонте, тут будет некоторый поток сознания;-(

Есть многомерный массив, причем он может быть устроен достаточно сложным образом. Нам нужно взять каждый элемент этого массива и что то с ним сделать с учетом его соседей. Соседи расположены по некоторому шаблону, скажем ближайшие соседи (слева/справа/сверху/снизу) это шаблон «крест», бывают и более сложные шаблоны. Это называется stencil-вычислениями и условно половина числодробилок именно таким вот и занимается.

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

Уже хочется наконец какой то вменяемой концепции для решения таких задач. Пока что придумалось следующее.

  1. Есть счетчик size_t i (потому что OpenMP), все ячейки массива пронумерованы подряд.

  2. Доступ к элементу массива по такому счетчику это дорого. Поэтому есть некий недоитератор I (я не знаю как это называется правильно), который может быть настроен на основе i. Если все сделано прямыми руками, то небольшие изменения i как правило приводят к минимальной перестройке I. Тогда можно написать что то вроде

#pragma omp parallel for firstprivate(I)
   for(size_t i=0; i<N; i++){ 
       I.update(i); 
       ...
    }

Будучи настроенным, I ведет себя как умный указатель, то есть у него перегружены операции -> и *. М.б. его и инкрементировать можно - тогда это обычный итератор, но с возможностью update(i). Кроме того I может давать кучу дополнительной информации (координаты ячейки например), и тогда это уже больше чем итератор получается?

  1. Есть шаблон S[n], это набор из n смещений относительно обрабатываемого элемента массива. Шаблон известен заранее, поэтому можно сгенерировать заранее массив каких то структур, которые относительно малой кровью позволяют от I обращаться к его соседям. Для обычного многомерного массива (который эмулируется на основе одномерного массива + адресная арифметика) это будут просто целые числа, в более сложных случаях это может быть что то выморочное. Есть нюанс - при обращении к соседям надо как то обрабатывать выход за границы многомерного массива.

С обработкой границ все сложно и это уже сильно зависит от того что именно за многомерный массив и что именно мы делаем при выходе за границу. По крайней мере можно рассмотреть два подхода:

  1. I.get_nb(S[k]) — принимает какой то элемент шаблона, возвращает указатель на соседнюю ячейку или nullptr. Хотя это кривовато - для анализа выхода за границу может понадобиться много операций, кроме того nullptr может оказаться недостаточно, иногда хочется унать куда именно (налево/направо) мы вылетели.

  2. I.get_nb(k) — принимает номер элемента шаблона, возвращает указатель на соседнюю ячейку или nullptr. Это чуть лучше, поскольку шаблон известен заранее, можно сделать маски какой элемент шаблона куда сдвинут.

Наверное можно и каких то методов навешать на I что бы понимать куда относительно границы мы попали…

Вопрос - как правильно называются I? Как правильно называются S (если называются)? И как вообще Ъ делают такие вещи в Ъ программировании?;-)

Cast @pon4ik, @monk, @peregrine

 , , , ,

AntonI ()

Openmp and POSIX in GCC 8.2.0

Добрый день! Поясните пожалуйста следующий вопрос: собрал Linux для ARM Cortex A9 (Zynq FPGA) с компилятором: gcc version 8.2.0

Пытаюсь скомпилировать С файл с примером для Openmp:

#include <omp.h>
#include "stdio.h"
int omp_get_thread_num();
int main()
{
	# pragma omp parallel
	{
	  printf("Thread rank: %d\n", omp_get_thread_num());
	}
}

появляется ошибка

fatal error: omp.h: No such file or directory

вывод команды gcc -v

Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/libexec/gcc/arm-xilinx-linux-gnueabi/8.2.0/lto-wrapper Target: arm-xilinx-linux-gnueabi Configured with: ../../../../../../work-shared/gcc-8.2.0-r0/gcc-8.2.0/configure --build=x86_64-linux --host=arm-xilinx-linux-gnueabi --target=arm-xilinx-linux-gnueabi --prefix=/usr --exec_prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --libexecdir=/usr/libexec --datadir=/usr/share --sysconfdir=/etc --sharedstatedir=/com --localstatedir=/var --libdir=/usr/lib --includedir=/usr/include --oldincludedir=/usr/include --infodir=/usr/share/info --mandir=/usr/share/man --disable-silent-rules --disable-dependency-tracking --with-libtool-sysroot=/scratch/petalinux-yocto/yocto_downloads_2019.1_zynq-generic/build_zynq-generic/tmp/work/cortexa9t2hf-neon-xilinx-linux-gnueabi/gcc/8.2.0-r0/recipe-sysroot --with-gnu-ld --enable-shared --enable-languages=c,c++ --enable-threads=posix --enable-multilib --enable-default-pie --enable-c99 --enable-long-long --enable-symvers=gnu --enable-libstdcxx-pch --program-prefix=arm-xilinx-linux-gnueabi- --without-local-prefix --enable-lto --disable-libssp --enable-libitm --disable-bootstrap --disable-libmudflap --with-system-zlib --with-linker-hash-style=gnu --enable-linker-build-id --with-ppl=no --with-cloog=no --enable-checking=release --enable-cheaders=c_global --without-isl --with-float=hard --with-sysroot=/ --with-build-sysroot=/scratch/petalinux-yocto/yocto_downloads_2019.1_zynq-generic/build_zynq-generic/tmp/work/cortexa9t2hf-neon-xilinx-linux-gnueabi/gcc/8.2.0-r0/recipe-sysroot --with-gxx-include-dir=/usr/include/c++/8.2.0 --without-long-double-128 libgcc_cv_powerpc_float128=no --disable-static --enable-nls --enable-initfini-array --with-arch=armv7-a+fp Thread model: posix gcc version 8.2.0 (GCC)

Файлы с POSIX компилируются без проблем, но очень хочется иметь поддержку Openmp. Какие существуют возможные варианты решения данной ситуации?

 , , ,

Alexey_Rostov ()

OpenMP + ARM Linux нет увеличения скорости for loop

Здравствуйте! Подскажите пожалуйста почему при подключении openmp не удается уменьшить время работы программы.

Плата imx8 с Cortex A53

Содержимое файла main.cpp

#include <iostream>
#include <opencv2/opencv.hpp>
#include <vector>
#include <math.h>
#include <time.h>
#include <omp.h>

#define CHANNELS 4
using namespace std;
using namespace cv;

int main()
{
    cout << "Start programm" << endl;

    vector<Mat>      matrix_1(CHANNELS);
    vector<Mat>      matrix_2(CHANNELS);
    vector<Mat>      result(CHANNELS);
    Mat rnd_image = Mat(2048, 2048, CV_32FC1, Scalar(0));
    // matrix initialization

    clock_t start, end;
    double cpu_time_used;
	
	for (int i = 0; i < CHANNELS; i++) {
        randn(rnd_image, Scalar(0), Scalar(16000));
        rnd_image.copyTo(matrix_1[i]);
        randn(rnd_image, Scalar(0), Scalar(16000));
        rnd_image.copyTo(matrix_2[i]);
	}
	
	start = clock();
    for (int i = 0; i < CHANNELS; i++) {
        multiply(matrix_1[i], matrix_2[i], result[i]);
    }
    end = clock();
    cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;

    cout << "Time taken by for_loop: " << cpu_time_used << " seconds " << endl;
	
    start = clock();
	
	#pragma omp parallel num_threads(2)
	for (int i = 0; i < CHANNELS; i++) {
		multiply(matrix_1[i], matrix_2[i], result[i]);
	}

    end = clock();
    cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;

    cout << "Time taken by for_loop with openmp: " << cpu_time_used << " seconds " << endl;
    return 0;
}

Команда для компиляции (флаг -fopenmp добавлен)

g++ main.cpp -fopenmp -I /usr/include/opencv2 -L /usr/lib -lopencv_core

Прописал переменную

root@imx8m-var-dart:~/test# printenv OMP_NUM_THREADS
2
root@imx8m-var-dart:~/test#

Компилирую и запускаю программу

root@imx8m-var-dart:~/test# ./a.out
Start programm
Time taken by for_loop: 0.930273 seconds
Time taken by for_loop with openmp: 1.83559 seconds
root@imx8m-var-dart:~/test#

По идее время на выполнение должно быть в два раза меньше... Что делаю не так?

 , , ,

Alexey_Rostov ()

Инструмент для обнаружения гонки данных?

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

А теперь как мне проверить что это правильно работает?;-)

Ну то есть понятно, что я могу запустить последовательную версию и сравнить ее результаты с параллельной. Но может есть какая то хитрая утилита которая сразу ткнет меня носом - вот тут конфликт между потоками?

 , , ,

AntonI ()

Распараллеливание брутфорса с помощью OpenMP

Пытаюсь ускорить процесс подбора ключа, но не понимаю, как правильно применить распараллеливание.

Прошу наставлений и помощи, так как знаний не хватает, а Си я вижу буквально 5-й день в жизни. Код следующий:

int brute ( u8 brute_key[0x10], char *target_dat, char *target_key )
{
  // (TODO) Не хочу читать одн и тот же кусок файла при каждом проходе:
  static u8 buffer_enc_default[0x40];   // Будет хранить оригинальное значение
  memset (buffer_enc_default, 0, 0x40); // Очистка выделенной памяти

  FILE *fp=fopen(target_dat,"rb");
  fseek(fp,0x40,SEEK_SET);
  fread(buffer_enc_default,1,0x40,fp);  // Чтение оригинального значения
  fclose(fp);

  static int i1,i2,i3,i4,i5,i6,i7,i8; // Перебор младших 8 байт (i = индекс)
  i1=i2=i3=i4=i5=i6=i7=i8=0;
  static int flag = TRUE; // Этот флаг позволит прыгнуть на стартовую позицию

  for(i1=0;i1<=0xFF;i1++){
    for(i2=0;i2<=0xFF;i2++){
      for(i3=0;i3<=0xFF;i3++){
        for(i4=0;i4<=0xFF;i4++){
          for(i5=0;i5<=0xFF;i5++){
            for(i6=0;i6<=0xFF;i6++){
              for(i7=0;i7<=0xFF;i7++){
                // #prigmi omp pirillel for // <=== FIXME
                for(i8=0;i8<=0xFF;i8++){

                  if(flag){ // Переход к стартовой позиции:
                    i1 = brute_key[0x08];
                    i2 = brute_key[0x09];
                    i3 = brute_key[0x0A];
                    i4 = brute_key[0x0B];
                    i5 = brute_key[0x0C];
                    i6 = brute_key[0x0D];
                    i7 = brute_key[0x0E];
                    i8 = brute_key[0x0F];
                    flag = FALSE;
                  }

                  // Перенос текущего позиции в brute_key:
                  brute_key[0x08] = (char)i1;
                  brute_key[0x09] = (char)i2;
                  brute_key[0x0A] = (char)i3;
                  brute_key[0x0B] = (char)i4;
                  brute_key[0x0C] = (char)i5;
                  brute_key[0x0D] = (char)i6;
                  brute_key[0x0E] = (char)i7;
                  brute_key[0x0F] = (char)i8;

                  // Объявление переменных:
                  u8 buffer[0x40];
                  u8 zero_iv[0x10];
                  u8 buffer_enc[0x40];
                  u8 buffer_dec[0x40];
                  u8 key[0x10];
                  u8 iv[0x10];

                  // Заполнение переменных нолями:
                  memset (buffer, 0, 0x40);
                  memset (buffer_enc, 0, 0x40);
                  memset (buffer_dec, 0, 0x40);
                  memset (zero_iv, 0, 0x10);

                  // Магия:
                  memcpy (buffer, brute_key, 0x10);
                  vtrm_encrypt (3, buffer, zero_iv);
                  memcpy (key, buffer, 0x10);
                  memcpy (iv, buffer + 0x10, 0x10);
                  memcpy (buffer_enc, buffer_enc_default, 0x40); // <=== TODO
                  aes128cbc (key, iv, buffer_enc, 0x40, buffer_dec);

                  // Проверка результата:
                  if(memcmp(buffer_dec+0x30,zero_iv,0x10)==0){
                    printf("Поздравляю!\n");
                    FILE *fx= fopen(target_key,"wb");
                    fwrite(brute_key,1,0x10,fx);
                    fclose(fx);
                    exit (1) ; //return 0;
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  return -1;
}

 , ,

zzdnx ()

Как распараллелить данный код openmp?

Помогите пожалуйста распараллелить задачу n ферзей. Код работает правильно, осталось только распараллелить

#include<iostream>
#include<stdio.h>
#include <sys/time.h>
#include <cmath>
#include "omp.h"
using namespace std;
//Размерность доски NхN (Количество ферзей - N)
   const int N=12;  int X[N];  int Count;

  bool P(int X[N],int k,int y){  // Поиск позиции для ферзя
	int i=0;
	while ((i<k)&&(y!=X[i])&&(abs(k-i)!=abs(y-X[i]))) {i++;}
	if(i==k)
	return true;
	else return false;  
	}

  void Backtracking(int k){ // Поиск с возвратом позиций
		int i,y;
		for (y=0;y<N;y++)
		if (P(X,k,y)){ 
				X[k]=y;
				if (k==N-1){
					Count++; 
				}
			Backtracking(k+1); 		
		} 
	}	
	
 int main(){ 
	double iv;
	struct timeval st, et;
	gettimeofday(&st, NULL); 
	Count=0;
	cout<<"Doska "<<N<<" na "<<N<<endl;
	omp_set_num_threads(1);
	
	Backtracking(0);
	
   	gettimeofday(&et, NULL);
    iv = (et.tv_sec * 1.0e6 + et.tv_usec) - (st.tv_sec * 1.0e6 + st.tv_usec);
	cout<<"Vsego "<<Count<<" rasstanovok";
   	cout<<"Time: "<< iv / 1e6 <<"sec." << endl;
   }

 ,

ADamCarraway ()

Потоки в си

Есть 2 потока. Один принимает данные, другой ждёт, когда данные придут и что-то делает. Потом опять ждёт и т.д. по кругу. Нужен красивый и простой пример с openmp или кроссплатформенной либой. На pthread сделал, а с openmp какая-то жесть, вообще не понимаю, что они там мутят.

 , ,

crutch_master ()

Распараллеливание с помощью openmp

Вообщем пытаюсь использовать Openmp, чтобы распараллелить задачу вычисления экспоненты с помощью ряда Тейлора. Программа работает, но при сравнении времени выполнения последовательного кода и с Openmp, нет прироста скорости, а даже наоборот выполняется дольше с Openmp. В чем может быть причина?

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>
int fact(int c);
double taylor(double x, int n);
 
int main(int argc, char *argv[]) {
  double x=0;
  int n=0;
  int n_max = 32;
  if (argc != 3) {
  printf("Input three parametrs!\n");
  return 1;
}
  sscanf(argv[1], "%lf", &x);
  sscanf(argv[2], "%d", &n);

 if((n>n_max)||(n<0)) {
 printf("Invalid parameter n, enter n from 0..10\n");
 return 1;
 }
    
 int i; 
 double sum=0 ;
 double t = omp_get_wtime();
 
  #pragma omp parallel for private(i) reduction(+: sum)
   for (i=1; i<=n; i++) {
	  double taylor = pow(x,i)/fact(i);
	  sum+=taylor;
  }
  
  double diff = omp_get_wtime() - t; 
  printf("e^x = %lf\n Time: \t %lf\n", ++sum, diff);
  return 0;
}

int fact(int c) {
   int fact=1;
   int i;
   for (i = 1; i <= c; i++ ) {
      fact *=i;
   }
   return fact;
}

 , , , ,

shonny ()

Чем объясняется снижение эффективности параллельных вычислений

На примере openmp Количество потоков - Эффективность 1 - 100%, 2 - 72%, 4 - 64%,

На практике эффективность убывает при увеличении числа процессоров. Чем это объяснить?

 

brecon ()

Ошибка при совместном ипользовании OpenMP и MPI на Ломоносове-1

Есть довольно монструозный проект, одновременно использующий OpenMP и MPI. При запуске на Ломоносов-1 в OpenMP возникает довольно странная ситуация - при входе в параллельную область

#pragma omp parallel
{
}
запускается несколько нитей (это видно по отладочному выводу и пр. диагностике), при этом все нити имеют нулевой ID, в каждой нити число запущенных нитей указывается как единица, и omp_get_level() возвращает ноль.

Иерархический параллелизм (так кажется оно называется) OpenMP не используется, т.е. pragma parallel не вложена. Ошибка наблюдается только на Ломоносове-1 (из доступных машин, на к100 ее нет), причем минимальный тест сделать не получается (в минимальном тесте все работает). Проект здоровый, вычленить там что то весьма затруднительно, с учетом того что каждого запуска приходиться ждать...

Кто то с таким сталкивался? Что можно сделать, ну кроме как отказаться от OpenMP (что мы пока и сделали)?

Опции компиляции

-fopenmp -msse2 -msse -mpreferred-stack-boundary=4 -std=c++11 -O2 -g -Wall -I./
компилятор
$ mpicxx -v
mpiicpc for the Intel(R) MPI Library 5.0 Update 1 for Linux*
Copyright(C) 2003-2014, Intel Corporation.  All rights reserved.
icpc version 15.0.0 (gcc version 4.4.7 compatibility)

 ,

AntonI ()

Пытаюсь освоить openmp

Задача: сложить два массива в третий (все массивы одинаковой длины для простоты).
Как пытаюсь решить: http://pastebin.com/GSMzMZhT
По какой-то причине не работает на входах размером от 32к (суммы в случае последовательного кода и параллельного получаются разными). ЧЯДНТ?

 ,

DaniilA ()

Прервать выполнение openmp-секции

Хочется сделать что то вроде:

int foo(cinst size_t n){
	#pragma omp parallel for
	for(size_t i=0; i<n; n++){
		...
		if(smth_error) return 1;
	}
	#pragma omp parallel for
	for(size_t i=0; i<n; n++){
		...
		if(other_error) return 2;
	}
	return 0;
}
Но return из openmp блока сделать нельзя, а городить исключения не хочется. Как сделать правильно?

 , ,

thunar ()

Синхронизировать цикл внутри openmp секции?

Имеется следующая структура программы:

while(true){
	bool cond;
	#pragma omp parallel
	{
		#pragma omp single
		{
			cond = true;
		}
		while(cond){
			int n = omp_get_thread_num();
			do_stuff(n);
			#pragma omp barrier

			#pragma omp single
			{
				sync_stuff();
				cond = is_end();
			}
		}
	}
}
Есть внешний бесконечный цикл, внутри него параллельная секция. В каждом треде необходимо циклически обрабатывать независимый массив данных. Логика такова, что после каждой внутренней итерации запускается некоторый последовательный код, проверяющий, не выполнено ли условие выхода из цикла.

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

В конечном итоге, нужно просто циклически параллельно запускать do_struff(), а вся эта свистопляска с синхронизацией циклов вылезла из за того, что если написать просто:

while(true){
	bool cond = true;
	while(cond){
		#pragma omp parallel
		{
			int n = omp_get_thread_num();
			do_stuff(n);
		}
		sync_stuff();
		cond = is_end();
	}
}
то, временные затраты на спавн тредов оказываются слишком большими.

 ,

thunar ()

openmp и сигналы

Как в openmp-приложении правильно обрабатывать сигналы? Например, имеется приложение, которое в бесконечном цикле выполянет некоторую работу, нужно по получении сигнала остановить параллельную секцию и выполнить обработку, а затем продолжить счёт. Как это правильно сделать, должны ли внутри обработчика быть какие-то openmp-директивы?

int main(int argc, char** argv){
	signal(SIGINT, signal_callback_handler);
	while(true){
		#pragma omp parallel
		{
			//some work
		}
	}
}

 , ,

thunar ()

посоветуйте тредобезопасный генератор случайных чисел

Необходимо в нескольких потоках генерировать много случайных чисел для Монте-Карло моделирования. Что посоветуете использовать?

 , ,

thunar ()

несоответствие версий библиотек на разных компьютерах

написал маленький hello_world с велосипедами и #pragma omp parallel (для распараллеливания)...
скомпилировал: с++11 -fopenmp -O3
этого показалось не достаточно...
и я скинул hello_world на кластер с pbs-планировщиком:

1. #pragma omp parallel работает же на кластерах?

но проблемы появились ранее ожидаемого:

$ ldd hello_world
./hello_world: /usr/lib/x86_64-linux-gnu/libgomp.so.1: version 'GOMP_4.0' not found (required by ./hello_world)
./hello_world: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version 'GLIBCXX_3.4.21' not found (required by ./hello_world)

2. как бороться с этими несоответствиями в версиях библиотек при компиляции?

p.s. прав root'a нет.
p.s.s видел решение в виде копирования libgomp.so.1 файла в папку и последующим запуском: $ ./libgomp.so.1 ./hello_world но это же не выход?

 , , ,

rgB ()

Вебинар: Основы распараллеливания С/С++ программ при помощи OpenMP

Команда FlyElephant продолжает проведение вебинаров и я хочу пригласить всех 28 сентября в 17.00 на вебинар, на котором мы рассмотрим основы распараллеливания С/С++ программ при помощи OpenMP, познакомимся с функционалом FlyElephant и освоим на примерах принципы работы с платформой. Поговорим о программе бета-тестирования и новом функционале, который будет доступен в ближайшее время.

Отдельно в рамках вебинара мы анонсируем специальную программу поддержки открытых исследований, которая позволит проектам бесплатно пользоваться платформой.

Зарегистрироваться на вебинар можно здесь.

FlyElephant - платформа для научных вычислений и управления данными. В едином месте доступны различные вычислительные ресурсы (многоядерные системы, HPC и GPU кластера), программы, шаблоны, алгоритмы и данные, которые пользователи могут комбинировать для быстрого и эффективного решения своих вычислительных задач. Пользователи также могут совместно работать над проектами, отслеживать изменения в результатах вычислений и публиковать полученные решения как публичные или частные облачные сервисы.

Сейчас платформа запущена в тестовом режиме и позволяет выполнять вычислительные программы написанные на С/С++ с поддержкой OpenMP на серверах с количеством ядер от 1 до 32 и ОЗУ до 448 ГБ, а также работать с данными в хранилище, просматривать и загружать результаты расчетов.

Для нас очень важны любые замечания, предложения и комментарии. Я с радостью отвечу на них в комментариях к этому посту или на почте support@flyelephant.net.

Присоединяйтесь к нам в Facebook, Twitter и Habrahabr.

Буду рад сотрудничеству.

С уважением,
Дмитрий Сподарец
CEO & Founder FlyElephant

Регистрация

Перемещено splinter из conference

 , ,

m31 ()

собрать Qt приложение с openmp

Решил распараллелить некоторый код в Qt приложении. Расчеты выполняются в цикле и больших усилий процесс расспараллеливания не вызывает (в код всего лишь добывил перед циклом #pragma omp parallel for ...). Пробую собрать:

qmake -project && qmake QT+=sql QMAKE_CXXFLAGS+=-fopenmp && make 

ошибки:

undefined reference to `GOMP_loop_static_start'
undefined reference to `GOMP_loop_static_next'
undefined reference to `GOMP_loop_end_nowait'
undefined reference to `GOMP_parallel_start'
undefined reference to `GOMP_parallel_end'

в чем может бють проблема, если просто консольные программы без Qt нормально собираются с ключем -fopenmp? как устранить?

 ,

developer-cpp ()

MPI+OpenMP

Можно ли запустить 1 поток на одном узле и 4 потока на втором?

P.S. По умолчанию потоки деляться поровну при их запуске mpirun -np N, несмотря на OMP_NUM_THREADS, omp_set_num_threads ...

 ,

phys2015 ()

clang линкует libgomp но не использует доп. потоки

Так clang (3.4, 3.5) умеет OpenMP через libgomp или нет? Добавляю -fopenmp. Всё успешно собирается, хотя _OPENMP и не определено. Запускаю, omp_get_max_threads() реагирует на изменения OMP_NUM_THREADS, но используется всё равно только один поток. Такое впечатление, что clang просто проигнорировал все pragma, но слинковал omp_ функции к libgomp. Но кому такое нужно?

 , ,

gag ()