MBDyn-1.7.3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups
mtdataman.cc
Go to the documentation of this file.
1 /* $Header: /var/cvs/mbdyn/mbdyn/mbdyn-1.0/mbdyn/base/mtdataman.cc,v 1.75 2017/01/12 14:46:10 masarati Exp $ */
2 /*
3  * MBDyn (C) is a multibody analysis code.
4  * http://www.mbdyn.org
5  *
6  * Copyright (C) 1996-2017
7  *
8  * Pierangelo Masarati <masarati@aero.polimi.it>
9  * Paolo Mantegazza <mantegazza@aero.polimi.it>
10  *
11  * Dipartimento di Ingegneria Aerospaziale - Politecnico di Milano
12  * via La Masa, 34 - 20156 Milano, Italy
13  * http://www.aero.polimi.it
14  *
15  * Changing this copyright notice is forbidden.
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation (version 2 of the License).
20  *
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30  */
31 
32 /* datamanager */
33 
34 #include "mbconfig.h" /* This goes first in every *.c,*.cc file */
35 
36 #ifdef USE_MULTITHREAD
37 
38 extern "C" {
39 #include <time.h>
40 #ifdef HAVE_SYS_TIMES_H
41 #include <sys/times.h>
42 #endif /* HAVE_SYS_TIMES_H */
43 #ifdef HAVE_SCHED_H
44 #include <sched.h>
45 #endif /* HAVE_SCHED_H */
46 
47 
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #include <fcntl.h>
51 #ifdef HAVE_SYS_IOCTL_H
52 #include <sys/ioctl.h>
53 #endif
54 #include <stdio.h>
55 }
56 
57 #include <cerrno>
58 
59 #include "mtdataman.h"
60 #include "spmapmh.h"
61 #include "task2cpu.h"
62 
63 static inline void
64 do_lock(volatile AO_TS_t *p)
65 {
66  while (mbdyn_test_and_set(p) == AO_TS_SET);
67 }
68 
69 static inline void
70 do_unlock(AO_TS_t *p)
71 {
72  AO_CLEAR(p);
73 }
74 
75 static void
76 naivepsad(doublereal **ga, integer **gri,
77  integer *gnzr, integer **gci, integer *gnzc, char **gnz,
78  doublereal **a, integer **ci, integer *nzc,
79  integer from, integer to, AO_TS_t *lock)
80 {
81 
82  for (integer r = from; r < to; r++) {
83  integer nc = nzc[r];
84 
85  if (nc) {
86  doublereal *pgar = ga[r];
87  doublereal *par = a[r];
88 
89  for (integer i = 0; i < nc; i++) {
90  integer c = ci[r][i];
91 
92  if (gnz[r][c]) {
93  pgar[c] += par[c];
94 
95  } else {
96  pgar[c] = par[c];
97  gci[r][gnzc[r]] = c;
98  /* This can only be set to 1 from 0,
99  * so concurrency is harmless
100  */
101  gnz[r][c] = 1;
102 
103  do_lock(&lock[c]);
104 
105  gri[c][gnzr[c]] = r;
106  gnzr[c]++;
107 
108  do_unlock(&lock[c]);
109  gnzc[r]++;
110  }
111  }
112  }
113  }
114 }
115 
116 
117 /* MultiThreadDataManager - begin */
118 
119 
120 /*
121  * costruttore: inizializza l'oggetto, legge i dati e crea le strutture di
122  * gestione di Dof, nodi, elementi e drivers.
123  */
124 
125 MultiThreadDataManager::MultiThreadDataManager(MBDynParser& HP,
126  unsigned OF,
127  Solver* pS,
128  doublereal dInitialTime,
129  const char* sOutputFileName,
130  const char* sInputFileName,
131  bool bAbortAfterInput,
132  unsigned nThreads)
133 :
134 DataManager(HP, OF, pS, dInitialTime, sOutputFileName, sInputFileName, bAbortAfterInput),
135 AssMode(ASS_UNKNOWN),
136 CCReady(CC_NO),
137 thread_data(0),
138 op(MultiThreadDataManager::OP_UNKNOWN),
139 thread_count(0),
140 propagate_ErrMatrixRebuild(AO_TS_INITIALIZER)
141 {
142  DataManager::nThreads = nThreads;
143 
144 #if 0 /* no effects ... */
145  struct sched_param sp;
146  int policy = SCHED_FIFO;
147  int rc;
148 
149  rc = sched_getparam(0, &sp);
150  if (rc != 0) {
151  silent_cerr("sched_getparam() failed: " << errno << std::endl);
153  }
154 
155  int pmin = sched_get_priority_min(policy);
156  int pmax = sched_get_priority_max(policy);
157 
158  silent_cout("current priority is " << sp.sched_priority
159  << " {" << pmin << "," << pmax << "}" << std::endl);
160 
161  if (sp.sched_priority > pmax || sp.sched_priority < pmin) {
162  sp.sched_priority = pmax;
163  }
164 
165  rc = sched_setscheduler(0, policy, &sp);
166  if (rc != 0) {
167  silent_cerr("sched_setscheduler() unable "
168  "to set SCHED_FIFO scheduling policy: "
169  << errno
170  << std::endl);
172  }
173 #endif
174 
175  if (pthread_mutex_init(&thread_mutex, NULL)) {
176  silent_cerr("MultiThreadDataManager::MultiThreadDataManager(): "
177  "mutex init failed" << std::endl);
179  }
180 
181  if (pthread_cond_init(&thread_cond, NULL)) {
182  silent_cerr("MultiThreadDataManager::MultiThreadDataManager(): "
183  "cond init failed" << std::endl);
185  }
186 
187  ThreadSpawn();
188 }
189 
190 MultiThreadDataManager::~MultiThreadDataManager(void)
191 {
192  pthread_mutex_destroy(&thread_mutex);
193  pthread_cond_destroy(&thread_cond);
194 }
195 
196 clock_t
197 MultiThreadDataManager::ThreadDestroy(void)
198 {
199  if (thread_data == 0) {
200  return 0;
201  }
202 
203  clock_t cputime = 0;
204 
205  op = MultiThreadDataManager::OP_EXIT;
206  thread_count = nThreads - 1;
207 
208  for (unsigned i = 1; i < nThreads; i++) {
209  void *retval = NULL;
210 
211  sem_post(&thread_data[i].sem);
212  if (pthread_join(thread_data[i].thread, &retval)) {
213  silent_cerr("pthread_join() failed on thread " << i
214  << std::endl);
215  /* already shutting down ... */
216  }
217 
218  cputime += thread_data[i].cputime;
219  }
220 
221  if (thread_data[0].lock) {
222  SAFEDELETEARR(thread_data[0].lock);
223  }
224  thread_cleanup(&thread_data[0]);
225 
226  SAFEDELETEARR(thread_data);
227  thread_data = 0;
228 
229  return cputime;
230 }
231 
232 
233 void *
234 MultiThreadDataManager::thread(void *p)
235 {
236  MultiThreadDataManager::ThreadData *arg
237  = (MultiThreadDataManager::ThreadData *)p;
238 
239  silent_cout("MultiThreadDataManager: thread " << arg->threadNumber
240  << " [self=" << pthread_self()
241  << ",pid=" << getpid() << "]"
242  << " starting..." << std::endl);
243 
244  bool bKeepGoing = true;
245 
246 #ifdef HAVE_PTHREAD_SIGMASK
247  /* deal with signals ... */
248  sigset_t newset /* , oldset */ ;
249  sigemptyset(&newset);
250  sigaddset(&newset, SIGTERM);
251  sigaddset(&newset, SIGINT);
252  sigaddset(&newset, SIGHUP);
253  pthread_sigmask(SIG_BLOCK, &newset, /* &oldset */ NULL);
254 #endif
255 
256  (void)mbdyn_task2cpu(arg->threadNumber - 1);
257 
258  while (bKeepGoing) {
259  /* stop here until told to start */
260  /*
261  * NOTE: here
262  * - the requested operation must be set;
263  * - the appropriate operation args must be set
264  * - the thread_count must be set to nThreads - 1
265  */
266  sem_wait(&arg->sem);
267 
268  DEBUGCOUT("thread " << arg->threadNumber << ": "
269  "op " << arg->pDM->op << std::endl);
270 
271  /* select requested operation */
272  switch (arg->pDM->op) {
273  case MultiThreadDataManager::OP_ASSJAC_CC:
274  //arg->pJacHdl->Reset();
275  try {
276  arg->pDM->DataManager::AssJac(*arg->pJacHdl,
277  arg->dCoef,
278  arg->ElemIter,
279  *arg->pWorkMat);
280 
282  silent_cerr("thread " << arg->threadNumber
283  << " caught ErrRebuildMatrix"
284  << std::endl);
285 
286  mbdyn_test_and_set(&arg->pDM->propagate_ErrMatrixRebuild);
287 
288  } catch (...) {
289  throw;
290  }
291  break;
292 
293  case MultiThreadDataManager::OP_ASSJAC_NAIVE:
294 #if 0
295  arg->ppNaiveJacHdl[arg->threadNumber]->Reset();
296 #endif
297  /* NOTE: Naive should never throw
298  * ErrRebuildMatrix ... */
299  arg->pDM->DataManager::AssJac(*arg->ppNaiveJacHdl[arg->threadNumber],
300  arg->dCoef,
301  arg->ElemIter,
302  *arg->pWorkMat);
303  break;
304 
305  case MultiThreadDataManager::OP_SUM_NAIVE:
306  {
307  /* FIXME: if the naive matrix is permuted (colamd),
308  * this should not impact the parallel assembly,
309  * because all the matrices refer to the same
310  * permutation vector */
311  NaiveMatrixHandler* to = arg->ppNaiveJacHdl[0];
312  integer nn = to->iGetNumRows();
313  integer iFrom = (nn*(arg->threadNumber))/arg->pDM->nThreads;
314  integer iTo = (nn*(arg->threadNumber + 1))/arg->pDM->nThreads;
315  for (unsigned int matrix = 1; matrix < arg->pDM->nThreads; matrix++) {
316  NaiveMatrixHandler* from = arg->ppNaiveJacHdl[matrix];
317  naivepsad(to->ppdRows,
318  to->ppiRows, to->piNzr,
319  to->ppiCols, to->piNzc, to->ppnonzero,
320  from->ppdRows, from->ppiCols, from->piNzc,
321  iFrom, iTo, arg->lock);
322  }
323  break;
324  }
325 
326 #ifdef MBDYN_X_MT_ASSRES
327  case MultiThreadDataManager::OP_ASSRES:
328  arg->pResHdl->Reset();
329  arg->pDM->DataManager::AssRes(*arg->pResHdl,
330  arg->dCoef,
331  arg->ElemIter,
332  *arg->pWorkVec);
333  break;
334 #endif /* MBDYN_X_MT_ASSRES */
335 
336  case MultiThreadDataManager::OP_EXIT:
337  /* cleanup */
338  thread_cleanup(arg);
339  bKeepGoing = false;
340  break;
341 
342  default:
343  silent_cerr("MultiThreadDataManager: unhandled op"
344  << std::endl);
346  }
347 
348  /* decrease counter and signal if last
349  * (mutex + cond) */
350  arg->pDM->EndOfOp();
351  }
352 
353  /* all threads are joined */
354  pthread_exit(NULL);
355 }
356 
357 void
358 MultiThreadDataManager::thread_cleanup(ThreadData *arg)
359 {
360  /* cleanup */
361  SAFEDELETE(arg->pWorkMatA);
362  SAFEDELETE(arg->pWorkMatB);
363  SAFEDELETE(arg->pWorkVec);
364  if (arg->threadNumber > 0) {
365  if (arg->pJacHdl) {
366  SAFEDELETE(arg->pJacHdl);
367  }
368  SAFEDELETE(arg->pResHdl);
369 
370  } else {
371  if (arg->ppNaiveJacHdl) {
372  // can be nonzero only when in Naive form
373  SAFEDELETEARR(arg->ppNaiveJacHdl);
374  }
375  }
376  sem_destroy(&arg->sem);
377 
378 #ifdef HAVE_SYS_TIMES_H
379  /* Tempo di CPU impiegato */
380  struct tms tmsbuf;
381  times(&tmsbuf);
382 
383  pedantic_cout("thread " << arg->threadNumber << ":" << std::endl
384  << "\tutime: " << tmsbuf.tms_utime << std::endl
385  << "\tstime: " << tmsbuf.tms_stime << std::endl
386  << "\tcutime: " << tmsbuf.tms_cutime << std::endl
387  << "\tcstime: " << tmsbuf.tms_cstime << std::endl);
388 
389  arg->cputime = tmsbuf.tms_utime + tmsbuf.tms_cutime
390  + tmsbuf.tms_stime + tmsbuf.tms_cstime;
391 #endif /* HAVE_SYS_TIMES_H */
392 }
393 
394 void
395 MultiThreadDataManager::EndOfOp(void)
396 {
397  bool last;
398 
399  /* decrement the thread counter */
400  pthread_mutex_lock(&thread_mutex);
401  thread_count--;
402  last = (thread_count == 0);
403 
404  /* if last thread, signal to restart */
405  if (last) {
406  pthread_cond_signal(&thread_cond);
407  // pthread_cond_broadcast(&thread_cond);
408  }
409 
410  pthread_mutex_unlock(&thread_mutex);
411 }
412 
413 /* starts the helper threads */
414 void
415 MultiThreadDataManager::ThreadSpawn(void)
416 {
417  ASSERT(nThreads > 1);
418 
419  SAFENEWARRNOFILL(thread_data, MultiThreadDataManager::ThreadData, nThreads);
420 
421  for (unsigned i = 0; i < nThreads; i++) {
422  /* callback data */
423  thread_data[i].pDM = this;
424  sem_init(&thread_data[i].sem, 0, 0);
425  thread_data[i].threadNumber = i;
426  thread_data[i].ElemIter.Init(&Elems[0], Elems.size());
427  thread_data[i].lock = 0;
428 
429  /* SubMatrixHandlers */
430  thread_data[i].pWorkMatA = 0;
431  SAFENEWWITHCONSTRUCTOR(thread_data[i].pWorkMatA,
433  VariableSubMatrixHandler(iMaxWorkNumRowsJac,
434  iMaxWorkNumColsJac,
435  iMaxWorkNumItemsJac));
436 
437  thread_data[i].pWorkMatB = 0;
438  SAFENEWWITHCONSTRUCTOR(thread_data[i].pWorkMatB,
440  VariableSubMatrixHandler(iMaxWorkNumRowsJac,
441  iMaxWorkNumColsJac,
442  iMaxWorkNumItemsJac));
443 
444  thread_data[i].pWorkMat = thread_data[i].pWorkMatA;
445 
446  thread_data[i].pWorkVec = 0;
447  SAFENEWWITHCONSTRUCTOR(thread_data[i].pWorkVec,
449  MySubVectorHandler(iMaxWorkNumRowsRes));
450 
451  /* set by AssJac when in CC form */
452  thread_data[i].pJacHdl = 0;
453 
454  /* set by AssJac when in Naive form */
455  thread_data[i].ppNaiveJacHdl = 0;
456 
457  /* set below */
458  thread_data[i].pResHdl = 0;
459 
460  /* to be sure... */
461  thread_data[i].pMatA = 0;
462  thread_data[i].pMatB = 0;
463 
464  if (i == 0) {
465  continue;
466  }
467 
468  SAFENEWWITHCONSTRUCTOR(thread_data[i].pResHdl,
469  MyVectorHandler, MyVectorHandler(iTotDofs));
470 
471  /* create thread */
472  if (pthread_create(&thread_data[i].thread, NULL, thread,
473  &thread_data[i]) != 0) {
474  silent_cerr("pthread_create() failed "
475  "for thread " << i
476  << " of " << nThreads << std::endl);
478  }
479  }
480 
481  (void)mbdyn_task2cpu(nThreads - 1);
482 }
483 
484 void
485 MultiThreadDataManager::AssJac(MatrixHandler& JacHdl, doublereal dCoef)
486 {
487 retry:;
488  switch (AssMode) {
489  case ASS_CC:
490  CCAssJac(JacHdl, dCoef);
491  break;
492 
493  case ASS_NAIVE:
494  ASSERT(thread_data[0].ppNaiveJacHdl != 0);
495  if (&JacHdl == thread_data[0].ppNaiveJacHdl[0]) {
496  /*
497  * NOTE: this test is here to detect whether JacHdl changed
498  * (typically it changes any time Solver::SetupSolmans() is called)
499  * However, just looking at the pointer does not suffice;
500  * we also need to check that "perm" did not change.
501  * For this purpose, we compare the address of "perm"
502  * in JacHdl and in the MatrixHandler of the second thread.
503  */
504  NaivePermMatrixHandler *pNaivePermJacHdl = dynamic_cast<NaivePermMatrixHandler *>(&JacHdl);
505  bool bDoAssemble(false);
506  if (!pNaivePermJacHdl) {
507  bDoAssemble = true;
508 
509  } else {
510  NaivePermMatrixHandler *pNaivePermJacHdl2 = dynamic_cast<NaivePermMatrixHandler *>(thread_data[0].ppNaiveJacHdl[1]);
511  ASSERT(pNaivePermJacHdl2 != 0);
512  if (&pNaivePermJacHdl->GetPerm() == &pNaivePermJacHdl2->GetPerm()) {
513  bDoAssemble = true;
514  }
515  }
516 
517  if (bDoAssemble) {
518  NaiveAssJac(JacHdl, dCoef);
519  break;
520  }
521  }
522 
523  for (unsigned i = 1; i < nThreads; i++) {
524  if (thread_data[0].ppNaiveJacHdl[i]) {
525  SAFEDELETE(thread_data[0].ppNaiveJacHdl[i]);
526  thread_data[0].ppNaiveJacHdl[i] = 0;
527  }
528  }
529 
530  SAFEDELETEARR(thread_data[0].lock);
531  thread_data[0].lock = 0;
532 
533  /* intentionally continue to next block */
534 
535  case ASS_UNKNOWN:
536  {
537  NaiveMatrixHandler *pNaiveJacHdl = dynamic_cast<NaiveMatrixHandler *>(&JacHdl);
538  if (pNaiveJacHdl) {
539  AssMode = ASS_NAIVE;
540 
541  /* use JacHdl as matrix for the first thread,
542  * and create copies for the other threads;
543  * each thread sees the array of all the matrices,
544  * and uses only its own for element assembly,
545  * all for per-thread matrix summation */
546  SAFENEWARR(thread_data[0].lock, AO_TS_t, JacHdl.iGetNumRows());
547  for (integer i = 0; i < JacHdl.iGetNumRows(); i++) {
548  thread_data[0].lock[i] = AO_TS_INITIALIZER;
549  }
550 
551  thread_data[0].ppNaiveJacHdl = 0;
552  SAFENEWARR(thread_data[0].ppNaiveJacHdl,
553  NaiveMatrixHandler*, nThreads);
554  thread_data[0].ppNaiveJacHdl[0] = pNaiveJacHdl;
555 
556  NaivePermMatrixHandler *pNaivePermJacHdl = dynamic_cast<NaivePermMatrixHandler *>(&JacHdl);
557  for (unsigned i = 1; i < nThreads; i++) {
558  thread_data[i].lock = thread_data[0].lock;
559  thread_data[i].ppNaiveJacHdl = thread_data[0].ppNaiveJacHdl;
560  thread_data[0].ppNaiveJacHdl[i] = 0;
561 
562  if (pNaivePermJacHdl) {
563  SAFENEWWITHCONSTRUCTOR(thread_data[0].ppNaiveJacHdl[i],
566  pNaivePermJacHdl->GetPerm(),
567  pNaivePermJacHdl->GetInvPerm()));
568 
569  } else {
570  SAFENEWWITHCONSTRUCTOR(thread_data[0].ppNaiveJacHdl[i],
572  NaiveMatrixHandler(JacHdl.iGetNumRows()));
573  }
574  }
575  goto retry;
576  }
577 
578  AssMode = ASS_CC;
579  goto retry;
580  }
581 
582  default:
583  silent_cerr("unable to detect jacobian matrix type "
584  "for multithread assembly" << std::endl);
586  }
587 }
588 
589 void
590 MultiThreadDataManager::CCAssJac(MatrixHandler& JacHdl, doublereal dCoef)
591 {
592  ASSERT(thread_data != NULL);
593 
594  AO_CLEAR(&propagate_ErrMatrixRebuild);
595 
597  = dynamic_cast<CompactSparseMatrixHandler *>(&JacHdl);
598 
599  while (false) {
600 retry:;
601  CCReady = CC_NO;
602  for (unsigned i = 1; i < nThreads; i++) {
603  SAFEDELETE(thread_data[i].pJacHdl);
604  thread_data[i].pJacHdl = 0;
605  }
606  }
607 
608  switch (CCReady) {
609  case CC_NO:
610  DEBUGCERR("CC_NO => CC_FIRST" << std::endl);
611 
612  ASSERT(dynamic_cast<SpMapMatrixHandler *>(&JacHdl) != 0);
613 
614  DataManager::AssJac(JacHdl, dCoef, ElemIter, *pWorkMat);
615  CCReady = CC_FIRST;
616 
617  return;
618 
619  case CC_FIRST:
620  if (pMH == 0) {
621  goto retry;
622  }
623 
624  DEBUGCERR("CC_FIRST => CC_YES" << std::endl);
625 
626  for (unsigned i = 1; i < nThreads; i++) {
627  thread_data[i].pJacHdl = pMH->Copy();
628  }
629 
630  CCReady = CC_YES;
631 
632  break;
633 
634  case CC_YES:
635  if (pMH == 0) {
636  goto retry;
637  }
638 
639  DEBUGCERR("CC_YES" << std::endl);
640 
641  break;
642 
643  default:
645 
646  }
647 
648  thread_data[0].ElemIter.ResetAccessData();
649  op = MultiThreadDataManager::OP_ASSJAC_CC;
650  thread_count = nThreads - 1;
651 
652  for (unsigned i = 1; i < nThreads; i++) {
653  thread_data[i].dCoef = dCoef;
654 
655  sem_post(&thread_data[i].sem);
656  }
657 
658  try {
659  DataManager::AssJac(JacHdl, dCoef, thread_data[0].ElemIter,
660  *thread_data[0].pWorkMat);
661 
663  silent_cerr("thread " << thread_data[0].threadNumber
664  << " caught ErrRebuildMatrix"
665  << std::endl);
666 
667  mbdyn_test_and_set(&propagate_ErrMatrixRebuild);
668 
669  } catch (...) {
670  throw;
671  }
672 
673  pthread_mutex_lock(&thread_mutex);
674  if (thread_count > 0) {
675  pthread_cond_wait(&thread_cond, &thread_mutex);
676  }
677  pthread_mutex_unlock(&thread_mutex);
678 
679  if (propagate_ErrMatrixRebuild == AO_TS_SET) {
680  for (unsigned i = 1; i < nThreads; i++) {
681  SAFEDELETE(thread_data[i].pJacHdl);
682  thread_data[i].pJacHdl = 0;
683  }
684  CCReady = CC_NO;
685 
687  }
688 
689  for (unsigned i = 1; i < nThreads; i++) {
690  pMH->AddUnchecked(*thread_data[i].pJacHdl);
691  }
692 }
693 
694 void
695 MultiThreadDataManager::NaiveAssJac(MatrixHandler& JacHdl, doublereal dCoef)
696 {
697  ASSERT(thread_data != NULL);
698 
699  /* Assemble per-thread matrix */
700  thread_data[0].ElemIter.ResetAccessData();
701  op = MultiThreadDataManager::OP_ASSJAC_NAIVE;
702  thread_count = nThreads - 1;
703 
704  for (unsigned i = 1; i < nThreads; i++) {
705  thread_data[i].dCoef = dCoef;
706 
707  sem_post(&thread_data[i].sem);
708  }
709 
710  /* FIXME Right now it's already done before calling AssJac;
711  * needs be moved here to improve parallel performances... */
712 #if 0
713  thread_data[0].ppNaiveJacHdl[0]->Reset();
714 #endif
715  DataManager::AssJac(*thread_data[0].ppNaiveJacHdl[0],
716  dCoef,
717  thread_data[0].ElemIter,
718  *thread_data[0].pWorkMat);
719 
720  pthread_mutex_lock(&thread_mutex);
721  if (thread_count > 0) {
722  pthread_cond_wait(&thread_cond, &thread_mutex);
723  }
724  pthread_mutex_unlock(&thread_mutex);
725 
726  /* Sum per-thread matrices */
727  op = MultiThreadDataManager::OP_SUM_NAIVE;
728  thread_count = nThreads - 1;
729  for (unsigned i = 1; i < nThreads; i++) {
730  sem_post(&thread_data[i].sem);
731  }
732 
733  NaiveMatrixHandler* to = thread_data[0].ppNaiveJacHdl[0];
734  integer nn = to->iGetNumRows();
735  integer iFrom = 0;
736  integer iTo = nn/nThreads;
737  for (unsigned matrix = 1; matrix < nThreads; matrix++) {
738  NaiveMatrixHandler* from = thread_data[0].ppNaiveJacHdl[matrix];
739  naivepsad(to->ppdRows,
740  to->ppiRows, to->piNzr,
741  to->ppiCols, to->piNzc, to->ppnonzero,
742  from->ppdRows, from->ppiCols, from->piNzc,
743  iFrom, iTo, thread_data[0].lock);
744  }
745 
746  pthread_mutex_lock(&thread_mutex);
747  if (thread_count > 0) {
748  pthread_cond_wait(&thread_cond, &thread_mutex);
749  }
750 
751  pthread_mutex_unlock(&thread_mutex);
752 }
753 
754 #ifdef MBDYN_X_MT_ASSRES
755 void
756 MultiThreadDataManager::AssRes(VectorHandler& ResHdl, doublereal dCoef)
757  throw(ChangedEquationStructure)
758 {
759  ASSERT(thread_data != NULL);
760 
761  thread_data[0].ElemIter.ResetAccessData();
762  op = MultiThreadDataManager::OP_ASSRES;
763  thread_count = nThreads - 1;
764 
765  for (unsigned i = 1; i < nThreads; i++) {
766  thread_data[i].dCoef = dCoef;
767 
768  sem_post(&thread_data[i].sem);
769  }
770 
771  DataManager::AssRes(ResHdl, dCoef, thread_data[0].ElemIter,
772  *thread_data[0].pWorkVec);
773 
774  pthread_mutex_lock(&thread_mutex);
775  if (thread_count > 0) {
776  pthread_cond_wait(&thread_cond, &thread_mutex);
777  }
778  pthread_mutex_unlock(&thread_mutex);
779 
780  for (unsigned i = 1; i < nThreads; i++) {
781  ResHdl += *thread_data[i].pResHdl;
782  }
783 }
784 #endif /* MBDYN_X_MT_ASSRES */
785 
786 clock_t
787 MultiThreadDataManager::GetCPUTime(void) const
788 {
789  return const_cast<MultiThreadDataManager *>(this)->ThreadDestroy();
790 }
791 
792 #endif /* USE_MULTITHREAD */
793 
integer iGetNumRows(void) const
Definition: naivemh.h:111
doublereal ** ppdRows
Definition: naivemh.h:60
integer * piNzr
Definition: naivemh.h:63
virtual CompactSparseMatrixHandler * Copy(void) const =0
#define MBDYN_EXCEPT_ARGS
Definition: except.h:63
void AddUnchecked(const CompactSparseMatrixHandler &m)
Definition: spmh.cc:72
doublereal i
Definition: motor.h:85
#define SAFEDELETEARR(pnt)
Definition: mynewmem.h:713
integer ** ppiRows
Definition: naivemh.h:61
integer * piNzc
Definition: naivemh.h:63
char ** ppnonzero
Definition: naivemh.h:62
virtual void AssRes(VectorHandler &ResHdl, doublereal dCoef)
Definition: elman.cc:498
#define DEBUGCERR(msg)
Definition: myassert.h:235
Definition: matrix.h:61
int mbdyn_task2cpu(int cpu)
Definition: task2cpu.cc:56
const std::vector< integer > & GetPerm(void) const
Definition: naivemh.cc:578
octave_value_list retval
#define DEBUGCOUT(msg)
Definition: myassert.h:232
integer ** ppiCols
Definition: naivemh.h:61
virtual void AssJac(MatrixHandler &JacHdl, doublereal dCoef)
Definition: elman.cc:392
#define ASSERT(expression)
Definition: colamd.c:977
#define SAFENEWWITHCONSTRUCTOR(pnt, item, constructor)
Definition: mynewmem.h:698
Definition: solver.h:78
static std::stack< cleanup * > c
Definition: cleanup.cc:59
struct matrix matrix
#define SAFENEWARRNOFILL(pnt, item, sz)
Definition: mynewmem.h:704
#define SAFENEWARR(pnt, item, sz)
Definition: mynewmem.h:701
static const doublereal a
Definition: hfluid_.h:289
double doublereal
Definition: colamd.c:52
long int integer
Definition: colamd.c:51
const std::vector< integer > & GetInvPerm(void) const
Definition: naivemh.cc:591
virtual integer iGetNumRows(void) const =0
#define SAFEDELETE(pnt)
Definition: mynewmem.h:710