Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
rewriting
[simgrid.git] / src / smpi / smpi_replay.c
1 /* Copyright (c) 2009, 2010, 2011, 2012. 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
8 #include "private.h"
9 #include <stdio.h>
10 #include <xbt.h>
11 #include <xbt/replay.h>
12
13 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_replay,smpi,"Trace Replay with SMPI");
14
15 int communicator_size = 0;
16 static int active_processes = 0;
17 xbt_dynar_t *reqq;
18
19 MPI_Datatype MPI_DEFAULT_TYPE, MPI_CURRENT_TYPE;
20
21 static void log_timed_action (const char *const *action, double clock){
22   if (XBT_LOG_ISENABLED(smpi_replay, xbt_log_priority_verbose)){
23     char *name = xbt_str_join_array(action, " ");
24     XBT_VERB("%s %f", name, smpi_process_simulated_elapsed()-clock);
25     free(name);
26   }
27 }
28
29 typedef struct {
30   xbt_dynar_t isends; /* of MPI_Request */
31   xbt_dynar_t irecvs; /* of MPI_Request */
32 } s_smpi_replay_globals_t, *smpi_replay_globals_t;
33
34
35 /* Helper function */
36 static double parse_double(const char *string)
37 {
38   double value;
39   char *endptr;
40   value = strtod(string, &endptr);
41   if (*endptr != '\0')
42     THROWF(unknown_error, 0, "%s is not a double", string);
43   return value;
44 }
45
46 static MPI_Datatype decode_datatype(const char *const action)
47 {
48 // Declared datatypes,
49  
50   switch(atoi(action))
51   {
52     case 0:
53       MPI_CURRENT_TYPE=MPI_DOUBLE;
54       break;
55     case 1:
56       MPI_CURRENT_TYPE=MPI_INT;
57       break;
58     case 2:
59       MPI_CURRENT_TYPE=MPI_CHAR;
60       break;
61     case 3:
62       MPI_CURRENT_TYPE=MPI_SHORT;
63       break;
64     case 4:
65       MPI_CURRENT_TYPE=MPI_LONG;
66       break;
67     case 5:
68       MPI_CURRENT_TYPE=MPI_FLOAT;
69       break;
70     case 6:
71       MPI_CURRENT_TYPE=MPI_BYTE;
72       break;
73     default:
74       MPI_CURRENT_TYPE=MPI_DEFAULT_TYPE;
75   
76   }
77    return MPI_CURRENT_TYPE;
78 }
79
80 static void action_init(const char *const *action)
81 {
82   int i;
83   XBT_DEBUG("Initialize the counters");
84   smpi_replay_globals_t globals =  xbt_new(s_smpi_replay_globals_t, 1);
85   globals->isends = xbt_dynar_new(sizeof(MPI_Request),NULL);
86   globals->irecvs = xbt_dynar_new(sizeof(MPI_Request),NULL);
87
88   if(action[2]) MPI_DEFAULT_TYPE= MPI_DOUBLE; // default MPE dataype 
89   else MPI_DEFAULT_TYPE= MPI_BYTE; // default TAU datatype
90   
91   smpi_process_set_user_data((void*) globals);
92
93   /* start a simulated timer */
94   smpi_process_simulated_start();
95   /*initialize the number of active processes */
96   active_processes = smpi_process_count();
97
98   reqq=xbt_new0(xbt_dynar_t,active_processes);
99   
100   for(i=0;i<active_processes;i++){
101     reqq[i]=xbt_dynar_new(sizeof(MPI_Request),NULL);
102   }
103 }
104
105 static void action_finalize(const char *const *action)
106 {
107   smpi_replay_globals_t globals =
108       (smpi_replay_globals_t) smpi_process_get_user_data();
109   if (globals){
110     XBT_DEBUG("There are %lu isends and %lu irecvs in the dynars",
111          xbt_dynar_length(globals->isends),xbt_dynar_length(globals->irecvs));
112     xbt_dynar_free_container(&(globals->isends));
113     xbt_dynar_free_container(&(globals->irecvs));
114   }
115   free(globals);
116 }
117
118 static void action_comm_size(const char *const *action)
119 {
120   double clock = smpi_process_simulated_elapsed();
121
122   communicator_size = parse_double(action[2]);
123   log_timed_action (action, clock);
124 }
125
126 static void action_comm_split(const char *const *action)
127 {
128   double clock = smpi_process_simulated_elapsed();
129
130   log_timed_action (action, clock);
131 }
132
133 static void action_comm_dup(const char *const *action)
134 {
135   double clock = smpi_process_simulated_elapsed();
136
137   log_timed_action (action, clock);
138 }
139
140 static void action_compute(const char *const *action)
141 {
142   double clock = smpi_process_simulated_elapsed();
143   smpi_execute_flops(parse_double(action[2]));
144
145   log_timed_action (action, clock);
146 }
147
148 static void action_send(const char *const *action)
149 {
150   int to = atoi(action[2]);
151   double size=parse_double(action[3]);
152   double clock = smpi_process_simulated_elapsed();
153
154   if(action[4]) {
155     MPI_CURRENT_TYPE=decode_datatype(action[4]);
156   } else {
157     MPI_CURRENT_TYPE= MPI_DEFAULT_TYPE;
158   }
159     
160 #ifdef HAVE_TRACING
161   int rank = smpi_comm_rank(MPI_COMM_WORLD);
162   TRACE_smpi_computing_out(rank);
163   int dst_traced = smpi_group_rank(smpi_comm_group(MPI_COMM_WORLD), to);
164   TRACE_smpi_ptp_in(rank, rank, dst_traced, __FUNCTION__);
165   TRACE_smpi_send(rank, rank, dst_traced);
166 #endif
167
168   smpi_mpi_send(NULL, size, MPI_CURRENT_TYPE, to , 0, MPI_COMM_WORLD);
169
170   log_timed_action (action, clock);
171
172   #ifdef HAVE_TRACING
173   TRACE_smpi_ptp_out(rank, rank, dst_traced, __FUNCTION__);
174   TRACE_smpi_computing_in(rank);
175 #endif
176
177 }
178
179 static void action_Isend(const char *const *action)
180 {
181   int to = atoi(action[2]);
182   double size=parse_double(action[3]);
183   double clock = smpi_process_simulated_elapsed();
184   MPI_Request request;
185
186   if(action[4]) MPI_CURRENT_TYPE=decode_datatype(action[4]);
187   else MPI_CURRENT_TYPE= MPI_DEFAULT_TYPE;
188
189   smpi_replay_globals_t globals =
190      (smpi_replay_globals_t) smpi_process_get_user_data();
191 #ifdef HAVE_TRACING
192   int rank = smpi_comm_rank(MPI_COMM_WORLD);
193   TRACE_smpi_computing_out(rank);
194   int dst_traced = smpi_group_rank(smpi_comm_group(MPI_COMM_WORLD), to);
195   TRACE_smpi_ptp_in(rank, rank, dst_traced, __FUNCTION__);
196   TRACE_smpi_send(rank, rank, dst_traced);
197 #endif
198
199   request = smpi_mpi_isend(NULL, size, MPI_CURRENT_TYPE, to, 0,MPI_COMM_WORLD);
200   
201 #ifdef HAVE_TRACING
202   TRACE_smpi_ptp_out(rank, rank, dst_traced, __FUNCTION__);
203   request->send = 1;
204   TRACE_smpi_computing_in(rank);
205 #endif
206
207   xbt_dynar_push(globals->isends,&request);
208   xbt_dynar_push(reqq[smpi_comm_rank(MPI_COMM_WORLD)],&request);
209
210   log_timed_action (action, clock);
211 }
212
213 static void action_recv(const char *const *action) {
214   int from = atoi(action[2]);
215   double size=parse_double(action[3]);
216   double clock = smpi_process_simulated_elapsed();
217   MPI_Status status;
218
219   if(action[4]) MPI_CURRENT_TYPE=decode_datatype(action[4]);
220   else MPI_CURRENT_TYPE= MPI_DEFAULT_TYPE;
221   
222 #ifdef HAVE_TRACING
223   int rank = smpi_comm_rank(MPI_COMM_WORLD);
224   int src_traced = smpi_group_rank(smpi_comm_group(MPI_COMM_WORLD), from);
225   TRACE_smpi_computing_out(rank);
226
227   TRACE_smpi_ptp_in(rank, src_traced, rank, __FUNCTION__);
228 #endif
229
230   smpi_mpi_recv(NULL, size, MPI_CURRENT_TYPE, from, 0, MPI_COMM_WORLD, &status);
231
232 #ifdef HAVE_TRACING
233   TRACE_smpi_ptp_out(rank, src_traced, rank, __FUNCTION__);
234   TRACE_smpi_recv(rank, src_traced, rank);
235   TRACE_smpi_computing_in(rank);
236 #endif
237
238   log_timed_action (action, clock);
239 }
240
241 static void action_Irecv(const char *const *action)
242 {
243   int from = atoi(action[2]);
244   double size=parse_double(action[3]);
245   double clock = smpi_process_simulated_elapsed();
246   MPI_Request request;
247
248   smpi_replay_globals_t globals =
249      (smpi_replay_globals_t) smpi_process_get_user_data();
250   
251   if(action[4]) MPI_CURRENT_TYPE=decode_datatype(action[4]);
252   else MPI_CURRENT_TYPE= MPI_DEFAULT_TYPE;
253
254 #ifdef HAVE_TRACING
255   int rank = smpi_comm_rank(MPI_COMM_WORLD);
256   int src_traced = smpi_group_rank(smpi_comm_group(MPI_COMM_WORLD), from);
257   TRACE_smpi_ptp_in(rank, src_traced, rank, __FUNCTION__);
258 #endif
259
260   request = smpi_mpi_irecv(NULL, size, MPI_CURRENT_TYPE, from, 0, MPI_COMM_WORLD);
261   
262 #ifdef HAVE_TRACING
263   TRACE_smpi_ptp_out(rank, src_traced, rank, __FUNCTION__);
264   request->recv = 1;
265 #endif
266   xbt_dynar_push(globals->irecvs,&request);
267   xbt_dynar_push(reqq[smpi_comm_rank(MPI_COMM_WORLD)],&request);
268
269   log_timed_action (action, clock);
270 }
271
272 static void action_wait(const char *const *action){
273   double clock = smpi_process_simulated_elapsed();
274   MPI_Request request;
275   MPI_Status status;
276   smpi_replay_globals_t globals =
277       (smpi_replay_globals_t) smpi_process_get_user_data();
278
279   xbt_assert(xbt_dynar_length(globals->irecvs),
280       "action wait not preceded by any irecv: %s",
281       xbt_str_join_array(action," "));
282   request = xbt_dynar_pop_as(globals->irecvs,MPI_Request);
283 #ifdef HAVE_TRACING
284   int rank = request && request->comm != MPI_COMM_NULL
285       ? smpi_comm_rank(request->comm)
286       : -1;
287   TRACE_smpi_computing_out(rank);
288
289   MPI_Group group = smpi_comm_group(request->comm);
290   int src_traced = smpi_group_rank(group, request->src);
291   int dst_traced = smpi_group_rank(group, request->dst);
292   int is_wait_for_receive = request->recv;
293   TRACE_smpi_ptp_in(rank, src_traced, dst_traced, __FUNCTION__);
294 #endif
295   smpi_mpi_wait(&request, &status);
296 #ifdef HAVE_TRACING
297   TRACE_smpi_ptp_out(rank, src_traced, dst_traced, __FUNCTION__);
298   if (is_wait_for_receive) {
299     TRACE_smpi_recv(rank, src_traced, dst_traced);
300   }
301   TRACE_smpi_computing_in(rank);
302 #endif
303
304   log_timed_action (action, clock);
305 }
306
307 static void action_waitall(const char *const *action){
308   double clock = smpi_process_simulated_elapsed();
309   int count_requests=0;
310   unsigned int i=0;
311
312   count_requests=xbt_dynar_length(reqq[smpi_comm_rank(MPI_COMM_WORLD)]);
313
314   if (count_requests>0) {
315     MPI_Request requests[count_requests];
316     MPI_Status status[count_requests];
317   
318     /*  The reqq is an array of dynars. Its index corresponds to the rank.
319      Thus each rank saves its own requests to the array request. */
320     xbt_dynar_foreach(reqq[smpi_comm_rank(MPI_COMM_WORLD)],i,requests[i]); 
321     
322   #ifdef HAVE_TRACING
323    //save information from requests
324  
325    xbt_dynar_t srcs = xbt_dynar_new(sizeof(int), NULL);
326    xbt_dynar_t dsts = xbt_dynar_new(sizeof(int), NULL);
327    xbt_dynar_t recvs = xbt_dynar_new(sizeof(int), NULL);
328    for (i = 0; i < count_requests; i++) {
329     if(requests[i]){
330       int *asrc = xbt_new(int, 1);
331       int *adst = xbt_new(int, 1);
332       int *arecv = xbt_new(int, 1);
333       *asrc = requests[i]->src;
334       *adst = requests[i]->dst;
335       *arecv = requests[i]->recv;
336       xbt_dynar_insert_at(srcs, i, asrc);
337       xbt_dynar_insert_at(dsts, i, adst);
338       xbt_dynar_insert_at(recvs, i, arecv);
339       xbt_free(asrc);
340       xbt_free(adst);
341       xbt_free(arecv);
342     }else {
343       int *t = xbt_new(int, 1);
344       xbt_dynar_insert_at(srcs, i, t);
345       xbt_dynar_insert_at(dsts, i, t);
346       xbt_dynar_insert_at(recvs, i, t);
347       xbt_free(t);
348     }
349    }
350    int rank_traced = smpi_process_index();
351    TRACE_smpi_computing_out(rank_traced);
352
353    TRACE_smpi_ptp_in(rank_traced, -1, -1, __FUNCTION__);
354   #endif
355
356     smpi_mpi_waitall(count_requests, requests, status);
357
358   #ifdef HAVE_TRACING
359    for (i = 0; i < count_requests; i++) {
360     int src_traced, dst_traced, is_wait_for_receive;
361     xbt_dynar_get_cpy(srcs, i, &src_traced);
362     xbt_dynar_get_cpy(dsts, i, &dst_traced);
363     xbt_dynar_get_cpy(recvs, i, &is_wait_for_receive);
364     if (is_wait_for_receive) {
365       TRACE_smpi_recv(rank_traced, src_traced, dst_traced);
366     }
367    }
368    TRACE_smpi_ptp_out(rank_traced, -1, -1, __FUNCTION__);
369    //clean-up of dynars
370    xbt_dynar_free(&srcs);
371    xbt_dynar_free(&dsts);
372    xbt_dynar_free(&recvs);
373    TRACE_smpi_computing_in(rank_traced);
374   #endif
375    
376    xbt_dynar_reset(reqq[smpi_comm_rank(MPI_COMM_WORLD)]);
377   }
378   log_timed_action (action, clock);
379 }
380
381 static void action_barrier(const char *const *action){
382   double clock = smpi_process_simulated_elapsed();
383 #ifdef HAVE_TRACING
384   int rank = smpi_comm_rank(MPI_COMM_WORLD);
385   TRACE_smpi_computing_out(rank);
386   TRACE_smpi_collective_in(rank, -1, __FUNCTION__);
387 #endif
388   smpi_mpi_barrier(MPI_COMM_WORLD);
389 #ifdef HAVE_TRACING
390   TRACE_smpi_collective_out(rank, -1, __FUNCTION__);
391   TRACE_smpi_computing_in(rank);
392 #endif
393
394   log_timed_action (action, clock);
395 }
396
397
398 static void action_bcast(const char *const *action)
399 {
400   double size = parse_double(action[2]);
401   double clock = smpi_process_simulated_elapsed();
402   int root=0;
403   /*
404    * Initialize MPI_CURRENT_TYPE in order to decrease
405    * the number of the checks
406    * */
407   MPI_CURRENT_TYPE= MPI_DEFAULT_TYPE;  
408
409   if(action[3]) {
410     root= atoi(action[3]);
411     if(action[4]) {
412       MPI_CURRENT_TYPE=decode_datatype(action[4]);   
413     }
414   }
415   
416 #ifdef HAVE_TRACING
417   int rank = smpi_comm_rank(MPI_COMM_WORLD);
418   TRACE_smpi_computing_out(rank);
419   int root_traced = smpi_group_rank(smpi_comm_group(MPI_COMM_WORLD), 0);
420   TRACE_smpi_collective_in(rank, root_traced, __FUNCTION__);
421 #endif
422
423   smpi_mpi_bcast(NULL, size, MPI_CURRENT_TYPE, root, MPI_COMM_WORLD);
424 #ifdef HAVE_TRACING
425   TRACE_smpi_collective_out(rank, root_traced, __FUNCTION__);
426   TRACE_smpi_computing_in(rank);
427 #endif
428
429   log_timed_action (action, clock);
430 }
431
432 static void action_reduce(const char *const *action)
433 {
434   double comm_size = parse_double(action[2]);
435   double comp_size = parse_double(action[3]);
436   double clock = smpi_process_simulated_elapsed();
437   int root=0;
438   MPI_CURRENT_TYPE= MPI_DEFAULT_TYPE;
439   
440   if(action[4]) {
441       root= atoi(action[4]);
442       if(action[5]) {
443         MPI_CURRENT_TYPE=decode_datatype(action[5]);
444       }
445   }
446
447 #ifdef HAVE_TRACING
448   int rank = smpi_comm_rank(MPI_COMM_WORLD);
449   TRACE_smpi_computing_out(rank);
450   int root_traced = smpi_group_rank(smpi_comm_group(MPI_COMM_WORLD), 0);
451   TRACE_smpi_collective_in(rank, root_traced, __FUNCTION__);
452 #endif
453    smpi_mpi_reduce(NULL, NULL, comm_size, MPI_CURRENT_TYPE, MPI_OP_NULL, root, MPI_COMM_WORLD);
454    smpi_execute_flops(comp_size);
455 #ifdef HAVE_TRACING
456   TRACE_smpi_collective_out(rank, root_traced, __FUNCTION__);
457   TRACE_smpi_computing_in(rank);
458 #endif
459
460   log_timed_action (action, clock);
461 }
462
463 static void action_allReduce(const char *const *action) {
464   double comm_size = parse_double(action[2]);
465   double comp_size = parse_double(action[3]);
466   
467   if(action[4]) MPI_CURRENT_TYPE=decode_datatype(action[4]);
468   else MPI_CURRENT_TYPE= MPI_DEFAULT_TYPE;
469   
470   double clock = smpi_process_simulated_elapsed();
471 #ifdef HAVE_TRACING
472   int rank = smpi_comm_rank(MPI_COMM_WORLD);
473   TRACE_smpi_computing_out(rank);
474   TRACE_smpi_collective_in(rank, -1, __FUNCTION__);
475 #endif
476   smpi_mpi_reduce(NULL, NULL, comm_size, MPI_CURRENT_TYPE, MPI_OP_NULL, 0, MPI_COMM_WORLD);
477   smpi_execute_flops(comp_size);
478   smpi_mpi_bcast(NULL, comm_size, MPI_CURRENT_TYPE, 0, MPI_COMM_WORLD);
479 #ifdef HAVE_TRACING
480   TRACE_smpi_collective_out(rank, -1, __FUNCTION__);
481   TRACE_smpi_computing_in(rank);
482 #endif
483
484   log_timed_action (action, clock);
485 }
486
487 static void action_allToAll(const char *const *action) {
488   double clock = smpi_process_simulated_elapsed();
489   int comm_size = smpi_comm_size(MPI_COMM_WORLD);
490   int send_size = atoi(action[2]);
491   int recv_size = atoi(action[3]);
492   void *send = xbt_new0(int, send_size*comm_size);  
493   void *recv = xbt_new0(int, send_size*comm_size);
494   
495   if(action[4]) MPI_CURRENT_TYPE=decode_datatype(action[4]);
496   else MPI_CURRENT_TYPE= MPI_DEFAULT_TYPE;
497
498 #ifdef HAVE_TRACING
499   int rank = smpi_process_index();
500   TRACE_smpi_computing_out(rank);
501   TRACE_smpi_collective_in(rank, -1, __FUNCTION__);
502 #endif
503
504   if (send_size < 200 && comm_size > 12) {
505     smpi_coll_tuned_alltoall_bruck(send, send_size, MPI_CURRENT_TYPE,
506                                    recv, recv_size, MPI_CURRENT_TYPE,
507                                    MPI_COMM_WORLD);
508   } else if (send_size < 3000) {
509   
510     smpi_coll_tuned_alltoall_basic_linear(send, send_size, MPI_CURRENT_TYPE,
511                                           recv, recv_size, MPI_CURRENT_TYPE,
512                                           MPI_COMM_WORLD);
513   } else {
514     smpi_coll_tuned_alltoall_pairwise(send, send_size, MPI_CURRENT_TYPE,
515                                       recv, recv_size, MPI_CURRENT_TYPE,
516                                       MPI_COMM_WORLD);
517   }
518
519 #ifdef HAVE_TRACING
520   TRACE_smpi_collective_out(rank, -1, __FUNCTION__);
521   TRACE_smpi_computing_in(rank);
522 #endif
523
524   log_timed_action (action, clock);
525   xbt_free(send);
526   xbt_free(recv);
527 }
528
529 static void action_allToAllv(const char *const *action) {
530   /*
531  The structure of the allToAllV action for the rank 0 (total 4 processes) 
532  is the following:   
533   0 allToAllV 100 1 7 10 12 5 10 20 45 100 1 70 10 5 1 5 77 90
534
535   where: 
536   1) 100 is the size of the send buffer *sizeof(int),
537   2) 1 7 10 12 is the sendcounts array
538   3) 5 10 20 45 is the sdispls array
539   4) 100*sizeof(int) is the size of the receiver buffer
540   5)  1 70 10 5 is the recvcounts array
541   6) 1 5 77 90 is the rdispls array
542     
543    */
544   
545   
546   double clock = smpi_process_simulated_elapsed();
547   
548   int comm_size = smpi_comm_size(MPI_COMM_WORLD);
549   int send_buf_size=0,recv_buf_size=0,i=0;
550   int *sendcounts = xbt_new0(int, comm_size);  
551   int *recvcounts = xbt_new0(int, comm_size);  
552   int *senddisps = xbt_new0(int, comm_size);  
553   int *recvdisps = xbt_new0(int, comm_size);  
554   
555   send_buf_size=atoi(action[2]);
556   recv_buf_size=atoi(action[3+2*comm_size]);
557
558   int *sendbuf = xbt_new0(int, send_buf_size);  
559   int *recvbuf = xbt_new0(int, recv_buf_size);  
560
561   if(action[4+4*comm_size]) MPI_CURRENT_TYPE=decode_datatype(action[4+4*comm_size]);    
562   else MPI_CURRENT_TYPE= MPI_DEFAULT_TYPE;
563
564   for(i=0;i<comm_size;i++) {
565     sendcounts[i] = atoi(action[i+3]);
566     senddisps[i] = atoi(action[i+3+comm_size]);
567     recvcounts[i] = atoi(action[i+4+2*comm_size]);
568     recvdisps[i] = atoi(action[i+4+3*comm_size]);
569   }
570   
571
572 #ifdef HAVE_TRACING
573   int rank = MPI_COMM_WORLD != MPI_COMM_NULL ? smpi_process_index() : -1;
574   TRACE_smpi_computing_out(rank);
575   TRACE_smpi_collective_in(rank, -1, __FUNCTION__);
576 #endif
577     smpi_coll_basic_alltoallv(sendbuf, sendcounts, senddisps,   MPI_CURRENT_TYPE,
578                                recvbuf, recvcounts, recvdisps, MPI_CURRENT_TYPE,
579                                MPI_COMM_WORLD);
580 #ifdef HAVE_TRACING
581   TRACE_smpi_collective_out(rank, -1, __FUNCTION__);
582   TRACE_smpi_computing_in(rank);
583 #endif
584    
585   log_timed_action (action, clock);
586   xbt_free(sendbuf);
587   xbt_free(recvbuf);
588   xbt_free(sendcounts);
589   xbt_free(recvcounts);
590   xbt_free(senddisps);
591   xbt_free(recvdisps);
592
593   
594 }
595
596 void smpi_replay_init(int *argc, char***argv){
597   PMPI_Init(argc, argv);
598   if (!smpi_process_index()){
599     _xbt_replay_action_init();
600     xbt_replay_action_register("init",       action_init);
601     xbt_replay_action_register("finalize",   action_finalize);
602     xbt_replay_action_register("comm_size",  action_comm_size);
603     xbt_replay_action_register("comm_split", action_comm_split);
604     xbt_replay_action_register("comm_dup",   action_comm_dup);
605     xbt_replay_action_register("send",       action_send);
606     xbt_replay_action_register("Isend",      action_Isend);
607     xbt_replay_action_register("recv",       action_recv);
608     xbt_replay_action_register("Irecv",      action_Irecv);
609     xbt_replay_action_register("wait",       action_wait);
610     xbt_replay_action_register("waitAll",    action_waitall);
611     xbt_replay_action_register("barrier",    action_barrier);
612     xbt_replay_action_register("bcast",      action_bcast);
613     xbt_replay_action_register("reduce",     action_reduce);
614     xbt_replay_action_register("allReduce",  action_allReduce);
615     xbt_replay_action_register("allToAll",   action_allToAll);
616     xbt_replay_action_register("allToAllV",  action_allToAllv);
617     xbt_replay_action_register("compute",    action_compute);
618   }
619
620   xbt_replay_action_runner(*argc, *argv);
621 }
622
623 int smpi_replay_finalize(){
624   double sim_time= 1.;
625   /* One active process will stop. Decrease the counter*/
626   active_processes--;
627   if(!active_processes){
628     /* Last process alive speaking */
629     /* end the simulated timer */
630     xbt_dynar_free(reqq);
631     sim_time = smpi_process_simulated_elapsed();
632     XBT_INFO("Simulation time %g", sim_time);
633     _xbt_replay_action_exit();
634   }
635   return PMPI_Finalize();
636 }