Технологии вычислений на многоядерных процессорах

Вчера собирал wine из исходников, интересно было просто, дык открыл для себя ключ к make, ключ -j8…. Ну процессор у меня Intel Core i7… Я чуть печенькой не подавился - все ядра загрузились на 100% wine минуты за три собрался.

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

На деле в моем проекте нагружается на 100% только пока одно ядро, на которое я повесил, принудительно привязав к нему поток решения системы диффур
Да пребудет с нами Сила...!
CPU Intel Core i9 10900-KF/RAM DDR4 128 Gb/NVidia GForce GTX 1080 Ti Turbo 11Gb/SSD M2 512 Gb/HDD Seagate SATA3 2 Tb/HDD Toshiba 3Tb/HDD Toshiba 6Tb
http://rusrailsim.org
ИМХО, смотреть в сторону OpenCL (оно распределяет нагрузку не только на GPU, но и на CPU). На хабре небольшие обзоры были (“Используем OpenCL в Python”, “Введение в OpenCL”).
Если вы хорошо помните присказку:“женщина может выносить ребенка за девять месяцев, но девять женщин не смогут справиться с этой задачей за один месяц” то можете попробовать.

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

В принципе если изобретать велосипед, то можно разделить вычисления на N процессов с получением данных через открытый tcp/udp порт. и выделить серверный процесс который будет рулить вычислениями.
А если что нибудь попроще то тупо и банально курить ман про кластера, и подготовку (компиляцию с дополнительными параметрами и библиотеками) приложений для работы на вычислительных кластерах. Там достаточно приличная область знаний.
Да пребудет с вами знание ip адреса
Есть смысл смотреть в сторону MPI как технологии и OpenMPI как открытой реализации в частности.
Википедия тоже дает широкий выбор путей.
ключ -j8
Это оптимизация гдето если не ошибаюсь на 4 ядра.
Про остальное, читать выше, я вопрос подобный не поднимал для себя.
Лозунг у них был такой: "Познание бесконечности требует бесконечного времени". С этим я не спорил, но они делали из этого неожиданный вывод: "А потому работай не работай — все едино". И в интересах неувеличения энтропии Вселенной они не работали. (с)
Если речь идёт о ядрах, то достаточно OpenMP. Модификация кода как правило ограничивается несколькими строками.
такие дела.
Если задача (и CPU – в i7 вроде есть) позволяет, то через OpenCL будет задействован AVX

Оба процессора содержат 4 реальных и 8 виртуальных ядер, а OpenCL как раз и сделан для того, чтобы все ядра использовать, но улучшение у нас гораздо больше, чем 4Х. А тут надо сказать спасибо Intel, которая в своей реализации OpenCL, добавила поддержку автоматической векторизации, т.е. без каких-либо изменений в коде, OpenCL использует SSE или AVX, в зависимости от того, что доступно. Учитывая, что SSE у нас 128битное, а AVX работает с 256битами, получается, что производительность должна подняться в 16X и 32X соответственно.
Про OpenCL слышал, а вот про OpenMP и OpenMPI - впервые.

За что люблю арч - всё перечисленное легко достал из репозитория. Буду разбираться, спасибо

sirocco
через OpenCL будет задействован AVX

Есть ключики к компилятору gcc -march=corei7-avx и -mtune=corei7-avx. Не знаю правда насколько эффективны. Ну одними ключами проблемы не решатся, канеш
Да пребудет с нами Сила...!
CPU Intel Core i9 10900-KF/RAM DDR4 128 Gb/NVidia GForce GTX 1080 Ti Turbo 11Gb/SSD M2 512 Gb/HDD Seagate SATA3 2 Tb/HDD Toshiba 3Tb/HDD Toshiba 6Tb
http://rusrailsim.org
Ещё раз настоятельно рекомендую OpenMP. Он “из коробки” в gcc, модификация кода – мизерная, профит – моментальный.
такие дела.
С утра хотел написать, да провайдер меня подвел.

Так вот, попробовал я OpenMP, благо чтобы его задействовать достаточно включить #include <omp.h> и поставить компилятору ключик -fopenmp

cucullus
модификация кода – мизерная, профит – моментальный

Абсолютно согласен :) В качестве задачи для теста выбрал простенькую реализацию той задачи что решаю в своем проекте - движение поезда с учетом усилий возникающих в автосцепках. Сразу скажу, что приведенный пример это не та модель что используется в проекте, проект - здоровенное приложение с ООП и динамической загрузкой матмоделей подвижных единиц из *.so… Это предельно упрощенная постановка задача движения поезда из N подвижных единиц, с моделью сцепки в виде упругой связи, без учета сил сопротивления движению и прочего, то есть такой “сферический поезд в вакууме”

Вот код с применением OpenMP
//==============================================================================
//
//      Тестовая задача реализации параллельных вычислений OpenMP
//      (с) Притыкин Д. Е., к.т.н., доцент кафедры "Теоретическая механика"
//
//==============================================================================
#include        "openmp_train.h"
const   int     VEHICLES = 200;    
const   int     N = VEHICLES + 1;
const   double   c = 1.5e7;
double   dt = 1e-7;
double   t = 0;
double   tk = 10.0;
double  m[N]; // массы подвижных единиц (ПЕ)
double  y[2*N]; // фазовые координаты ПЕ
double  T[N+1]; // усилия в сцепках ПЕ
double  F[N]; // вектор внешних сил
double print_time = 0.0;
bool first_print = true;
timeval time0;
timeval time1;
double  calc_time = 0;
int i = 0;
int j = 0;
double dT = 0.01;
//------------------------------------------------------------------------------
//
//------------------------------------------------------------------------------
void OdeStep(double* mass, double* Y, double* Tc, double* force, double deltaT)
{
    #pragma omp for nowait
    for (i = 0; i < N; i++)
    {
        Tc[i+1] = c*(Y[i] - Y[i+1]);
        Tc[0] = 0.0;
        Tc[N] = 0.0;
        Y[i] = Y[i] + Y[i+N]*deltaT;
        Y[i+N] = Y[i+N] + deltaT*(force[i] + Tc[i] - Tc[i+1])/mass[i];
    }    
}
//------------------------------------------------------------------------------
//
//------------------------------------------------------------------------------
int main(void)
{
    // Инициализация
    m[0] = 129*1000;
    F[0] = 450*1000;
        
    for (i = 1; i < N; i++)
    {
        m[i] = 58*1000;
        F[i] = 0.0;
    }
    
    for (i = 0; i < 2*N; i++)
    {
        y[i] = 0.0;
    }
    
    for (i = 0; i < N+1; i++)
    {
        T[i] = 0.0;
    }   
      
    // Инициализация OpenMP
    omp_set_dynamic(0); // Запрещаем менять число потокв при выполнении
    omp_set_num_threads(8); // Задаем 8 потоков
          
    // Засекаем время начала расчета
    gettimeofday(&time0, NULL);  
// Задаем регион кода, вычисляемый параллелльно
#pragma omp parallel shared(m, y, T, F) private(i)
{
    while (t <= tk)
    {
        // Выполняем шаг интегрирования
        OdeStep(m, y, T, F, dt);  
        
        // Выводим результат на экран
       
        if ( ( t >= dT*j) || (j == 0) )
        {
                printf("%5i| time: %8.2f, с | progress: %5.1f % | T1: %8.1f, кН\n", j, t, t*100/tk, T[1]/1000.0);
                j++;            
        }
        
        
        t += dt;
    }
}
    
    // Засекаем время окончания расчета
    gettimeofday(&time1, NULL);
    
    // Вычисляем время расчета
    calc_time = ( time1.tv_sec + time1.tv_usec/1e6 ) - ( time0.tv_sec + time0.tv_usec/1e6 );
    
    printf(" time: %8.2f, с | progress: %5.1f % | T1: %8.1f, кН\n", t, t*100/tk, T[1]/1000.0);
    printf("\nCalculation time: %f, s\n", calc_time);    
    
    return 0;
}

Сабж подключается путем включения в код директив #pragma omp parallel shared(m, y, T, F) private(i) {….} и #pragma omp for nowait, причем последняя, перед циклом, подлежащим распараллеливанию. Распараллеливанию здесь подлежит расчет усилий в сцепках вагонов, расчет ускорений вагонов, и собственно вычесление значения фазовых координат (скорости и перемещения вагонов) на текущем шаге по значениям ускорений и скоростей на предыдущем шаге. То есть это интегрирования самым простецким явным методом Эйлера. Вот функция OdeStep() в данной реализации выполняется параллельно на восьми потоках (хочется сказать ядрах) моего intel core i7.

Пришлось покорвырятся, чтобы получить приемлемый результат. Условия расчета такие: время расчета (модельное) - 10 секунд движения поезда, шаг интегрирования - 0.1 микросекунды. Считалось для разного числа вагонов как в параллельном варианте, так и без распараллеливания.

Результат - все 8 “ядер” (ну буду я их ядрами звать, проще, знаю я что там 4 ядра с гипертрейдингом…) грузятся на 100% (смотрел по Conky). Производительность расчетов иллюстрирую графиками



С ростом числа решаемых диффур прирост производительности становится всё более существенным :) Видно по синему графику, что с ростом числа диффур время расчета увеличивается крайне незначительно, то есть распараллеливание дает здесь хороший эффект.

Конечно, этот код можно ещё оптимизировать, например перейти к расчету сил в упругих связях матричным методом, а операции с матрицами как известно являются хорошо распараллеливаемыми. Ну и деления умножения минимизировать, тоже тут необъятное поля для деятельности…

Ок, буду разбираться дальше.

P.S.: Ашник не закинул, да там ничего интересного, но все же

#pragma         once
#include        <stdio.h>
#include        <math.h>
#include        <omp.h>
#include        <stdlib.h>
#include        <sys/time.h>
Да пребудет с нами Сила...!
CPU Intel Core i9 10900-KF/RAM DDR4 128 Gb/NVidia GForce GTX 1080 Ti Turbo 11Gb/SSD M2 512 Gb/HDD Seagate SATA3 2 Tb/HDD Toshiba 3Tb/HDD Toshiba 6Tb
http://rusrailsim.org
 
Зарегистрироваться или войдите чтобы оставить сообщение.