Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
fix comments
[simgrid.git] / src / smpi / smpi_global.c
1 /* Copyright (c) 2007, 2008, 2009, 2010. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5   * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10
11 #include "private.h"
12 #include "smpi_mpi_dt_private.h"
13 #include "mc/mc.h"
14 #include "surf/surf.h"
15 #include "simix/smx_private.h"
16 #include "simgrid/sg_config.h"
17
18
19 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_kernel, smpi,
20                                 "Logging specific to SMPI (kernel)");
21
22 typedef struct s_smpi_process_data {
23   int index;
24   int* argc;
25   char*** argv;
26   smx_rdv_t mailbox;
27   smx_rdv_t mailbox_small;
28   xbt_os_timer_t timer;
29   double simulated;
30   MPI_Comm comm_self;
31   void *data; /* user data */
32 } s_smpi_process_data_t;
33
34 static smpi_process_data_t *process_data = NULL;
35 static int process_count = 0;
36
37 MPI_Comm MPI_COMM_WORLD = MPI_COMM_NULL;
38 int MPI_UNIVERSE_SIZE;
39
40 MPI_Errhandler* MPI_ERRORS_RETURN = NULL;
41 MPI_Errhandler* MPI_ERRORS_ARE_FATAL = NULL;
42 MPI_Errhandler* MPI_ERRHANDLER_NULL = NULL;
43
44 #define MAILBOX_NAME_MAXLEN (5 + sizeof(int) * 2 + 1)
45
46 static char* get_mailbox_name(char* str, int index) {
47   snprintf(str, MAILBOX_NAME_MAXLEN, "SMPI-%0*x", (int)(sizeof(int) * 2), index);
48   return str;
49 }
50
51 static char* get_mailbox_name_small(char* str, int index) {
52   snprintf(str, MAILBOX_NAME_MAXLEN, "small%0*x", (int)(sizeof(int) * 2), index);
53   return str;
54 }
55
56 void smpi_process_init(int *argc, char ***argv)
57 {
58   int index;
59   smpi_process_data_t data;
60   smx_process_t proc;
61
62   if(argc && argv) {
63     proc = SIMIX_process_self();
64     index = atoi((*argv)[1]);
65     data = smpi_process_remote_data(index);
66     simcall_process_set_data(proc, data);
67     if (*argc > 2) {
68       free((*argv)[1]);
69       memmove(&(*argv)[1], &(*argv)[2], sizeof(char *) * (*argc - 2));
70       (*argv)[(*argc) - 1] = NULL;
71     }
72     (*argc)--;
73     data->argc = argc;
74     data->argv = argv;
75     simcall_rdv_set_receiver(data->mailbox_small, proc);// set the process attached to the mailbox
76     XBT_DEBUG("<%d> New process in the game: %p", index, proc);
77   }
78 }
79
80 void smpi_process_destroy(void)
81 {
82   int index = smpi_process_index();
83   process_data[index]->index=-100;
84   XBT_DEBUG("<%d> Process left the game", index);
85 }
86
87 /**
88  * @brief Prepares the current process for termination.
89  */
90 void smpi_process_finalize(void)
91 {
92   // wait for all pending asynchronous comms to finish
93   while (SIMIX_process_has_pending_comms(SIMIX_process_self())) {
94     simcall_process_sleep(0.01);
95   }
96 }
97
98 /**
99  * @brief Check if a process is finalized
100  */
101 int smpi_process_finalized()
102 {
103    return (smpi_process_index()==-100);
104   // If finalized, this value has been set to -100;
105 }
106
107
108 #ifdef SMPI_F2C
109 int smpi_process_argc(void) {
110   smpi_process_data_t data = smpi_process_data();
111
112   return data->argc ? *(data->argc) - 1 : 0;
113 }
114
115 int smpi_process_getarg(integer* index, char* dst, ftnlen len) {
116   smpi_process_data_t data = smpi_process_data();
117   char* arg;
118   ftnlen i;
119
120   if(!data->argc || !data->argv
121      || *index < 1 || *index >= *(data->argc)) {
122     return -1;
123   }
124   arg = (*data->argv)[*index];
125   for(i = 0; i < len && arg[i] != '\0'; i++) {
126     dst[i] = arg[i];
127   }
128   for(; i < len; i++) {
129     dst[i] = ' ';
130   }
131   return 0;
132 }
133
134 int smpi_global_size(void) {
135    char* value = getenv("SMPI_GLOBAL_SIZE");
136
137    if(!value) {
138      fprintf(stderr, "Please set env var SMPI_GLOBAL_SIZE to expected number of processes.\n");
139      xbt_abort();
140    }
141    return atoi(value);
142 }
143 #endif
144
145 smpi_process_data_t smpi_process_data(void)
146 {
147   return SIMIX_process_self_get_data(SIMIX_process_self());
148 }
149
150 smpi_process_data_t smpi_process_remote_data(int index)
151 {
152   return process_data[index];
153 }
154
155 void smpi_process_set_user_data(void *data)
156 {
157   smpi_process_data_t process_data = smpi_process_data();
158   process_data->data = data;
159 }
160
161 void* smpi_process_get_user_data(){
162   smpi_process_data_t process_data = smpi_process_data();
163   return process_data->data;
164 }
165
166 int smpi_process_count(void)
167 {
168   return process_count;
169 }
170
171 int smpi_process_index(void)
172 {
173   smpi_process_data_t data = smpi_process_data();
174   //return -1 if not initialized
175   return data? data->index : MPI_UNDEFINED;
176 }
177
178 smx_rdv_t smpi_process_mailbox(void) {
179   smpi_process_data_t data = smpi_process_data();
180
181   return data->mailbox;
182 }
183
184 smx_rdv_t smpi_process_mailbox_small(void) {
185   smpi_process_data_t data = smpi_process_data();
186
187   return data->mailbox_small;
188 }
189
190 smx_rdv_t smpi_process_remote_mailbox(int index) {
191   smpi_process_data_t data = smpi_process_remote_data(index);
192
193   return data->mailbox;
194 }
195
196
197 smx_rdv_t smpi_process_remote_mailbox_small(int index) {
198   smpi_process_data_t data = smpi_process_remote_data(index);
199
200   return data->mailbox_small;
201 }
202
203 xbt_os_timer_t smpi_process_timer(void)
204 {
205   smpi_process_data_t data = smpi_process_data();
206
207   return data->timer;
208 }
209
210 void smpi_process_simulated_start(void) {
211   smpi_process_data_t data = smpi_process_data();
212
213   data->simulated = SIMIX_get_clock();
214 }
215
216 double smpi_process_simulated_elapsed(void) {
217   smpi_process_data_t data = smpi_process_data();
218
219   return SIMIX_get_clock() - data->simulated;
220 }
221
222 MPI_Comm smpi_process_comm_self(void) {
223   smpi_process_data_t data = smpi_process_data();
224
225   return data->comm_self;
226 }
227
228 void print_request(const char *message, MPI_Request request) {
229   XBT_DEBUG("%s  request %p  [buf = %p, size = %zu, src = %d, dst = %d, tag = %d, flags = %x]",
230          message, request, request->buf, request->size,
231          request->src, request->dst, request->tag, request->flags);
232 }
233
234 static void SMPI_comm_copy_buffer_callback(smx_action_t comm, void* buff, size_t buff_size)
235 {
236   XBT_DEBUG("Copy the data over");
237   memcpy(comm->comm.dst_buff, buff, buff_size);
238   if (comm->comm.detached) { // if this is a detached send, the source buffer was duplicated by SMPI sender to make the original buffer available to the application ASAP
239     xbt_free(buff);
240     //It seems that the request is used after the call there this should
241     //be free somewhereelse  but where???
242     //xbt_free(comm->comm.src_data);// inside SMPI the request is keep
243     //inside the user data and should be free 
244     comm->comm.src_buff = NULL;
245   }
246 }
247
248 void smpi_global_init(void)
249 {
250   int i;
251   MPI_Group group;
252   char name[MAILBOX_NAME_MAXLEN];
253
254   SIMIX_comm_set_copy_data_callback(&SMPI_comm_copy_buffer_callback);
255   process_count = SIMIX_process_count();
256   process_data = xbt_new(smpi_process_data_t, process_count);
257   for (i = 0; i < process_count; i++) {
258     process_data[i] = xbt_new(s_smpi_process_data_t, 1);
259     process_data[i]->index = i;
260     process_data[i]->argc = NULL;
261     process_data[i]->argv = NULL;
262     process_data[i]->mailbox = simcall_rdv_create(get_mailbox_name(name, i));
263     process_data[i]->mailbox_small = simcall_rdv_create(get_mailbox_name_small(name, i));
264     process_data[i]->timer = xbt_os_timer_new();
265     group = smpi_group_new(1);
266     process_data[i]->comm_self = smpi_comm_new(group);
267     smpi_group_set_mapping(group, i, 0);
268   }
269   group = smpi_group_new(process_count);
270   MPI_COMM_WORLD = smpi_comm_new(group);
271   MPI_UNIVERSE_SIZE = smpi_comm_size(MPI_COMM_WORLD);
272   for (i = 0; i < process_count; i++) {
273     smpi_group_set_mapping(group, i, i);
274   }
275 }
276
277 void smpi_global_destroy(void)
278 {
279   int count = smpi_process_count();
280   int i;
281
282   smpi_bench_destroy();
283   smpi_group_unuse(smpi_comm_group(MPI_COMM_WORLD));
284   smpi_comm_destroy(MPI_COMM_WORLD);
285   MPI_COMM_WORLD = MPI_COMM_NULL;
286   for (i = 0; i < count; i++) {
287     smpi_group_unuse(smpi_comm_group(process_data[i]->comm_self));
288     smpi_comm_destroy(process_data[i]->comm_self);
289     xbt_os_timer_free(process_data[i]->timer);
290     simcall_rdv_destroy(process_data[i]->mailbox);
291     simcall_rdv_destroy(process_data[i]->mailbox_small);
292     xbt_free(process_data[i]);
293   }
294   xbt_free(process_data);
295   process_data = NULL;
296
297   smpi_free_static();
298 }
299
300 /* Fortran specific stuff */
301 /* With smpicc, the following weak symbols are used */
302 /* With smpiff, the following weak symbols are replaced by those in libf2c */
303 int __attribute__((weak)) xargc;
304 char** __attribute__((weak)) xargv;
305
306 #ifndef WIN32
307 void __attribute__((weak)) user_main_(){
308   xbt_die("Should not be in this smpi_simulated_main");
309   return;
310 }
311 int __attribute__((weak)) smpi_simulated_main_(int argc, char** argv) {
312   smpi_process_init(&argc, &argv);
313   user_main_();
314   //xbt_die("Should not be in this smpi_simulated_main");
315   return 0;
316 }
317
318 int __attribute__((weak)) main(int argc, char** argv) {
319    return smpi_main(smpi_simulated_main_,argc,argv);
320 }
321
322 int __attribute__((weak)) MAIN__(){
323   return smpi_main(smpi_simulated_main_,xargc, xargv);
324 };
325 #endif
326
327 int smpi_main(int (*realmain) (int argc, char *argv[]),int argc, char *argv[])
328 {
329   srand(SMPI_RAND_SEED);
330   
331   if(getenv("SMPI_PRETEND_CC") != NULL) {
332   /* Hack to ensure that smpicc can pretend to be a simple compiler. Particularly handy to pass it to the configuration tools */
333     return 0;
334   }
335
336   /* Connect log categories.  See xbt/log.c */
337   XBT_LOG_CONNECT(smpi);  /* Keep this line as soon as possible in this
338                              function: xbt_log_appender_file.c depends on it
339                              DO NOT connect this in XBT or so, or it will be
340                              useless to xbt_log_appender_file.c */
341 #ifdef HAVE_TRACING
342   XBT_LOG_CONNECT(instr_smpi);
343 #endif
344   XBT_LOG_CONNECT(smpi_base);
345   XBT_LOG_CONNECT(smpi_bench);
346   XBT_LOG_CONNECT(smpi_coll);
347   XBT_LOG_CONNECT(smpi_comm);
348   XBT_LOG_CONNECT(smpi_group);
349   XBT_LOG_CONNECT(smpi_kernel);
350   XBT_LOG_CONNECT(smpi_mpi);
351   XBT_LOG_CONNECT(smpi_mpi_dt);
352   XBT_LOG_CONNECT(smpi_pmpi);
353   XBT_LOG_CONNECT(smpi_replay);
354   XBT_LOG_CONNECT(smpi_colls);
355
356 #ifdef HAVE_TRACING
357   TRACE_global_init(&argc, argv);
358
359   TRACE_add_start_function(TRACE_smpi_alloc);
360   TRACE_add_end_function(TRACE_smpi_release);
361 #endif
362
363   SIMIX_global_init(&argc, argv);
364
365 #ifdef HAVE_TRACING
366   TRACE_start();
367 #endif
368
369   // parse the platform file: get the host list
370   SIMIX_create_environment(argv[1]);
371
372   SIMIX_function_register_default(realmain);
373   SIMIX_launch_application(argv[2]);
374
375   int gather_id = find_coll_description(mpi_coll_gather_description,
376                                            sg_cfg_get_string("smpi/gather"));
377   mpi_coll_gather_fun = (int (*)(void *, int, MPI_Datatype,
378                                     void*, int, MPI_Datatype, int, MPI_Comm))
379                            mpi_coll_gather_description[gather_id].coll;
380
381   int allgather_id = find_coll_description(mpi_coll_allgather_description,
382                                            sg_cfg_get_string("smpi/allgather"));
383   mpi_coll_allgather_fun = (int (*)(void *, int, MPI_Datatype,
384                                     void*, int, MPI_Datatype, MPI_Comm))
385                            mpi_coll_allgather_description[allgather_id].coll;
386
387   int allgatherv_id = find_coll_description(mpi_coll_allgatherv_description,
388                                            sg_cfg_get_string("smpi/allgatherv"));
389   mpi_coll_allgatherv_fun = (int (*)(void *, int, MPI_Datatype,
390                                     void*, int*, int*, MPI_Datatype, MPI_Comm))
391                            mpi_coll_allgatherv_description[allgatherv_id].coll;
392
393   int allreduce_id = find_coll_description(mpi_coll_allreduce_description,
394                                            sg_cfg_get_string("smpi/allreduce"));
395   mpi_coll_allreduce_fun = (int (*)(void *sbuf, void *rbuf, int rcount, \
396                                     MPI_Datatype dtype, MPI_Op op, MPI_Comm comm))
397                            mpi_coll_allreduce_description[allreduce_id].coll;
398
399   int alltoall_id = find_coll_description(mpi_coll_alltoall_description,
400                                           sg_cfg_get_string("smpi/alltoall"));
401   mpi_coll_alltoall_fun = (int (*)(void *, int, MPI_Datatype,
402                                    void*, int, MPI_Datatype, MPI_Comm))
403                           mpi_coll_alltoall_description[alltoall_id].coll;
404
405   int alltoallv_id = find_coll_description(mpi_coll_alltoallv_description,
406                                           sg_cfg_get_string("smpi/alltoallv"));
407   mpi_coll_alltoallv_fun = (int (*)(void *, int*, int*, MPI_Datatype,
408                                     void*, int*, int*, MPI_Datatype, MPI_Comm))
409                           mpi_coll_alltoallv_description[alltoallv_id].coll;
410
411   int bcast_id = find_coll_description(mpi_coll_bcast_description,
412                                           sg_cfg_get_string("smpi/bcast"));
413   mpi_coll_bcast_fun = (int (*)(void *buf, int count, MPI_Datatype datatype, \
414                                 int root, MPI_Comm com))
415                        mpi_coll_bcast_description[bcast_id].coll;
416
417   int reduce_id = find_coll_description(mpi_coll_reduce_description,
418                                           sg_cfg_get_string("smpi/reduce"));
419   mpi_coll_reduce_fun = (int (*)(void *buf, void *rbuf, int count, MPI_Datatype datatype, \
420                                  MPI_Op op, int root, MPI_Comm comm))
421                         mpi_coll_reduce_description[reduce_id].coll;
422
423   int reduce_scatter_id = find_coll_description(mpi_coll_reduce_scatter_description,
424                                            sg_cfg_get_string("smpi/reduce_scatter"));
425   mpi_coll_reduce_scatter_fun = (int (*)(void *sbuf, void *rbuf, int *rcounts,\
426                     MPI_Datatype dtype,MPI_Op  op,MPI_Comm  comm))
427                            mpi_coll_reduce_scatter_description[reduce_scatter_id].coll;
428
429   int scatter_id = find_coll_description(mpi_coll_scatter_description,
430                                            sg_cfg_get_string("smpi/scatter"));
431   mpi_coll_scatter_fun = (int (*)(void *sendbuf, int sendcount, MPI_Datatype sendtype,\
432                 void *recvbuf, int recvcount, MPI_Datatype recvtype,\
433                 int root, MPI_Comm comm))
434                            mpi_coll_scatter_description[scatter_id].coll;
435
436   int barrier_id = find_coll_description(mpi_coll_barrier_description,
437                                            sg_cfg_get_string("smpi/barrier"));
438   mpi_coll_barrier_fun = (int (*)(MPI_Comm comm))
439                            mpi_coll_barrier_description[barrier_id].coll;
440
441   smpi_global_init();
442
443   /* Clean IO before the run */
444   fflush(stdout);
445   fflush(stderr);
446
447   if (MC_is_active())
448     MC_modelcheck_safety();
449   else
450     SIMIX_run();
451
452   if (sg_cfg_get_boolean("smpi/display_timing"))
453     XBT_INFO("Simulation time: %g seconds.", SIMIX_get_clock());
454
455   smpi_global_destroy();
456
457 #ifdef HAVE_TRACING
458   TRACE_end();
459 #endif
460
461   return 0;
462 }