1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
11 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
12 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
13 * Copyright (c) 2001-2004, The GROMACS development team,
14 * check out http://www.gromacs.org for more information.
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * If you want to redistribute modifications, please consider that
22 * scientific software is very special. Version control is crucial -
23 * bugs must be traceable. We will be happy to consider code for
24 * inclusion in the official distribution, but derived work must not
25 * be called official GROMACS. Details are found in the README & COPYING
26 * files - if they are missing, get the official version at www.gromacs.org.
28 * To help us fund GROMACS development, we humbly ask that you cite
29 * the papers on the package - you can find them in the top README file.
31 * For more info, check our website at http://www.gromacs.org
34 * GROningen Mixture of Alchemy and Childrens' Stories
46 #include "gmx_fatal.h"
57 #include "thread_mpi.h"
60 /* The source code in this file should be thread-safe.
61 Please keep it that way. */
68 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
75 /* this is not strictly thread-safe, but it's only written to at the beginning
76 of the simulation, once by each thread with the same value. We assume
77 that writing to an int is atomic.*/
78 static bool parallel_env_val
;
80 tMPI_Thread_mutex_t parallel_env_mutex
=TMPI_THREAD_MUTEX_INITIALIZER
;
84 /* returns 1 when running in a parallel environment, so could also be 1 if
85 mdrun was started with: mpirun -np 1.
87 Use this function only to check whether a parallel environment has
88 been initialized, for example when checking whether gmx_finalize()
89 needs to be called. Use PAR(cr) to check whether the simulation actually
90 has more than one node/thread. */
91 bool gmx_parallel_env_initialized(void)
95 tMPI_Thread_mutex_lock(¶llel_env_mutex
);
99 tMPI_Thread_mutex_unlock(¶llel_env_mutex
);
104 static void set_parallel_env(bool val
)
107 tMPI_Thread_mutex_lock(¶llel_env_mutex
);
109 if (!parallel_env_val
)
111 /* we only allow it to be set, not unset */
112 parallel_env_val
=val
;
115 tMPI_Thread_mutex_unlock(¶llel_env_mutex
);
120 static void par_fn(char *base
,int ftp
,const t_commrec
*cr
,
121 bool bAppendSimId
,bool bAppendNodeId
,
122 char buf
[],int bufsize
)
126 if((size_t)bufsize
<(strlen(base
)+10))
127 gmx_mem("Character buffer too small!");
129 /* Copy to buf, and strip extension */
131 buf
[strlen(base
) - strlen(ftp2ext(fn2ftp(base
))) - 1] = '\0';
134 sprintf(buf
+strlen(buf
),"%d",cr
->ms
->sim
);
138 sprintf(buf
+strlen(buf
),"%d",cr
->nodeid
);
142 /* Add extension again */
143 strcat(buf
,(ftp
== efTPX
) ? "tpr" : (ftp
== efEDR
) ? "edr" : ftp2ext(ftp
));
144 if (cr
->nodeid
== 0) {
145 printf("node %d par_fn '%s'\n",cr
->nodeid
,buf
);
146 if (fn2ftp(buf
) == efLOG
) {
152 void check_multi_int(FILE *log
,const gmx_multisim_t
*ms
,int val
,
158 fprintf(log
,"Multi-checking %s ... ",name
);
162 "check_multi_int called with a NULL communication pointer");
166 gmx_sumi_sim(ms
->nsim
,ibuf
,ms
);
169 for(p
=1; p
<ms
->nsim
; p
++)
170 bCompatible
= bCompatible
&& (ibuf
[p
-1] == ibuf
[p
]);
175 fprintf(log
,"\n%s is not equal for all subsystems\n",name
);
176 for(p
=0; p
<ms
->nsim
; p
++)
177 fprintf(log
," subsystem %d: %d\n",p
,ibuf
[p
]);
178 gmx_fatal(FARGS
,"The %d subsystems are not compatible\n",ms
->nsim
);
184 void gmx_log_open(const char *lognm
,const t_commrec
*cr
,bool bMasterOnly
,
185 unsigned long Flags
, FILE** fplog
)
188 char buf
[256],host
[256];
190 char timebuf
[STRLEN
];
194 bool bAppend
= Flags
& MD_APPENDFILES
;
198 /* Communicate the filename for logfile */
199 if (cr
->nnodes
> 1 && !bMasterOnly
201 /* With thread MPI the non-master log files are opened later
202 * when the files names are already known on all nodes.
210 len
= strlen(lognm
) + 1;
212 gmx_bcast(sizeof(len
),&len
,cr
);
221 gmx_bcast(len
*sizeof(*tmpnm
),tmpnm
,cr
);
232 /* Since log always ends with '.log' let's use this info */
233 par_fn(tmpnm
,efLOG
,cr
,FALSE
,!bMasterOnly
,buf
,255);
234 fp
= gmx_fio_fopen(buf
, bAppend
? "a+" : "w+" );
238 fp
= gmx_fio_fopen(tmpnm
, bAppend
? "a+" : "w+" );
243 gmx_fatal_set_log_file(fp
);
245 /* Get some machine parameters */
247 if (gethostname(host
,255) != 0)
249 sprintf(host
,"unknown");
252 sprintf(host
,"unknown");
258 # if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
272 "-----------------------------------------------------------\n"
273 "Restarting from checkpoint, appending to previous log file.\n"
278 gmx_ctime_r(&t
,timebuf
,STRLEN
);
281 "Log file opened on %s"
282 "Host: %s pid: %d nodeid: %d nnodes: %d\n",
283 timebuf
,host
,pid
,cr
->nodeid
,cr
->nnodes
);
285 #if (defined BUILD_MACHINE && defined BUILD_TIME && defined BUILD_USER)
287 "The Gromacs distribution was built %s by\n"
288 "%s (%s)\n\n\n",BUILD_TIME
,BUILD_USER
,BUILD_MACHINE
);
297 void gmx_log_close(FILE *fp
)
300 gmx_fatal_set_log_file(NULL
);
305 static void comm_args(const t_commrec
*cr
,int *argc
,char ***argv
)
310 gmx_bcast(sizeof(*argc
),argc
,cr
);
314 fprintf(stderr
,"NODEID=%d argc=%d\n",cr
->nodeid
,*argc
);
315 for(i
=0; (i
<*argc
); i
++) {
317 len
= strlen((*argv
)[i
])+1;
318 gmx_bcast(sizeof(len
),&len
,cr
);
320 snew((*argv
)[i
],len
);
321 /*gmx_bcast(len*sizeof((*argv)[i][0]),(*argv)[i],cr);*/
322 gmx_bcast(len
*sizeof(char),(*argv
)[i
],cr
);
327 void init_multisystem(t_commrec
*cr
,int nsim
, int nfile
,
328 const t_filenm fnm
[],bool bParFn
)
331 int nnodes
,nnodpersim
,sim
,i
,ftp
;
334 MPI_Group mpi_group_world
;
341 gmx_fatal(FARGS
,"This binary is compiled without MPI support, can not do multiple simulations.");
346 if (nnodes
% nsim
!= 0)
348 gmx_fatal(FARGS
,"The number of nodes (%d) is not a multiple of the number of simulations (%d)",nnodes
,nsim
);
351 nnodpersim
= nnodes
/nsim
;
352 sim
= cr
->nodeid
/nnodpersim
;
356 fprintf(debug
,"We have %d simulations, %d nodes per simulation, local simulation is %d\n",nsim
,nnodpersim
,sim
);
364 /* Create a communicator for the master nodes */
366 for(i
=0; i
<ms
->nsim
; i
++)
368 rank
[i
] = i
*nnodpersim
;
370 MPI_Comm_group(MPI_COMM_WORLD
,&mpi_group_world
);
371 MPI_Group_incl(mpi_group_world
,nsim
,rank
,&ms
->mpi_group_masters
);
373 MPI_Comm_create(MPI_COMM_WORLD
,ms
->mpi_group_masters
,
374 &ms
->mpi_comm_masters
);
376 #if !defined(GMX_THREADS) && !defined(MPI_IN_PLACE_EXISTS)
377 /* initialize the MPI_IN_PLACE replacement buffers */
382 ms
->mpb
->ibuf_alloc
=0;
383 ms
->mpb
->fbuf_alloc
=0;
384 ms
->mpb
->dbuf_alloc
=0;
389 /* Reduce the intra-simulation communication */
390 cr
->sim_nodeid
= cr
->nodeid
% nnodpersim
;
391 cr
->nnodes
= nnodpersim
;
393 MPI_Comm_split(MPI_COMM_WORLD
,sim
,cr
->sim_nodeid
,&cr
->mpi_comm_mysim
);
394 cr
->mpi_comm_mygroup
= cr
->mpi_comm_mysim
;
395 cr
->nodeid
= cr
->sim_nodeid
;
400 fprintf(debug
,"This is simulation %d",cr
->ms
->sim
);
403 fprintf(debug
,", local number of nodes %d, local nodeid %d",
404 cr
->nnodes
,cr
->sim_nodeid
);
406 fprintf(debug
,"\n\n");
411 /* Patch output and tpx, cpt and rerun input file names */
412 for(i
=0; (i
<nfile
); i
++)
414 /* Because of possible multiple extensions per type we must look
415 * at the actual file name
417 if (is_output(&fnm
[i
]) ||
418 fnm
[i
].ftp
== efTPX
|| fnm
[i
].ftp
== efCPT
||
419 strcmp(fnm
[i
].opt
,"-rerun") == 0)
421 ftp
= fn2ftp(fnm
[i
].fns
[0]);
422 par_fn(fnm
[i
].fns
[0],ftp
,cr
,TRUE
,FALSE
,buf
,255);
423 sfree(fnm
[i
].fns
[0]);
424 fnm
[i
].fns
[0] = strdup(buf
);
430 t_commrec
*init_par(int *argc
,char ***argv_ptr
)
444 #ifdef GMX_CHECK_MPI_ENV
445 /* Do not use MPI calls when env.var. GMX_CHECK_MPI_ENV is not set */
446 if (getenv(GMX_CHECK_MPI_ENV
) == NULL
)
448 #endif /* GMX_CHECK_MPI_ENV */
449 #endif /* GMX_LIB_MPI */
450 set_parallel_env(pe
);
452 cr
->sim_nodeid
= gmx_setup(argc
,argv
,&cr
->nnodes
);
459 set_parallel_env(pe
);
464 if (!PAR(cr
) && (cr
->sim_nodeid
!= 0))
465 gmx_comm("(!PAR(cr) && (cr->sim_nodeid != 0))");
470 cr
->mpi_comm_mysim
= MPI_COMM_WORLD
;
471 cr
->mpi_comm_mygroup
= cr
->mpi_comm_mysim
;
474 cr
->nodeid
= cr
->sim_nodeid
;
476 cr
->duty
= (DUTY_PP
| DUTY_PME
);
478 /* Communicate arguments if parallel */
481 comm_args(cr
,argc
,argv_ptr
);
482 #endif /* GMX_THREADS */
485 #if !defined(GMX_THREADS) && !defined(MPI_IN_PLACE_EXISTS)
486 /* initialize the MPI_IN_PLACE replacement buffers */
491 cr
->mpb
->ibuf_alloc
=0;
492 cr
->mpb
->fbuf_alloc
=0;
493 cr
->mpb
->dbuf_alloc
=0;
500 t_commrec
*init_par_threads(const t_commrec
*cro
)
506 /* make a thread-specific commrec */
508 /* now copy the whole thing, so settings like the number of PME nodes
512 /* and we start setting our own thread-specific values for things */
513 MPI_Initialized(&initialized
);
515 gmx_comm("Initializing threads without comm");
516 set_parallel_env(TRUE
);
517 /* once threads will be used together with MPI, we'll
518 fill the cr structure with distinct data here. This might even work: */
519 cr
->sim_nodeid
= gmx_setup(0,NULL
, &cr
->nnodes
);
521 cr
->mpi_comm_mysim
= MPI_COMM_WORLD
;
522 cr
->mpi_comm_mygroup
= cr
->mpi_comm_mysim
;
523 cr
->nodeid
= cr
->sim_nodeid
;
524 cr
->duty
= (DUTY_PP
| DUTY_PME
);
533 t_commrec
*init_cr_nopar(void)
540 /* cr->nthreads = 1; */
543 /* cr->threadid = 0; */
544 cr
->duty
= (DUTY_PP
| DUTY_PME
);