Как проверить производительность масштабирования кода по размеру проблемы

Я запускаю простое ядро, которое добавляет два потока комплексных значений двойной точности. Я распараллелил это с помощью OpenMP с пользовательским планированием: контейнер slice_indices содержит разные индексы для разных потоков.

    for (const auto& index : slice_indices)
    {
        auto* tens1_data_stream = tens1.get_slice_data(index);
        const auto* tens2_data_stream = tens2.get_slice_data(index);
        #pragma omp simd safelen(8)
        for (auto d_index = std::size_t{}; d_index < tens1.get_slice_size(); ++d_index)
        {
            tens1_data_stream[d_index].real += tens2_data_stream[d_index].real;
            tens1_data_stream[d_index].imag += tens2_data_stream[d_index].imag;
        }
    }

Целевой компьютер имеет процессор Intel(R) Xeon(R) Platinum 8168 с тактовой частотой 2,70 ГГц, 24 ядра, кэш-память L1 32 КБ, кэш-память L2 1 МБ и кэш-память L3 33 МБ. Общая пропускная способность памяти составляет 115 ГБ/с.

Ниже показано, как мой код масштабируется с размером задачи S = ​​N x N x N. Как проверить производительность масштабирования кода по размеру проблемы

Может ли кто-нибудь сказать мне информацию, которую я предоставил, если:

  1. он хорошо масштабируется и/или
  2. как я могу выяснить, использует ли он все доступные ему ресурсы?

Заранее спасибо.

РЕДАКТИРОВАТЬ:

Теперь я изобразил производительность в GFLOP/s с 24 ядрами и 48 ядрами (два узла NUMA, один и тот же процессор). Выглядит так: Как проверить производительность масштабирования кода по размеру проблемы

А теперь графики сильного и слабого масштабирования: Как проверить производительность масштабирования кода по размеру проблемыКак проверить производительность масштабирования кода по размеру проблемы

Примечание: Я измерил полосу пропускания, и оказалось, что она составляет 105 ГБ/с.

Вопрос: Значение странного пика при 6 потоках/размере задачи 90x90x90x16 B на графике слабого масштабирования мне не очевидно. Кто-нибудь может это прояснить?

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

paleonix 04.05.2022 14:21

О вашем редактировании: 1. еще много точек данных, пожалуйста. Посмотрите размеры своего кеша (вероятно, 64 КБ и 2 МБ или около того) и убедитесь, что вы попали в размеры внутри/снаружи. 2. с 48 ядрами я бы протестировал 4,8,12,....44,46,48, чтобы увидеть, есть ли у вас явление «исчерпания пропускной способности». Постройте это для достаточно большого набора данных. И используйте размер набора данных в мегабайтах для построения графика, а не параметр вашей проблемы N. 3. с 2 узлами Numa проверьте влияние параметра OMP_PROC_BIND.

Victor Eijkhout 04.05.2022 17:07

Все хорошие моменты, возможно, были частью ответа :)

MotiveHunter 05.05.2022 08:52

Еще один полезный способ показать данные — построить график «Параллельная эффективность»; Измерение параллельной производительности Насколько хорошо масштабируется мое приложение? — хорошее введение.

Jim Cownie 05.05.2022 09:46

Еще больше объяснений принципов масштабирования: theartofhpc.com/istc/parallel.html#Theoreticalconcepts.

Victor Eijkhout 05.05.2022 14:34
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Ваш график имеет примерно правильную форму: крошечные массивы должны помещаться в кеш L1, а значит, получать очень высокую производительность. Массивы в мегабайт или около того помещаются в L2 и получают более низкую производительность, кроме того, вы должны выполнять потоковую передачу из памяти и получать низкую производительность. Таким образом, связь между размером задачи и временем выполнения действительно должна становиться все круче с увеличением размера. Однако результирующий график (кстати, количество операций в секунду встречается чаще, чем просто время выполнения) должен иметь ступенчатую структуру по мере того, как вы достигаете последовательных границ кеша. Я бы сказал, что у вас недостаточно данных, чтобы продемонстрировать это.

Кроме того, обычно вы повторяете каждый «эксперимент» несколько раз, чтобы 1. сгладить статистические сбои и 2. убедиться, что данные действительно находятся в кеше.

Поскольку вы пометили этот «openmp», вам также следует изучить возможность выбора заданного размера массива и изменения количества ядер. Затем вы должны получить более или менее линейный прирост производительности, пока у процессора не будет достаточно пропускной способности для поддержки всех ядер.

Комментатор упомянул о концепциях сильного/слабого масштабирования. Сильное масштабирование означает: при заданном размере задачи использовать все больше и больше ядер. Это должно повысить производительность, но с уменьшающейся отдачей, поскольку накладные расходы начинают доминировать. Слабое масштабирование означает: оставить размер задачи на процесс/поток/что угодно постоянным и увеличить количество обрабатывающих элементов. Это должно дать вам почти линейное увеличение производительности до тех пор, пока, как я уже говорил, у вас не закончится полоса пропускания. То, что вы, кажется, делаете, на самом деле не является ни тем, ни другим: вы делаете «оптимистическое масштабирование»: увеличиваете размер проблемы, а все остальное остается постоянным. Это должно дать вам все лучшую и лучшую производительность, за исключением эффектов кеша, как я указал.

Поэтому, если вы хотите сказать, что «этот код масштабируется», вы должны решить, при каком сценарии. Как бы то ни было, ваша цифра в 200 Гбит/с вполне правдоподобна. Это зависит от деталей вашей архитектуры, но для относительно недавнего узла Intel это звучит разумно.

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