Падение производительности: раздвоенный код Vs.открытый код - PullRequest
0 голосов
/ 04 октября 2018

У меня есть параллельный код с использованием fork () для «чтения и преобразования изображений в градациях серого в двоичный файл».Я преобразовал код в многопоточный код, используя openmp.Но я заметил, что код openmp дает низкую производительность по сравнению с кодом, использующим fork.Сначала я подозревал, что это может быть openmp, и поэтому пытался напрямую использовать pthreads.Но я замечаю ту же картину.Время выполнения pthreaded-кода также выше по сравнению с разветвленным кодом (примечание: pthreads немного лучше, чем openmp, всего за несколько микросекунд)

Вот время выполнения при идентичных условиях.

+-----------------+-------------+--------------+
| No. of children | using fork  | using openmp |
+-----------------+-------------+--------------+
|              20 | 1.3         | 1.6          |
|              50 | 1.6         | 2.2          |
|             100 | 2.7         | 3.7          |
|             150 | 3.7         | 5.3          |
|             200 | 4.5         | 7.1          |
|             250 | 6.0         | 9.0          |
|             600 | 15.2        | 22.06        |
+-----------------+-------------+--------------+

Редактировать: добавлен код.Компилятор: gcc-4.8.5, Количество процессоров: 256

функция вызывается следующими кодами:

void imgProcess(char* nam){
  Pix *pixg = pixRead(nam);      
  Pix *pixb, *pixgray;
  pixgray = pixConvertRGBToGray(pixg,0.33,0.33,0.34);
  pixSauvolaBinarizeTiled(pixgray, 8, 0.34, 1, 1, NULL, &pixb); 
  pixDestroy(&pixg);    
  pixDestroy(&pixb);    
}

Код с использованием fork ():

int main() { 

  char prefix[60]="/root/Test/img_";  
  struct timespec i1, i2;
  long long elapsed;
  clock_gettime(CLOCK_MONOTONIC, &i1);  

  int count = 200;
  for(int i=0; i<count; i++){   
      if(fork() == 0){
        char filname[60];
        sprintf(filname,"%s%d%s",prefix,i,".jpg"); 
        imgProcess(filname);
        exit(0);
      }
  }    

  for(int i=0; i<count; i++)
    wait(NULL); 


  clock_gettime(CLOCK_MONOTONIC, &i2);
  elapsed = i2.tv_sec*1000000000LL + i2.tv_nsec - i1.tv_sec*1000000000LL - i1.tv_nsec;
  cout<<"Total : "<<(double)elapsed/1000000000LL<<endl;

  return 0;
}

Код с использованием openmp:

int main() { 
  int count = 200;
  omp_set_num_threads(count);

  char prefix[60]="/root/Test/img_";  
  struct timespec i1, i2;
  long long elapsed;
  clock_gettime(CLOCK_MONOTONIC, &i1);

  #pragma omp parallel for
  for(int j=0;j<count;j++){ 
      char filname[60];
      sprintf(filname,"%s%d%s",prefix,j,".jpg");         
      imgProcess(filname);
  }


  clock_gettime(CLOCK_MONOTONIC, &i2);
  elapsed = i2.tv_sec*1000000000LL + i2.tv_nsec - i1.tv_sec*1000000000LL - i1.tv_nsec;
  cout<<"Total : "<<(double)elapsed/1000000000LL<<endl;

  return 0;
}

Даже если я признаю, что после некоторого числа forks () будет быстрее, чемпотоков, в соответствии с этим потоком , я все еще не думаю, что они будут быстрее на несколько секунд.

Дополнительная информация: Я провел два небольших теста.

  1. Первый тест: Вместо использования функции imgProcess (), указанной выше, в качестве единицы работы, теперь у меня есть простая «трата времени на цикл» в качестве единицы работы дляпараллельных заданий и заметил, что openmp и разветвленный код имеют почти одинаковые тайминги.
  2. Второй тест: Вместо использования функции imgProcess () выше в качестве единицы работы, моя единица измеренияработа для параллельной работы - «чтение текстового файла» с использованием потока C ++.Времена для openmp-кода и разветвленного кода также схожи в этом случае.

    +---------+-------+--------+
    | threads | fork  | openmp |
    +---------+-------+--------+
    |      20 | 0.018 | 0.008  |
    |      50 | 0.04  | 0.01   |
    |     100 | 0.08  | 0.04   |
    |     150 | 0.11  | 0.03   |
    |     200 | 0.16  | 0.07   |
    |     250 | 0.19  | 0.08   |
    +---------+-------+--------+
    

Вопросы:

  1. Я был подТакое впечатление, что потоки и вилки должны иметь одинаковое время выполнения.Есть идеи выяснить, почему многопоточный код ведет себя по-разному в разных случаях?
  2. До сих пор я просто заменял часть fork () на потоки.На самом деле есть область для распараллеливания самого алгоритма преобразования серого в двоичное изображение, чего я еще не сделал.Видя вышеприведенное время, я чувствую, что не стоит продолжать распараллеливание алгоритма.Что вы мне предлагаете?Считаете ли вы, что это может быть полезным для распараллеливания?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...