Aleksei_Rostov 0 14 февраля, 2020 Опубликовано 14 февраля, 2020 · Жалоба Здравствуйте! Подскажите пожалуйста почему при подключении 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# По идее время на выполнение должно быть в два раза меньше... Что делаю не так? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 63 14 февраля, 2020 Опубликовано 14 февраля, 2020 · Жалоба 5 minutes ago, Alexey_Rostov said: По идее время на выполнение должно быть в два раза меньше... Что делаю не так? Так 4 итерации цикла - маловато для оценки, мягко говоря. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Aleksei_Rostov 0 14 февраля, 2020 Опубликовано 14 февраля, 2020 · Жалоба 3 minutes ago, aaarrr said: Так 4 итерации цикла - маловато для оценки, мягко говоря. Но в каждой итерации у меня перемножаются по два массива... Как я понимаю каждое ядро выполняет по одной итерации. Более того, запускаю программу на Windows в Visual studio, прирост в производительности есть. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 63 14 февраля, 2020 Опубликовано 14 февраля, 2020 · Жалоба Ну, я бы все же довел время выполнения тестового фрагмента до десятков-сотен мс, чтобы точно отвязаться от возможных погрешностей измерения. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Aleksei_Rostov 0 14 февраля, 2020 Опубликовано 14 февраля, 2020 · Жалоба 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 время увеличилось в два раза... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Eddy_Em 1 14 февраля, 2020 Опубликовано 14 февраля, 2020 · Жалоба randn(rnd_image А ничего, что эта штука - общая переменная для обоих потоков. И они вынуждены вызывать синхронизацию, в результате чего время будет больше, чем без OMP! Заводите временные переменные прямо внутри цикла. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Aleksei_Rostov 0 14 февраля, 2020 Опубликовано 14 февраля, 2020 · Жалоба 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$ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Eddy_Em 1 14 февраля, 2020 Опубликовано 14 февраля, 2020 (изменено) · Жалоба А нельзя ли сделать MWE такой, чтобы гадость (opencv) с собой не тащило? Могу на генте проверить. Изменено 14 февраля, 2020 пользователем Eddy_Em Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Aleksei_Rostov 0 14 февраля, 2020 Опубликовано 14 февраля, 2020 · Жалоба 7 minutes ago, Eddy_Em said: А нельзя ли сделать MWE такой, чтобы гадость (opencv) с собой не тащило? Могу на генте проверить. Запускаю на Windows в VS 2019, программа работает как и ожидается: использование OpenMP позволило ускорить for в несколько раз. На Ubuntu и на ARM Linux не получается .... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Eddy_Em 1 14 февраля, 2020 Опубликовано 14 февраля, 2020 (изменено) · Жалоба Блин! ЗАчем здесь 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 "железных" ядер... Но накладные расходы во втором случае все съедают. Изменено 14 февраля, 2020 пользователем Eddy_Em Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Aleksei_Rostov 0 14 февраля, 2020 Опубликовано 14 февраля, 2020 · Жалоба 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. Выйгрыш во времени более чем в два раза Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Eddy_Em 1 14 февраля, 2020 Опубликовано 14 февраля, 2020 (изменено) · Жалоба Читаем man clock: Quote Функция clock() возвращает приблизительное процессорное время, использованное программой. И понимаем, что в многопоточном режиме она выдаст СУММАРНОЕ время по всем потокам! // прикола ради я проверил у себя, заменив dtime() на clock(), реально в многопоточном режиме вышло время значительно больше, т.к. время выполнения было умножено на 8. Изменено 14 февраля, 2020 пользователем Eddy_Em Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Aleksei_Rostov 0 14 февраля, 2020 Опубликовано 14 февраля, 2020 · Жалоба Just now, Eddy_Em said: Читаем man clock: И понимаем, что в многопоточном режиме она выдаст СУММАРНОЕ время по всем потокам! Спасибо, уже понял, что некорректно ее использовать: в VS по точкам дебага временные затраты другие иллюстрируются.... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Eddy_Em 1 14 февраля, 2020 Опубликовано 14 февраля, 2020 · Жалоба 4 minutes ago, Alexey_Rostov said: Вот вывод консоли для Windows похоже, в мастдайке функция clock() делает что-то другое… Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Aleksei_Rostov 0 14 февраля, 2020 Опубликовано 14 февраля, 2020 · Жалоба 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 "железных" ядер... Но накладные расходы во втором случае все съедают. Спасибо еще раз! Заработало! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться