2015-03-01 6 views
1

Я только что начал с openMP; Я написал небольшой C-код, чтобы проверить, правильно ли я изучил. Однако я нашел некоторые проблемы; вот main.c кодOpenMP для начинающих

#include "stdio.h" 
#include "stdlib.h" 
#include "omp.h" 
#include "time.h" 

int main(){ 

float msec_kernel; 
const int N = 1000000; 
int i, a[N]; 

clock_t start = clock(), diff; 
#pragma omp parallel for private(i) 
for (i = 1; i <= N; i++){ 
    a[i] = 2 * i; 
} 
diff = clock() - start; 
msec_kernel = diff * 1000/CLOCKS_PER_SEC; 
printf("Kernel Time: %e s\n",msec_kernel*1e-03); 
printf("a[N] = %d\n",a[N]); 
return 0; 
} 

Моя цель состоит в том, чтобы увидеть, сколько времени требуется на ПК, чтобы сделать такую ​​операцию с использованием 1 и 2 процессора; для того, чтобы компилировать программу я введите следующую строку в терминале:

gcc -fopenmp main.c -o main 

А потом выбрать количество процессоров, так как:

export OMP_NUM_THREADS=N 

, где N равен 1 или 2; однако я не получаю правильное время выполнения; мои результаты на самом деле являются:

Kernel Time: 5.000000e-03 s 
a[N] = 2000000 

и

Kernel Time: 6.000000e-03 s 
a[N] = 2000000 

И, соответствующее N = 1 и N = 2. как вы можете видеть, когда я использую 2 процессора, требуется немного больше времени, чем использование только одного! Что я делаю не так? Как я могу исправить эту проблему?

+3

Что вы делаете неправильно использует 'часы()' на Linux, чтобы получить время стены. Используйте 'omp_get_wtime()'. –

ответ

0

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

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

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

Итак, вы должны начать читать некоторые вещи об общей производительности алгоритма. Для использования нескольких ядер с использованием общего кеша, на мой взгляд, сущность. Сегодняшние компьютеры вышли на сцену, где процессор намного быстрее, чем распределение памяти, чтение или запись. Это означает, что при использовании нескольких ядер вы получите преимущество только в том случае, если используете такие вещи, как общий кеш, поскольку распределение данных, инициализация потоков и управление ими также будут использовать время. Чтобы действительно увидеть производительность speedup (см. Ссылку, существенный термин в параллельных вычислениях), вы должны запрограммировать алгоритм, который имеет большой акцент при вычислении не в памяти; это связано с locality (еще один важный термин).

Так что если вы хотите испытать большой прирост производительности, используя несколько ядер, проверьте его на матричном умножении матрицы на большие матрицы, такие как 10'000 * 10'000. И зарисуйте некоторые графики с вводом (размер матрицы) на время и размер матрицы до gflops и сравните многоядерность с последовательной версией.

Также устраивайте себя с анализом сложности (обозначение Big O). Матрично-матричное умножение имеет локальность O (n).

Надеется, что это помогает :-)

Я предлагаю установку числа ядер/потоков в коде себя либо непосредственно на #pragma линии #pragma omp parallel for num_threads(2) или с помощью omp_set_num_threads функционировать omp_set_num_threads(2);

Кроме того, при выполнении времени/performance analysis, очень важно всегда запускать программу несколько раз, а затем принимать среднее значение для всех исполняемых файлов или что-то в этом роде. Выполнение соответствующих программ только один раз не даст вам значимого чтения используемого времени. Всегда вызывать несколько раз подряд. Не забывайте также чередовать качество данных.

Я предлагаю писать test.c файл, который принимает действительную функцию программы в цикле, а затем вычисляет время каждого выполнения функции:

int executiontimes = 20; 
clock_t initial_time = clock(); 
for(int i = 0; i < executiontimes; i++){ 
    function_multiplication(values);  
} 
clock_t final_time = clock(); 
clock_t passed_time = final_time - initial_time; 
clock_t time_per_exec = passed_time/executiontimes; 

Улучшить этот алгоритм теста, добавить рандов() для ваших значений и т. д. засеивайте их с помощью srand() и т. д. Если у вас есть дополнительные вопросы по этому вопросу или мой ответ, оставляйте комментарий, и я попытаюсь объяснить дальше, добавив больше объяснений.

0

Функция clock() возвращает истекшее время процессора, которое включает в себя тики со всех ядер. Поскольку для использования нескольких потоков есть некоторые накладные расходы, когда вы суммируете время выполнения всех потоков, общее время процессора всегда будет больше, чем последовательное время.

Если вы хотите в режиме реального времени (настенные часы времени), попробуйте использовать функцию OMP Runtime Library omp_get_wtime(), определенную в omp.h. Это кросс-платформенный портативный и должен быть предпочтительным способом выполнения настенной синхронизации.

Вы также можете использовать функции POSIX, определенные в time.h:

struct timespec start, stop; 
clock_gettime(CLOCK_REALTIME, &start); 
// action 
clock_gettime(CLOCK_REALTIME, &stop); 
double elapsed_time = (stop.tv_sec - start.tv_sec) + 
         1e-9 * (stop.tv_nsec - start.tv_nsec);