С Новым годом! Форум программистов, компьютерный форум, киберфорум
Наши страницы

C++

Войти
Регистрация
Восстановить пароль
 
Annie Moro
0 / 0 / 0
Регистрация: 19.05.2015
Сообщений: 2
#1

Как добиться ускорения OpenMP C++ - C++

02.05.2016, 14:13. Просмотров 418. Ответов 3
Метки нет (Все метки)

Доброго времени суток.
Я новичок в параллельном программировании. Передо мной поставили задачу расспараллелить с помощью OpenMP решение системы диффуров(в моем случае блочным методом), чтобы было ускорение хоть незначительное. Но у меня получается среднее время выполнение немного больше, в сравнении с последовательным.
Есть подозрения, что просто напросто время создания потоков и различных синхронизаций больше времени вычисления самой задачи. Например, в MPI это время существенно по понятным причинам.
Вопрос. Правильны ли мои догадки?
Спасибо
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#include <iostream>
#include <math.h>
#include <ctime>
#include <Windows.h>
#include <omp.h>
using namespace std;
 
#define M_PI 3.14159265358979323846264
 
double* func(double, double*);
 
int main()
{ int k,nx;
  double err,norm_uk,norm_u;
  
  k = 4;
 
  double *b  = new double[k];
  double **a = new double*[k];
  for (int i=0; i<k; i++) a[i] = new double[k];
 
  // численные параметры метода
  switch (k){
      case 3: b[0] =  0.375000000988621;
              b[1] =  0.166666667112590;
              b[2] =  0.125000000367365;
 
a[0][0] = 0.791666664858906; a[0][1] =  -0.208333332171824; a[0][2] =    0.041666666386801;
a[1][0] = 0.666666665998845; a[1][1] =   0.166666667065973; a[1][2] =  -0.000000000094075;
a[2][0] = 0.374999999483541; a[2][1] =   0.375000000309568; a[2][2] =   0.124999999927026;
              break;
      case 4: b[0] = 0.348611113377678;
              b[1] = 0.161111112870624;
              b[2] = 0.112500001104145;
              b[3] = 0.077777778709850;
              
a[0][0] =  0.897222216827019; a[0][1] = -0.366666661429374; a[0][2] =  0.147222219680671; a[0][3] = -0.026388888390867;
a[1][0] =  0.688888884782252; a[1][1] =  0.133333337319852; a[1][2] =  0.022222220287626; a[1][3] = -0.005555555176466;
a[2][0] =  0.424999997597292; a[2][1] =  0.300000002262193; a[2][2] =  0.174999998913219; a[2][3] = -0.012499999788098;
a[3][0] =  0.355555553501783; a[3][1] =  0.133333335324043; a[3][2] =  0.355555554589430; a[3][3] =  0.077777777967116;
              break;
  }
 
  nx = 3;   // размерность вектора решения системы ОДУ
  double *tk = new double[k];
  double *y  = new double[nx];
  double *u0 = new double[nx];
  double *uk = new double[nx];
  double **u = new double*[k],
         **s = new double*[k],
         **F = new double*[k],
         **p = new double*[k];
  for (int i=0; i<k; i++){
      u[i] = new double[nx];
      s[i] = new double[nx];
      F[i] = new double[nx];
      p[i] = new double[nx];
  }
 
  double *F0,*fx;
 
  double  t = 0;            // текущее время
  double tN = 2;            // конечное время
  double  h = 0.1;          // шаг интегрирования
  double tay = h / k;       // шаг между узлами
 
  //Время
    double start_time, end_time;
    start_time = omp_get_wtime();
 
  for (int i=0; i<k; i++) tk[i] = (i+1) * tay;
 
  // начальные условия
  y[0] = 0.01745;  y[1] = 0.035; y[2] = 0.051;
 
 // int temp_tN=tN*10;
 
   omp_set_num_threads(3);
 
//#pragma omp parallel for //private(F0,fx,u0,u,uk,err,s,F,p)
  for (t=0; t<=tN; t+=h){ 
      // начальные значения вектора узлов блока
      #pragma omp parallel for
      for (int i=0; i<k; i++) u0[i] = y[i]; 
      
      F0 = func(t,u0);
#pragma omp parallel
      {
     #pragma omp for
      for (int i=0; i<k; i++)
          for (int j=0; j<nx; j++) 
              u[i][j] = u0[j] + tk[i]*F0[j];
 
      // итерационный процесс
     #pragma omp for
      for (int j=0; j<nx; j++) uk[j] = u[k-1][j];
      }
      err = 1; 
      while (err > 1e-12){
#pragma omp parallel 
          {
        #pragma omp for
          for (int i=0; i<k; i++)
              for (int j=0; j<nx; j++)
                  s[i][j] = u0[j] + b[i]*F0[j]*tk[i]; 
      
        #pragma omp for
          for (int i=0; i<k; i++){
              fx = func(t+tk[i],u[i]);
              for ( int j=0; j<nx; j++) F[i][j] = fx[j];
          }
 
        #pragma omp for
          for (int i=0; i<k; i++){
              for (int j=0; j<nx; j++){
                  p[i][j] = 0;
                  for (int q=0; q<k; q++) p[i][j] += a[i][q]*F[q][j];
              }
          }
         
        #pragma omp for
          for (int i=0; i<k; i++)
              for (int j=0; j<nx; j++)
                  u[i][j] = s[i][j] + tk[i]*p[i][j];
      }
          norm_uk = 0; norm_u = 0;
          
        #pragma omp parallel for reduction(+:norm_uk)
          for (int j=0; j<nx; j++){
              norm_uk += uk[j]*uk[j];
          }
         #pragma omp parallel for reduction(+:norm_u)
          for (int j=0; j<nx; j++){
              norm_u  += u[k-1][j]*u[k-1][j];
          }
         
          err = fabs(sqrt(norm_uk) - sqrt(norm_u));
         
         #pragma omp parallel for
          for (int j=0; j<nx; j++) y[j] = uk[j] = u[k-1][j]; 
 
          delete fx;    
      
      }
 
      cout << t+h << '\t';
      for (int j=0; j<nx; j++)
          cout << y[j] << '\t';
      cout << '\n';
      } 
      delete F0;
 
  //Время
    end_time = omp_get_wtime();
    cout<<"time = "<< end_time-start_time<<'\n'; 
    cout<<"clock = "<<clock()<<'\n';
 
    cin.get();
    cin.get();
   
  return 1;
}
 
double* func(double t , double* x)
{ //***** Функция вычисления правой части дифференциального уравнения
  // x(1) - psi, x(2) - theta, x(3) - fi
  double *z = new double[3];
 
    #pragma omp parallel sections
    {       
        #pragma omp section
        {  
            z[0] = (0.1*sin(2*M_PI*2*t)*cos(x[2]) - 0.152*sin(2*M_PI*3*t)*sin(x[2])) / cos(x[1]);
        }
        #pragma omp section     
        { 
            z[1] = 0.1*sin(2*M_PI*2*t)*sin(x[2]) + 0.152*sin(2*M_PI*3*t)*cos(x[2]);
        }
        #pragma omp section 
        { 
            z[2] = 0.052*sin(2*M_PI*1*t) - (0.1*sin(2*M_PI*2*t)*cos(x[2]) - 0.152*sin(2*M_PI*3*t)*sin(x[2]))*tan(x[1]); 
        }
}
  return z;
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
02.05.2016, 14:13
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Как добиться ускорения OpenMP C++ (C++):

OpenMP распараллеливание цикла - C++
Привет кодеры! Нужна ваша помощь. У меня есть код который нужно распараллелить и тем самым получить выигрыш по времени выполнения. Для...

C++ OpenMP Определенный интеграл - метод Симпсона - C++
Ребят, имею следующее задание. В С++ не мастер, но я никак не могу понять, как реализовать этот интеграл с OpenMP, может кто-нибудь сможет...

Перемножения матриц с OpenMP дольше чем... - C++
Здравствуйте! Написал 2 программы перемножения матриц, одну с использованием OpenMP, другую - просто. 2 матрицы 1000х1000 с...

Параллельная программа для метода холецкого с помощью openMp и mpi - C++
Товарищи,помогите пожалуйста с параллельным программированием: надо написать параллельную программу для метода холецкого с помощью openMp...

Как ускорить эту часть кода с использованием OpenMp? - Visual C++
я пытаюсь ускорить, но разницы вообще никакой... for (int y = 0; y &lt; src-&gt;height - findp-&gt;height; y++) for (int x = 0; x &lt;...

OpenMP - Visual C++
здравствуйте, народ я делал консольное приложение с openmp, решил вот красиво оформить в формочку, а тут ошибка Command line error...

3
Petrolion
24 / 24 / 7
Регистрация: 02.02.2016
Сообщений: 124
03.05.2016, 20:02 #2
Хотел уточнить, в какой среде используете OMP?
MS VS нужно в свойствах проекта еще разрешить, иначе балласт.
Сколько ядер доступно в системе? Если ядер меньше 3 то omp_set_num_threads(3); бесполезен.
Не обязательно заходить в параллельную секцию, чтобы выполнить параллельный for. Вход-выход в секцию занимает время. Уж если зашли, так не выходите.
Но в вашем случае потери должны быть минимальны. И для вашего же случая k настолько мало, что накладные расходы по созданию и завершению процесса могут превысить полезный эффект. (Шла бы речь о k = 100; или более...). Так что ваши догадки правильные.
Попробуйте изменить алгоритм загрузив параллельные потоки, при минимальном их создании/удалении.
Например оптимизировать с 83 по 97 строки кода:
C++
1
2
3
4
5
6
7
8
9
10
11
12
F0 = func(t,y);
#pragma omp for
     for (int i=0; i<k; i++)
          for (int j=0; j<nx; j++)
          {
                 u[i][j] = y[j] + tk[i]*F0[j];
                 if (i == k-1)
                 {
                        uk[j] = u[k-1][j];
                        u0[j] = y[j];
                 }
          }
И т.д.
(Кстати, имхо, в 84 строке у вас ошибка. Почему не рушатся данные или не ругается ваш компилятор...)
А ваша функция быстрее будет работать с другой оптимизацией:
C++
1
2
3
4
5
6
7
8
9
10
11
double* func(double t , double* x)
{ //***** Функция вычисления правой части дифференциального уравнения
  // x(1) - psi, x(2) - theta, x(3) - fi
  double *z = new double[3];
  double si22 = 0.1*sin(2*M_PI*2*t);
  double si23 = 0.152*sin(2*M_PI*3*t);
  z[0] = (si22*cos(x[2]) - si23*sin(x[2])) / cos(x[1]);
  z[1] = si22*sin(x[2]) + si23*cos(x[2]);
  z[2] = 0.052*sin(2*M_PI*1*t) - (si22*cos(x[2]) - si23*sin(x[2]))*tan(x[1]); 
  return z;
}
Добавлено через 28 минут
Кажется здесь вы неэффективно используете reduction.
Цитата Сообщение от Annie Moro Посмотреть сообщение
#pragma omp parallel for reduction(+:norm_uk)
for (int j=0; j<nx; j++){
norm_uk += uk[j]*uk[j];
}
#pragma omp parallel for reduction(+:norm_u)
for (int j=0; j<nx; j++){
norm_u *+= u[k-1][j]*u[k-1][j];
}
Т.к. временные издержки ее создания превышают даже издержки создания параллельной секции. А для цикла всего из 3-х элементов.... в трехпоточной секции... да еще последовательно два таких цикла...
Судите сами.
1
Annie Moro
0 / 0 / 0
Регистрация: 19.05.2015
Сообщений: 2
04.05.2016, 20:30  [ТС] #3
MS VS , OpenMP подключила в свойствах проекта, ядер 8. Распараллеливает все как надо.
Спасибо большое за развернутый ответ с объяснениями. Все ошибки и неточности по коду поняла, буду пытаться оптимизировать. В будущем эта программа будет на 12 уравнений,но преподаватель вынудил сначала ускорить вычисление трех, хоть я и пыталась объяснить, что это не очень разумно.
Еще раз благодарю за ответ.
0
Petrolion
24 / 24 / 7
Регистрация: 02.02.2016
Сообщений: 124
04.05.2016, 20:41 #4
У вас там есть немного, что еще распараллелить.
Попробуйте на листке бумаги разложить весь алгоритм и вы найдете что можно в пучки повязать

ЗЫ. Забыл добавить. в 80 строке вашего кода вы правильно отказались от //#pragma omp parallel for
Параллельная секция работает только для for (int i=0; ... целых, с известным количеством итераций.
Посмотрите, нет ли варианте этот момент "сэмулировать" для компилятора.
0
04.05.2016, 20:41
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
04.05.2016, 20:41
Привет! Вот еще темы с ответами:

OpenMP планировщик - добиться равномерного распределения задач - C (СИ)
Есть следующий код: #include &lt;stdio.h&gt; #include &lt;unistd.h&gt; int cnttotal = 0; int cnt1 = 0, cnt2 = 0; int main() ...

Найти ускорения грузов массами m1 и m2 и угловые ускорения блоков - Механика
Добрый день, господа. Прошу помочь в решении данной задачи, интересуют два пункта: 6 и 8, остальные (по которым есть методичка с примерами...

OpenMP. Время выполнения программы больше чем без OpenMP - C++
Сегодня первый раз сел за OpenMP. Читаю на сайте майкрософта как работает этот API. Так вот там сказано:&quot;Директива #pragma omp for...

Как подключить openMP? - C (СИ)
#include &lt;stdio.h&gt; #include &lt;time.h&gt; #include &lt;conio.h&gt; #include &lt;locale.h&gt; #include &lt;stdlib.h&gt; volatile long unsigned C, A, B; ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.