Как одно общее загруженное ядро ​​процессора может повлиять на общую загрузку процессора openmp?

Моя системная настройка: система Linux, 12 ядер, изолированные ядра 2–11. Использование ядер 0 и 1 какой-то другой программой почти на 100%. Все остальные ядра простаивают.

тест первого тура.

export GOMP_CPU_AFFINITY=2,3,4
export OMP_NUM_THREADS=3
taskset -c $GOMP_CPU_AFFINITY perf stat -d ./test_openmp

вывод:

 Performance counter stats for './test_openmp':

         47,654.74 msec task-clock:u              #    2.981 CPUs utilized          
                 0      context-switches:u        #    0.000 /sec                   
                 0      cpu-migrations:u          #    0.000 /sec                   
           115,358      page-faults:u             #    2.421 K/sec                  
   159,245,881,934      cycles:u                  #    3.342 GHz                    
   250,009,309,156      instructions:u            #    1.57  insn per cycle         
    20,002,132,172      branches:u                #  419.730 M/sec                  
           117,268      branch-misses:u           #    0.00% of all branches        
   110,002,614,320      L1-dcache-loads:u         #    2.308 G/sec                  
    10,796,435,741      L1-dcache-load-misses:u   #    9.81% of all L1-dcache accesses
                 0      LLC-loads:u               #    0.000 /sec                   
                 0      LLC-load-misses:u         #    0.00% of all LL-cache accesses

      15.986638336 seconds time elapsed

      47.175831000 seconds user
       0.414928000 seconds sys

второй тур теста.

export GOMP_CPU_AFFINITY=1,2,3,4
export OMG_NUM_THREADS=4

taskset -c $GOMP_CPU_AFFINITY perf stat -d ./test_openmp

результат

pid: 4118342

 Performance counter stats for './test_openmp':

         48,241.03 msec task-clock:u              #    1.072 CPUs utilized          
                 0      context-switches:u        #    0.000 /sec                   
                 0      cpu-migrations:u          #    0.000 /sec                   
           119,879      page-faults:u             #    2.485 K/sec                  
   161,605,704,451      cycles:u                  #    3.350 GHz                    
   250,011,376,400      instructions:u            #    1.55  insn per cycle         
    20,002,726,448      branches:u                #  414.641 M/sec                  
           118,657      branch-misses:u           #    0.00% of all branches        
   110,002,938,510      L1-dcache-loads:u         #    2.280 G/sec                  
    10,796,444,713      L1-dcache-load-misses:u   #    9.81% of all L1-dcache accesses
                 0      LLC-loads:u               #    0.000 /sec                   
                 0      LLC-load-misses:u         #    0.00% of all LL-cache accesses

      45.012033357 seconds time elapsed

      47.764469000 seconds user
       0.399934000 seconds sys

Мой вопрос: почему во второй раз я назначил программе еще одно ядро ​​(ядро 1), но время работы должно быть больше (15,98 секунды против 45,01 секунды), а загрузка процессора очень низкая (2,98 против 1,07)

Вот тестовый код, который я запустил.

#include <iostream>
#include <cstdint>
#include <unistd.h>

constexpr int64_t N = 100000;
int m = N;
int n = N;

int main() {
  double* a = new double[N];
  double* c = new double[N];
  double* b = new double[N*N];

  std::cout << "pid: " << getpid() << std::endl;

#pragma omp parallel for default(none) shared(m,n,a,b,c)

for (int i=0; i<m; i++) {
 double sum = 0.0;
 for (int j=0; j<n; j++)
   sum += b[i+j*N]*c[j];
   a[i] = sum;
}

  return 0;
}

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

Alan Birtles 01.08.2024 07:09

Я так понимаю одно ядро ​​уже занято. Но почему бы openmp просто не распределить больше рабочей нагрузки на ядро ​​Idel и не выделить меньше работы на занятое ядро, чтобы общая загрузка процессора составляла около 3?

Xiaoyong Guo 01.08.2024 07:20

Примечание: откажитесь от явных вызовов new/delete (у вас уже есть утечка памяти). double* a = new double[N]; -> std::vector<double> a(N);

Pepijn Kramer 01.08.2024 07:21

Каковы ваши параметры загрузки ядра для изоляции этих ядер? Вы можете попробовать запустить программу с помощью планировщика реального времени (chrt -r ....)

KSH 01.08.2024 07:41

Вы сказали ему использовать четыре потока, поэтому он будет использовать четыре, простаивающих ядер недостаточно для запуска четырех потоков, поэтому у вас возникнут конфликты и снизится производительность.

Alan Birtles 01.08.2024 07:49

Поскольку вы смотрите на производительность, вам следует убедиться, что ваши вычисления имеют какой-либо видимый побочный эффект. Компиляторы могут быть весьма агрессивными в устранении мертвого кода. Обычно достаточно напечатать a[0], a[N/2] и a[N-1].

Joachim 01.08.2024 10:54
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если вы не указываете расписание для цикла совместной работы, расписание определяется реализацией. Большинство реализаций выбирают статическое расписание, поскольку оно обеспечивает минимальные затраты времени выполнения для большинства рабочих нагрузок. Статическое расписание распределяет одинаковое количество итераций по каждому потоку.

В вашем случае вы специально хотите, чтобы openmp по-разному распределял работу между потоками. Попробуйте добавить schedule(dynamic) к параллельной директиве.

Вы также можете выбрать schedule(runtime) и управлять расписанием, устанавливая переменную среды для каждого выполнения.

Большое спасибо, этот ответ полностью решил мою проблему.

Xiaoyong Guo 01.08.2024 08:19

Другие вопросы по теме