Your SlideShare is downloading. ×
0
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повышения производительности численных расчётов

327

Published on

Евгений Крутько, НИЦ «Курчатовский институт». …

Евгений Крутько, НИЦ «Курчатовский институт».

В докладе на примере программы моделирования динамики движения конструкций по методу конечных элементов рассматриваются возможности и практика распараллеливания вычислений. Речь в нём пойдёт как о технике создания новых вычислительных потоков, так и об использовании стандартов openMP и MPI.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
327
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. C++  User  Group  Mee-ng,  Nizhniy  Novgorod,  19.04.14   Опыт  внедрения  технологий  параллельных  вычислений   для  повышения  производительности  численных  расчетов   Крутько  Е.С.   НИЦ  «Курчатовский  институт»   e.s.krutko@gmail.com  
  • 2. План  презентации   •  Рассмотрение  кода  программы  моделирования  динамики   твердого  тела  по  методу  конечных  элементов   •  Использование  openmp   •  Явное  создание  вычислительных  потоков   •  Использование  MPI   •  Комбинированный  подход   Репозиторий  проекта:   hnps://github.com/eskrut/directIntegra-onSolver.git   2  
  • 3. Кратко  о  теории   M¨q + C ˙q + Kq = f q = {dx0, dy0, dz0, · · · dxN 1, dyN 1, dzN 1}T M = 0 B B B @ m0 0 0 0 0 m1 0 0 0 0 ... 0 0 0 0 mN 1 1 C C C A 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 Задача   решается   по   методу   к о н е ч н ы х   э л е м е н т о в   с   использованием   явной   схемы   интегрирования   по   времени.   Вся   необходимая   логика   МКЭ   реализована   во   внешней   библиотеке,  необходимо  только   построить   на   ее   основе   решатель.   3  
  • 4. Объект  исследования   ~250  000    узлов   4  
  • 5. Ветка:   Коммит:   Основной  код  программы   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>(&ampX)->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  
  • 6. Ветка:   Коммит:   Основной  код  программы   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  
  • 7. Ветка:   Коммит:   Основной  код  программы   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  
  • 8. Ветка:   Коммит:   Поиск  узкого  места   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  
  • 9. 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  
  • 10. Ветка:   Коммит:   Первая  попытка  с  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  
  • 11. Ветка:   Коммит:   Нормальная  работа  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  
  • 12. Ветка:   Коммит:   Реорганизация  области  параллельности   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  
  • 13. Ветка:   Коммит:   Параллельное  выполнение  секций  кода   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  
  • 14. Явное  создание  отдельных  вычислительных  потоков   Основные  инструменты  работы  с  потоками:   •  POSIX  /  WinAPI   •  boost::thread   •  std::thread   14  
  • 15. Ветка:   Коммит:   Создание  новых  потоков  вычисления   матричного  умножения  и  разностного  шага   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  
  • 16. Ветка:   Коммит:   Потоки  с  оповещениями  «начинай»/«сделал»   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  
  • 17. Ветка:   Коммит:   Потоки  с  оповещениями  «начинай»/«сделал»   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  
  • 18. Ветка:   Коммит:   Параллельное  выполнение  независимых   секций  кода   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  
  • 19. 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  
  • 20. Ветка:   Коммит:   Использование  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  
  • 21. Ветка:   Коммит:   Использование  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  
  • 22. Ветка:   Коммит:   Использование  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  
  • 23. Ветка:   Коммит:   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  
  • 24. Вместо  выводов   Один  поток   openMP   threads   MPI   MPI  +   threads   97   20   21   42   31   IMHO:   •  При  современном  развитии  вычислительной  техники  разработчику  непростительно   написание  не  параллельных  программ,  особенно  в  области  расчетов   •  Современные  стандарты  и  их  реализации  позволяют  относительно  быстро   внедрять  их  в  существующие  или  вновь  создаваемые  проекты   •  Хотя,  возможно  в  ближайшем  будущем  компиляторы  научатся  делать  все  за  нас  :)   24  
  • 25. Крутько  Евгений   e.s.krutko@gmail.com   google.com/+ЕвгенийКрутько   Репозиторий  проекта:   hnps://github.com/eskrut/directIntegra-onSolver.git   25  

×