Перейти к содержанию
    

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(32, 32, CV_32FC1, Scalar(0));
    // matrix initialization

    clock_t start, end;
    double cpu_time_used;
	
	start = clock();
    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]);
        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++) {
		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]);
		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# g++ main.cpp -fopenmp -I /usr/include/opencv2     -L /usr/lib     -lopencv_core
root@imx8m-var-dart:~/test# ./a.out
Start programm
Time taken by for_loop: 0.000802 seconds
Time taken by for_loop with openmp: 0.000789 seconds
root@imx8m-var-dart:~/test#

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 minutes ago, Alexey_Rostov said:

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

Так 4 итерации цикла - маловато для оценки, мягко говоря.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 minutes ago, aaarrr said:

Так 4 итерации цикла - маловато для оценки, мягко говоря.

Но в каждой итерации у меня перемножаются по два массива... Как я понимаю каждое ядро выполняет по одной итерации. Более того, запускаю программу на Windows в Visual studio, прирост в производительности есть.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 minutes ago, aaarrr said:

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

Я понимаю что вы имеете в виду, но у меня в задаче 4 канала и в каждом канале набор последовательных арифметических действий (умножение\деление\фильтрация) над массивами (изображениями). Вот и пытаюсь оптимизировать программу по быстродействию. 

Увеличил размер перемножаемых массивов до 2048 х 2048

результат

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

С openmp время увеличилось в два раза...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

randn(rnd_image

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

Заводите временные переменные прямо внутри цикла.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

29 minutes ago, Eddy_Em said:

randn(rnd_image

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

Заводите временные переменные прямо внутри цикла.

Исправил, вынес инициализацию вне for

 

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

без изменений...

Запускаю эту же программу под Ubuntu 16.04

alexey@ubuntu:~/test$ g++ main.cpp -fopenmp -I /usr/include/opencv2 -L /usr/lib -lopencv_core
alexey@ubuntu:~/test$ ./a.out 
Start programm
Time taken by for_loop: 0.091176 seconds 
Time taken by for_loop with openmp: 0.017327 seconds 
alexey@ubuntu:~/test$ 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А нельзя ли сделать MWE такой, чтобы гадость (opencv) с собой не тащило? Могу на генте проверить.

 

Изменено пользователем Eddy_Em

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

7 minutes ago, Eddy_Em said:

А нельзя ли сделать MWE такой, чтобы гадость (opencv) с собой не тащило? Могу на генте проверить.

 

 

Запускаю на Windows в VS 2019, программа работает как и ожидается: использование OpenMP позволило ускорить for в несколько раз. На Ubuntu и на ARM Linux не получается ....

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Блин! ЗАчем здесь clock? оно ж не время считает!!!

Вот, пожалуйста, мой пример:

#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

static double dtime(){
    double t;
    struct timeval tv;
    gettimeofday(&tv, NULL);
    t = tv.tv_sec + ((double)tv.tv_usec)/1e6;
    return t;
}

static void mularr0(int *a1, int *a2, int *a3){
        for(int i = 0; i < 1000; ++i) a3[i] = a1[i] * a2[i];
}

static void mularr8(int *a1, int *a2, int *a3){
        #pragma omp parallel for num_threads(8)
        for(int i = 0; i < 1000; ++i) a3[i] = a1[i] * a2[i];
}

void main(){
        int arr1[1000], arr2[1000], arr3[1000];
        for(int i = 0; i < 1000; ++i){ arr1[i] = rand(); arr2[i] = rand();}
        double start = dtime();
        for(int x = 0; x < 1000000; ++x) mularr0(arr1, arr2, arr3);
        printf("1 thread: %gs\n", dtime() - start);
        start = dtime();
        for(int x = 0; x < 1000000; ++x) mularr8(arr1, arr2, arr3);
        printf("8 threads: %gs\n", dtime() - start);
}

Проверяем без openmp:

gcc 1.c && ./a.out 
1 thread: 2.37255s
8 threads: 2.35688s

А теперь - с openmp:

gcc 1.c -fopenmp && ./a.out 
1 thread: 2.40718s
8 threads: 1.47267s

Прикола ради добавил 4 потока, получил:

gcc 1.c -fopenmp && ./a.out 
1 thread: 2.44632s
4 threads: 1.4663s
8 threads: 1.48998s

Хотя у меня 8 "железных" ядер... Но накладные расходы во втором случае все съедают.

Изменено пользователем Eddy_Em

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 minutes ago, Eddy_Em said:

Блин! ЗАчем здесь clock? оно ж не время считает!!!

Разницу между start и end. На Винде с клоком тоже работает...

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

 

Вот вывод консоли для Windows

Start programm
Time taken by for_loop: 0.401 seconds
Time taken by for_loop with openmp: 0.143 seconds
Done !

Размер массивов задал 8192х8192. Выйгрыш во времени более чем в два раза

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Читаем man clock:

Quote

Функция clock() возвращает приблизительное процессорное время, использованное программой.

И понимаем, что в многопоточном режиме она выдаст СУММАРНОЕ время по всем потокам!

// прикола ради я проверил у себя, заменив dtime() на clock(), реально в многопоточном режиме вышло время значительно больше, т.к. время выполнения было умножено на 8.

Изменено пользователем Eddy_Em

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Just now, Eddy_Em said:

Читаем man clock:

И понимаем, что в многопоточном режиме она выдаст СУММАРНОЕ время по всем потокам!

Спасибо, уже понял, что некорректно ее использовать: в VS по точкам дебага временные затраты другие иллюстрируются.... 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 minutes ago, Alexey_Rostov said:

Вот вывод консоли для Windows

похоже, в мастдайке функция clock() делает что-то другое…

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

13 minutes ago, Eddy_Em said:

Блин! ЗАчем здесь clock? оно ж не время считает!!!

Вот, пожалуйста, мой пример:


#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

static double dtime(){
    double t;
    struct timeval tv;
    gettimeofday(&tv, NULL);
    t = tv.tv_sec + ((double)tv.tv_usec)/1e6;
    return t;
}

static void mularr0(int *a1, int *a2, int *a3){
        for(int i = 0; i < 1000; ++i) a3[i] = a1[i] * a2[i];
}

static void mularr8(int *a1, int *a2, int *a3){
        #pragma omp parallel for num_threads(8)
        for(int i = 0; i < 1000; ++i) a3[i] = a1[i] * a2[i];
}

void main(){
        int arr1[1000], arr2[1000], arr3[1000];
        for(int i = 0; i < 1000; ++i){ arr1[i] = rand(); arr2[i] = rand();}
        double start = dtime();
        for(int x = 0; x < 1000000; ++x) mularr0(arr1, arr2, arr3);
        printf("1 thread: %gs\n", dtime() - start);
        start = dtime();
        for(int x = 0; x < 1000000; ++x) mularr8(arr1, arr2, arr3);
        printf("8 threads: %gs\n", dtime() - start);
}

Проверяем без openmp:


gcc 1.c && ./a.out 
1 thread: 2.37255s
8 threads: 2.35688s

А теперь - с openmp:


gcc 1.c -fopenmp && ./a.out 
1 thread: 2.40718s
8 threads: 1.47267s

Прикола ради добавил 4 потока, получил:


gcc 1.c -fopenmp && ./a.out 
1 thread: 2.44632s
4 threads: 1.4663s
8 threads: 1.48998s

Хотя у меня 8 "железных" ядер... Но накладные расходы во втором случае все съедают.

 

 

Спасибо еще раз! Заработало!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...