Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Saky
0 / 0 / 0
Регистрация: 16.12.2015
Сообщений: 35
#1

OpenMP и SIMD - C++

01.06.2016, 09:59. Просмотров 243. Ответов 4
Метки нет (Все метки)

Добрый день. Не могу исправить код, чтобы использовалось 4 ядра, а не 1. В функцию proizv нужно добавить распараллеливание вычислений с помощью OpenMP. Заранее спасибо
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
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <ctime>
#include <locale.h>
#include <xmmintrin.h>
 
void create(double *mas, int x) {  //создание матрицы
    for (int i = 0; i < x; i++)
        for (int j = 0; j < x; j++) {
            *(mas + i*x + j) = rand() % 10 + 1;
        }
}
 
void transp(double *mas, int x) {  //транспонирование
    double a;
    for (int i = 0; i < x; i++)
        for (int j = i; j < x; j++) {
            a = mas[j*x + i];
            mas[j*x + i] = mas[i*x + j];
            mas[i*x + j] = a;
        }
}
 
double *proizv(double *mas1, double*mas2, int x) {  //произведение после транспонирования
    double *mas3; float sum;
    __m128 *a, *b;
    __m128 c, d;
    a = (__m128 *)mas1;
    b = (__m128 *)mas2;
    mas3 = (double *)_mm_malloc(x*x*sizeof(double), 16);
    for (int i = 0; i < x; i++) {
        for (int j = 0; j < x; j++) {
            d = _mm_set_ps1(0);
            for (int k = 0; k < (x / 4); k++) {
                c = _mm_mul_ps(a[i*x / 4 + k], b[j*x / 4 + k]);
                d = _mm_add_ps(d, c);
            }
            c = _mm_movehl_ps(c, d);
            d = _mm_add_ps(d, c);
            c = _mm_shuffle_ps(d, d, 1);
            d = _mm_add_ss(d, c);
            _mm_store_ss(&sum, d);
            mas3[i*x + j] = sum;
        }
    }
    return mas3;
}
 
int main() {
    srand(time(0));
    int i, x;
    double *mas1, *mas2, *mas3;
    float start_time, end_time;
    printf("Vvedite razmernost' matric\n");
    scanf("%d", &x);
    mas1 = (double *)_mm_malloc(x*x*sizeof(double), 16);
    mas2 = (double *)_mm_malloc(x*x*sizeof(double), 16);
    create(mas1, x);
    create(mas2, x);
    transp(mas2, x);
    start_time = clock();
    mas3 = proizv(mas1, mas2, x);
    end_time = clock();
    float search_time = (end_time - start_time) / 1000;
    printf("runtime = %.1f", search_time);
    _mm_free(mas1);
    _mm_free(mas2);
    _mm_free(mas3);
    _getch();
}
Добавлено через 10 минут
Пыталась изменить на это:
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
double *proizv(double *mas1, double*mas2, int x) {  //произведение после транспонирования
    double *mas3; float sum;
    __m128 *a, *b;
    __m128 c, d;
    a = (__m128 *)mas1;
    b = (__m128 *)mas2;
    mas3 = (double *)_mm_malloc(x*x*sizeof(double), 16);
    for (int i = 0; i < x; i++) {
        for (int j = 0; j < x; j++) {
            d = _mm_set_ps1(0);
#pragma omp parallel
            {
#pragma omp for
                for (int k = 0; k < (x / 4); k++) {
                    c = _mm_mul_ps(a[i*x / 4 + k], b[j*x / 4 + k]);
                    d = _mm_add_ps(d, c);
                }
            }
            c = _mm_movehl_ps(c, d);
            d = _mm_add_ps(d, c);
            c = _mm_shuffle_ps(d, d, 1);
            d = _mm_add_ss(d, c);
            _mm_store_ss(&sum, d);
            mas3[i*x + j] = sum;
        }
    }
    return mas3;
}
Но время выполнения с 5 секунд увеличивается до 18

Добавлено через 12 минут
При подобном варианте:
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
double *proizv(double *mas1, double*mas2, int x) {  //произведение после транспонирования
    double *mas3; float sum; int i, j;
    __m128 *a, *b;
    __m128 c, d;
    a = (__m128 *)mas1;
    b = (__m128 *)mas2;
    mas3 = (double *)_mm_malloc(x*x*sizeof(double), 16);
#pragma omp parallel
    {
#pragma omp for
        for (i = 0; i < x; i++) {
            for (j = 0; j < x; j++) {
                d = _mm_set_ps1(0);
                for (int k = 0; k < (x / 4); k++) {
                    c = _mm_mul_ps(a[i*x / 4 + k], b[j*x / 4 + k]);
                    d = _mm_add_ps(d, c);
                }
            }
            c = _mm_movehl_ps(c, d);
            d = _mm_add_ps(d, c);
            c = _mm_shuffle_ps(d, d, 1);
            d = _mm_add_ss(d, c);
            _mm_store_ss(&sum, d);
            mas3[i*x + j] = sum;
        }
    }
    return mas3;
}
Выполняется 1,4 секунды, но заканчивается ошибкой
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
01.06.2016, 09:59
Здравствуйте! Я подобрал для вас темы с ответами на вопрос OpenMP и SIMD (C++):

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

Оптимизация кода с использование SIMD - C++
Есть код inline double dot(const float* v1, const float* v2) { return v1 * v2 + v1 * v2 + v1 * v2; } Переписал его вот...

OpenMP - C++
#pragma omp parallel private(i) shared(j) { #pragma omp for for (j = 0; j &lt; n; j++) { for (i = 0; i &lt; m;...

OpenMP - C++
есть код в общем виде... #pragma omp parallel for for (i = 0; i &lt; n; ++i) { temp = B; // обращаемся for (j = 0; j &lt; k; ++j)...

Технологии OpenMP - C++
Доброго времени суток. Объясните, почему на такой код void quickSortR(int left,int right,int *mass) { int i,j; bool f; double...

Магия OpenMP - C++
Есть такой код: Expr = ... // vector&lt;pair&lt;size_t, double&gt;&gt; #ifdef _OPENMP #pragma omp parallel num_threads( 2==(size_level-ptr) ? 1...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
AlexVRud
442 / 152 / 38
Регистрация: 04.07.2014
Сообщений: 431
01.06.2016, 10:13 #2
Saky, а тебя не смущает, что c и d вычисляются последовательно, на каждом шаге? В таком варианте алгоритма, не один из циклов не может быть распараллелен.
1
nonedark2008
909 / 648 / 134
Регистрация: 28.07.2012
Сообщений: 1,760
01.06.2016, 10:16 #3
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от Saky Посмотреть сообщение
ыполняется 1,4 секунды, но заканчивается ошибкой
Общие переменные, в которые что-то присваивается, нужно указывать явно в директиве.
Попробуй так:
убери строчку 8, в 10 - "#pragma omp parallel for", а переменные c, d внеси под первый цикл.
1
AlexVRud
442 / 152 / 38
Регистрация: 04.07.2014
Сообщений: 431
01.06.2016, 10:22 #4
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Только сеёчас заметил что у тебя блок съехал
C++
1
2
3
4
5
6
            c = _mm_movehl_ps(c, d);
            d = _mm_add_ps(d, c);
            c = _mm_shuffle_ps(d, d, 1);
            d = _mm_add_ss(d, c);
            _mm_store_ss(&sum, d);
            mas3[i*x + j] = sum;
Добавлено через 4 минуты
Возьми первый вариант, паралелить можно только цикл по i. И как выше сказали, определение временных переменных (c,d,sum) внеси внутрь этого цикла
1
Saky
0 / 0 / 0
Регистрация: 16.12.2015
Сообщений: 35
01.06.2016, 10:38  [ТС] #5
Цитата Сообщение от nonedark2008 Посмотреть сообщение
Общие переменные, в которые что-то присваивается, нужно указывать явно в директиве.
Попробуй так:
убери строчку 8, в 10 - "#pragma omp parallel for", а переменные c, d внеси под первый цикл.
Цитата Сообщение от AlexVRud Посмотреть сообщение
Только сеёчас заметил что у тебя блок съехал
C++
1
2
3
4
5
6
            c = _mm_movehl_ps(c, d);
            d = _mm_add_ps(d, c);
            c = _mm_shuffle_ps(d, d, 1);
            d = _mm_add_ss(d, c);
            _mm_store_ss(&sum, d);
            mas3[i*x + j] = sum;
Добавлено через 4 минуты
Возьми первый вариант, паралелить можно только цикл по i. И как выше сказали, определение временных переменных (c,d,sum) внеси внутрь этого цикла
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
double *proizv(double *mas1, double*mas2, int x) {  //произведение после транспонирования
    double *mas3;
    __m128 *a, *b;
    a = (__m128 *)mas1;
    b = (__m128 *)mas2;
    mas3 = (double *)_mm_malloc(x*x*sizeof(double), 16);
#pragma omp parallel for
    for (int i = 0; i < x; i++) {
        float sum; __m128 c, d;
        for (int j = 0; j < x; j++) {
            d = _mm_set_ps1(0);
            for (int k = 0; k < (x / 4); k++) {
                c = _mm_mul_ps(a[i*x / 4 + k], b[j*x / 4 + k]);
                d = _mm_add_ps(d, c);
            }
            c = _mm_movehl_ps(c, d);
            d = _mm_add_ps(d, c);
            c = _mm_shuffle_ps(d, d, 1);
            d = _mm_add_ss(d, c);
            _mm_store_ss(&sum, d);
            mas3[i*x + j] = sum;
        }
    }
    return mas3;
}
Получилось вот это, время выполнения- 1,5 сек.. Посмотрите, пожалуйста, так должно выглядеть?
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
01.06.2016, 10:38
Привет! Вот еще темы с ответами:

Не работает openmp - C++
Написал простенькую программку с распараллеливанием собрал откомпилил, но распараллеливания нет. Программка выглядит так: ...

Программирование на OpenMP - C++
Такой вопрос, у меня есть прога, которая работает ~сутки, не буду вдаваться что и как она делает, мне посоветовали для быстроты...

Параллельность в openMP - C++
Использую Visual Studio 2013. Проц - двухъядерный Intel E6550. omp_get_max_threads() возвращает 2, что логично, но прагма omp parallel...

Цикл for и OpenMP - C++
Недавно распаралелил свой цикл for, а теперь решил посмотреть на сколько я выигрываю от этого. Но вот неожиданность, все многопоточные...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
01.06.2016, 10:38
Ответ Создать тему
Опции темы

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