OpenMP in Linux. What is wrong?

Тема в разделе "WASM.UNIX", создана пользователем REASY, 1 ноя 2010.

  1. REASY

    REASY New Member

    Публикаций:
    0
    Регистрация:
    24 дек 2007
    Сообщения:
    108
    Доброго времени суток!
    Недавно познакомился с библиотекой OpenMP. Написал последовательный и параллельный map. Вот код. Файл map_reduce_omp.hpp:
    Код (Text):
    1. bool init_omp(int max_threads, bool is_dynamic)
    2. {
    3.     if (max_threads <= 0)
    4.         max_threads = omp_get_num_procs();
    5.     omp_set_dynamic(is_dynamic);
    6.     omp_set_num_threads(max_threads);
    7. #ifndef _OPENMP
    8.     printf("-err. OPENMP not active!!!\n");
    9.     getchar();
    10.     return false;
    11. #endif
    12.     return true;
    13. }
    14. template <typename T>
    15. T* map_serial(T* array, int size, T (*f)(const T &), double *time)
    16. {
    17.     if (size <= 0)
    18.         return NULL;
    19.     T* result = new T[size];
    20.     if (result == NULL)
    21.         return NULL;
    22.  
    23.     *time = omp_get_wtime();
    24.     for(int i = 0; i < size; i++)
    25.         result[i] = f(array[i]);
    26.     *time = omp_get_wtime() - *time;
    27.  
    28.     return result;
    29. }
    30. template <typename T>
    31. T* map_omp(T* array, int size, T (*f)(const T &), double *time)
    32. {
    33.  
    34.     if (size <= 0)
    35.         return NULL;
    36.     T* result = new T[size];
    37.     if (result == NULL)
    38.         return NULL;
    39.  
    40.     *time = omp_get_wtime();
    41.     int i;
    42.     #pragma omp parallel shared(array, result) private(i)
    43.     {  
    44.         #pragma omp for
    45.         for(i = 0; i < size; i++)
    46.             result[i] = f(array[i]);
    47.     }
    48.     *time = omp_get_wtime() - *time;
    49.  
    50.     return result;
    51. }
    52. template <typename T>
    53. T mul_2(const T &x)
    54. {
    55.     return (x * 2);
    56. }
    57. ............................
    Вот программа, тестирующая их. Файл test_map.cpp:
    Код (Text):
    1. //#include <windows.h>
    2. #include <stdio.h>
    3. #include <stdlib.h>
    4. #include <memory.h>
    5. #include <iostream>
    6. #include <ctime>
    7. #include <cmath>
    8. #include "map_reduce_omp.hpp"
    9.  
    10. using namespace std;
    11.  
    12. const int start = 1000000;
    13. const int end = 128000000;
    14.  
    15.  
    16. int main(int argc, char *argv[])
    17. {
    18.     int i, sz;
    19.     int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    20.     const int size = sizeof(a)/sizeof(int);
    21.  
    22.     int* array = new int[size];
    23.     memcpy(array, a, sizeof(int)*size);
    24.    
    25.     if(!init_omp(0, false))
    26.         return -1;
    27.  
    28.     cout << "************Map Multiply************" << endl;
    29.     cout << "Array: " << endl;
    30.     PrintArray(array, size);
    31.     cout << endl;
    32.  
    33.     double time = 0;
    34.  
    35.     int* g = map_serial<int>(array, size, mul_2, &time);
    36.     cout << "***Serial*** Array[i] * 2 : " << endl;
    37.     PrintArray(g, size);
    38.     cout << endl;
    39.    
    40.     int* b = map_omp<int>(array, size, mul_2, &time);
    41.     cout << "***Parallel*** Array[i] * 2 : " << endl;
    42.     PrintArray(b, size);
    43.     cout << endl;
    44.  
    45.     delete[] b;
    46.     delete[] g;
    47.  
    48.     delete[] array;
    49.    
    50.     cout << endl;
    51.     cout << "******************************************" << endl;
    52.     cout << "Testing SERIAL and PARALLEL map." << endl;
    53.     printf("%3d <= array size <= %d\n",start, end);
    54.     cout << "******************************************" << endl;
    55.  
    56. //  LARGE_INTEGER tStart, tEnd, freq;
    57. //  SetThreadAffinityMask(GetCurrentThread(), 1);
    58. //  QueryPerformanceFrequency(&freq);
    59.  
    60.     printf("Accuracy: %lf\n", omp_get_wtick());
    61.     for (sz = start; sz <= end; sz *= 2)
    62.     {
    63.         array = new int[sz];
    64.         for (i = 0; i < sz; i++)
    65.             array[i] = rand();
    66.  
    67.         cout << "Size = " << sz << endl;
    68.  
    69.         cout << "map_serial() ";
    70.         int* t = map_serial<int>(array, sz, mul_2, &time);
    71.         if (t == NULL){
    72.             delete[] array;
    73.             cout << "-err. Can't allocate memory. Exiting..." << endl;
    74.             return -1;
    75.         }      
    76.         printf("Time: %lf ms\n", time*1000);
    77.  
    78. #ifdef _TEST
    79.         cout << "Check calcs...";
    80.         for (i = 0; i < sz; i++)
    81.             if (t[i] != array[i]* 2){
    82.                 cout << "-err. Something wrong!!!" << endl;
    83.                 break;
    84.             }
    85.         if (i == sz)
    86.             cout << " OK" << endl;
    87. #endif
    88.         delete[] t;
    89.         cout << "map_omp()    ";
    90. //      QueryPerformanceCounter(&tStart);
    91.         int *r = map_omp<int>(array, sz, mul_2, &time);
    92.         if (r == NULL){
    93.             cout << "-err. Can't allocate memory. Exiting..." << endl;
    94.             delete[] array;
    95.             return -1;
    96.         }
    97.         printf("Time: %lf ms\n", time*1000);
    98. /*
    99.         QueryPerformanceCounter(&tEnd);
    100.         tEnd.QuadPart -= tStart.QuadPart;
    101.         double span = 1000*(double) tEnd.QuadPart / freq.QuadPart;
    102.         cout << endl << "span = " << span << endl;
    103. */
    104. #ifdef _TEST
    105.         cout << "Check calcs...";
    106.         for (i = 0; i < sz; i++)
    107.             if (r[i] != array[i]* 2){
    108.                 cout << "-err. Something wrong!!!" << endl;
    109.                 break;
    110.             }
    111.         if (i == sz)
    112.             cout << " OK" << endl;
    113. #endif
    114.         cout << endl;
    115.         delete[] r;
    116.         delete[] array;
    117.     }
    118.    
    119.     cout << "Press Enter to terminate.";
    120.     cin.get();
    121. }
    Теперь вопрос: Почему когда собираю в Linux'e(openSUSE 11.3) время параллельного выполнения больше последовательного?
    CPU: AMD Athlon(tm) 64 X2 Dual Core Processor 6000+, 2 Gb RAM.
    Вот результаты тестов на Windows XP собранный с помощью MS Visual Studio 2008. Release (Microsoft (R) C/C++ версии 15.00.30729.01)(В Диспетчере задач видно, что при параллельном выполнении оба ядра загружены на 99%):
    ************Map Multiply************
    Array:
    1 2 3 4 5 6 7 8 9 10
    ***Serial*** Array * 2 :
    2 4 6 8 10 12 14 16 18 20
    ***Parallel*** Array * 2 :
    2 4 6 8 10 12 14 16 18 20

    ******************************************
    Testing SERIAL and PARALLEL map.
    1000000 <= array size <= 128000000
    ******************************************
    Accuracy: 0.000000
    Size = 1000000
    map_serial() Time: 4.901182 ms
    map_omp() Time: 3.589562 ms

    Size = 2000000
    map_serial() Time: 9.933665 ms
    map_omp() Time: 7.087493 ms

    Size = 4000000
    map_serial() Time: 19.601095 ms
    map_omp() Time: 14.547938 ms

    Size = 8000000
    map_serial() Time: 39.309465 ms
    map_omp() Time: 28.374556 ms

    Size = 16000000
    map_serial() Time: 80.801331 ms
    map_omp() Time: 59.188808 ms

    Size = 32000000
    map_serial() Time: 156.464299 ms
    map_omp() Time: 112.683875 ms

    Size = 64000000
    map_serial() Time: 333.650785 ms
    map_omp() Time: 230.298544 ms

    Size = 128000000
    map_serial() Time: 630.555839 ms
    map_omp() Time: 542.296297 ms

    А вот время работы той же программы, собранной в Linux(openSUSE 11.3, Linux linux-030z 2.6.34-12-desktop #1 SMP PREEMPT 2010-06-29 02:39:08 +0200 i686 athlon i386 GNU/Linux)(а в этом случае top показывает, что только одно ядро используется на 100%, другое нет). Собирал g++ test_map.cpp -o test_map -O3 --openmp. :
    ************Map Multiply************
    Array:
    1 2 3 4 5 6 7 8 9 10
    ***Serial*** Array * 2 :
    2 4 6 8 10 12 14 16 18 20
    ***Parallel*** Array * 2 :
    2 4 6 8 10 12 14 16 18 20

    ******************************************
    Testing SERIAL and PARALLEL map.
    1000000 <= array size <= 128000000
    ******************************************
    Accuracy: 0.000000
    Size = 1000000
    map_serial() Time: 4.824302 ms
    map_omp() Time: 13.938827 ms

    Size = 2000000
    map_serial() Time: 9.297206 ms
    map_omp() Time: 8.859497 ms

    Size = 4000000
    map_serial() Time: 18.562291 ms
    map_omp() Time: 17.737430 ms

    Size = 8000000
    map_serial() Time: 37.429889 ms
    map_omp() Time: 62.919832 ms

    Size = 16000000
    map_serial() Time: 74.855028 ms
    map_omp() Time: 71.277933 ms

    Size = 32000000
    map_serial() Time: 149.903632 ms
    map_omp() Time: 173.817039 ms

    Size = 64000000
    map_serial() Time: 312.852235 ms
    map_omp() Time: 325.017878 ms

    Size = 128000000
    map_serial() Time: 548.998882 ms
    map_omp() Time: 637.584637 ms
     
  2. valterg

    valterg Active Member

    Публикаций:
    0
    Регистрация:
    19 авг 2004
    Сообщения:
    2.105
    Возможно дело в переменной окружения OMP_NUM_THREADS.
    Видимо автоматом она не задана. Соответственно 2-е ядро не используется.
    А вообще лучше такие вопросы на opennet.ru задавать. Там масса ребят мапы тестирует :)
     
  3. contopt

    contopt New Member

    Публикаций:
    0
    Регистрация:
    2 дек 2010
    Сообщения:
    1
    Там ребята не только map'ы тестируют :)