Евгений Крутько — Опыт внедрения технологий...
-
Upload
yandex -
Category
Technology
-
view
349 -
download
0
Transcript of Евгений Крутько — Опыт внедрения технологий...
C++ User Group Mee-ng, Nizhniy Novgorod, 19.04.14
Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчетов
Крутько Е.С. НИЦ «Курчатовский институт»
План презентации
• Рассмотрение кода программы моделирования динамики твердого тела по методу конечных элементов
• Использование openmp • Явное создание вычислительных потоков • Использование MPI • Комбинированный подход
Репозиторий проекта: hnps://github.com/eskrut/directIntegra-onSolver.git
2
Кратко о теории
M q̈+ Cq̇+Kq = f
q = {dx0, dy0, dz0, · · · dxN�1, dyN�1, dzN�1}T
M =
0
BBB@
m0 0 0 00 m1 0 0
0 0. . . 0
0 0 0 mN�1
1
CCCA
C = ⇠M
q̇ =qt+�t � qt��t
2�t
, q̈ =qt+�t � 2qt + qt��t
2�t
qt+�t(a0M + a1C) = f �Kq+ a2Mqt � (a0M � a1C)qt��t
1
Задача решается по методу к о н е ч н ы х э л е м е н т о в с использованием явной схемы интегрирования по времени. Вся необходимая логика МКЭ реализована во внешней библиотеке, необходимо только по с трои т ь н а е е о снове решатель.
3
Объект исследования
~250 000 узлов
4
Ветка: Коммит:
Основной код программы master 9f49d14
int main(int argc, char ** argv)!{! int discretParam, numOutput;! double t, tStop, dt, dtOut, tNextOut, transT;! double ampX, freqX, ksi;! bool recreateMesh = false;! bool makeNodesRenumbering = true;! po::options_description desc("Program options");! desc.add_options()! ("help,h", "print help message")! ("dt", po::value<double>(&dt)->default_value(1e-5), "integration time step")! ("tStop,t", po::value<double>(&tStop)->default_value(1e1), "time range")! ("transT", po::value<double>(&transT)->default_value(1e-3), "load transition time")! ("ampX,a", po::value<double>(&X)->default_value(1e-3), "displacement amplitude")! ("freqX,f", po::value<double>(&freqX)->default_value(1e0), "displacement frequency [Hz]")! ("ksi,k", po::value<double>(&ksi)->default_value(1e-1), "damping factor")! ("numOutput,n", po::value<int>(&numOutput)->default_value(500), "number of outputs")! ("discretParam,d", po::value<int>(&discretParam)->default_value(2), "discretisation parameter")! ("recreateMesh,m", "recreate mesh")! ("no-nr", "do not optimize nodes numbering")! ;! po::variables_map vm;! po::store(po::parse_command_line(argc, argv, desc), vm);! po::notify(vm);! if (vm.count("help") || vm.count("h")) { std::cout << desc << "\n"; return 1; }! if (vm.count("recreateMesh") || vm.count("m")) { recreateMesh = true; }! if (vm.count("no-nr")) { makeNodesRenumbering = false; }!! t = tNextOut = 0;! dtOut = tStop/numOutput;! double a0, a1, a2;! a0 = 1.0/(dt*dt); a1 = 1.0/(2.0*dt); a2 = 2.0*a0;
5
Ветка: Коммит:
Основной код программы master 9f49d14
// Create appropriate mesh! std::unique_ptr<sbfMesh> meshPtr(new sbfMesh);! if( recreateMesh || meshPtr->readMeshFromFiles() ){! meshPtr.reset(createMesh(discretParam));! if ( makeNodesRenumbering ) meshPtr->optimizeNodesNumbering();! meshPtr->writeMeshToFiles();! }! sbfMesh *mesh = meshPtr.get();! const int numNodes = mesh->numNodes();!! // Create and compute stiffness matrix! std::unique_ptr<sbfStiffMatrixBlock3x3> stiffPtr(createStiffMatrix(mesh, recreateMesh));! sbfStiffMatrixBlock3x3 *stiff = stiffPtr.get();!! // Create nodes data storages! NodesData<double, 3> displ_m1(mesh), displ("displ", mesh), displ_p1(mesh);! NodesData<double, 3> force(mesh), mass("mass", mesh), demp(mesh), rezKU(mesh);! mass.null(); force.null(); demp.null(); displ_m1.null(); displ.null();!! // Fill mass and demping arrays! computeMassDemp(mass, demp, mesh, stiff->propSet(), ksi, recreateMesh);!! // Get indexes of kinematic loaded nodes! std::vector<int> loadedNodesDown, loadedNodesUp;! double maxY = mesh->maxY();! for(int ct = 0; ct < numNodes; ct++){! if( std::fabs(mesh->node(ct).y()) < 1e-5) loadedNodesDown.push_back(ct);! if( std::fabs(mesh->node(ct).y() - maxY) < 1e-5 ) loadedNodesUp.push_back(ct);! }! const int numLDown = loadedNodesDown.size(), numLUp = loadedNodesUp.size();!! // Stiffness matrix iteration halper! std::unique_ptr<sbfMatrixIterator> iteratorPtr(stiff->createIterator());! sbfMatrixIterator *iterator = iteratorPtr.get();
6
Ветка: Коммит:
Основной код программы master 9f49d14
// Time integration loop! report.createNewProgress("Time integration");! while( t < tStop ) { // Time loop! // Update displacements of kinematically loaded nodes! double tmp[3], temp; getDispl(t, tmp, ampX, freqX, transT);! for(int nodeCt = 0; nodeCt < numLDown; ++nodeCt) for(int ct = 0; ct < 3; ct++)! displ.data(loadedNodesDown[nodeCt], ct) = tmp[ct];! for(int nodeCt = 0; nodeCt < numLUp; ++nodeCt) for(int ct = 0; ct < 3; ct++)! displ.data(loadedNodesUp[nodeCt], ct) = tmp[ct]/3;!! for(int nodeCt = 0; nodeCt < numNodes; nodeCt++) {! // Make multiplication of stiffness matrix over displacement vector! iterator->setToRow(nodeCt);! double *rez = rezKU.data() + nodeCt*3;! rez[0] = rez[1] = rez[2] = 0.0;! while(iterator->isValid()) {! int columnID = iterator->column();! double *vectPart = displ.data() + columnID*3;! double *block = iterator->data();! for(int rowCt = 0; rowCt < 3; ++rowCt)! for(int colCt = 0; colCt < 3; ++colCt)! rez[rowCt] += block[rowCt*3+colCt]*vectPart[colCt];! iterator->next();! }! // Perform finite difference step! for(int ct = 0; ct < 3; ct++) {! temp=force.data(nodeCt, ct) - rezKU.data(nodeCt, ct) +! a2*mass.data(nodeCt, ct)*displ.data(nodeCt, ct) -! (a0*mass.data(nodeCt, ct) - a1*demp.data(nodeCt, ct))*displ_m1.data(nodeCt, ct);! displ_p1.data(nodeCt, ct) = temp/(a0*mass.data(nodeCt, ct) + a1*demp.data(nodeCt, ct));! }! }! // Make output if required! if(t >= tNextOut) { displ.writeToFile();tNextOut += dtOut;report.updateProgress(t/tStop*100);}! // Prepere for next step! t += dt;! displ_m1.copyData(displ); displ.copyData(displ_p1);! } // End time loop! report.finalizeProgress();! return 0; 7
Ветка: Коммит:
Поиск узкого места master 6d51e09
// Time integration loop! report.createNewProgress("Time integration");! std::chrono::nanoseconds period1(0), period2(0), period3(0), period4(0);! while( t < tStop ) { // Time loop! auto timePoint_0 = Clock::now();! // Update displacements of kinematically loaded nodes! // .... //! auto timePoint_1 = Clock::now();! for(int nodeCt = 0; nodeCt < numNodes; nodeCt++) {! // Make multiplication of stiffness matrix over displacement vector! // .... //! }! auto timePoint_2 = Clock::now();! for(int nodeCt = 0; nodeCt < numNodes; nodeCt++) {! // Perform finite difference step! // .... //! }! auto timePoint_3 = Clock::now();! // Make output if required! // Prepere for next step! // .... //! auto timePoint_4 = Clock::now();! period1 += std::chrono::duration_cast<std::chrono::nanoseconds>(timePoint_1 - timePoint_0);! period2 += std::chrono::duration_cast<std::chrono::nanoseconds>(timePoint_2 - timePoint_1);! period3 += std::chrono::duration_cast<std::chrono::nanoseconds>(timePoint_3 - timePoint_2);! period4 += std::chrono::duration_cast<std::chrono::nanoseconds>(timePoint_4 - timePoint_3);! } // End time loop! report.finalizeProgress();!! report("Prepare part time : ", period1.count());! report("Matrix multiplication time : ", period2.count());! report("Finite difference step time : ", period3.count());! report("Finilizing part time : ", period4.count());!!Вывод: Prepare part time : 26608769!Matrix multiplication time : 87985118534!Finite difference step time : 7031352999!Finilizing part time : 2039084873! 8
OpenMP
OpenMP (Open Mul--‐Processing) — открытый стандарт для распараллеливания программ на языках Си, Си++ и Фортран. Описывает совокупность директив компилятора, библиотечных процедур и переменных окружения, которые предназначены для программирования многопоточных приложений на многопроцессорных системах с общей памятью //Wikipedia
#pragma omp parallel #pragma omp for #pragma omp sec-ons #pragma omp single #pragma omp parallel for #pragma omp parallel sec-ons #pragma omp task #pragma omp master #pragma omp cri-cal #pragma omp barrier
void omp_set_num_threads(int ); int omp_get_num_threads(void); int omp_get_max_threads(void); int omp_get_thread_num(void); int omp_get_num_procs(void); int omp_in_parallel(void); void omp_set_dynamic(int ); void omp_set_lock(omp_lock_t *); int omp_test_lock(omp_lock_t *);
OMP_SCHEDULE type[,chunk] OMP_NUM_THREADS num OMP_DYNAMIC dynamic OMP_NESTED nested OMP_STACKSIZE size OMP_WAIT_POLICY policy OMP_MAX_ACTIVE_LEVELS levels OMP_THREAD_LIMIT limit
9
Ветка: Коммит:
Первая попытка с openMP (не работает) openMP 99940bc
CMakeLists.txt!!find_package(OpenMP REQUIRED) !set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") !!main.cpp!!#include <omp.h> !// ... //! // Stiffness matrix iteration halper! std::unique_ptr<sbfMatrixIterator> iteratorPtr(stiff->createIterator()); ! sbfMatrixIterator *iterator = iteratorPtr.get(); !! // Time integration loop! report.createNewProgress("Time integration"); ! while( t < tStop ) { // Time loop! // Update displacements of kinematically loaded nodes! // ... //!#pragma omp parallel for ! for(int nodeCt = 0; nodeCt < numNodes; nodeCt++) { ! // Make multiplication of stiffness matrix over displacement vector! iterator->setToRow(nodeCt); ! // ... //! while(iterator->isValid()) { ! // ... //! iterator->next(); ! } ! // Perform finite difference step! for(int ct = 0; ct < 3; ct++) { ! temp=force.data(nodeCt, ct) // ... //;! displ_p1.data(nodeCt, ct) = temp/(a0*mass.data(nodeCt, ct)// ... //);! } ! } ! // Make output if required! // Prepere for next step! } // End time loop 10
Ветка: Коммит:
Нормальная работа openMP openMP 3f10371
// Time integration loop! report.createNewProgress("Time integration");! while( t < tStop ) { // Time loop! double tmp[3], temp;! // Update displacements of kinematically loaded nodes! // ... //!#pragma omp parallel private(temp)! {! // Stiffness matrix iteration halper! std::unique_ptr<sbfMatrixIterator> iteratorPtr(stiff->createIterator());! sbfMatrixIterator *iterator = iteratorPtr.get();!#pragma omp for! for(int nodeCt = 0; nodeCt < numNodes; nodeCt++) {! // Make multiplication of stiffness matrix over displacement vector! iterator->setToRow(nodeCt);! // ... //! while(iterator->isValid()) {! // ... //! iterator->next();! }! // Perform finite difference step! for(int ct = 0; ct < 3; ct++) {! temp=force.data(nodeCt, ct) - rezKU.data(nodeCt, ct) +! a2*mass.data(nodeCt, ct)*displ.data(nodeCt, ct) -! (a0*mass.data(nodeCt, ct) - a1*demp.data(nodeCt, ct))*displ_m1.data(nodeCt, ct);! displ_p1.data(nodeCt, ct) = temp/(a0*mass.data(nodeCt, ct) + a1*demp.data(nodeCt, ct));! }! }//End of #pragma omp for! }//End of #pragma omp parallel! // Make output if required! // Prepere for next step! } // End time loop
11
Ветка: Коммит:
Реорганизация области параллельности openMP 4579611
// Time integration loop! double tmp[3]; !#pragma omp parallel ! { ! // Stiffness matrix iteration halper! std::unique_ptr<sbfMatrixIterator> iteratorPtr(stiff->createIterator()); ! sbfMatrixIterator *iterator = iteratorPtr.get(); ! while( t < tStop ) { // Time loop! // Update displacements of kinematically loaded nodes!#pragma omp master ! getDispl(t, tmp, ampX, freqX, transT); !#pragma omp for nowait! for(int nodeCt = 0; nodeCt < numLDown; ++nodeCt) for(int ct = 0; ct < 3; ct++) ! displ.data(loadedNodesDown[nodeCt], ct) = tmp[ct]; !#pragma omp for ! for(int nodeCt = 0; nodeCt < numLUp; ++nodeCt) for(int ct = 0; ct < 3; ct++) ! displ.data(loadedNodesUp[nodeCt], ct) = tmp[ct]/3;!#pragma omp for ! for(int nodeCt = 0; nodeCt < numNodes; nodeCt++) { ! // Make multiplication of stiffness matrix over displacement vector! iterator->setToRow(nodeCt); ! // ... //! while(iterator->isValid()) { ! // ... //! iterator->next(); ! } ! // Perform finite difference step! for(int ct = 0; ct < 3; ct++) ! // ... //! }//End of #pragma omp for!#pragma omp master ! {// Make output if required! t += dt;}//End of #pragma omp master!#pragma omp for ! for(int nodeCt = 0; nodeCt < numNodes; nodeCt++) { ! // Prepere for next step! for(int ct = 0; ct < 3; ct++) { ! displ_m1.data()[3*nodeCt+ct] = displ.data()[3*nodeCt+ct];} ! }//End of #pragma omp for! } // End time loop! }//End of #pragma omp parallel 12
Ветка: Коммит:
Параллельное выполнение секций кода openMP 84f7a19
sbfMesh *mesh = new sbfMesh, tmp;! std::unique_ptr<sbfMesh> c(new sbfMesh);! std::unique_ptr<sbfMesh> plus(new sbfMesh);!#pragma omp parallel sections private(tmp)! {!#pragma omp section! {! //Construct C letter! std::unique_ptr<sbfMesh> roundInner(sbfMesh::makeCylinderPart(1,2,0,2*std::atan(1),0,1,d,2*d,d));! std::unique_ptr<sbfMesh> roundOuter(sbfMesh::makeCylinderPart(5,6,0,2*std::atan(1),0,1,d,8*d,d));! std::unique_ptr<sbfMesh> round(new sbfMesh);! round->addMesh(roundInner.get());! round->addMesh(roundOuter.get());! std::unique_ptr<sbfMesh> part0(sbfMesh::makeBlock(4, 1, 1, 4*d, d, d));! std::unique_ptr<sbfMesh> part4(sbfMesh::makeBlock(3, 1, 1, 3*d, d, d));! part0->translate(0, 4, 0);! c->addMesh(part0.get());! tmp = *round.get();! tmp.translate(4, 19, 0);! c->addMesh(tmp);! // ... ///! }//End of #pragma omp section!!#pragma omp section! {! //Construct plus sign! std::unique_ptr<sbfMesh> part10(sbfMesh::makeBlock(11, 1, 1, 11*d, d, d));! std::unique_ptr<sbfMesh> part11(sbfMesh::makeBlock(1, 3, 1, d, 3*d, d));! std::unique_ptr<sbfMesh> part12(sbfMesh::makeBlock(10, 1, 1, 10*d, d, d));! part11->translate(0, 1, 0);! part12->translate(0, 4, 0);! tmp = *part10.get();! // ... //! }//End of #pragma omp section! }//End of#pragma omp parallel sections private(tmp) 13
Явное создание отдельных вычислительных потоков
Основные инструменты работы с потоками: • POSIX / WinAPI • boost::thread • std::thread
14
Ветка: Коммит:
Создание новых потоков вычисления матричного умножения и разностного шага
threads 94fc6ee
#include <thread>! // ... //! int numThreads;! desc.add_options()! ("nt", po::value<int>(&numThreads)->default_value(8), "number of worker threads”);! // ... //! // Time integration loop! report.createNewProgress("Time integration");! while( t < tStop ) { // Time loop! // Update displacements of kinematically loaded nodes! // ... //! auto procFunc = [&](int start, int stop){! std::unique_ptr<sbfMatrixIterator> iteratorPtr(stiff->createIterator());! sbfMatrixIterator *iterator = iteratorPtr.get();! for(int nodeCt = start; nodeCt < stop; nodeCt++) {! // Make multiplication of stiffness matrix over displacement vector! iterator->setToRow(nodeCt);! while(iterator->isValid()) { /* ... */ }! // Perform finite difference step! for(int ct = 0; ct < 3; ct++) { /* ... */ }! }! };! std::vector<std::thread> threads; threads.resize(numThreads);! for(int ct = 0; ct < numThreads; ct++) threads[ct] =! std::thread( std::bind( procFunc,! numNodes/numThreads*ct,! ct != (numThreads-1) ? numNodes/numThreads*(ct+1) : numNodes) );! for(auto & th : threads) th.join();! // Make output if required! // Prepere for next step! } // End time loop
15
Ветка: Коммит:
Потоки с оповещениями «начинай»/«сделал» threads �b6882
#include <mutex>!#include <condition_variable>! // ... //! struct event{! std::mutex mtx;! std::condition_variable cond;! bool state{false};! void wait() {! std::unique_lock<std::mutex> lock(mtx);! while(!state) cond.wait(lock);! state = false;! }! void set() {! std::unique_lock<std::mutex> lock(mtx);! state = true;! cond.notify_one();! }! };! ! std::vector<event*> eventsStart, eventsStop;! std::vector<std::thread> threads; threads.resize(numThreads);!! auto procFunc = [&](int start, int stop, event *evStart, event *evStop){! std::unique_ptr<sbfMatrixIterator> iteratorPtr(stiff->createIterator());! sbfMatrixIterator *iterator = iteratorPtr.get();! evStop->set();! while(true){! evStart->wait();! for(int nodeCt = start; nodeCt < stop; nodeCt++) {! // Make multiplication of stiffness matrix over displacement vector! // Perform finite difference step! }! evStop->set();! }! }; 16
Ветка: Коммит:
Потоки с оповещениями «начинай»/«сделал» threads �b6882
for(int ct = 0; ct < numThreads; ct++) {! eventsStart.push_back(new event);! eventsStop.push_back(new event);! threads[ct] = std::thread(std::bind(! procFunc, numNodes/numThreads*ct,! ct != (numThreads-1) ? numNodes/numThreads*(ct+1) : numNodes,! eventsStart[ct], eventsStop[ct]));! threads[ct].detach();! }! for(auto ev : eventsStop) ev->wait();! ! // Time integration loop! report.createNewProgress("Time integration");! while( t < tStop ) { // Time loop! // Update displacements of kinematically loaded nodes! ! for(auto ev : eventsStart) ev->set();! for(auto ev : eventsStop) ev->wait();! ! // Make output if required! // Prepere for next step! } // End time loop
17
Ветка: Коммит:
Параллельное выполнение независимых секций кода
threads 7f1534d
#include <thread>!!sbfMesh *createMesh(int discretParam)!{! report("Recreating mesh");! sbfMesh *mesh = new sbfMesh;! ! std::unique_ptr<sbfMesh> c(new sbfMesh);! std::unique_ptr<sbfMesh> plus(new sbfMesh);! ! auto threadC = std::thread([&](){! sbfMesh tmp;! //Construct C letter! // ... //! c->addMesh(part4.get());! });! ! auto threadPlus = std::thread([&](){! sbfMesh tmp;! //Construct plus sign! // ... //! plus->translate(2.5, 12.5, 0);! });! ! threadC.join();! threadPlus.join();! ! // Use of "c" and "plus" to make mesh//! ! return mesh;!}
18
MPI
Message Passing Interface (MPI, интерфейс передачи сообщений) — программный интерфейс для передачи информации, который позволяет обмениваться сообщениями между процессами, выполняющими одну задачу. //Wikipedia
MPI_Comm_size (comm,&size) MPI_Comm_rank (comm,&rank) MPI_Send(&buffer,count,type,dest,tag,comm) MPI_Isend(&buffer,count,type,dest,tag,comm,request) MPI_Recv(&buffer,count,type,source,tag,comm,status) MPI_Irecv(&buffer,count,type,source,tag,comm,request) MPI_Bcast (&buffer,count,datatype,root,comm) MPI_Reduce (&sendbuf,&recvbuf,count,datatype,op,root,comm) MPI_Allreduce (&sendbuf,&recvbuf,count,datatype,op,comm) MPI_Barrier (comm)
19
Ветка: Коммит:
Использование MPI MPI b42b24a
CMakeLists.txt!!find_package(MPI REQUIRED)!include_directories(${MPI_INCLUDE_PATH})!target_link_libraries(${PROJECT_NAME} ${MPI_LIBRARIES})!set(CMAKE_CXX_COMPILE_FLAGS ${CMAKE_CXX_COMPILE_FLAGS} ${MPI_COMPILE_FLAGS})!set(CMAKE_CXX_LINK_FLAGS ${CMAKE_CXX_LINK_FLAGS} ${MPI_LINK_FLAGS})!!main.cpp!!#include <mpi.h>! // ... //! MPI_Init(&argc, &argv);! int procID, numProcs;! MPI_Comm_size(MPI_COMM_WORLD, &numProcs);! MPI_Comm_rank(MPI_COMM_WORLD, &procID);! ! // Create appropriate mesh! std::unique_ptr<sbfMesh> meshPtr(new sbfMesh);! if ( procID == 0 ) if( recreateMesh || meshPtr->readMeshFromFiles() ){! meshPtr.reset(createMesh(discretParam));! }! sbfMesh *mesh = meshPtr.get();! const int numNodes = mesh->numNodes();! MPI_Bcast(const_cast<int*>(&numNodes), 1, MPI_INT, 0, MPI_COMM_WORLD);!
20
Ветка: Коммит:
Использование MPI MPI b42b24a
// Create and compute stiffness matrix! std::unique_ptr<sbfStiffMatrixBlock3x3> stiffPtr(new sbfStiffMatrixBlock3x3);! int numBlocks[2], type;! if ( procID == 0 ) {! stiffPtr.reset(createStiffMatrix(mesh, recreateMesh));! numBlocks[0] = stiffPtr->numBlocks();! numBlocks[1] = stiffPtr->numBlocksAlter();! type = static_cast<int>(stiffPtr->type());! }! MPI_Bcast(numBlocks, 2, MPI_INT, 0, MPI_COMM_WORLD);! MPI_Bcast(&type, 1, MPI_INT, 0, MPI_COMM_WORLD);! if ( procID != 0 ) {! stiffPtr.reset(new sbfStiffMatrixBlock3x3(numBlocks[0], numNodes, numBlocks[1]));! stiffPtr->setType(static_cast<MatrixType>(type));! }! sbfStiffMatrixBlock3x3 *stiff = stiffPtr.get();! MPI_Bcast(const_cast<int *>(stiff->indData()), numBlocks[0], MPI_INT, 0, MPI_COMM_WORLD);! MPI_Bcast(const_cast<int *>(stiff->shiftIndData()), numNodes+1, MPI_INT, 0, MPI_COMM_WORLD);! if (numBlocks[1]) {! MPI_Bcast(const_cast<int *>(stiff->indDataAlter()), numBlocks[1], MPI_INT, 0, MPI_COMM_WORLD);! MPI_Bcast(const_cast<int *>(stiff->shiftIndDataAlter()), numNodes+1, MPI_INT, 0, MPI_COMM_WORLD);! }! MPI_Bcast(const_cast<double *>(stiff->data()), numBlocks[0]*9, MPI_DOUBLE, 0, MPI_COMM_WORLD);! if ( procID != 0 ) stiff->updataAlterPtr();!! // ... //!! // Fill mass and demping arrays! if ( procID == 0 ) computeMassDemp(mass, demp, mesh, stiff->propSet(), ksi, recreateMesh);! MPI_Bcast(mass.data(), numNodes*3, MPI_DOUBLE, 0, MPI_COMM_WORLD);! MPI_Bcast(demp.data(), numNodes*3, MPI_DOUBLE, 0, MPI_COMM_WORLD);!
21
Ветка: Коммит:
Использование MPI MPI b42b24a
// Time integration loop! int nodeStart = numNodes/numProcs*procID;! int nodeStop = procID != numProcs - 1 ? numNodes/numProcs*(procID+1) : numNodes;! if ( procID == 0 ) report.createNewProgress("Time integration");! while( t < tStop ) { // Time loop! // Update displacements of kinematically loaded nodes! // ... //! ! MPI_Bcast(displ.data(), numNodes*3, MPI_DOUBLE, 0, MPI_COMM_WORLD);! rezKU.null();! reduceBuf.null();! for(int nodeCt = nodeStart; nodeCt < nodeStop; nodeCt++) {! // Make multiplication of stiffness matrix over displacement vector! iterator->setToRow(nodeCt);! while(iterator->isValid()) { /* ... */ iterator->next(); }! // Perform finite difference step! for(int ct = 0; ct < 3; ct++) {! // ... //! reduceBuf.data()[3*nodeCt+ct] = temp/(a0*mass.data()[3*nodeCt+ct] + a1*demp.data()[3*nodeCt+ct]);! }! }! MPI_Allreduce(reduceBuf.data(), displ_p1.data(), numNodes*3, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);! ! // Make output if required! if ( procID == 0 ) if(t >= tNextOut) { /* ... */ }! // Prepere for next step! t += dt;! displ_m1.copyData(displ); displ.copyData(displ_p1);! } // End time loop! if ( procID == 0 ) report.finalizeProgress();! ! MPI_Finalize();!
22
Ветка: Коммит:
MPI + потоки MPI_threads 7b033e3
int nodeStart = numNodes/numProcs*procID;! int nodeStop = procID != numProcs - 1 ? numNodes/numProcs*(procID+1) : numNodes;! ! for(int ct = 0; ct < numThreads; ct++) {! eventsStart.push_back(new event);! eventsStop.push_back(new event);! int threadStartNode = nodeStart + (nodeStop - nodeStart)/numThreads*ct;! int threadStopNode = nodeStart + (nodeStop - nodeStart)/numThreads*(ct+1);! if(ct == numThreads-1) threadStopNode = nodeStop;! threads[ct] = std::thread(std::bind(procFunc, threadStartNode, threadStopNode, eventsStart[ct], eventsStop[ct]));! threads[ct].detach();! }! for(auto ev : eventsStop) ev->wait();! ! // Time integration loop! if ( procID == 0 ) report.createNewProgress("Time integration");! while( t < tStop ) { // Time loop! // Update displacements of kinematically loaded nodes! ! MPI_Bcast(displ.data(), numNodes*3, MPI_DOUBLE, 0, MPI_COMM_WORLD);! rezKU.null(); reduceBuf.null();! for(auto ev : eventsStart) ev->set();! for(auto ev : eventsStop) ev->wait();! MPI_Allreduce(reduceBuf.data(), displ_p1.data(), numNodes*3, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);! ! // Make output if required! if ( procID == 0 ) if(t >= tNextOut) { /* ... */}! // Prepere for next step! t += dt; displ_m1.copyData(displ); displ.copyData(displ_p1);! } // End time loop! if ( procID == 0 ) report.finalizeProgress();
23
Вместо выводов
Один поток openMP threads MPI MPI + threads
97 20 21 42 31
IMHO: • При современном развитии вычислительной техники разработчику непростительно
написание не параллельных программ, особенно в области расчетов • Современные стандарты и их реализации позволяют относительно быстро
внедрять их в существующие или вновь создаваемые проекты • Хотя, возможно в ближайшем будущем компиляторы научатся делать все за нас :)
24
Крутько Евгений [email protected]
google.com/+ЕвгенийКрутько Репозиторий проекта:
hnps://github.com/eskrut/directIntegra-onSolver.git
25