소스 검색

nmad,mpi: final step towards code merge

Nathalie Furmento 7 년 전
부모
커밋
c1d643ea5c
55개의 변경된 파일5518개의 추가작업 그리고 54개의 파일을 삭제
  1. 8 0
      configure.ac
  2. 2 0
      include/starpu_config.h.in
  3. 8 4
      mpi/examples/Makefile.am
  4. 2 0
      mpi/include/starpu_mpi_lb.h
  5. 6 5
      mpi/src/Makefile.am
  6. 5 0
      mpi/src/load_balancer/load_balancer.c
  7. 5 0
      mpi/src/load_balancer/policy/data_movements_interface.c
  8. 5 0
      mpi/src/load_balancer/policy/load_data_interface.c
  9. 5 0
      mpi/src/load_balancer/policy/load_heat_propagation.c
  10. 4 0
      mpi/src/mpi/starpu_mpi_comm.c
  11. 3 0
      mpi/src/mpi/starpu_mpi_comm.h
  12. 3 0
      mpi/src/mpi/starpu_mpi_early_data.c
  13. 3 0
      mpi/src/mpi/starpu_mpi_early_data.h
  14. 4 0
      mpi/src/mpi/starpu_mpi_early_request.c
  15. 3 0
      mpi/src/mpi/starpu_mpi_early_request.h
  16. 3 0
      mpi/src/mpi/starpu_mpi_mpi.c
  17. 3 0
      mpi/src/mpi/starpu_mpi_sync_data.c
  18. 3 0
      mpi/src/mpi/starpu_mpi_sync_data.h
  19. 4 0
      mpi/src/mpi/starpu_mpi_tag.c
  20. 3 0
      mpi/src/mpi/starpu_mpi_tag.h
  21. 767 0
      mpi/src/nmad/starpu_mpi_nmad.c
  22. 8 3
      mpi/src/starpu_mpi.c
  23. 6 1
      mpi/src/starpu_mpi_init.c
  24. 11 11
      mpi/src/starpu_mpi_private.h
  25. 6 3
      mpi/tests/Makefile.am
  26. 1 1
      mpi/tests/load_balancer.c
  27. 2 0
      nmad/Makefile.am
  28. 8 2
      nmad/examples/Makefile.am
  29. 290 0
      nmad/examples/stencil/stencil5_lb.c
  30. 44 0
      nmad/include/starpu_mpi_lb.h
  31. 22 4
      nmad/src/Makefile.am
  32. 161 0
      nmad/src/load_balancer/load_balancer.c
  33. 286 0
      nmad/src/load_balancer/policy/data_movements_interface.c
  34. 48 0
      nmad/src/load_balancer/policy/data_movements_interface.h
  35. 53 0
      nmad/src/load_balancer/policy/load_balancer_policy.h
  36. 274 0
      nmad/src/load_balancer/policy/load_data_interface.c
  37. 70 0
      nmad/src/load_balancer/policy/load_data_interface.h
  38. 643 0
      nmad/src/load_balancer/policy/load_heat_propagation.c
  39. 224 0
      nmad/src/mpi/starpu_mpi_comm.c
  40. 43 0
      nmad/src/mpi/starpu_mpi_comm.h
  41. 124 0
      nmad/src/mpi/starpu_mpi_early_data.c
  42. 59 0
      nmad/src/mpi/starpu_mpi_early_data.h
  43. 121 0
      nmad/src/mpi/starpu_mpi_early_request.c
  44. 47 0
      nmad/src/mpi/starpu_mpi_early_request.h
  45. 1640 0
      nmad/src/mpi/starpu_mpi_mpi.c
  46. 153 0
      nmad/src/mpi/starpu_mpi_sync_data.c
  47. 46 0
      nmad/src/mpi/starpu_mpi_sync_data.h
  48. 122 0
      nmad/src/mpi/starpu_mpi_tag.c
  49. 43 0
      nmad/src/mpi/starpu_mpi_tag.h
  50. 6 2
      nmad/src/nmad/starpu_mpi_nmad.c
  51. 8 3
      nmad/src/starpu_mpi.c
  52. 6 1
      nmad/src/starpu_mpi_init.c
  53. 11 11
      nmad/src/starpu_mpi_private.h
  54. 8 3
      nmad/tests/Makefile.am
  55. 75 0
      nmad/tests/load_balancer.c

+ 8 - 0
configure.ac

@@ -602,10 +602,18 @@ AC_SUBST(USE_MPI, $build_mpi_lib)
 AM_CONDITIONAL(USE_MPI, test x$build_mpi_lib = xyes)
 if test x$build_mpi_lib = xyes -o x$build_nmad_lib = xyes ; then
 	AC_DEFINE(STARPU_USE_MPI,[1],[whether the StarPU MPI library is available])
+	if test x$build_mpi_lib = xyes ; then
+		AC_DEFINE(STARPU_USE_MPI_MPI,[1],[whether the StarPU MPI library (with a native MPI implementation) is available])
+	else
+		AC_DEFINE(STARPU_USE_MPI_NMAD,[1],[whether the StarPU MPI library (with a NewMadeleine implementation) is available])
+	fi
 else
 	running_mpi_check=no
 fi
 
+AM_CONDITIONAL(STARPU_USE_MPI_MPI, test x$build_mpi_lib = xyes)
+AM_CONDITIONAL(STARPU_USE_MPI_NMADI, test x$build_nmad_lib = xyes)
+
 AC_ARG_WITH(mpiexec-args, [AS_HELP_STRING([--with-mpiexec-args[=<arguments to give when running mpiexec>]],
 			[Arguments for mpiexec])],
 	[

+ 2 - 0
include/starpu_config.h.in

@@ -49,6 +49,8 @@
 #undef STARPU_HAVE_ICC
 
 #undef STARPU_USE_MPI
+#undef STARPU_USE_MPI_MPI
+#undef STARPU_USE_MPI_NMAD
 
 #undef STARPU_ATLAS
 #undef STARPU_GOTO

+ 8 - 4
mpi/examples/Makefile.am

@@ -120,13 +120,17 @@ AM_LDFLAGS = $(STARPU_OPENCL_LDFLAGS) $(STARPU_CUDA_LDFLAGS) $(FXT_LDFLAGS) $(ST
 # Stencil example #
 ###################
 if BUILD_EXAMPLES
-examplebin_PROGRAMS +=				\
-	stencil/stencil5			\
-	stencil/stencil5_lb
+examplebin_PROGRAMS +=		\
+	stencil/stencil5
+starpu_mpi_EXAMPLES	+=	\
+	stencil/stencil5
 
+if STARPU_USE_MPI_MPI
+examplebin_PROGRAMS +=		\
+	stencil/stencil5_lb
 starpu_mpi_EXAMPLES	+=	\
-	stencil/stencil5	\
 	stencil/stencil5_lb
+endif
 
 endif
 

+ 2 - 0
mpi/include/starpu_mpi_lb.h

@@ -18,6 +18,8 @@
 #ifndef __STARPU_MPI_LOAD_BALANCER_H__
 #define __STARPU_MPI_LOAD_BALANCER_H__
 
+#include <starpu.h>
+
 #ifdef __cplusplus
 extern "C"
 {

+ 6 - 5
mpi/src/Makefile.am

@@ -21,10 +21,10 @@ BUILT_SOURCES =
 
 CLEANFILES = *.gcno *.gcda *.linkinfo
 
-AM_CFLAGS = -Wall $(STARPU_CUDA_CPPFLAGS) $(STARPU_OPENCL_CPPFLAGS) $(FXT_CFLAGS) $(MAGMA_CFLAGS) $(HWLOC_CFLAGS) $(GLOBAL_AM_CFLAGS) -DSTARPU_MPI_MPI
-LIBS = $(top_builddir)/src/@LIBSTARPU_LINK@ @LIBS@ $(FXT_LIBS) $(MAGMA_LIBS)
+AM_CFLAGS = -Wall $(STARPU_CUDA_CPPFLAGS) $(STARPU_OPENCL_CPPFLAGS) $(FXT_CFLAGS) $(MAGMA_CFLAGS) $(HWLOC_CFLAGS) $(GLOBAL_AM_CFLAGS) $(NMAD_CFLAGS)
+LIBS = $(top_builddir)/src/@LIBSTARPU_LINK@ @LIBS@ $(FXT_LIBS) $(MAGMA_LIBS) $(NMAD_LIBS)
 AM_CPPFLAGS = -I$(top_srcdir)/include/ -I$(top_srcdir)/src/ -I$(top_builddir)/src -I$(top_builddir)/include -I$(top_srcdir)/mpi/include -I$(top_srcdir)/mpi/src
-AM_LDFLAGS = $(STARPU_OPENCL_LDFLAGS) $(STARPU_CUDA_LDFLAGS) $(STARPU_COI_LDFLAGS) $(STARPU_SCIF_LDFLAGS)
+AM_LDFLAGS = $(STARPU_OPENCL_LDFLAGS) $(STARPU_CUDA_LDFLAGS) $(STARPU_COI_LDFLAGS) $(STARPU_SCIF_LDFLAGS) $(NMAD_LDFLAGS)
 
 ldflags =
 
@@ -64,13 +64,13 @@ noinst_HEADERS =					\
 	starpu_mpi_cache.h				\
 	starpu_mpi_select_node.h			\
 	starpu_mpi_cache_stats.h			\
+	starpu_mpi_task_insert.h			\
+	starpu_mpi_init.h				\
 	mpi/starpu_mpi_early_data.h			\
 	mpi/starpu_mpi_early_request.h			\
 	mpi/starpu_mpi_sync_data.h			\
 	mpi/starpu_mpi_comm.h				\
 	mpi/starpu_mpi_tag.h				\
-	starpu_mpi_task_insert.h			\
-	starpu_mpi_init.h				\
 	load_balancer/policy/data_movements_interface.h	\
 	load_balancer/policy/load_data_interface.h	\
 	load_balancer/policy/load_balancer_policy.h
@@ -89,6 +89,7 @@ libstarpumpi_@STARPU_EFFECTIVE_VERSION@_la_SOURCES =	\
 	starpu_mpi_fortran.c				\
 	starpu_mpi_task_insert_fortran.c		\
 	starpu_mpi_init.c				\
+	nmad/starpu_mpi_nmad.c				\
 	mpi/starpu_mpi_mpi.c				\
 	mpi/starpu_mpi_early_data.c			\
 	mpi/starpu_mpi_early_request.c			\

+ 5 - 0
mpi/src/load_balancer/load_balancer.c

@@ -21,10 +21,13 @@
 #include <starpu_mpi.h>
 #include <starpu_scheduler.h>
 #include <common/utils.h>
+#include <common/config.h>
 
 #include <starpu_mpi_lb.h>
 #include "policy/load_balancer_policy.h"
 
+#if defined(STARPU_USE_MPI_MPI)
+
 static struct load_balancer_policy *defined_policy = NULL;
 typedef void (*_post_exec_hook_func_t)(struct starpu_task *task, unsigned sched_ctx_id);
 static _post_exec_hook_func_t saved_post_exec_hook[STARPU_NMAX_SCHED_CTXS];
@@ -154,3 +157,5 @@ void starpu_mpi_lb_shutdown()
 	}
 	defined_policy = NULL;
 }
+
+#endif /* STARPU_USE_MPI_MPI */

+ 5 - 0
mpi/src/load_balancer/policy/data_movements_interface.c

@@ -18,9 +18,12 @@
 #include <starpu.h>
 #include <stdlib.h>
 #include <starpu_mpi_private.h>
+#include <common/config.h>
 
 #include "data_movements_interface.h"
 
+#if defined(STARPU_USE_MPI_MPI)
+
 int **data_movements_get_ref_tags_table(starpu_data_handle_t handle)
 {
 	struct data_movements_interface *dm_interface =
@@ -279,3 +282,5 @@ void data_movements_data_register(starpu_data_handle_t *handleptr, unsigned home
 
 	starpu_data_register(handleptr, home_node, &data_movements, &interface_data_movements_ops);
 }
+
+#endif

+ 5 - 0
mpi/src/load_balancer/policy/load_data_interface.c

@@ -17,9 +17,12 @@
 
 #include <starpu.h>
 #include <stdlib.h>
+#include <common/config.h>
 
 #include "load_data_interface.h"
 
+#if defined(STARPU_USE_MPI_MPI)
+
 int load_data_get_sleep_threshold(starpu_data_handle_t handle)
 {
 	struct load_data_interface *ld_interface =
@@ -267,3 +270,5 @@ void load_data_data_register(starpu_data_handle_t *handleptr, unsigned home_node
 
 	starpu_data_register(handleptr, home_node, &load_data, &interface_load_data_ops);
 }
+
+#endif

+ 5 - 0
mpi/src/load_balancer/policy/load_heat_propagation.c

@@ -24,6 +24,9 @@
 #include "load_balancer_policy.h"
 #include "data_movements_interface.h"
 #include "load_data_interface.h"
+#include <common/config.h>
+
+#if defined(STARPU_USE_MPI_MPI)
 
 static int TAG_LOAD(int n)
 {
@@ -636,3 +639,5 @@ struct load_balancer_policy load_heat_propagation_policy =
 	.finished_task_entry_point = finished_task_heat,
 	.policy_name = "heat"
 };
+
+#endif

+ 4 - 0
mpi/src/mpi/starpu_mpi_comm.c

@@ -22,6 +22,8 @@
 #include <mpi/starpu_mpi_comm.h>
 #include <common/list.h>
 
+#ifdef STARPU_USE_MPI_MPI
+
 struct _starpu_mpi_comm
 {
 	MPI_Comm comm;
@@ -218,3 +220,5 @@ void _starpu_mpi_comm_cancel_recv()
 	}
 	STARPU_PTHREAD_MUTEX_UNLOCK(&_starpu_mpi_comms_mutex);
 }
+
+#endif /* STARPU_USE_MPI_MPI */

+ 3 - 0
mpi/src/mpi/starpu_mpi_comm.h

@@ -21,6 +21,8 @@
 #include <stdlib.h>
 #include <mpi.h>
 
+#ifdef STARPU_USE_MPI_MPI
+
 #ifdef __cplusplus
 extern "C"
 {
@@ -37,4 +39,5 @@ void _starpu_mpi_comm_cancel_recv();
 }
 #endif
 
+#endif // STARPU_USE_MPI_MPI
 #endif // __STARPU_MPI_COMM_H__

+ 3 - 0
mpi/src/mpi/starpu_mpi_early_data.c

@@ -21,6 +21,8 @@
 #include <starpu_mpi_private.h>
 #include <common/uthash.h>
 
+#ifdef STARPU_USE_MPI_MPI
+
 struct _starpu_mpi_early_data_handle_hashlist
 {
 	struct _starpu_mpi_early_data_handle_list list;
@@ -119,3 +121,4 @@ void _starpu_mpi_early_data_add(struct _starpu_mpi_early_data_handle *early_data
 	STARPU_PTHREAD_MUTEX_UNLOCK(&_starpu_mpi_early_data_handle_mutex);
 }
 
+#endif // STARPU_USE_MPI_MPI

+ 3 - 0
mpi/src/mpi/starpu_mpi_early_data.h

@@ -25,6 +25,8 @@
 #include <common/list.h>
 #include <starpu_mpi_private.h>
 
+#ifdef STARPU_USE_MPI_MPI
+
 #ifdef __cplusplus
 extern "C"
 {
@@ -53,4 +55,5 @@ void _starpu_mpi_early_data_add(struct _starpu_mpi_early_data_handle *early_data
 }
 #endif
 
+#endif /*  STARPU_USE_MPI_MPI */
 #endif /* __STARPU_MPI_EARLY_DATA_H__ */

+ 4 - 0
mpi/src/mpi/starpu_mpi_early_request.c

@@ -21,6 +21,8 @@
 #include <mpi/starpu_mpi_early_request.h>
 #include <common/uthash.h>
 
+#ifdef STARPU_USE_MPI_MPI
+
 /** stores application requests for which data have not been received yet */
 struct _starpu_mpi_early_request_hashlist
 {
@@ -115,3 +117,5 @@ void _starpu_mpi_early_request_enqueue(struct _starpu_mpi_req *req)
 	_starpu_mpi_early_request_hash_count ++;
 	STARPU_PTHREAD_MUTEX_UNLOCK(&_starpu_mpi_early_request_mutex);
 }
+
+#endif // STARPU_USE_MPI_MPI

+ 3 - 0
mpi/src/mpi/starpu_mpi_early_request.h

@@ -24,6 +24,8 @@
 #include <common/config.h>
 #include <common/list.h>
 
+#ifdef STARPU_USE_MPI_MPI
+
 #ifdef __cplusplus
 extern "C"
 {
@@ -41,4 +43,5 @@ struct _starpu_mpi_req* _starpu_mpi_early_request_dequeue(int data_tag, int sour
 }
 #endif
 
+#endif /* STARPU_USE_MPI_MPI */
 #endif /* __STARPU_MPI_EARLY_REQUEST_H__ */

+ 3 - 0
mpi/src/mpi/starpu_mpi_mpi.c

@@ -41,6 +41,8 @@
 #include <core/topology.h>
 #include <core/workers.h>
 
+#ifdef STARPU_USE_MPI_MPI
+
 /* Number of ready requests to process before polling for completed requests */
 static unsigned nready_process;
 
@@ -1635,3 +1637,4 @@ void _starpu_mpi_progress_shutdown(int *value)
         STARPU_PTHREAD_COND_DESTROY(&barrier_cond);
 }
 
+#endif /* STARPU_USE_MPI_MPI */

+ 3 - 0
mpi/src/mpi/starpu_mpi_sync_data.c

@@ -20,6 +20,8 @@
 #include <starpu_mpi_private.h>
 #include <common/uthash.h>
 
+#ifdef STARPU_USE_MPI_MPI
+
 struct _starpu_mpi_sync_data_handle_hashlist
 {
 	struct _starpu_mpi_req_list list;
@@ -148,3 +150,4 @@ void _starpu_mpi_sync_data_add(struct _starpu_mpi_req *sync_req)
 #endif
 }
 
+#endif // STARPU_USE_MPI_MPI

+ 3 - 0
mpi/src/mpi/starpu_mpi_sync_data.h

@@ -23,6 +23,8 @@
 #include <common/config.h>
 #include <common/list.h>
 
+#ifdef STARPU_USE_MPI_MPI
+
 #ifdef __cplusplus
 extern "C"
 {
@@ -40,4 +42,5 @@ int _starpu_mpi_sync_data_count();
 }
 #endif
 
+#endif /* STARPU_USE_MPI_MPI */
 #endif /* __STARPU_MPI_SYNC_DATA_H__ */

+ 4 - 0
mpi/src/mpi/starpu_mpi_tag.c

@@ -23,6 +23,8 @@
 #include <common/starpu_spinlock.h>
 #include <datawizard/coherency.h>
 
+#ifdef STARPU_USE_MPI_MPI
+
 /* Entry in the `registered_tag_handles' hash table.  */
 struct handle_tag_entry
 {
@@ -116,3 +118,5 @@ int _starpu_mpi_tag_data_release(starpu_data_handle_t handle)
 	}
 	return 0;
 }
+
+#endif // STARPU_USE_MPI_MPI

+ 3 - 0
mpi/src/mpi/starpu_mpi_tag.h

@@ -21,6 +21,8 @@
 #include <stdlib.h>
 #include <mpi.h>
 
+#ifdef STARPU_USE_MPI_MPI
+
 #ifdef __cplusplus
 extern "C"
 {
@@ -37,4 +39,5 @@ starpu_data_handle_t _starpu_mpi_tag_get_data_handle_from_tag(int tag);
 }
 #endif
 
+#endif // STARPU_USE_MPI_MPI
 #endif // __STARPU_MPI_TAG_H__

+ 767 - 0
mpi/src/nmad/starpu_mpi_nmad.c

@@ -0,0 +1,767 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2009, 2010-2014, 2017  Université de Bordeaux
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015  Centre National de la Recherche Scientifique
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#include <stdlib.h>
+#include <limits.h>
+#include <starpu_mpi.h>
+#include <starpu_mpi_datatype.h>
+#include <starpu_mpi_private.h>
+#include <starpu_mpi_cache.h>
+#include <starpu_profiling.h>
+#include <starpu_mpi_stats.h>
+#include <starpu_mpi_cache.h>
+#include <starpu_mpi_select_node.h>
+#include <starpu_mpi_init.h>
+#include <common/config.h>
+#include <common/thread.h>
+#include <datawizard/coherency.h>
+#include <core/task.h>
+#include <core/topology.h>
+
+#ifdef STARPU_USE_MPI_NMAD
+
+#include <nm_sendrecv_interface.h>
+#include <nm_mpi_nmad.h>
+
+static void _starpu_mpi_handle_request_termination(struct _starpu_mpi_req *req,nm_sr_event_t event);
+#ifdef STARPU_VERBOSE
+static char *_starpu_mpi_request_type(enum _starpu_mpi_request_type request_type);
+#endif
+static void _starpu_mpi_handle_new_request(void *arg);
+
+static void _starpu_mpi_handle_pending_request(struct _starpu_mpi_req *req);
+static void _starpu_mpi_add_sync_point_in_fxt(void);
+
+static int mpi_thread_cpuid = -1;
+int _starpu_mpi_fake_world_size = -1;
+int _starpu_mpi_fake_world_rank = -1;
+
+/* Condition to wake up waiting for all current MPI requests to finish */
+static starpu_pthread_t progress_thread;
+static starpu_pthread_cond_t progress_cond;
+static starpu_pthread_mutex_t progress_mutex;
+static volatile int running = 0;
+
+extern struct _starpu_mpi_req *_starpu_mpi_irecv_common(starpu_data_handle_t data_handle, int source, int data_tag, MPI_Comm comm, unsigned detached, unsigned sync, void (*callback)(void *), void *arg, int sequential_consistency, int is_internal_req, starpu_ssize_t count);
+
+/* Count requests posted by the application and not yet submitted to MPI, i.e pushed into the new_requests list */
+
+static volatile int pending_request = 0;
+
+#define REQ_FINALIZED 0x1
+
+PUK_LFSTACK_TYPE(callback,	struct _starpu_mpi_req *req;);
+static callback_lfstack_t callback_stack = NULL;
+
+static starpu_sem_t callback_sem;
+
+void _starpu_mpi_request_init(struct _starpu_mpi_req **req)
+{
+	_STARPU_MPI_CALLOC(*req, 1, sizeof(struct _starpu_mpi_req));
+
+	/* Initialize the request structure */
+	(*req)->data_handle = NULL;
+	(*req)->prio = 0;
+	(*req)->completed = 0;
+
+	(*req)->datatype = 0;
+	(*req)->datatype_name = NULL;
+	(*req)->ptr = NULL;
+	(*req)->count = -1;
+	(*req)->registered_datatype = -1;
+
+	(*req)->node_tag.rank = -1;
+	(*req)->node_tag.data_tag = -1;
+	(*req)->node_tag.comm = 0;
+
+	(*req)->func = NULL;
+
+	(*req)->status = NULL;
+	//	(*req)->data_request = 0;
+	(*req)->flag = NULL;
+
+	(*req)->ret = -1;
+	piom_cond_init(&((*req)->req_cond), 0);
+	//STARPU_PTHREAD_MUTEX_INIT(&((*req)->req_mutex), NULL);
+	//STARPU_PTHREAD_COND_INIT(&((*req)->req_cond), NULL);
+	//	STARPU_PTHREAD_MUTEX_INIT(&((*req)->posted_mutex), NULL);
+	//STARPU_PTHREAD_COND_INIT(&((*req)->posted_cond), NULL);
+
+	(*req)->request_type = UNKNOWN_REQ;
+
+	(*req)->submitted = 0;
+	(*req)->completed = 0;
+	(*req)->posted = 0;
+
+	//(*req)->other_request = NULL;
+
+	(*req)->sync = 0;
+	(*req)->detached = -1;
+	(*req)->callback = NULL;
+	(*req)->callback_arg = NULL;
+
+	//	(*req)->size_req = 0;
+	//(*req)->internal_req = NULL;
+	//(*req)->is_internal_req = 0;
+	//(*req)->to_destroy = 1;
+	//(*req)->early_data_handle = NULL;
+	//(*req)->envelope = NULL;
+	(*req)->sequential_consistency = 1;
+	(*req)->pre_sync_jobid = -1;
+	(*req)->post_sync_jobid = -1;
+
+#ifdef STARPU_SIMGRID
+	starpu_pthread_queue_init(&((*req)->queue));
+	starpu_pthread_queue_register(&wait, &((*req)->queue));
+	(*req)->done = 0;
+#endif
+}
+
+void _starpu_mpi_request_destroy(struct _starpu_mpi_req *req)
+{
+	piom_cond_destroy(&(req->req_cond));
+	free(req);
+}
+
+/********************************************************/
+/*                                                      */
+/*  Send/Receive functionalities                        */
+/*                                                      */
+/********************************************************/
+
+static void nop_acquire_cb(void *arg)
+{
+	starpu_data_release(arg);
+}
+
+struct _starpu_mpi_req *_starpu_mpi_isend_irecv_common(starpu_data_handle_t data_handle,
+						       int srcdst, int data_tag, MPI_Comm comm,
+						       unsigned detached, unsigned sync, int prio, void (*callback)(void *), void *arg,
+						       enum _starpu_mpi_request_type request_type, void (*func)(struct _starpu_mpi_req *),
+						       enum starpu_data_access_mode mode,
+						       int sequential_consistency,
+						       int is_internal_req,
+						       starpu_ssize_t count)
+{
+
+	struct _starpu_mpi_req *req;
+
+	if (_starpu_mpi_fake_world_size != -1)
+	{
+		/* Don't actually do the communication */
+		starpu_data_acquire_on_node_cb_sequential_consistency(data_handle, STARPU_MAIN_RAM, mode, nop_acquire_cb, data_handle, sequential_consistency);
+		return NULL;
+	}
+
+	_STARPU_MPI_LOG_IN();
+	STARPU_ATOMIC_ADD( &pending_request, 1);
+
+	/* Initialize the request structure */
+	_starpu_mpi_request_init(&req);
+	req->request_type = request_type;
+	/* prio_list is sorted by increasing values */
+	req->prio = prio;
+	req->data_handle = data_handle;
+	req->node_tag.rank = srcdst;
+	req->node_tag.data_tag = data_tag;
+	req->node_tag.comm = comm;
+	req->detached = detached;
+	req->sync = sync;
+	req->callback = callback;
+	req->callback_arg = arg;
+	req->func = func;
+	req->sequential_consistency = sequential_consistency;
+	nm_mpi_nmad_dest(&req->session, &req->gate, comm, req->node_tag.rank);
+
+	/* Asynchronously request StarPU to fetch the data in main memory: when
+	 * it is available in main memory, _starpu_mpi_submit_new_mpi_request(req) is called and
+	 * the request is actually submitted */
+	starpu_data_acquire_on_node_cb_sequential_consistency_sync_jobids(data_handle, STARPU_MAIN_RAM, mode, _starpu_mpi_handle_new_request, (void *)req, sequential_consistency, &req->pre_sync_jobid, &req->post_sync_jobid);
+
+	_STARPU_MPI_LOG_OUT();
+	return req;
+}
+
+/********************************************************/
+/*                                                      */
+/*  Send functionalities                                */
+/*                                                      */
+/********************************************************/
+
+static void _starpu_mpi_isend_data_func(struct _starpu_mpi_req *req)
+{
+	_STARPU_MPI_LOG_IN();
+
+	_STARPU_MPI_DEBUG(30, "post MPI isend request %p type %s tag %d src %d data %p datasize %ld ptr %p datatype '%s' count %d registered_datatype %d sync %d\n", req, _starpu_mpi_request_type(req->request_type), req->node_tag.data_tag, req->node_tag.rank, req->data_handle, starpu_data_get_size(req->data_handle), req->ptr, req->datatype_name, (int)req->count, req->registered_datatype, req->sync);
+
+	_starpu_mpi_comm_amounts_inc(req->node_tag.comm, req->node_tag.rank, req->datatype, req->count);
+
+	_STARPU_MPI_TRACE_ISEND_SUBMIT_BEGIN(req->node_tag.rank, req->node_tag.data_tag, 0);
+
+	struct nm_data_s data;
+	nm_mpi_nmad_data(&data, (void*)req->ptr, req->datatype, req->count);
+	nm_sr_send_init(req->session, &(req->data_request));
+	nm_sr_send_pack_data(req->session, &(req->data_request), &data);
+	nm_sr_send_set_priority(req->session, &req->data_request, req->prio);
+
+	if (req->sync == 0)
+	{
+		req->ret = nm_sr_send_isend(req->session, &(req->data_request), req->gate, req->node_tag.data_tag);
+		STARPU_ASSERT_MSG(req->ret == NM_ESUCCESS, "MPI_Isend returning %d", req->ret);
+	}
+	else
+	{
+		req->ret = nm_sr_send_issend(req->session, &(req->data_request), req->gate, req->node_tag.data_tag);
+		STARPU_ASSERT_MSG(req->ret == NM_ESUCCESS, "MPI_Issend returning %d", req->ret);
+	}
+
+	_STARPU_MPI_TRACE_ISEND_SUBMIT_END(req->node_tag.rank, req->node_tag.data_tag, starpu_data_get_size(req->data_handle), req->pre_sync_jobid);
+
+	_starpu_mpi_handle_pending_request(req);
+
+	_STARPU_MPI_LOG_OUT();
+}
+
+void _starpu_mpi_isend_size_func(struct _starpu_mpi_req *req)
+{
+	_starpu_mpi_datatype_allocate(req->data_handle, req);
+
+	if (req->registered_datatype == 1)
+	{
+		req->waited = 1;
+		req->count = 1;
+		req->ptr = starpu_data_get_local_ptr(req->data_handle);
+	}
+	else
+	{
+		starpu_ssize_t psize = -1;
+		int ret;
+		req->waited =2;
+
+		// Do not pack the data, just try to find out the size
+		starpu_data_pack(req->data_handle, NULL, &psize);
+
+		if (psize != -1)
+		{
+			// We already know the size of the data, let's send it to overlap with the packing of the data
+			_STARPU_MPI_DEBUG(20, "Sending size %ld (%ld %s) to node %d (first call to pack)\n", psize, sizeof(req->count), "MPI_BYTE", req->node_tag.rank);
+			req->count = psize;
+			//ret = nm_sr_isend(nm_mpi_communicator_get_session(p_req->p_comm),nm_mpi_communicator_get_gate(p_comm,req->srcdst), req->mpi_tag,&req->count, sizeof(req->count), &req->size_req);
+			ret = nm_sr_isend(req->session,req->gate, req->node_tag.data_tag,&req->count, sizeof(req->count), &req->size_req);
+
+			//	ret = MPI_Isend(&req->count, sizeof(req->count), MPI_BYTE, req->srcdst, req->mpi_tag, req->comm, &req->size_req);
+			STARPU_ASSERT_MSG(ret == NM_ESUCCESS, "when sending size, nm_sr_isend returning %d", ret);
+		}
+
+		// Pack the data
+		starpu_data_pack(req->data_handle, &req->ptr, &req->count);
+		if (psize == -1)
+		{
+			// We know the size now, let's send it
+			_STARPU_MPI_DEBUG(1, "Sending size %ld (%ld %s) with tag %d to node %d (second call to pack)\n", req->count, sizeof(req->count), "MPI_BYTE", req->node_tag.data_tag, req->node_tag.rank);
+			ret = nm_sr_isend(req->session,req->gate, req->node_tag.data_tag,&req->count, sizeof(req->count), &req->size_req);
+			STARPU_ASSERT_MSG(ret == NM_ESUCCESS, "when sending size, nm_sr_isend returning %d", ret);
+		}
+		else
+		{
+			// We check the size returned with the 2 calls to pack is the same
+			STARPU_ASSERT_MSG(req->count == psize, "Calls to pack_data returned different sizes %ld != %ld", req->count, psize);
+		}
+
+		// We can send the data now
+	}
+	_starpu_mpi_isend_data_func(req);
+}
+
+/********************************************************/
+/*                                                      */
+/*  Receive functionalities                             */
+/*                                                      */
+/********************************************************/
+
+static void _starpu_mpi_irecv_data_func(struct _starpu_mpi_req *req)
+{
+	_STARPU_MPI_LOG_IN();
+
+	_STARPU_MPI_DEBUG(20, "post MPI irecv request %p type %s tag %d src %d data %p ptr %p datatype '%s' count %d registered_datatype %d \n", req, _starpu_mpi_request_type(req->request_type), req->node_tag.data_tag, req->node_tag.rank, req->data_handle, req->ptr, req->datatype_name, (int)req->count, req->registered_datatype);
+
+	_STARPU_MPI_TRACE_IRECV_SUBMIT_BEGIN(req->node_tag.rank, req->node_tag.data_tag);
+
+	//req->ret = MPI_Irecv(req->ptr, req->count, req->datatype, req->srcdst, req->mpi_tag, req->comm, &req->request);
+	struct nm_data_s data;
+	nm_mpi_nmad_data(&data, (void*)req->ptr, req->datatype, req->count);
+	nm_sr_recv_init(req->session, &(req->data_request));
+	nm_sr_recv_unpack_data(req->session, &(req->data_request), &data);
+	nm_sr_recv_irecv(req->session, &(req->data_request), req->gate, req->node_tag.data_tag, NM_TAG_MASK_FULL);
+
+	_STARPU_MPI_TRACE_IRECV_SUBMIT_END(req->node_tag.rank, req->node_tag.data_tag);
+
+	_starpu_mpi_handle_pending_request(req);
+
+	_STARPU_MPI_LOG_OUT();
+}
+
+struct _starpu_mpi_irecv_size_callback
+{
+	starpu_data_handle_t handle;
+	struct _starpu_mpi_req *req;
+};
+
+static void _starpu_mpi_irecv_size_callback(void *arg)
+{
+	struct _starpu_mpi_irecv_size_callback *callback = (struct _starpu_mpi_irecv_size_callback *)arg;
+
+	starpu_data_unregister(callback->handle);
+	callback->req->ptr = malloc(callback->req->count);
+	STARPU_ASSERT_MSG(callback->req->ptr, "cannot allocate message of size %ld", callback->req->count);
+	_starpu_mpi_irecv_data_func(callback->req);
+	free(callback);
+}
+
+void _starpu_mpi_irecv_size_func(struct _starpu_mpi_req *req)
+{
+	_STARPU_MPI_LOG_IN();
+
+	_starpu_mpi_datatype_allocate(req->data_handle, req);
+	if (req->registered_datatype == 1)
+	{
+		req->count = 1;
+		req->ptr = starpu_data_get_local_ptr(req->data_handle);
+		_starpu_mpi_irecv_data_func(req);
+	}
+	else
+	{
+		struct _starpu_mpi_irecv_size_callback *callback = malloc(sizeof(struct _starpu_mpi_irecv_size_callback));
+		callback->req = req;
+		starpu_variable_data_register(&callback->handle, 0, (uintptr_t)&(callback->req->count), sizeof(callback->req->count));
+		_STARPU_MPI_DEBUG(4, "Receiving size with tag %d from node %d\n", req->node_tag.data_tag, req->node_tag.rank);
+		_starpu_mpi_irecv_common(callback->handle, req->node_tag.rank, req->node_tag.data_tag, req->node_tag.comm, 1, 0, _starpu_mpi_irecv_size_callback, callback,1,0,0);
+	}
+
+}
+
+/********************************************************/
+/*                                                      */
+/*  Wait functionalities                                */
+/*                                                      */
+/********************************************************/
+
+#define _starpu_mpi_req_status(PUBLIC_REQ,STATUS) do {			\
+	STATUS->MPI_SOURCE=PUBLIC_REQ->node_tag.rank; /**< field name mandatory by spec */ \
+	STATUS->MPI_TAG=PUBLIC_REQ->node_tag.data_tag;    /**< field name mandatory by spec */ \
+	STATUS->MPI_ERROR=PUBLIC_REQ->ret;  /**< field name mandatory by spec */ \
+	STATUS->size=PUBLIC_REQ->count;       /**< size of data received */ \
+	STATUS->cancelled=0;  /**< whether request was cancelled */	\
+} while(0)
+
+int _starpu_mpi_wait(starpu_mpi_req *public_req, MPI_Status *status)
+{
+	_STARPU_MPI_LOG_IN();
+	STARPU_MPI_ASSERT_MSG(public_req, "starpu_mpi_wait needs a valid starpu_mpi_req");
+	struct _starpu_mpi_req *req = *public_req;
+	STARPU_MPI_ASSERT_MSG(!req->detached, "MPI_Wait cannot be called on a detached request");
+
+	/* we must do a test_locked to avoid race condition :
+	 * without req_cond could still be used and couldn't be freed)*/
+	while (!req->completed || ! piom_cond_test_locked(&(req->req_cond),REQ_FINALIZED))
+	{
+		piom_cond_wait(&(req->req_cond),REQ_FINALIZED);
+	}
+
+	if (status!=MPI_STATUS_IGNORE)
+		_starpu_mpi_req_status(req,status);
+
+	_starpu_mpi_request_destroy(req);
+	*public_req = NULL;
+	_STARPU_MPI_LOG_OUT();
+	return MPI_SUCCESS;
+}
+
+/********************************************************/
+/*                                                      */
+/*  Test functionalities                                */
+/*                                                      */
+/********************************************************/
+
+int _starpu_mpi_test(starpu_mpi_req *public_req, int *flag, MPI_Status *status)
+{
+	_STARPU_MPI_LOG_IN();
+	STARPU_MPI_ASSERT_MSG(public_req, "starpu_mpi_test needs a valid starpu_mpi_req");
+	struct _starpu_mpi_req *req = *public_req;
+	STARPU_MPI_ASSERT_MSG(!req->detached, "MPI_Test cannot be called on a detached request");
+	_STARPU_MPI_DEBUG(2, "Test request %p type %s tag %d src %d data %p ptr %p datatype '%s' count %d registered_datatype %d \n",
+			  req, _starpu_mpi_request_type(req->request_type), req->node_tag.data_tag, req->node_tag.rank, req->data_handle, req->ptr, req->datatype_name, (int)req->count, req->registered_datatype);
+
+	_STARPU_MPI_TRACE_UTESTING_BEGIN(req->node_tag.rank, req->node_tag.data_tag);
+
+	/* we must do a test_locked to avoid race condition :
+	 * without req_cond could still be used and couldn't be freed)*/
+	*flag = req->completed && piom_cond_test_locked(&(req->req_cond),REQ_FINALIZED);
+	if (*flag && status!=MPI_STATUS_IGNORE)
+		_starpu_mpi_req_status(req,status);
+
+	_STARPU_MPI_TRACE_UTESTING_END(req->node_tag.rank, req->node_tag.data_tag);
+
+	if(*flag)
+	{
+		_starpu_mpi_request_destroy(req);
+		*public_req = NULL;
+	}
+	_STARPU_MPI_LOG_OUT();
+	return MPI_SUCCESS;
+}
+
+/********************************************************/
+/*                                                      */
+/*  Barrier functionalities                             */
+/*                                                      */
+/********************************************************/
+
+int _starpu_mpi_barrier(MPI_Comm comm)
+{
+	_STARPU_MPI_LOG_IN();
+	int ret;
+	//	STARPU_ASSERT_MSG(!barrier_running, "Concurrent starpu_mpi_barrier is not implemented, even on different communicators");
+	ret = MPI_Barrier(comm);
+
+	STARPU_ASSERT_MSG(ret == MPI_SUCCESS, "MPI_Barrier returning %d", ret);
+
+	_STARPU_MPI_LOG_OUT();
+	return ret;
+}
+
+/********************************************************/
+/*                                                      */
+/*  Progression                                         */
+/*                                                      */
+/********************************************************/
+
+#ifdef STARPU_VERBOSE
+static char *_starpu_mpi_request_type(enum _starpu_mpi_request_type request_type)
+{
+	switch (request_type)
+	{
+		case SEND_REQ: return "SEND_REQ";
+		case RECV_REQ: return "RECV_REQ";
+		case WAIT_REQ: return "WAIT_REQ";
+		case TEST_REQ: return "TEST_REQ";
+		case BARRIER_REQ: return "BARRIER_REQ";
+		default: return "unknown request type";
+	}
+}
+#endif
+
+static void _starpu_mpi_handle_request_termination(struct _starpu_mpi_req *req,nm_sr_event_t event)
+{
+	_STARPU_MPI_LOG_IN();
+
+	_STARPU_MPI_DEBUG(2, "complete MPI request %p type %s tag %d src %d data %p ptr %p datatype '%s' count %d registered_datatype %d \n",
+			  req, _starpu_mpi_request_type(req->request_type), req->node_tag.data_tag, req->node_tag.rank, req->data_handle, req->ptr, req->datatype_name, (int)req->count, req->registered_datatype);
+
+	if (req->request_type == RECV_REQ || req->request_type == SEND_REQ)
+	{
+		if (req->registered_datatype == 0)
+		{
+			if (req->request_type == SEND_REQ)
+			{
+				req->waited--;
+				// We need to make sure the communication for sending the size
+				// has completed, as MPI can re-order messages, let's count
+				// recerived message.
+				// FIXME concurent access.
+				STARPU_ASSERT_MSG(event == NM_SR_EVENT_FINALIZED, "Callback with event %d", event);
+				if(req->waited>0)
+					return;
+
+			}
+			if (req->request_type == RECV_REQ)
+				// req->ptr is freed by starpu_data_unpack
+				starpu_data_unpack(req->data_handle, req->ptr, req->count);
+			else
+				free(req->ptr);
+		}
+		else
+		{
+			_starpu_mpi_datatype_free(req->data_handle, &req->datatype);
+		}
+		starpu_data_release(req->data_handle);
+	}
+
+	/* Execute the specified callback, if any */
+	if (req->callback)
+	{
+		struct callback_lfstack_cell_s* c = padico_malloc(sizeof(struct callback_lfstack_cell_s));
+		c->req = req;
+		/* The main thread can exit without waiting
+		* the end of the detached request. Callback thread
+		* must then be kept alive if they have a callback.*/
+
+		callback_lfstack_push(&callback_stack, c);
+		starpu_sem_post(&callback_sem);
+	}
+	else
+	{
+		if(req->detached)
+		{
+			_starpu_mpi_request_destroy(req);
+			// a detached request wont be wait/test (and freed inside).
+		}
+		else
+		{
+			/* tell anyone potentially waiting on the request that it is
+			 * terminated now (should be done after the callback)*/
+			req->completed = 1;
+			piom_cond_signal(&req->req_cond, REQ_FINALIZED);
+		}
+		int pending_remaining = STARPU_ATOMIC_ADD(&pending_request, -1);
+		if (!running && !pending_remaining)
+			starpu_sem_post(&callback_sem);
+	}
+	_STARPU_MPI_LOG_OUT();
+}
+
+void _starpu_mpi_handle_request_termination_callback(nm_sr_event_t event, const nm_sr_event_info_t*event_info, void*ref)
+{
+	_starpu_mpi_handle_request_termination(ref,event);
+}
+
+static void _starpu_mpi_handle_pending_request(struct _starpu_mpi_req *req)
+{
+	if(req->request_type == SEND_REQ && req->waited>1)
+	{
+		nm_sr_request_set_ref(&(req->size_req), req);
+		nm_sr_request_monitor(req->session, &(req->size_req), NM_SR_EVENT_FINALIZED,_starpu_mpi_handle_request_termination_callback);
+	}
+	/* the if must be before, because the first callback can directly free
+	* a detached request (the second callback free if req->waited>1). */
+	nm_sr_request_set_ref(&(req->data_request), req);
+
+	nm_sr_request_monitor(req->session, &(req->data_request), NM_SR_EVENT_FINALIZED,_starpu_mpi_handle_request_termination_callback);
+}
+
+static void _starpu_mpi_handle_new_request(void *arg)
+{
+	_STARPU_MPI_LOG_IN();
+	struct _starpu_mpi_req *req = arg;
+	STARPU_ASSERT_MSG(req, "Invalid request");
+
+	/* submit the request to MPI */
+	_STARPU_MPI_DEBUG(2, "Handling new request %p type %s tag %d src %d data %p ptr %p datatype '%s' count %d registered_datatype %d \n",
+			  req, _starpu_mpi_request_type(req->request_type), req->node_tag.data_tag, req->node_tag.rank, req->data_handle, req->ptr, req->datatype_name, (int)req->count, req->registered_datatype);
+	req->func(req);
+
+	_STARPU_MPI_LOG_OUT();
+}
+
+static void *_starpu_mpi_progress_thread_func(void *arg)
+{
+	struct _starpu_mpi_argc_argv *argc_argv = (struct _starpu_mpi_argc_argv *) arg;
+
+	starpu_pthread_setname("MPI");
+
+#ifndef STARPU_SIMGRID
+	if (mpi_thread_cpuid >= 0)
+		_starpu_bind_thread_on_cpu(mpi_thread_cpuid, STARPU_NOWORKERID);
+	_starpu_mpi_do_initialize(argc_argv);
+	if (mpi_thread_cpuid >= 0)
+		/* In case MPI changed the binding */
+		_starpu_bind_thread_on_cpu(mpi_thread_cpuid, STARPU_NOWORKERID);
+#endif
+
+	_starpu_mpi_fake_world_size = starpu_get_env_number("STARPU_MPI_FAKE_SIZE");
+	_starpu_mpi_fake_world_rank = starpu_get_env_number("STARPU_MPI_FAKE_RANK");
+
+#ifdef STARPU_SIMGRID
+	/* Now that MPI is set up, let the rest of simgrid get initialized */
+	char **argv_cpy;
+	_STARPU_MPI_MALLOC(argv_cpy, *(argc_argv->argc) * sizeof(char*));
+	int i;
+	for (i = 0; i < *(argc_argv->argc); i++)
+		argv_cpy[i] = strdup((*(argc_argv->argv))[i]);
+	MSG_process_create_with_arguments("main", smpi_simulated_main_, NULL, _starpu_simgrid_get_host_by_name("MAIN"), *(argc_argv->argc), argv_cpy);
+	/* And set TSD for us */
+	void **tsd;
+	_STARPU_CALLOC(tsd, MAX_TSD + 1, sizeof(void*));
+	if (!smpi_process_set_user_data)
+	{
+		_STARPU_ERROR("Your version of simgrid does not provide smpi_process_set_user_data, we can not continue without it\n");
+	}
+	smpi_process_set_user_data(tsd);
+#endif
+
+#ifdef STARPU_USE_FXT
+	_starpu_fxt_wait_initialisation();
+#endif //STARPU_USE_FXT
+
+	{
+		_STARPU_MPI_TRACE_START(argc_argv->rank, argc_argv->world_size);
+#ifdef STARPU_USE_FXT
+		starpu_profiling_set_id(argc_argv->rank);
+#endif //STARPU_USE_FXT
+	}
+
+	_starpu_mpi_add_sync_point_in_fxt();
+	_starpu_mpi_comm_amounts_init(argc_argv->comm);
+	_starpu_mpi_cache_init(argc_argv->comm);
+	_starpu_mpi_select_node_init();
+	_starpu_mpi_datatype_init();
+
+	/* notify the main thread that the progression thread is ready */
+	STARPU_PTHREAD_MUTEX_LOCK(&progress_mutex);
+	running = 1;
+	STARPU_PTHREAD_COND_SIGNAL(&progress_cond);
+	STARPU_PTHREAD_MUTEX_UNLOCK(&progress_mutex);
+
+	while (1)
+	{
+		struct callback_lfstack_cell_s* c = callback_lfstack_pop(&callback_stack);
+		int err=0;
+
+		if(running || pending_request>0)
+		{/* shall we block ? */
+			err = starpu_sem_wait(&callback_sem);
+			//running pending_request can change while waiting
+		}
+		if(c==NULL)
+		{
+			c = callback_lfstack_pop(&callback_stack);
+			if (c == NULL)
+			{
+				if(running && pending_request>0)
+				{
+					STARPU_ASSERT_MSG(c!=NULL, "Callback thread awakened without callback ready with error %d.",err);
+				}
+				else
+				{
+					if (pending_request==0)
+						break;
+				}
+				continue;
+			}
+		}
+
+
+		c->req->callback(c->req->callback_arg);
+		if (c->req->detached)
+		{
+			_starpu_mpi_request_destroy(c->req);
+		}
+		else
+		{
+			c->req->completed=1;
+			piom_cond_signal(&(c->req->req_cond), REQ_FINALIZED);
+		}
+		STARPU_ATOMIC_ADD( &pending_request, -1);
+		/* we signal that the request is completed.*/
+
+		free(c);
+
+	}
+	STARPU_ASSERT_MSG(callback_lfstack_pop(&callback_stack)==NULL, "List of callback not empty.");
+	STARPU_ASSERT_MSG(pending_request==0, "Request still pending.");
+
+	if (argc_argv->initialize_mpi)
+	{
+		_STARPU_MPI_DEBUG(3, "Calling MPI_Finalize()\n");
+		MPI_Finalize();
+	}
+
+	starpu_sem_destroy(&callback_sem);
+	free(argc_argv);
+	return NULL;
+}
+
+/********************************************************/
+/*                                                      */
+/*  (De)Initialization methods                          */
+/*                                                      */
+/********************************************************/
+
+// #ifdef STARPU_MPI_ACTIVITY
+// static int hookid = - 1;
+// #endif /* STARPU_MPI_ACTIVITY */
+
+static void _starpu_mpi_add_sync_point_in_fxt(void)
+{
+#ifdef STARPU_USE_FXT
+	int rank;
+	int worldsize;
+	int ret;
+
+	starpu_mpi_comm_rank(MPI_COMM_WORLD, &rank);
+	starpu_mpi_comm_size(MPI_COMM_WORLD, &worldsize);
+
+	ret = MPI_Barrier(MPI_COMM_WORLD);
+	STARPU_MPI_ASSERT_MSG(ret == MPI_SUCCESS, "MPI_Barrier returning %s", _starpu_mpi_get_mpi_error_code(ret));
+
+	/* We generate a "unique" key so that we can make sure that different
+	 * FxT traces come from the same MPI run. */
+	int random_number;
+
+	/* XXX perhaps we don't want to generate a new seed if the application
+	 * specified some reproductible behaviour ? */
+	if (rank == 0)
+	{
+		srand(time(NULL));
+		random_number = rand();
+	}
+
+	ret = MPI_Bcast(&random_number, 1, MPI_INT, 0, MPI_COMM_WORLD);
+	STARPU_MPI_ASSERT_MSG(ret == MPI_SUCCESS, "MPI_Bcast returning %s", _starpu_mpi_get_mpi_error_code(ret));
+
+	_STARPU_MPI_TRACE_BARRIER(rank, worldsize, random_number);
+
+	_STARPU_MPI_DEBUG(3, "unique key %x\n", random_number);
+#endif
+}
+
+int _starpu_mpi_progress_init(struct _starpu_mpi_argc_argv *argc_argv)
+{
+        STARPU_PTHREAD_MUTEX_INIT(&progress_mutex, NULL);
+        STARPU_PTHREAD_COND_INIT(&progress_cond, NULL);
+
+	starpu_sem_init(&callback_sem, 0, 0);
+	running = 0;
+	mpi_thread_cpuid = starpu_get_env_number_default("STARPU_MPI_THREAD_CPUID", -1);
+
+	STARPU_PTHREAD_CREATE(&progress_thread, NULL, _starpu_mpi_progress_thread_func, argc_argv);
+
+        STARPU_PTHREAD_MUTEX_LOCK(&progress_mutex);
+        while (!running)
+                STARPU_PTHREAD_COND_WAIT(&progress_cond, &progress_mutex);
+        STARPU_PTHREAD_MUTEX_UNLOCK(&progress_mutex);
+
+        return 0;
+}
+
+void _starpu_mpi_progress_shutdown(int *value)
+{
+	/* kill the progression thread */
+        STARPU_PTHREAD_MUTEX_LOCK(&progress_mutex);
+        running = 0;
+        STARPU_PTHREAD_COND_BROADCAST(&progress_cond);
+        STARPU_PTHREAD_MUTEX_UNLOCK(&progress_mutex);
+
+	starpu_sem_post(&callback_sem);
+
+	starpu_pthread_join(progress_thread, &value);
+
+        STARPU_PTHREAD_MUTEX_DESTROY(&progress_mutex);
+        STARPU_PTHREAD_COND_DESTROY(&progress_cond);
+}
+
+#endif /* STARPU_USE_MPI_NMAD*/

+ 8 - 3
mpi/src/starpu_mpi.c

@@ -36,6 +36,11 @@
 #include <core/topology.h>
 #include <core/workers.h>
 
+#if defined(STARPU_USE_MPI_MPI)
+#include <mpi/starpu_mpi_comm.h>
+#include <mpi/starpu_mpi_tag.h>
+#endif
+
 static struct _starpu_mpi_req *_starpu_mpi_isend_common(starpu_data_handle_t data_handle,
 							int dest, int data_tag, MPI_Comm comm,
 							unsigned detached, unsigned sync, int prio, void (*callback)(void *), void *arg,
@@ -211,7 +216,7 @@ int starpu_mpi_barrier(MPI_Comm comm)
 
 void _starpu_mpi_data_clear(starpu_data_handle_t data_handle)
 {
-#if defined(STARPU_MPI_MPI)
+#if defined(STARPU_USE_MPI_MPI)
 	_starpu_mpi_tag_data_release(data_handle);
 #endif
 	_starpu_mpi_cache_data_clear(data_handle);
@@ -233,7 +238,7 @@ void starpu_mpi_data_register_comm(starpu_data_handle_t data_handle, int tag, in
 		mpi_data->node_tag.rank = -1;
 		mpi_data->node_tag.comm = MPI_COMM_WORLD;
 		data_handle->mpi_data = mpi_data;
-#if defined(STARPU_MPI_MPI)
+#if defined(STARPU_USE_MPI_MPI)
 		_starpu_mpi_tag_data_register(data_handle, tag);
 #endif
 		_starpu_mpi_cache_data_init(data_handle);
@@ -249,7 +254,7 @@ void starpu_mpi_data_register_comm(starpu_data_handle_t data_handle, int tag, in
 		_STARPU_MPI_TRACE_DATA_SET_RANK(data_handle, rank);
 		mpi_data->node_tag.rank = rank;
 		mpi_data->node_tag.comm = comm;
-#if defined(STARPU_MPI_MPI)
+#if defined(STARPU_USE_MPI_MPI)
 		_starpu_mpi_comm_register(comm);
 #endif
 	}

+ 6 - 1
mpi/src/starpu_mpi_init.c

@@ -32,6 +32,11 @@
 #include <core/simgrid.h>
 #include <core/task.h>
 
+#if defined(STARPU_USE_MPI_MPI)
+#include <mpi/starpu_mpi_comm.h>
+#include <mpi/starpu_mpi_tag.h>
+#endif
+
 #ifdef STARPU_SIMGRID
 static int _mpi_world_size;
 static int _mpi_world_rank;
@@ -177,7 +182,7 @@ int starpu_mpi_shutdown(void)
 	_starpu_mpi_comm_amounts_display(stderr, rank);
 	_starpu_mpi_comm_amounts_shutdown();
 	_starpu_mpi_cache_shutdown(world_size);
-#if defined(STARPU_MPI_MPI)
+#if defined(STARPU_USE_MPI_MPI)
 	_starpu_mpi_tag_shutdown();
 	_starpu_mpi_comm_shutdown();
 #endif

+ 11 - 11
mpi/src/starpu_mpi_private.h

@@ -26,7 +26,7 @@
 #include <common/list.h>
 #include <common/prio_list.h>
 #include <core/simgrid.h>
-#if defined(STARPU_MPI_NMAD)
+#if defined(STARPU_USE_MPI_NMAD)
 #include <pioman.h>
 #include <nm_sendrecv_interface.h>
 #include <nm_session_interface.h>
@@ -157,7 +157,7 @@ int _starpu_debug_rank;
 #  define _STARPU_MPI_LOG_OUT()
 #endif
 
-#if defined(STARPU_MPI_MPI)
+#if defined(STARPU_USE_MPI_MPI)
 extern int _starpu_mpi_tag;
 #define _STARPU_MPI_TAG_ENVELOPE  _starpu_mpi_tag
 #define _STARPU_MPI_TAG_DATA      _starpu_mpi_tag+1
@@ -173,7 +173,7 @@ struct _starpu_mpi_envelope
 	int data_tag;
 	unsigned sync;
 };
-#endif /* STARPU_MPI_MPI */
+#endif /* STARPU_USE_MPI_MPI */
 
 enum _starpu_mpi_request_type
 {
@@ -217,7 +217,7 @@ LIST_TYPE(_starpu_mpi_req,
 
 	/* who are we talking to ? */
 	struct _starpu_mpi_node_tag node_tag;
-#if defined(STARPU_MPI_NMAD)
+#if defined(STARPU_USE_MPI_NMAD)
 	nm_gate_t gate;
 	nm_session_t session;
 #endif
@@ -225,10 +225,10 @@ LIST_TYPE(_starpu_mpi_req,
 	void (*func)(struct _starpu_mpi_req *);
 
 	MPI_Status *status;
-#if defined(STARPU_MPI_NMAD)
+#if defined(STARPU_USE_MPI_NMAD)
 	nm_sr_request_t data_request;
 	int waited;
-#elif defined(STARPU_MPI_MPI)
+#elif defined(STARPU_USE_MPI_MPI)
 	MPI_Request data_request;
 #endif
 
@@ -236,9 +236,9 @@ LIST_TYPE(_starpu_mpi_req,
 	unsigned sync;
 
 	int ret;
-#if defined(STARPU_MPI_NMAD)
+#if defined(STARPU_USE_MPI_NMAD)
 	piom_cond_t req_cond;
-#elif defined(STARPU_MPI_MPI)
+#elif defined(STARPU_USE_MPI_MPI)
 	starpu_pthread_mutex_t req_mutex;
 	starpu_pthread_cond_t req_cond;
 	starpu_pthread_mutex_t posted_mutex;
@@ -260,13 +260,13 @@ LIST_TYPE(_starpu_mpi_req,
 	void (*callback)(void *);
 
         /* in the case of user-defined datatypes, we need to send the size of the data */
-#if defined(STARPU_MPI_NMAD)
+#if defined(STARPU_USE_MPI_NMAD)
 	nm_sr_request_t size_req;
-#elif defined(STARPU_MPI_MPI)
+#elif defined(STARPU_USE_MPI_MPI)
 	MPI_Request size_req;
 #endif
 
-#if defined(STARPU_MPI_MPI)
+#if defined(STARPU_USE_MPI_MPI)
 	struct _starpu_mpi_envelope* envelope;
 
 	unsigned is_internal_req:1;

+ 6 - 3
mpi/tests/Makefile.am

@@ -101,7 +101,7 @@ AM_LDFLAGS = $(STARPU_OPENCL_LDFLAGS) $(STARPU_CUDA_LDFLAGS) $(FXT_LDFLAGS) $(ST
 
 if BUILD_TESTS
 
-starpu_mpi_TESTS =				
+starpu_mpi_TESTS =
 
 starpu_mpi_TESTS +=				\
 	cache					\
@@ -155,8 +155,12 @@ starpu_mpi_TESTS +=				\
 	tags_checking				\
 	sync					\
 	gather					\
-	gather2					\
+	gather2
+
+if STARPU_USE_MPI_MPI
+starpu_mpi_TESTS +=				\
 	load_balancer
+endif
 
 # Expected to fail
 starpu_mpi_TESTS +=				\
@@ -220,7 +224,6 @@ noinst_PROGRAMS =				\
 	starpu_redefine				\
 	load_balancer
 
-
 XFAIL_TESTS=					\
 	policy_register_toomany			\
 	policy_unregister			\

+ 1 - 1
mpi/tests/load_balancer.c

@@ -18,7 +18,7 @@
 #include <starpu_mpi_lb.h>
 #include "helper.h"
 
-#if !defined(STARPU_HAVE_UNSETENV)
+#if !defined(STARPU_HAVE_UNSETENV) || !defined(STARPU_USE_MPI_MPI)
 
 #warning unsetenv is not defined. Skipping test
 int main(int argc, char **argv)

+ 2 - 0
nmad/Makefile.am

@@ -2,6 +2,7 @@
 #
 # Copyright (C) 2009-2013, 2015  Université de Bordeaux
 # Copyright (C) 2010, 2011, 2012, 2013, 2017  CNRS
+# Copyright (C) 2016  Inria
 #
 # StarPU is free software; you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published by
@@ -22,6 +23,7 @@ pkgconfig_DATA = libstarpumpi.pc starpumpi-1.0.pc starpumpi-1.1.pc starpumpi-1.2
 versincludedir = $(includedir)/starpu/$(STARPU_EFFECTIVE_VERSION)
 versinclude_HEADERS = 					\
 	include/starpu_mpi.h				\
+	include/starpu_mpi_lb.h				\
 	include/fstarpu_mpi_mod.f90
 
 recheck:

+ 8 - 2
nmad/examples/Makefile.am

@@ -120,12 +120,18 @@ AM_LDFLAGS = $(STARPU_OPENCL_LDFLAGS) $(STARPU_CUDA_LDFLAGS) $(FXT_LDFLAGS) $(ST
 # Stencil example #
 ###################
 if BUILD_EXAMPLES
-examplebin_PROGRAMS +=				\
+examplebin_PROGRAMS +=		\
 	stencil/stencil5
-
 starpu_mpi_EXAMPLES	+=	\
 	stencil/stencil5
 
+if STARPU_USE_MPI_MPI
+examplebin_PROGRAMS +=		\
+	stencil/stencil5_lb
+starpu_mpi_EXAMPLES	+=	\
+	stencil/stencil5_lb
+endif
+
 endif
 
 ##################

+ 290 - 0
nmad/examples/stencil/stencil5_lb.c

@@ -0,0 +1,290 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2011, 2013, 2015-2017              Université Bordeaux
+ * Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#include <starpu_mpi.h>
+#include <starpu_mpi_lb.h>
+#include <math.h>
+
+#define FPRINTF(ofile, fmt, ...) do { if (!getenv("STARPU_SSILENT")) {fprintf(ofile, fmt, ## __VA_ARGS__); }} while(0)
+#define FPRINTF_MPI(ofile, fmt, ...) do { if (!getenv("STARPU_SSILENT")) { \
+    						int _disp_rank; starpu_mpi_comm_rank(MPI_COMM_WORLD, &_disp_rank);       \
+                                                fprintf(ofile, "[%d][starpu_mpi][%s] " fmt , _disp_rank, __starpu_func__ ,## __VA_ARGS__); \
+                                                fflush(ofile); }} while(0);
+
+void stencil5_cpu(void *descr[], STARPU_ATTRIBUTE_UNUSED void *_args)
+{
+	float *xy = (float *)STARPU_VARIABLE_GET_PTR(descr[0]);
+	float *xm1y = (float *)STARPU_VARIABLE_GET_PTR(descr[1]);
+	float *xp1y = (float *)STARPU_VARIABLE_GET_PTR(descr[2]);
+	float *xym1 = (float *)STARPU_VARIABLE_GET_PTR(descr[3]);
+	float *xyp1 = (float *)STARPU_VARIABLE_GET_PTR(descr[4]);
+
+//	fprintf(stdout, "VALUES: %2.2f %2.2f %2.2f %2.2f %2.2f\n", *xy, *xm1y, *xp1y, *xym1, *xyp1);
+	*xy = (*xy + *xm1y + *xp1y + *xym1 + *xyp1) / 5;
+//	fprintf(stdout, "VALUES: %2.2f %2.2f %2.2f %2.2f %2.2f\n", *xy, *xm1y, *xp1y, *xym1, *xyp1);
+}
+
+struct starpu_codelet stencil5_cl =
+{
+	.cpu_funcs = {stencil5_cpu},
+	.nbuffers = 5,
+	.modes = {STARPU_RW, STARPU_R, STARPU_R, STARPU_R, STARPU_R}
+};
+
+#ifdef STARPU_QUICK_CHECK
+#  define NITER_DEF	10
+#  define X         	2
+#  define Y         	2
+#elif !defined(STARPU_LONG_CHECK)
+#  define NITER_DEF	10
+#  define X         	5
+#  define Y         	5
+#else
+#  define NITER_DEF	100
+#  define X         	20
+#  define Y         	20
+#endif
+
+int display = 0;
+int niter = NITER_DEF;
+
+/* Returns the MPI node number where data indexes index is */
+int my_distrib(int x, int y, int nb_nodes)
+{
+	/* Block distrib */
+	return ((int)(x / sqrt(nb_nodes) + (y / sqrt(nb_nodes)) * sqrt(nb_nodes))) % nb_nodes;
+}
+
+static void parse_args(int argc, char **argv)
+{
+	int i;
+	for (i = 1; i < argc; i++)
+	{
+		if (strcmp(argv[i], "-iter") == 0)
+		{
+			char *argptr;
+			niter = strtol(argv[++i], &argptr, 10);
+		}
+		if (strcmp(argv[i], "-display") == 0)
+		{
+			display = 1;
+		}
+	}
+}
+
+void get_neighbors(int **neighbor_ids, int *nneighbors)
+{
+	int rank, size;
+	starpu_mpi_comm_rank(MPI_COMM_WORLD, &rank);
+	starpu_mpi_comm_size(MPI_COMM_WORLD, &size);
+
+	if (size <= 2)
+	{
+		*nneighbors = 1;
+		*neighbor_ids = malloc(sizeof(int));
+		*neighbor_ids[0] = rank==size-1?0:rank+1;
+		fprintf(stderr, "rank %d has neighbor %d\n", rank, *neighbor_ids[0]);
+	}
+	else
+	{
+		*nneighbors = 2;
+		*neighbor_ids = malloc(2*sizeof(int));
+		(*neighbor_ids)[0] = rank==size-1?0:rank+1;
+		(*neighbor_ids)[1] = rank==0?size-1:rank-1;
+		fprintf(stderr, "rank %d has neighbor %d and %d\n", rank, (*neighbor_ids)[0], (*neighbor_ids)[1]);
+	}
+}
+
+struct data_node
+{
+	starpu_data_handle_t data_handle;
+	int node;
+};
+
+struct data_node data_nodes[X][Y];
+
+void get_data_unit_to_migrate(starpu_data_handle_t **handle_unit, int *nhandles, int dst_node)
+{
+	int rank, x, y;
+	starpu_mpi_comm_rank(MPI_COMM_WORLD, &rank);
+	fprintf(stderr, "Looking to move data from %d to %d\n", rank, dst_node);
+	for(x = 0; x < X; x++)
+	{
+		for (y = 0; y < Y; y++)
+		{
+			if (data_nodes[x][y].node == rank)
+			{
+				*handle_unit = malloc(sizeof(starpu_data_handle_t));
+				*handle_unit[0] = data_nodes[x][y].data_handle;
+				*nhandles = 1;
+				data_nodes[x][y].node = dst_node;
+				return;
+			}
+		}
+	}
+	*nhandles = 0;
+}
+
+int main(int argc, char **argv)
+{
+	int my_rank, size, x, y, loop;
+	float mean=0;
+	float matrix[X][Y];
+	struct starpu_mpi_lb_conf itf;
+
+	itf.get_neighbors = get_neighbors;
+	itf.get_data_unit_to_migrate = get_data_unit_to_migrate;
+
+	int ret = starpu_init(NULL);
+	STARPU_CHECK_RETURN_VALUE(ret, "starpu_init");
+	ret = starpu_mpi_init(&argc, &argv, 1);
+	STARPU_CHECK_RETURN_VALUE(ret, "starpu_mpi_init");
+	starpu_mpi_comm_rank(MPI_COMM_WORLD, &my_rank);
+	starpu_mpi_comm_size(MPI_COMM_WORLD, &size);
+
+	if (size > 2)
+	{
+		FPRINTF(stderr, "Only works with 2 nodes\n");
+		starpu_mpi_shutdown();
+		starpu_shutdown();
+		return 77;
+	}
+	if (starpu_cpu_worker_get_count() == 0)
+	{
+		FPRINTF(stderr, "We need at least 1 CPU worker.\n");
+		starpu_mpi_shutdown();
+		starpu_shutdown();
+		return 77;
+	}
+
+	setenv("LB_HEAT_SLEEP_THRESHOLD", "5", 1);
+	starpu_mpi_lb_init("heat", &itf);
+
+	parse_args(argc, argv);
+
+	/* Initial data values */
+	starpu_srand48((long int)time(NULL));
+	for(x = 0; x < X; x++)
+	{
+		for (y = 0; y < Y; y++)
+		{
+			matrix[x][y] = (float)starpu_drand48();
+			mean += matrix[x][y];
+		}
+	}
+	mean /= (X*Y);
+
+	if (display)
+	{
+		FPRINTF_MPI(stdout, "mean=%2.2f\n", mean);
+		for(x = 0; x < X; x++)
+		{
+			fprintf(stdout, "[%d] ", my_rank);
+			for (y = 0; y < Y; y++)
+			{
+				fprintf(stdout, "%2.2f ", matrix[x][y]);
+			}
+			fprintf(stdout, "\n");
+		}
+	}
+
+	/* Initial distribution */
+	for(x = 0; x < X; x++)
+	{
+		for (y = 0; y < Y; y++)
+		{
+			data_nodes[x][y].node = my_distrib(x, y, size);
+			if (data_nodes[x][y].node == my_rank)
+			{
+				//FPRINTF(stderr, "[%d] Owning data[%d][%d]\n", my_rank, x, y);
+				starpu_variable_data_register(&data_nodes[x][y].data_handle, 0, (uintptr_t)&(matrix[x][y]), sizeof(float));
+			}
+			else if (my_rank == my_distrib(x+1, y, size) || my_rank == my_distrib(x-1, y, size)
+				 || my_rank == my_distrib(x, y+1, size) || my_rank == my_distrib(x, y-1, size))
+			{
+				/* I don't own that index, but will need it for my computations */
+				//FPRINTF(stderr, "[%d] Neighbour of data[%d][%d]\n", my_rank, x, y);
+				starpu_variable_data_register(&data_nodes[x][y].data_handle, -1, (uintptr_t)NULL, sizeof(float));
+			}
+			else
+			{
+				/* I know it's useless to allocate anything for this */
+				data_nodes[x][y].data_handle = NULL;
+			}
+			if (data_nodes[x][y].data_handle)
+			{
+				starpu_data_set_coordinates(data_nodes[x][y].data_handle, 2, x, y);
+				starpu_mpi_data_register(data_nodes[x][y].data_handle, (y*X)+x, data_nodes[x][y].node);
+			}
+		}
+	}
+
+	/* First computation with initial distribution */
+	for(loop=0 ; loop<niter; loop++)
+	{
+		starpu_iteration_push(loop);
+
+		for (x = 1; x < X-1; x++)
+		{
+			for (y = 1; y < Y-1; y++)
+			{
+				starpu_mpi_task_insert(MPI_COMM_WORLD, &stencil5_cl, STARPU_RW, data_nodes[x][y].data_handle,
+						       STARPU_R, data_nodes[x-1][y].data_handle, STARPU_R, data_nodes[x+1][y].data_handle,
+						       STARPU_R, data_nodes[x][y-1].data_handle, STARPU_R, data_nodes[x][y+1].data_handle,
+						       STARPU_TAG_ONLY, ((starpu_tag_t)X)*x + y,
+						       0);
+			}
+		}
+		starpu_iteration_pop();
+	}
+	FPRINTF(stderr, "Waiting ...\n");
+	starpu_task_wait_for_all();
+
+	// The load balancer needs to be shutdown before unregistering data as it needs access to them
+	starpu_mpi_lb_shutdown();
+
+	/* Unregister data */
+	for(x = 0; x < X; x++)
+	{
+		for (y = 0; y < Y; y++)
+		{
+			if (data_nodes[x][y].data_handle)
+			{
+				starpu_data_unregister(data_nodes[x][y].data_handle);
+			}
+		}
+	}
+
+	starpu_mpi_shutdown();
+	starpu_shutdown();
+
+	if (display)
+	{
+		FPRINTF(stdout, "[%d] mean=%2.2f\n", my_rank, mean);
+		for(x = 0; x < X; x++)
+		{
+			FPRINTF(stdout, "[%d] ", my_rank);
+			for (y = 0; y < Y; y++)
+			{
+				FPRINTF(stdout, "%2.2f ", matrix[x][y]);
+			}
+			FPRINTF(stdout, "\n");
+		}
+	}
+
+	return 0;
+}

+ 44 - 0
nmad/include/starpu_mpi_lb.h

@@ -0,0 +1,44 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2016  Inria
+ * Copyright (C) 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#ifndef __STARPU_MPI_LOAD_BALANCER_H__
+#define __STARPU_MPI_LOAD_BALANCER_H__
+
+#include <starpu.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+struct starpu_mpi_lb_conf
+{
+	void (*get_neighbors)(int **neighbor_ids, int *nneighbors);
+	void (*get_data_unit_to_migrate)(starpu_data_handle_t **handle_unit, int *nhandles, int dst_node);
+};
+
+/* Inits the load balancer's environment with the load policy provided by the
+ * user
+ */
+void starpu_mpi_lb_init(const char *lb_policy_name, struct starpu_mpi_lb_conf *);
+void starpu_mpi_lb_shutdown();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __STARPU_MPI_LOAD_BALANCER_H__

+ 22 - 4
nmad/src/Makefile.am

@@ -21,7 +21,7 @@ BUILT_SOURCES =
 
 CLEANFILES = *.gcno *.gcda *.linkinfo
 
-AM_CFLAGS = -Wall $(STARPU_CUDA_CPPFLAGS) $(STARPU_OPENCL_CPPFLAGS) $(FXT_CFLAGS) $(MAGMA_CFLAGS) $(HWLOC_CFLAGS) $(GLOBAL_AM_CFLAGS) $(NMAD_CFLAGS) -DSTARPU_MPI_NMAD
+AM_CFLAGS = -Wall $(STARPU_CUDA_CPPFLAGS) $(STARPU_OPENCL_CPPFLAGS) $(FXT_CFLAGS) $(MAGMA_CFLAGS) $(HWLOC_CFLAGS) $(GLOBAL_AM_CFLAGS) $(NMAD_CFLAGS)
 LIBS = $(top_builddir)/src/@LIBSTARPU_LINK@ @LIBS@ $(FXT_LIBS) $(MAGMA_LIBS) $(NMAD_LIBS)
 AM_CPPFLAGS = -I$(top_srcdir)/include/ -I$(top_srcdir)/src/ -I$(top_builddir)/src -I$(top_builddir)/include -I$(top_srcdir)/mpi/include -I$(top_srcdir)/mpi/src
 AM_LDFLAGS = $(STARPU_OPENCL_LDFLAGS) $(STARPU_CUDA_LDFLAGS) $(STARPU_COI_LDFLAGS) $(STARPU_SCIF_LDFLAGS) $(NMAD_LDFLAGS)
@@ -65,10 +65,17 @@ noinst_HEADERS =					\
 	starpu_mpi_select_node.h			\
 	starpu_mpi_cache_stats.h			\
 	starpu_mpi_task_insert.h			\
-	starpu_mpi_init.h
+	starpu_mpi_init.h				\
+	mpi/starpu_mpi_early_data.h			\
+	mpi/starpu_mpi_early_request.h			\
+	mpi/starpu_mpi_sync_data.h			\
+	mpi/starpu_mpi_comm.h				\
+	mpi/starpu_mpi_tag.h				\
+	load_balancer/policy/data_movements_interface.h	\
+	load_balancer/policy/load_data_interface.h	\
+	load_balancer/policy/load_balancer_policy.h
 
 libstarpumpi_@STARPU_EFFECTIVE_VERSION@_la_SOURCES =	\
-	nmad/starpu_mpi_nmad.c				\
 	starpu_mpi.c					\
 	starpu_mpi_helper.c				\
 	starpu_mpi_datatype.c				\
@@ -81,7 +88,18 @@ libstarpumpi_@STARPU_EFFECTIVE_VERSION@_la_SOURCES =	\
 	starpu_mpi_cache_stats.c			\
 	starpu_mpi_fortran.c				\
 	starpu_mpi_task_insert_fortran.c		\
-	starpu_mpi_init.c
+	starpu_mpi_init.c				\
+	nmad/starpu_mpi_nmad.c				\
+	mpi/starpu_mpi_mpi.c				\
+	mpi/starpu_mpi_early_data.c			\
+	mpi/starpu_mpi_early_request.c			\
+	mpi/starpu_mpi_sync_data.c			\
+	mpi/starpu_mpi_comm.c				\
+	mpi/starpu_mpi_tag.c				\
+	load_balancer/policy/data_movements_interface.c	\
+	load_balancer/policy/load_data_interface.c	\
+	load_balancer/policy/load_heat_propagation.c	\
+	load_balancer/load_balancer.c
 
 showcheck:
 	-cat /dev/null

+ 161 - 0
nmad/src/load_balancer/load_balancer.c

@@ -0,0 +1,161 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2016  Inria
+ * Copyright (C) 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <starpu.h>
+#include <starpu_mpi.h>
+#include <starpu_scheduler.h>
+#include <common/utils.h>
+#include <common/config.h>
+
+#include <starpu_mpi_lb.h>
+#include "policy/load_balancer_policy.h"
+
+#if defined(STARPU_USE_MPI_MPI)
+
+static struct load_balancer_policy *defined_policy = NULL;
+typedef void (*_post_exec_hook_func_t)(struct starpu_task *task, unsigned sched_ctx_id);
+static _post_exec_hook_func_t saved_post_exec_hook[STARPU_NMAX_SCHED_CTXS];
+
+static void post_exec_hook_wrapper(struct starpu_task *task, unsigned sched_ctx_id)
+{
+	//fprintf(stderr,"I am called ! \n");
+	if (defined_policy && defined_policy->finished_task_entry_point)
+		defined_policy->finished_task_entry_point();
+	if (saved_post_exec_hook[sched_ctx_id])
+		saved_post_exec_hook[sched_ctx_id](task, sched_ctx_id);
+}
+
+static struct load_balancer_policy *predefined_policies[] =
+{
+	&load_heat_propagation_policy,
+	NULL
+};
+
+void starpu_mpi_lb_init(const char *lb_policy_name, struct starpu_mpi_lb_conf *itf)
+{
+	int ret;
+
+	const char *policy_name = starpu_getenv("STARPU_MPI_LB");
+	if (!policy_name)
+		policy_name = lb_policy_name;
+
+	if (!policy_name || (strcmp(policy_name, "help") == 0))
+	{
+		_STARPU_MSG("Warning : load balancing is disabled for this run.\n");
+		_STARPU_MSG("Use the STARPU_MPI_LB = <name> environment variable to use a load balancer.\n");
+		_STARPU_MSG("Available load balancers :\n");
+		struct load_balancer_policy **policy;
+		for(policy=predefined_policies ; *policy!=NULL ; policy++)
+		{
+			struct load_balancer_policy *p = *policy;
+			fprintf(stderr," - %s\n", p->policy_name);
+		}
+		return;
+	}
+
+	if (policy_name)
+	{
+		struct load_balancer_policy **policy;
+		for(policy=predefined_policies ; *policy!=NULL ; policy++)
+		{
+			struct load_balancer_policy *p = *policy;
+			if (p->policy_name)
+			{
+				if (strcmp(policy_name, p->policy_name) == 0)
+				{
+					/* we found a policy with the requested name */
+					defined_policy = p;
+					break;
+				}
+			}
+		}
+	}
+
+	if (!defined_policy)
+	{
+		_STARPU_MSG("Error : no load balancer with the name %s. Load balancing will be disabled for this run.\n", policy_name);
+		return;
+	}
+
+	ret = defined_policy->init(itf);
+	if (ret != 0)
+	{
+		_STARPU_MSG("Error (%d) in %s->init: invalid starpu_mpi_lb_conf. Load balancing will be disabled for this run.\n", ret, defined_policy->policy_name);
+		return;
+	}
+
+	/* starpu_register_hook(submitted_task, defined_policy->submitted_task_entry_point); */
+	if (defined_policy->submitted_task_entry_point)
+		starpu_mpi_pre_submit_hook_register(defined_policy->submitted_task_entry_point);
+
+	/* starpu_register_hook(finished_task, defined_policy->finished_task_entry_point); */
+	if (defined_policy->finished_task_entry_point)
+	{
+		int i;
+		for(i = 0; i < STARPU_NMAX_SCHED_CTXS; i++)
+		{
+			struct starpu_sched_policy *sched_policy = starpu_sched_ctx_get_sched_policy(i);
+			if (sched_policy)
+			{
+				_STARPU_DEBUG("Setting post_exec_hook for scheduling context %d %s (%d)\n", i, sched_policy->policy_name, STARPU_NMAX_SCHED_CTXS);
+				saved_post_exec_hook[i] = sched_policy->post_exec_hook;
+				sched_policy->post_exec_hook = post_exec_hook_wrapper;
+			}
+			else
+				saved_post_exec_hook[i] = NULL;
+		}
+	}
+
+	return;
+}
+
+void starpu_mpi_lb_shutdown()
+{
+	if (!defined_policy)
+		return;
+
+	int ret = defined_policy->deinit();
+	if (ret != 0)
+	{
+		_STARPU_MSG("Error (%d) in %s->deinit\n", ret, defined_policy->policy_name);
+		return;
+	}
+
+	/* starpu_unregister_hook(submitted_task, defined_policy->submitted_task_entry_point); */
+	if (defined_policy->submitted_task_entry_point)
+		starpu_mpi_pre_submit_hook_unregister();
+
+	/* starpu_unregister_hook(finished_task, defined_policy->finished_task_entry_point); */
+	if (defined_policy->finished_task_entry_point)
+	{
+		int i;
+		for(i = 0; i < STARPU_NMAX_SCHED_CTXS; i++)
+		{
+			if (saved_post_exec_hook[i])
+			{
+				struct starpu_sched_policy *sched_policy = starpu_sched_ctx_get_sched_policy(i);
+				sched_policy->post_exec_hook = saved_post_exec_hook[i];
+				saved_post_exec_hook[i] = NULL;
+			}
+		}
+	}
+	defined_policy = NULL;
+}
+
+#endif /* STARPU_USE_MPI_MPI */

+ 286 - 0
nmad/src/load_balancer/policy/data_movements_interface.c

@@ -0,0 +1,286 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2016  Inria
+ * Copyright (C) 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#include <starpu.h>
+#include <stdlib.h>
+#include <starpu_mpi_private.h>
+#include <common/config.h>
+
+#include "data_movements_interface.h"
+
+#if defined(STARPU_USE_MPI_MPI)
+
+int **data_movements_get_ref_tags_table(starpu_data_handle_t handle)
+{
+	struct data_movements_interface *dm_interface =
+		(struct data_movements_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	if (dm_interface->tags)
+		return &dm_interface->tags;
+	else
+		return NULL;
+}
+
+int **data_movements_get_ref_ranks_table(starpu_data_handle_t handle)
+{
+	struct data_movements_interface *dm_interface =
+		(struct data_movements_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	if (dm_interface->ranks)
+		return &dm_interface->ranks;
+	else
+		return NULL;
+}
+
+int *data_movements_get_tags_table(starpu_data_handle_t handle)
+{
+	struct data_movements_interface *dm_interface =
+		(struct data_movements_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	return dm_interface->tags;
+}
+
+int *data_movements_get_ranks_table(starpu_data_handle_t handle)
+{
+	struct data_movements_interface *dm_interface =
+		(struct data_movements_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	return dm_interface->ranks;
+}
+
+int data_movements_get_size_tables(starpu_data_handle_t handle)
+{
+	struct data_movements_interface *dm_interface =
+		(struct data_movements_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	return dm_interface->size;
+}
+
+int data_movements_reallocate_tables(starpu_data_handle_t handle, int size)
+{
+	struct data_movements_interface *dm_interface =
+		(struct data_movements_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	if (dm_interface->size)
+	{
+		STARPU_ASSERT(dm_interface->tags);
+		free(dm_interface->tags);
+		dm_interface->tags = NULL;
+
+		STARPU_ASSERT(dm_interface->ranks);
+		free(dm_interface->ranks);
+		dm_interface->ranks = NULL;
+	}
+	else
+	{
+		STARPU_ASSERT(!dm_interface->tags);
+		STARPU_ASSERT(!dm_interface->ranks);
+	}
+
+	dm_interface->size = size;
+
+	if (dm_interface->size)
+	{
+		_STARPU_MPI_MALLOC(dm_interface->tags, size*sizeof(int));
+		_STARPU_MPI_MALLOC(dm_interface->ranks, size*sizeof(int));
+	}
+
+	return 0 ;
+}
+
+static void data_movements_register_data_handle(starpu_data_handle_t handle, unsigned home_node, void *data_interface)
+{
+	struct data_movements_interface *dm_interface = (struct data_movements_interface *) data_interface;
+
+	unsigned node;
+	for (node = 0; node < STARPU_MAXNODES; node++)
+	{
+		struct data_movements_interface *local_interface = (struct data_movements_interface *)
+			starpu_data_get_interface_on_node(handle, node);
+
+		local_interface->size = dm_interface->size;
+		if (node == home_node)
+		{
+			local_interface->tags = dm_interface->tags;
+			local_interface->ranks = dm_interface->ranks;
+		}
+		else
+		{
+			local_interface->tags = NULL;
+			local_interface->ranks = NULL;
+		}
+	}
+}
+
+static starpu_ssize_t data_movements_allocate_data_on_node(void *data_interface, unsigned node)
+{
+	struct data_movements_interface *dm_interface = (struct data_movements_interface *) data_interface;
+
+	int *addr_tags = NULL;
+	int *addr_ranks = NULL;
+	starpu_ssize_t requested_memory = dm_interface->size * sizeof(int);
+
+	addr_tags = (int*) starpu_malloc_on_node(node, requested_memory);
+	if (!addr_tags)
+		goto fail_tags;
+	addr_ranks = (int*) starpu_malloc_on_node(node, requested_memory);
+	if (!addr_ranks)
+		goto fail_ranks;
+
+	/* update the data properly in consequence */
+	dm_interface->tags = addr_tags;
+	dm_interface->ranks = addr_ranks;
+
+	return 2*requested_memory;
+
+fail_ranks:
+	starpu_free_on_node(node, (uintptr_t) addr_tags, requested_memory);
+fail_tags:
+	return -ENOMEM;
+}
+
+static void data_movements_free_data_on_node(void *data_interface, unsigned node)
+{
+	struct data_movements_interface *dm_interface = (struct data_movements_interface *) data_interface;
+	starpu_ssize_t requested_memory = dm_interface->size * sizeof(int);
+
+	starpu_free_on_node(node, (uintptr_t) dm_interface->tags, requested_memory);
+	starpu_free_on_node(node, (uintptr_t) dm_interface->ranks, requested_memory);
+}
+
+static size_t data_movements_get_size(starpu_data_handle_t handle)
+{
+	size_t size;
+	struct data_movements_interface *dm_interface = (struct data_movements_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	size = (dm_interface->size * 2 * sizeof(int)) + sizeof(int);
+	return size;
+}
+
+static uint32_t data_movements_footprint(starpu_data_handle_t handle)
+{
+	return starpu_hash_crc32c_be(data_movements_get_size(handle), 0);
+}
+
+static int data_movements_pack_data(starpu_data_handle_t handle, unsigned node, void **ptr, starpu_ssize_t *count)
+{
+	STARPU_ASSERT(starpu_data_test_if_allocated_on_node(handle, node));
+
+	struct data_movements_interface *dm_interface = (struct data_movements_interface *)
+		starpu_data_get_interface_on_node(handle, node);
+
+	*count = data_movements_get_size(handle);
+	if (ptr != NULL)
+	{
+		char *data;
+		starpu_malloc_flags((void**) &data, *count, 0);
+		assert(data);
+		*ptr = data;
+		memcpy(data, &dm_interface->size, sizeof(int));
+		if (dm_interface->size)
+		{
+			memcpy(data+sizeof(int), dm_interface->tags, (dm_interface->size*sizeof(int)));
+			memcpy(data+sizeof(int)+(dm_interface->size*sizeof(int)), dm_interface->ranks, dm_interface->size*sizeof(int));
+		}
+	}
+
+	return 0;
+}
+
+static int data_movements_unpack_data(starpu_data_handle_t handle, unsigned node, void *ptr, size_t count)
+{
+	char *data = ptr;
+	STARPU_ASSERT(starpu_data_test_if_allocated_on_node(handle, node));
+
+	struct data_movements_interface *dm_interface = (struct data_movements_interface *)
+		starpu_data_get_interface_on_node(handle, node);
+
+	int size = 0;
+	memcpy(&size, data, sizeof(int));
+	STARPU_ASSERT(count == (2 * size * sizeof(int)) + sizeof(int));
+
+	data_movements_reallocate_tables(handle, size);
+
+	if (dm_interface->size)
+	{
+		memcpy(dm_interface->tags, data+sizeof(int), dm_interface->size*sizeof(int));
+		memcpy(dm_interface->ranks, data+sizeof(int)+(dm_interface->size*sizeof(int)), dm_interface->size*sizeof(int));
+	}
+
+    return 0;
+}
+
+static int copy_any_to_any(void *src_interface, unsigned src_node,
+			   void *dst_interface, unsigned dst_node,
+			   void *async_data)
+{
+	struct data_movements_interface *src_data_movements = src_interface;
+	struct data_movements_interface *dst_data_movements = dst_interface;
+	int ret = 0;
+
+	if (starpu_interface_copy((uintptr_t) src_data_movements->tags, 0, src_node,
+				    (uintptr_t) dst_data_movements->tags, 0, dst_node,
+				     src_data_movements->size*sizeof(int),
+				     async_data))
+		ret = -EAGAIN;
+	if (starpu_interface_copy((uintptr_t) src_data_movements->ranks, 0, src_node,
+				    (uintptr_t) dst_data_movements->ranks, 0, dst_node,
+				     src_data_movements->size*sizeof(int),
+				     async_data))
+		ret = -EAGAIN;
+	return ret;
+}
+
+static const struct starpu_data_copy_methods data_movements_copy_methods =
+{
+	.any_to_any = copy_any_to_any
+};
+
+static struct starpu_data_interface_ops interface_data_movements_ops =
+{
+	.register_data_handle = data_movements_register_data_handle,
+	.allocate_data_on_node = data_movements_allocate_data_on_node,
+	.free_data_on_node = data_movements_free_data_on_node,
+	.copy_methods = &data_movements_copy_methods,
+	.get_size = data_movements_get_size,
+	.footprint = data_movements_footprint,
+	.interfaceid = STARPU_UNKNOWN_INTERFACE_ID,
+	.interface_size = sizeof(struct data_movements_interface),
+	.handle_to_pointer = NULL,
+	.pack_data = data_movements_pack_data,
+	.unpack_data = data_movements_unpack_data,
+	.describe = NULL
+};
+
+void data_movements_data_register(starpu_data_handle_t *handleptr, unsigned home_node, int *tags, int *ranks, int size)
+{
+	struct data_movements_interface data_movements =
+	{
+		.tags = tags,
+		.ranks = ranks,
+		.size = size
+	};
+
+	if (interface_data_movements_ops.interfaceid == STARPU_UNKNOWN_INTERFACE_ID)
+	{
+		interface_data_movements_ops.interfaceid = starpu_data_interface_get_next_id();
+	}
+
+	starpu_data_register(handleptr, home_node, &data_movements, &interface_data_movements_ops);
+}
+
+#endif

+ 48 - 0
nmad/src/load_balancer/policy/data_movements_interface.h

@@ -0,0 +1,48 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2016  Inria
+ * Copyright (C) 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#include <starpu.h>
+
+#ifndef __DATA_MOVEMENTS_INTERFACE_H
+#define __DATA_MOVEMENTS_INTERFACE_H
+
+/* interface for data_movements */
+struct data_movements_interface
+{
+	/* Data tags table */
+	int *tags;
+	/* Ranks table (where to move the corresponding data) */
+	int *ranks;
+	/* Size of the tables */
+	int size;
+};
+
+void data_movements_data_register(starpu_data_handle_t *handle, unsigned home_node, int *ranks, int *tags, int size);
+
+int **data_movements_get_ref_tags_table(starpu_data_handle_t handle);
+int **data_movements_get_ref_ranks_table(starpu_data_handle_t handle);
+int data_movements_reallocate_tables(starpu_data_handle_t handle, int size);
+
+int *data_movements_get_tags_table(starpu_data_handle_t handle);
+int *data_movements_get_ranks_table(starpu_data_handle_t handle);
+int data_movements_get_size_tables(starpu_data_handle_t handle);
+
+#define DATA_MOVEMENTS_GET_SIZE_TABLES(interface)	(((struct data_movements_interface *)(interface))->size)
+#define DATA_MOVEMENTS_GET_TAGS_TABLE(interface)	(((struct data_movements_interface *)(interface))->tags)
+#define DATA_MOVEMENTS_GET_RANKS_TABLE(interface)	(((struct data_movements_interface *)(interface))->ranks)
+
+#endif /* __DATA_MOVEMENTS_INTERFACE_H */

+ 53 - 0
nmad/src/load_balancer/policy/load_balancer_policy.h

@@ -0,0 +1,53 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2016  Inria
+ * Copyright (C) 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#ifndef __LOAD_BALANCER_POLICY_H__
+#define __LOAD_BALANCER_POLICY_H__
+
+#include <starpu_mpi_lb.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* A load balancer consists in a collection of operations on a data
+ * representing the load of the application (in terms of computation, memory,
+ * whatever). StarPU allows several entry points for the user. The load
+ * balancer allows the user to give its load balancing methods to be used on
+ * these entry points of the runtime system. */
+struct load_balancer_policy
+{
+	int (*init)(struct starpu_mpi_lb_conf *);
+	int (*deinit)();
+	void (*submitted_task_entry_point)();
+	void (*finished_task_entry_point)();
+
+	/* Name of the load balancing policy. The selection of the load balancer is
+	 * performed through the use of the STARPU_MPI_LB=name environment
+	 * variable.
+	 */
+	const char *policy_name;
+};
+
+extern struct load_balancer_policy load_heat_propagation_policy;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LOAD_BALANCER_POLICY_H__

+ 274 - 0
nmad/src/load_balancer/policy/load_data_interface.c

@@ -0,0 +1,274 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2016  Inria
+ * Copyright (C) 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#include <starpu.h>
+#include <stdlib.h>
+#include <common/config.h>
+
+#include "load_data_interface.h"
+
+#if defined(STARPU_USE_MPI_MPI)
+
+int load_data_get_sleep_threshold(starpu_data_handle_t handle)
+{
+	struct load_data_interface *ld_interface =
+		(struct load_data_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	return ld_interface->sleep_task_threshold;
+}
+
+int load_data_get_wakeup_threshold(starpu_data_handle_t handle)
+{
+	struct load_data_interface *ld_interface =
+		(struct load_data_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	return ld_interface->wakeup_task_threshold;
+}
+
+int load_data_get_current_phase(starpu_data_handle_t handle)
+{
+	struct load_data_interface *ld_interface =
+		(struct load_data_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	return ld_interface->phase;
+}
+
+int load_data_get_nsubmitted_tasks(starpu_data_handle_t handle)
+{
+	struct load_data_interface *ld_interface =
+		(struct load_data_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	return ld_interface->nsubmitted_tasks;
+}
+
+int load_data_get_nfinished_tasks(starpu_data_handle_t handle)
+{
+	struct load_data_interface *ld_interface =
+		(struct load_data_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	return ld_interface->nfinished_tasks;
+}
+
+int load_data_inc_nsubmitted_tasks(starpu_data_handle_t handle)
+{
+	struct load_data_interface *ld_interface =
+		(struct load_data_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	(ld_interface->nsubmitted_tasks)++;
+
+	return 0;
+}
+
+int load_data_inc_nfinished_tasks(starpu_data_handle_t handle)
+{
+	struct load_data_interface *ld_interface =
+		(struct load_data_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	(ld_interface->nfinished_tasks)++;
+
+	return 0;
+}
+
+int load_data_next_phase(starpu_data_handle_t handle)
+{
+	struct load_data_interface *ld_interface =
+		(struct load_data_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	ld_interface->phase++;
+
+	return 0;
+}
+
+int load_data_update_elapsed_time(starpu_data_handle_t handle)
+{
+	struct load_data_interface *ld_interface =
+		(struct load_data_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	ld_interface->elapsed_time = starpu_timing_now() - ld_interface->start;
+
+	return 0;
+}
+
+double load_data_get_elapsed_time(starpu_data_handle_t handle)
+{
+	struct load_data_interface *ld_interface =
+		(struct load_data_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	return ld_interface->elapsed_time;
+}
+
+int load_data_update_wakeup_cond(starpu_data_handle_t handle)
+{
+	struct load_data_interface *ld_interface =
+		(struct load_data_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	int previous_threshold = ld_interface->wakeup_task_threshold;
+	ld_interface->wakeup_task_threshold += (ld_interface->nsubmitted_tasks - previous_threshold) * ld_interface->wakeup_ratio;
+
+	return 0;
+}
+
+int load_data_wakeup_cond(starpu_data_handle_t handle)
+{
+	struct load_data_interface *ld_interface =
+		(struct load_data_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+
+	return (ld_interface->wakeup_task_threshold > 0) && (ld_interface->nfinished_tasks == ld_interface->wakeup_task_threshold);
+}
+
+static void load_data_register_data_handle(starpu_data_handle_t handle, unsigned home_node, void *data_interface)
+{
+	(void) home_node;
+	struct load_data_interface *ld_interface = (struct load_data_interface *) data_interface;
+
+	unsigned node;
+	for (node = 0; node < STARPU_MAXNODES; node++)
+	{
+		struct load_data_interface *local_interface = (struct load_data_interface *)
+			starpu_data_get_interface_on_node(handle, node);
+
+		local_interface->start = ld_interface->start;
+		local_interface->elapsed_time = ld_interface->elapsed_time;
+		local_interface->phase = ld_interface->phase;
+		local_interface->nsubmitted_tasks = ld_interface->nsubmitted_tasks;
+		local_interface->nfinished_tasks = ld_interface->nsubmitted_tasks;
+		local_interface->wakeup_task_threshold = ld_interface->wakeup_task_threshold;
+		local_interface->wakeup_ratio = ld_interface->wakeup_ratio;
+		local_interface->sleep_task_threshold = ld_interface->sleep_task_threshold;
+	}
+}
+
+static starpu_ssize_t load_data_allocate_data_on_node(void *data_interface, unsigned node)
+{
+	(void) data_interface;
+	(void) node;
+
+	return 0;
+}
+
+static void load_data_free_data_on_node(void *data_interface, unsigned node)
+{
+	(void) data_interface;
+	(void) node;
+}
+
+static size_t load_data_get_size(starpu_data_handle_t handle)
+{
+	(void) handle;
+	return sizeof(struct load_data_interface);
+}
+
+static uint32_t load_data_footprint(starpu_data_handle_t handle)
+{
+	struct load_data_interface *ld_interface =
+		(struct load_data_interface *) starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);
+	return starpu_hash_crc32c_be(ld_interface->start,
+				     starpu_hash_crc32c_be(ld_interface->elapsed_time,
+							   starpu_hash_crc32c_be(ld_interface->nsubmitted_tasks,
+										 starpu_hash_crc32c_be(ld_interface->sleep_task_threshold, ld_interface->wakeup_task_threshold))));
+}
+
+static int load_data_pack_data(starpu_data_handle_t handle, unsigned node, void **ptr, starpu_ssize_t *count)
+{
+	STARPU_ASSERT(starpu_data_test_if_allocated_on_node(handle, node));
+
+	struct load_data_interface *ld_interface = (struct load_data_interface *)
+		starpu_data_get_interface_on_node(handle, node);
+
+	*count = load_data_get_size(handle);
+	if (ptr != NULL)
+	{
+		char *data;
+		starpu_malloc_flags((void**) &data, *count, 0);
+		*ptr = data;
+		memcpy(data, ld_interface, *count);
+	}
+
+	return 0;
+}
+
+static int load_data_unpack_data(starpu_data_handle_t handle, unsigned node, void *ptr, size_t count)
+{
+	char *data = ptr;
+	STARPU_ASSERT(starpu_data_test_if_allocated_on_node(handle, node));
+
+	struct load_data_interface *ld_interface = (struct load_data_interface *)
+		starpu_data_get_interface_on_node(handle, node);
+
+	STARPU_ASSERT(count == sizeof(struct load_data_interface));
+	memcpy(ld_interface, data, count);
+
+	return 0;
+}
+
+static int copy_any_to_any(void *src_interface, unsigned src_node,
+			   void *dst_interface, unsigned dst_node,
+			   void *async_data)
+{
+	(void) src_interface;
+	(void) dst_interface;
+	(void) src_node;
+	(void) dst_node;
+	(void) async_data;
+
+	return 0;
+}
+
+static const struct starpu_data_copy_methods load_data_copy_methods =
+{
+	.any_to_any = copy_any_to_any
+};
+
+static struct starpu_data_interface_ops interface_load_data_ops =
+{
+	.register_data_handle = load_data_register_data_handle,
+	.allocate_data_on_node = load_data_allocate_data_on_node,
+	.free_data_on_node = load_data_free_data_on_node,
+	.copy_methods = &load_data_copy_methods,
+	.get_size = load_data_get_size,
+	.footprint = load_data_footprint,
+	.interfaceid = STARPU_UNKNOWN_INTERFACE_ID,
+	.interface_size = sizeof(struct load_data_interface),
+	.handle_to_pointer = NULL,
+	.pack_data = load_data_pack_data,
+	.unpack_data = load_data_unpack_data,
+	.describe = NULL
+};
+
+void load_data_data_register(starpu_data_handle_t *handleptr, unsigned home_node, int sleep_task_threshold, double wakeup_ratio)
+{
+	struct load_data_interface load_data =
+	{
+		.start = starpu_timing_now(),
+		.elapsed_time = 0,
+		.phase = 0,
+		.nsubmitted_tasks = 0,
+		.nfinished_tasks = 0,
+		.sleep_task_threshold = sleep_task_threshold,
+		.wakeup_task_threshold = 0,
+		.wakeup_ratio = wakeup_ratio
+	};
+
+	if (interface_load_data_ops.interfaceid == STARPU_UNKNOWN_INTERFACE_ID)
+	{
+		interface_load_data_ops.interfaceid = starpu_data_interface_get_next_id();
+	}
+
+	starpu_data_register(handleptr, home_node, &load_data, &interface_load_data_ops);
+}
+
+#endif

+ 70 - 0
nmad/src/load_balancer/policy/load_data_interface.h

@@ -0,0 +1,70 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2016  Inria
+ * Copyright (C) 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#include <starpu.h>
+
+#ifndef __LOAD_DATA_INTERFACE_H
+#define __LOAD_DATA_INTERFACE_H
+
+/* interface for load_data */
+struct load_data_interface
+{
+	/* Starting time of the execution */
+	double start;
+	/* Elapsed time until the start time and the time when event "launch a load
+	 * balancing phase" is triggered */
+	double elapsed_time;
+	/* Current submission phase, i.e how many balanced steps have already
+	 * happened so far. */
+	int phase;
+	/* Number of currently submitted tasks */
+	int nsubmitted_tasks;
+	/* Number of currently finished tasks */
+	int nfinished_tasks;
+	/* Task threshold to sleep the submission thread */
+	int sleep_task_threshold;
+	/* Task threshold to wake-up the submission thread */
+	int wakeup_task_threshold;
+	/* Ratio of submitted tasks to wait for completion before waking up the
+	 * submission thread */
+	double wakeup_ratio;
+};
+
+void load_data_data_register(starpu_data_handle_t *handle, unsigned home_node, int sleep_task_threshold, double wakeup_ratio);
+
+int load_data_get_sleep_threshold(starpu_data_handle_t handle);
+int load_data_get_wakeup_threshold(starpu_data_handle_t handle);
+int load_data_get_current_phase(starpu_data_handle_t handle);
+int load_data_get_nsubmitted_tasks(starpu_data_handle_t handle);
+int load_data_get_nfinished_tasks(starpu_data_handle_t handle);
+
+int load_data_inc_nsubmitted_tasks(starpu_data_handle_t handle);
+int load_data_inc_nfinished_tasks(starpu_data_handle_t handle);
+
+int load_data_next_phase(starpu_data_handle_t handle);
+
+int load_data_update_elapsed_time(starpu_data_handle_t handle);
+double load_data_get_elapsed_time(starpu_data_handle_t handle);
+
+int load_data_update_wakeup_cond(starpu_data_handle_t handle);
+int load_data_wakeup_cond(starpu_data_handle_t handle);
+
+#define LOAD_DATA_GET_NSUBMITTED_TASKS(interface)	(((struct load_data_interface *)(interface))->nsubmitted_tasks)
+#define LOAD_DATA_GET_SLEEP_THRESHOLD(interface)	(((struct load_data_interface *)(interface))->sleep_task_threshold)
+#define LOAD_DATA_GET_WAKEUP_THRESHOLD(interface)	(((struct load_data_interface *)(interface))->wakeup_task_threshold)
+
+#endif /* __LOAD_DATA_INTERFACE_H */

+ 643 - 0
nmad/src/load_balancer/policy/load_heat_propagation.c

@@ -0,0 +1,643 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2016  Inria
+ * Copyright (C) 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#include <starpu_mpi.h>
+#include <mpi/starpu_mpi_tag.h>
+#include <common/uthash.h>
+#include <common/utils.h>
+#include <math.h>
+#include <starpu_mpi_private.h>
+#include "load_balancer_policy.h"
+#include "data_movements_interface.h"
+#include "load_data_interface.h"
+#include <common/config.h>
+
+#if defined(STARPU_USE_MPI_MPI)
+
+static int TAG_LOAD(int n)
+{
+	return (n+1) << 24;
+}
+
+static int TAG_MOV(int n)
+{
+	return (n+1) << 20;
+}
+
+/* Hash table of local pieces of data that has been moved out of the local MPI
+ * node by the load balancer. All of these pieces of data must be migrated back
+ * to the local node at the end of the execution. */
+struct moved_data_entry
+{
+	UT_hash_handle hh;
+	starpu_data_handle_t handle;
+};
+
+static struct moved_data_entry *mdh = NULL;
+
+static starpu_pthread_mutex_t load_data_mutex;
+static starpu_pthread_cond_t load_data_cond;
+
+/* MPI infos */
+static int my_rank;
+static int world_size;
+
+/* Number of neighbours of the local MPI node and their IDs. These are given by
+ * the get_neighbors() method, and thus can be easily changed. */
+static int *neighbor_ids = NULL;
+static int nneighbors = 0;
+
+/* Local load data */
+static starpu_data_handle_t *load_data_handle = NULL;
+static starpu_data_handle_t *load_data_handle_cpy = NULL;
+/* Load data of neighbours */
+static starpu_data_handle_t *neighbor_load_data_handles = NULL;
+
+/* Table which contains a data_movements_handle for each MPI node of
+ * MPI_COMM_WORLD. Since all the MPI nodes must be advised of any data
+ * movement, this table will be used to perform communications of data
+ * movements handles following an all-to-all model. */
+static starpu_data_handle_t *data_movements_handles = NULL;
+
+/* Load balancer interface which contains the application-specific methods for
+ * the load balancer to use. */
+static struct starpu_mpi_lb_conf *user_itf = NULL;
+
+static double time_threshold = 20000;
+
+/******************************************************************************
+ *                              Balancing                                     *
+ *****************************************************************************/
+
+
+/* Decides which data has to move where, and fills the
+ * data_movements_handles[my_rank] data handle from that.
+ * In data :
+ *  - local load_data_handle
+ *  - nneighbors
+ *  - neighbor_ids[nneighbors]
+ *  - neighbor_load_data_handles[nneighbors]
+ * Out data :
+ *  - data_movements_handles[my_rank]
+ */
+
+static void balance(starpu_data_handle_t load_data_cpy)
+{
+	int less_loaded = -1;
+	int n;
+	double ref_elapsed_time;
+	double my_elapsed_time = load_data_get_elapsed_time(load_data_cpy);
+
+	/* Search for the less loaded neighbor */
+	ref_elapsed_time = my_elapsed_time;
+	for (n = 0; n < nneighbors; n++)
+	{
+		double elapsed_time = load_data_get_elapsed_time(neighbor_load_data_handles[n]);
+		if (ref_elapsed_time > elapsed_time)
+		{
+			//fprintf(stderr,"Node%d: ref local time %lf vs neighbour%d time %lf\n", my_rank, ref_elapsed_time, neighbor_ids[n], elapsed_time);
+			less_loaded = neighbor_ids[n];
+			ref_elapsed_time = elapsed_time;
+		}
+	}
+
+	/* We found it */
+	if (less_loaded >= 0)
+	{
+		_STARPU_DEBUG("Less loaded found on node %d : %d\n", my_rank, less_loaded);
+		double diff_time = my_elapsed_time - ref_elapsed_time;
+		/* If the difference is higher than a time threshold, we move
+		 * one data to the less loaded neighbour. */
+		/* TODO: How to decide the time threshold ? */
+		if ((time_threshold > 0) && (diff_time >= time_threshold))
+		{
+			starpu_data_handle_t *handles = NULL;
+			int nhandles = 0;
+			user_itf->get_data_unit_to_migrate(&handles, &nhandles, less_loaded);
+
+			data_movements_reallocate_tables(data_movements_handles[my_rank], nhandles);
+
+			if (nhandles)
+			{
+				int *tags = data_movements_get_tags_table(data_movements_handles[my_rank]);
+				int *ranks = data_movements_get_ranks_table(data_movements_handles[my_rank]);
+
+				for (n = 0; n < nhandles; n++)
+				{
+					tags[n] = starpu_mpi_data_get_tag(handles[n]);
+					ranks[n] = less_loaded;
+				}
+
+				free(handles);
+			}
+		}
+		else
+			data_movements_reallocate_tables(data_movements_handles[my_rank], 0);
+	}
+	else
+		data_movements_reallocate_tables(data_movements_handles[my_rank], 0);
+}
+
+static void exchange_load_data_infos(starpu_data_handle_t load_data_cpy)
+{
+	int i;
+
+	/* Allocate all requests and status for point-to-point communications */
+	starpu_mpi_req load_send_req[nneighbors];
+	starpu_mpi_req load_recv_req[nneighbors];
+
+	MPI_Status load_send_status[nneighbors];
+	MPI_Status load_recv_status[nneighbors];
+
+	int flag;
+
+	/* Send the local load data to neighbour nodes, and receive the remote load
+	 * data from neighbour nodes */
+	for (i = 0; i < nneighbors; i++)
+	{
+		//_STARPU_DEBUG("[node %d] sending and receiving with %i-th neighbor %i\n", my_rank, i, neighbor_ids[i]);
+		starpu_mpi_isend(load_data_cpy, &load_send_req[i], neighbor_ids[i], TAG_LOAD(my_rank), MPI_COMM_WORLD);
+		starpu_mpi_irecv(neighbor_load_data_handles[i], &load_recv_req[i], neighbor_ids[i], TAG_LOAD(neighbor_ids[i]), MPI_COMM_WORLD);
+	}
+
+	/* Wait for completion of all send requests */
+	for (i = 0; i < nneighbors; i++)
+	{
+		flag = 0;
+		while (!flag)
+			starpu_mpi_test(&load_send_req[i], &flag, &load_send_status[i]);
+	}
+
+	/* Wait for completion of all receive requests */
+	for (i = 0; i < nneighbors; i++)
+	{
+		flag = 0;
+		while (!flag)
+			starpu_mpi_test(&load_recv_req[i], &flag, &load_recv_status[i]);
+	}
+}
+
+static void exchange_data_movements_infos()
+{
+	int i;
+
+	/* Allocate all requests and status for point-to-point communications */
+	starpu_mpi_req data_movements_send_req[world_size];
+	starpu_mpi_req data_movements_recv_req[world_size];
+
+	MPI_Status data_movements_send_status[world_size];
+	MPI_Status data_movements_recv_status[world_size];
+
+	int flag;
+
+	/* Send the new ranks of local data to all other nodes, and receive the new
+	 * ranks of all remote data from all other nodes */
+	for (i = 0; i < world_size; i++)
+	{
+		if (i != my_rank)
+		{
+			//_STARPU_DEBUG("[node %d] Send and receive data movement with %d\n", my_rank, i);
+			starpu_mpi_isend(data_movements_handles[my_rank], &data_movements_send_req[i], i, TAG_MOV(my_rank), MPI_COMM_WORLD);
+			starpu_mpi_irecv(data_movements_handles[i], &data_movements_recv_req[i], i, TAG_MOV(i), MPI_COMM_WORLD);
+		}
+	}
+
+	/* Wait for completion of all send requests */
+	for (i = 0; i < world_size; i++)
+	{
+		if (i != my_rank)
+		{
+			//fprintf(stderr,"Wait for sending data movement of %d to %d\n", my_rank, i);
+			flag = 0;
+			while (!flag)
+				starpu_mpi_test(&data_movements_send_req[i], &flag, &data_movements_send_status[i]);
+		}
+	}
+
+	/* Wait for completion of all receive requests */
+	for (i = 0; i < world_size; i++)
+	{
+		if (i != my_rank)
+		{
+			//fprintf(stderr,"Wait for recieving data movement from %d on %d\n", i, my_rank);
+			flag = 0;
+			while (!flag)
+				starpu_mpi_test(&data_movements_recv_req[i], &flag, &data_movements_recv_status[i]);
+		}
+	}
+}
+
+static void update_data_ranks()
+{
+	int i,j;
+
+	/* Update the new ranks for all concerned data */
+	for (i = 0; i < world_size; i++)
+	{
+		int ndata_to_update = data_movements_get_size_tables(data_movements_handles[i]);
+		if (ndata_to_update)
+		{
+			//fprintf(stderr,"Update %d data from table %d on node %d\n", ndata_to_update, i, my_rank);
+
+			for (j = 0; j < ndata_to_update; j++)
+			{
+				starpu_data_handle_t handle = _starpu_mpi_tag_get_data_handle_from_tag((data_movements_get_tags_table(data_movements_handles[i]))[j]);
+				STARPU_ASSERT(handle);
+				int dst_rank = (data_movements_get_ranks_table(data_movements_handles[i]))[j];
+
+				/* Save the fact that the data has been moved out of this node */
+				if (i == my_rank)
+				{
+					struct moved_data_entry *md;
+					_STARPU_MPI_MALLOC(md, sizeof(struct moved_data_entry));
+					md->handle = handle;
+					HASH_ADD_PTR(mdh, handle, md);
+				}
+				else if (dst_rank == my_rank)
+				{
+					/* The data has been moved out, and now is moved back, so
+					 * update the state of the moved_data hash table to reflect
+					 * this change */
+					struct moved_data_entry *md = NULL;
+					HASH_FIND_PTR(mdh, &handle, md);
+					if (md)
+					{
+						HASH_DEL(mdh, md);
+						free(md);
+					}
+				}
+
+				//if (i == my_rank)
+				//{
+				//    if (dst_rank != my_rank)
+				//        fprintf(stderr,"Move data %p (tag %d) from node %d to node %d\n", handle, (data_movements_get_tags_table(data_movements_handles[i]))[j], my_rank, dst_rank);
+				//    else
+				//        fprintf(stderr,"Bring back data %p (tag %d) from node %d on node %d\n", handle, (data_movements_get_tags_table(data_movements_handles[i]))[j], starpu_mpi_data_get_rank(handle), my_rank);
+				//}
+
+				_STARPU_DEBUG("Call of starpu_mpi_get_data_on_node(%d,%d) on node %d\n", starpu_mpi_data_get_tag(handle), dst_rank, my_rank);
+
+				/* Migrate the data handle */
+				starpu_mpi_get_data_on_node_detached(MPI_COMM_WORLD, handle, dst_rank, NULL, NULL);
+
+				_STARPU_DEBUG("New rank (%d) of data %d upgraded on node %d\n", dst_rank, starpu_mpi_data_get_tag(handle), my_rank);
+				starpu_mpi_data_set_rank_comm(handle, dst_rank, MPI_COMM_WORLD);
+			}
+		}
+	}
+}
+
+static void clean_balance()
+{
+	int i;
+	starpu_mpi_cache_flush(MPI_COMM_WORLD, *load_data_handle_cpy);
+	for (i = 0; i < nneighbors; i++)
+		starpu_mpi_cache_flush(MPI_COMM_WORLD, neighbor_load_data_handles[i]);
+	for (i = 0; i < world_size; i++)
+		starpu_mpi_cache_flush(MPI_COMM_WORLD, data_movements_handles[i]);
+}
+
+/* Core function of the load balancer. Computes from the load_data_cpy handle a
+ * load balancing of the work to come (if needed), perform the necessary data
+ * communications and negociate with the other nodes the rebalancing. */
+static void heat_balance(starpu_data_handle_t load_data_cpy)
+{
+	/* Exchange load data handles with neighboring nodes */
+	exchange_load_data_infos(load_data_cpy);
+
+	/* Determine if this node should sent data to other nodes :
+	 * which ones, how much data */
+	balance(load_data_cpy);
+
+	/* Exchange data movements with neighboring nodes */
+	exchange_data_movements_infos();
+
+	/* Perform data movements */
+	update_data_ranks();
+
+	/* Clean the data handles to properly launch the next balance phase */
+	clean_balance();
+}
+
+/******************************************************************************
+ *                      Heat Load Balancer Entry Points                       *
+ *****************************************************************************/
+
+static void submitted_task_heat(struct starpu_task *task)
+{
+	load_data_inc_nsubmitted_tasks(*load_data_handle);
+	//if (load_data_get_nsubmitted_tasks(*load_data_handle) > task->tag_id)
+	//{
+	//    fprintf(stderr,"Error : nsubmitted_tasks (%d) > tag_id (%lld) ! \n", load_data_get_nsubmitted_tasks(*load_data_handle), (long long int)task->tag_id);
+	//    STARPU_ASSERT(0);
+	//}
+
+	int phase = load_data_get_current_phase(*load_data_handle);
+	/* Numbering of tasks in StarPU-MPI should be given by the application with
+	 * the STARPU_TAG_ONLY insert task option for now. */
+	/* TODO: Properly implement a solution for numbering tasks in StarPU-MPI */
+	if ((task->tag_id / load_data_get_sleep_threshold(*load_data_handle)) > phase)
+	{
+		STARPU_PTHREAD_MUTEX_LOCK(&load_data_mutex);
+		load_data_update_wakeup_cond(*load_data_handle);
+		//fprintf(stderr,"Node %d sleep on tag %lld\n", my_rank, (long long int)task->tag_id);
+		//if (load_data_get_nsubmitted_tasks(*load_data_handle) < load_data_get_wakeup_threshold(*load_data_handle))
+		//{
+		//    fprintf(stderr,"Error : nsubmitted_tasks (%d) lower than wakeup_threshold (%d) !\n", load_data_get_nsubmitted_tasks(*load_data_handle), load_data_get_wakeup_threshold(*load_data_handle));
+		//    STARPU_ASSERT(0);
+		//}
+
+		if (load_data_get_wakeup_threshold(*load_data_handle) > load_data_get_nfinished_tasks(*load_data_handle))
+			STARPU_PTHREAD_COND_WAIT(&load_data_cond, &load_data_mutex);
+
+		load_data_next_phase(*load_data_handle);
+
+		/* Register a copy of the load data at this moment, to allow to compute
+		 * the heat balance while not locking the load data during the whole
+		 * balance step, which could cause all the workers to wait on the lock
+		 * to update the data. */
+		struct starpu_data_interface_ops *itf_load_data = starpu_data_get_interface_ops(*load_data_handle);
+		void* itf_src = starpu_data_get_interface_on_node(*load_data_handle, STARPU_MAIN_RAM);
+		void* itf_dst = starpu_data_get_interface_on_node(*load_data_handle_cpy, STARPU_MAIN_RAM);
+		memcpy(itf_dst, itf_src, itf_load_data->interface_size);
+
+		_STARPU_DEBUG("[node %d] Balance phase %d\n", my_rank, load_data_get_current_phase(*load_data_handle));
+		STARPU_PTHREAD_MUTEX_UNLOCK(&load_data_mutex);
+
+		heat_balance(*load_data_handle_cpy);
+	}
+}
+
+static void finished_task_heat()
+{
+	//fprintf(stderr,"Try to decrement nsubmitted_tasks...");
+	STARPU_PTHREAD_MUTEX_LOCK(&load_data_mutex);
+
+	load_data_inc_nfinished_tasks(*load_data_handle);
+	//fprintf(stderr,"Decrement nsubmitted_tasks, now %d\n", load_data_get_nsubmitted_tasks(*load_data_handle));
+	if (load_data_wakeup_cond(*load_data_handle))
+	{
+		//fprintf(stderr,"Wakeup ! nfinished_tasks = %d, wakeup_threshold = %d\n", load_data_get_nfinished_tasks(*load_data_handle), load_data_get_wakeup_threshold(*load_data_handle));
+		load_data_update_elapsed_time(*load_data_handle);
+		STARPU_PTHREAD_COND_SIGNAL(&load_data_cond);
+		STARPU_PTHREAD_MUTEX_UNLOCK(&load_data_mutex);
+	}
+	else
+		STARPU_PTHREAD_MUTEX_UNLOCK(&load_data_mutex);
+}
+
+/******************************************************************************
+ *                  Initialization / Deinitialization                         *
+ *****************************************************************************/
+
+static int init_heat(struct starpu_mpi_lb_conf *itf)
+{
+	int i;
+	int sleep_task_threshold;
+	double wakeup_ratio;
+
+	starpu_mpi_comm_size(MPI_COMM_WORLD, &world_size);
+	starpu_mpi_comm_rank(MPI_COMM_WORLD, &my_rank);
+
+	/* Immediately return if the starpu_mpi_lb_conf is invalid. */
+	if (!(itf && itf->get_neighbors && itf->get_data_unit_to_migrate))
+	{
+		_STARPU_MSG("Error: struct starpu_mpi_lb_conf %p invalid\n", itf);
+		return 1;
+	}
+
+	_STARPU_MPI_MALLOC(user_itf, sizeof(struct starpu_mpi_lb_conf));
+	memcpy(user_itf, itf, sizeof(struct starpu_mpi_lb_conf));
+
+	/* Get the neighbors of the local MPI node */
+	user_itf->get_neighbors(&neighbor_ids, &nneighbors);
+	if (nneighbors == 0)
+	{
+		_STARPU_MSG("Error: Function get_neighbors returning 0 neighbor\n");
+		free(user_itf);
+		user_itf = NULL;
+		return 2;
+	}
+
+	/* The sleep threshold is deducted from the numbering of tasks by the
+	 * application. For example, with this threshold, the submission thread
+	 * will stop when a task for which the numbering is 2000 or above will be
+	 * submitted to StarPU-MPI. However, much less tasks can be really
+	 * submitted to the local MPI node: the sleeping of the submission threads
+	 * checks the numbering of the tasks, not how many tasks have been
+	 * submitted to the local MPI node, which are two different things. */
+	char *sleep_env = starpu_getenv("LB_HEAT_SLEEP_THRESHOLD");
+	if (sleep_env)
+		sleep_task_threshold = atoi(sleep_env);
+	else
+		sleep_task_threshold = 2000;
+
+	char *wakeup_env = starpu_getenv("LB_HEAT_WAKEUP_RATIO");
+	if (wakeup_env)
+		wakeup_ratio = atof(wakeup_env);
+	else
+		wakeup_ratio = 0.5;
+
+	char *time_env = starpu_getenv("LB_HEAT_TIME_THRESHOLD");
+	if (time_env)
+		time_threshold = atoi(time_env);
+	else
+		time_threshold = 2000;
+
+	STARPU_PTHREAD_MUTEX_INIT(&load_data_mutex, NULL);
+	STARPU_PTHREAD_COND_INIT(&load_data_cond, NULL);
+
+	/* Allocate, initialize and register all the data handles that will be
+	 * needed for the load balancer, to not reallocate them at each balance
+	 * step. */
+
+	/* Local load data */
+	_STARPU_MPI_CALLOC(load_data_handle, 1, sizeof(starpu_data_handle_t));
+	load_data_data_register(load_data_handle, STARPU_MAIN_RAM, sleep_task_threshold, wakeup_ratio);
+
+	/* Copy of the local load data to enable parallel update of the load data
+	 * with communications to neighbor nodes */
+	_STARPU_MPI_CALLOC(load_data_handle_cpy, 1, sizeof(starpu_data_handle_t));
+	void *local_interface = starpu_data_get_interface_on_node(*load_data_handle, STARPU_MAIN_RAM);
+	struct starpu_data_interface_ops *itf_load_data = starpu_data_get_interface_ops(*load_data_handle);
+	starpu_data_register(load_data_handle_cpy, STARPU_MAIN_RAM, local_interface, itf_load_data);
+	starpu_mpi_data_register(*load_data_handle_cpy, TAG_LOAD(my_rank), my_rank);
+
+	/* Remote load data */
+	_STARPU_MPI_CALLOC(neighbor_load_data_handles, nneighbors, sizeof(starpu_data_handle_t));
+	for (i = 0; i < nneighbors; i++)
+	{
+		load_data_data_register(&neighbor_load_data_handles[i], STARPU_MAIN_RAM, sleep_task_threshold, wakeup_ratio);
+		starpu_mpi_data_register(neighbor_load_data_handles[i], TAG_LOAD(neighbor_ids[i]), neighbor_ids[i]);
+	}
+
+	/* Data movements handles */
+	_STARPU_MPI_MALLOC(data_movements_handles, world_size*sizeof(starpu_data_handle_t));
+	for (i = 0; i < world_size; i++)
+	{
+		data_movements_data_register(&data_movements_handles[i], STARPU_MAIN_RAM, NULL, NULL, 0);
+		starpu_mpi_data_register(data_movements_handles[i], TAG_MOV(i), i);
+	}
+
+	/* Hash table of moved data that will be brought back on the node at
+	 * termination time */
+	mdh = NULL;
+
+	return 0;
+}
+
+/* Move back all the data that has been migrated out of this node at
+ * denitialization time of the load balancer, to ensure the consistency with
+ * the ranks of data originally registered by the application. */
+static void move_back_data()
+{
+	int i,j;
+
+	/* Update the new ranks for all concerned data */
+	for (i = 0; i < world_size; i++)
+	{
+		/* In this case, each data_movements_handles contains the handles to move back on the specific node */
+		int ndata_to_update = data_movements_get_size_tables(data_movements_handles[i]);
+		if (ndata_to_update)
+		{
+			_STARPU_DEBUG("Move back %d data from table %d on node %d\n", ndata_to_update, i, my_rank);
+
+			for (j = 0; j < ndata_to_update; j++)
+			{
+				starpu_data_handle_t handle = _starpu_mpi_tag_get_data_handle_from_tag((data_movements_get_tags_table(data_movements_handles[i]))[j]);
+				STARPU_ASSERT(handle);
+
+				int dst_rank = (data_movements_get_ranks_table(data_movements_handles[i]))[j];
+				STARPU_ASSERT(i == dst_rank);
+
+				if (i == my_rank)
+				{
+					/* The data is moved back, so update the state of the
+					 * moved_data hash table to reflect this change */
+					struct moved_data_entry *md = NULL;
+					HASH_FIND_PTR(mdh, &handle, md);
+					if (md)
+					{
+						HASH_DEL(mdh, md);
+						free(md);
+					}
+				}
+
+				//fprintf(stderr,"Call of starpu_mpi_get_data_on_node(%d,%d) on node %d\n", starpu_mpi_data_get_tag(handle), dst_rank, my_rank);
+
+				/* Migrate the data handle */
+				starpu_mpi_get_data_on_node_detached(MPI_COMM_WORLD, handle, dst_rank, NULL, NULL);
+
+				//fprintf(stderr,"New rank (%d) of data %d upgraded on node %d\n", dst_rank, starpu_mpi_data_get_tag(handle), my_rank);
+				starpu_mpi_data_set_rank_comm(handle, dst_rank, MPI_COMM_WORLD);
+			}
+		}
+	}
+}
+
+static int deinit_heat()
+{
+	int i;
+
+	if ((!user_itf) || (nneighbors == 0))
+		return 1;
+
+	_STARPU_DEBUG("Shutting down heat lb policy\n");
+
+	unsigned int ndata_to_move_back = HASH_COUNT(mdh);
+
+	if (ndata_to_move_back)
+	{
+		_STARPU_DEBUG("Move back %u data on node %d ..\n", ndata_to_move_back, my_rank);
+		data_movements_reallocate_tables(data_movements_handles[my_rank], ndata_to_move_back);
+
+		int *tags = data_movements_get_tags_table(data_movements_handles[my_rank]);
+		int *ranks = data_movements_get_ranks_table(data_movements_handles[my_rank]);
+
+		int n = 0;
+		struct moved_data_entry *md, *tmp;
+		HASH_ITER(hh, mdh, md, tmp)
+		{
+			tags[n] = starpu_mpi_data_get_tag(md->handle);
+			ranks[n] = my_rank;
+			n++;
+		}
+	}
+	else
+		data_movements_reallocate_tables(data_movements_handles[my_rank], 0);
+
+	exchange_data_movements_infos();
+	move_back_data();
+
+	/* This assert ensures that all nodes have properly gotten back all the
+	 * data that has been moven out of the node. */
+	STARPU_ASSERT(HASH_COUNT(mdh) == 0);
+	free(mdh);
+	mdh = NULL;
+
+	starpu_data_unregister(*load_data_handle);
+	free(load_data_handle);
+	load_data_handle = NULL;
+
+	starpu_mpi_cache_flush(MPI_COMM_WORLD, *load_data_handle_cpy);
+	starpu_data_unregister(*load_data_handle_cpy);
+	free(load_data_handle_cpy);
+	load_data_handle_cpy = NULL;
+
+	for (i = 0; i < nneighbors; i++)
+	{
+		starpu_mpi_cache_flush(MPI_COMM_WORLD, neighbor_load_data_handles[i]);
+		starpu_data_unregister(neighbor_load_data_handles[i]);
+	}
+	free(neighbor_load_data_handles);
+	neighbor_load_data_handles = NULL;
+
+	nneighbors = 0;
+	free(neighbor_ids);
+	neighbor_ids = NULL;
+
+	for (i = 0; i < world_size; i++)
+	{
+		starpu_mpi_cache_flush(MPI_COMM_WORLD, data_movements_handles[i]);
+		data_movements_reallocate_tables(data_movements_handles[i], 0);
+		starpu_data_unregister(data_movements_handles[i]);
+	}
+	free(data_movements_handles);
+	data_movements_handles = NULL;
+
+	STARPU_PTHREAD_MUTEX_DESTROY(&load_data_mutex);
+	STARPU_PTHREAD_COND_DESTROY(&load_data_cond);
+	free(user_itf);
+	user_itf = NULL;
+
+	return 0;
+}
+
+/******************************************************************************
+ *                                  Policy                                    *
+ *****************************************************************************/
+
+struct load_balancer_policy load_heat_propagation_policy =
+{
+	.init = init_heat,
+	.deinit = deinit_heat,
+	.submitted_task_entry_point = submitted_task_heat,
+	.finished_task_entry_point = finished_task_heat,
+	.policy_name = "heat"
+};
+
+#endif

+ 224 - 0
nmad/src/mpi/starpu_mpi_comm.c

@@ -0,0 +1,224 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017  CNRS
+ * Copyright (C) 2011-2016  Université de Bordeaux
+ * Copyright (C) 2014 INRIA
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#include <starpu.h>
+#include <starpu_mpi.h>
+#include <starpu_mpi_private.h>
+#include <mpi/starpu_mpi_comm.h>
+#include <common/list.h>
+
+#ifdef STARPU_USE_MPI_MPI
+
+struct _starpu_mpi_comm
+{
+	MPI_Comm comm;
+	struct _starpu_mpi_envelope *envelope;
+	MPI_Request request;
+	int posted;
+
+#ifdef STARPU_SIMGRID
+	MPI_Status status;
+	starpu_pthread_queue_t queue;
+	unsigned done;
+#endif
+};
+struct _starpu_mpi_comm_hashtable
+{
+	UT_hash_handle hh;
+	MPI_Comm comm;
+};
+
+static starpu_pthread_mutex_t _starpu_mpi_comms_mutex;
+struct _starpu_mpi_comm_hashtable *_starpu_mpi_comms_cache;
+struct _starpu_mpi_comm **_starpu_mpi_comms;
+int _starpu_mpi_comm_nb;
+int _starpu_mpi_comm_allocated;
+int _starpu_mpi_comm_tested;
+
+void _starpu_mpi_comm_init(MPI_Comm comm)
+{
+	_STARPU_MPI_DEBUG(10, "allocating for %d communicators\n", _starpu_mpi_comm_allocated);
+	_starpu_mpi_comm_allocated=10;
+	_STARPU_MPI_CALLOC(_starpu_mpi_comms, _starpu_mpi_comm_allocated, sizeof(struct _starpu_mpi_comm *));
+	_starpu_mpi_comm_nb=0;
+	_starpu_mpi_comm_tested=0;
+	_starpu_mpi_comms_cache = NULL;
+	STARPU_PTHREAD_MUTEX_INIT(&_starpu_mpi_comms_mutex, NULL);
+
+	_starpu_mpi_comm_register(comm);
+}
+
+void _starpu_mpi_comm_shutdown()
+{
+	int i;
+	for(i=0 ; i<_starpu_mpi_comm_nb ; i++)
+	{
+		struct _starpu_mpi_comm *_comm = _starpu_mpi_comms[i]; // get the ith _comm;
+		free(_comm->envelope);
+#ifdef STARPU_SIMGRID
+		starpu_pthread_queue_unregister(&wait, &_comm->queue);
+		starpu_pthread_queue_destroy(&_comm->queue);
+#endif
+		free(_comm);
+	}
+	free(_starpu_mpi_comms);
+
+	struct _starpu_mpi_comm_hashtable *entry, *tmp;
+	HASH_ITER(hh, _starpu_mpi_comms_cache, entry, tmp)
+	{
+		HASH_DEL(_starpu_mpi_comms_cache, entry);
+		free(entry);
+	}
+
+	STARPU_PTHREAD_MUTEX_DESTROY(&_starpu_mpi_comms_mutex);
+}
+
+void _starpu_mpi_comm_register(MPI_Comm comm)
+{
+	struct _starpu_mpi_comm_hashtable *found;
+
+	STARPU_PTHREAD_MUTEX_LOCK(&_starpu_mpi_comms_mutex);
+	HASH_FIND(hh, _starpu_mpi_comms_cache, &comm, sizeof(MPI_Comm), found);
+	if (found)
+	{
+		_STARPU_MPI_DEBUG(10, "comm %ld (%ld) already registered\n", (long int)comm, (long int)MPI_COMM_WORLD);
+	}
+	else
+	{
+		if (_starpu_mpi_comm_nb == _starpu_mpi_comm_allocated)
+		{
+			_starpu_mpi_comm_allocated *= 2;
+			_STARPU_MPI_DEBUG(10, "reallocating for %d communicators\n", _starpu_mpi_comm_allocated);
+			_STARPU_MPI_REALLOC(_starpu_mpi_comms, _starpu_mpi_comm_allocated * sizeof(struct _starpu_mpi_comm *));
+		}
+		_STARPU_MPI_DEBUG(10, "registering comm %ld (%ld) number %d\n", (long int)comm, (long int)MPI_COMM_WORLD, _starpu_mpi_comm_nb);
+		struct _starpu_mpi_comm *_comm;
+		_STARPU_MPI_CALLOC(_comm, 1, sizeof(struct _starpu_mpi_comm));
+		_comm->comm = comm;
+		_STARPU_MPI_CALLOC(_comm->envelope, 1,sizeof(struct _starpu_mpi_envelope));
+		_comm->posted = 0;
+		_starpu_mpi_comms[_starpu_mpi_comm_nb] = _comm;
+		_starpu_mpi_comm_nb++;
+		struct _starpu_mpi_comm_hashtable *entry;
+		_STARPU_MPI_MALLOC(entry, sizeof(*entry));
+		entry->comm = comm;
+		HASH_ADD(hh, _starpu_mpi_comms_cache, comm, sizeof(entry->comm), entry);
+
+#ifdef STARPU_SIMGRID
+		starpu_pthread_queue_init(&_comm->queue);
+		starpu_pthread_queue_register(&wait, &_comm->queue);
+		_comm->done = 0;
+#endif
+	}
+	STARPU_PTHREAD_MUTEX_UNLOCK(&_starpu_mpi_comms_mutex);
+}
+
+void _starpu_mpi_comm_post_recv()
+{
+	int i;
+
+	STARPU_PTHREAD_MUTEX_LOCK(&_starpu_mpi_comms_mutex);
+	for(i=0 ; i<_starpu_mpi_comm_nb ; i++)
+	{
+		struct _starpu_mpi_comm *_comm = _starpu_mpi_comms[i]; // get the ith _comm;
+		if (_comm->posted == 0)
+		{
+			_STARPU_MPI_DEBUG(3, "Posting a receive to get a data envelop on comm %d %ld\n", i, (long int)_comm->comm);
+			_STARPU_MPI_COMM_FROM_DEBUG(_comm->envelope, sizeof(struct _starpu_mpi_envelope), MPI_BYTE, MPI_ANY_SOURCE, _STARPU_MPI_TAG_ENVELOPE, _STARPU_MPI_TAG_ENVELOPE, _comm->comm);
+			MPI_Irecv(_comm->envelope, sizeof(struct _starpu_mpi_envelope), MPI_BYTE, MPI_ANY_SOURCE, _STARPU_MPI_TAG_ENVELOPE, _comm->comm, &_comm->request);
+#ifdef STARPU_SIMGRID
+			_starpu_mpi_simgrid_wait_req(&_comm->request, &_comm->status, &_comm->queue, &_comm->done);
+#endif
+			_comm->posted = 1;
+		}
+	}
+	STARPU_PTHREAD_MUTEX_UNLOCK(&_starpu_mpi_comms_mutex);
+}
+
+int _starpu_mpi_comm_test_recv(MPI_Status *status, struct _starpu_mpi_envelope **envelope, MPI_Comm *comm)
+{
+	int i=_starpu_mpi_comm_tested;
+
+	STARPU_PTHREAD_MUTEX_LOCK(&_starpu_mpi_comms_mutex);
+	while (1)
+	{
+		struct _starpu_mpi_comm *_comm = _starpu_mpi_comms[i]; // get the ith _comm;
+
+		if (_comm->posted)
+		{
+			int flag, res;
+			/* test whether an envelope has arrived. */
+#ifdef STARPU_SIMGRID
+			res = _starpu_mpi_simgrid_mpi_test(&_comm->done, &flag);
+			memcpy(status, &_comm->status, sizeof(*status));
+#else
+			res = MPI_Test(&_comm->request, &flag, status);
+#endif
+			STARPU_ASSERT(res == MPI_SUCCESS);
+			if (flag)
+			{
+				_comm->posted = 0;
+				_starpu_mpi_comm_tested++;
+				if (_starpu_mpi_comm_tested == _starpu_mpi_comm_nb)
+					_starpu_mpi_comm_tested = 0;
+				*envelope = _comm->envelope;
+				*comm = _comm->comm;
+				STARPU_PTHREAD_MUTEX_UNLOCK(&_starpu_mpi_comms_mutex);
+				return 1;
+			}
+		}
+		i++;
+		if (i == _starpu_mpi_comm_nb)
+		{
+			i=0;
+		}
+		if (i == _starpu_mpi_comm_tested)
+		{
+			// We have tested all the requests, none has completed
+			STARPU_PTHREAD_MUTEX_UNLOCK(&_starpu_mpi_comms_mutex);
+			return 0;
+		}
+	}
+	STARPU_PTHREAD_MUTEX_UNLOCK(&_starpu_mpi_comms_mutex);
+	return 0;
+}
+
+void _starpu_mpi_comm_cancel_recv()
+{
+	int i;
+
+	STARPU_PTHREAD_MUTEX_LOCK(&_starpu_mpi_comms_mutex);
+	for(i=0 ; i<_starpu_mpi_comm_nb ; i++)
+	{
+		struct _starpu_mpi_comm *_comm = _starpu_mpi_comms[i]; // get the ith _comm;
+		if (_comm->posted == 1)
+		{
+			MPI_Cancel(&_comm->request);
+#ifndef STARPU_SIMGRID
+			{
+				MPI_Status status;
+				MPI_Wait(&_comm->request, &status);
+			}
+#endif
+			_comm->posted = 0;
+		}
+	}
+	STARPU_PTHREAD_MUTEX_UNLOCK(&_starpu_mpi_comms_mutex);
+}
+
+#endif /* STARPU_USE_MPI_MPI */

+ 43 - 0
nmad/src/mpi/starpu_mpi_comm.h

@@ -0,0 +1,43 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2015, 2016, 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#ifndef __STARPU_MPI_COMM_H__
+#define __STARPU_MPI_COMM_H__
+
+#include <starpu.h>
+#include <stdlib.h>
+#include <mpi.h>
+
+#ifdef STARPU_USE_MPI_MPI
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+void _starpu_mpi_comm_init(MPI_Comm comm);
+void _starpu_mpi_comm_shutdown();
+void _starpu_mpi_comm_register(MPI_Comm comm);
+void _starpu_mpi_comm_post_recv();
+int _starpu_mpi_comm_test_recv(MPI_Status *status, struct _starpu_mpi_envelope **envelope, MPI_Comm *comm);
+void _starpu_mpi_comm_cancel_recv();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // STARPU_USE_MPI_MPI
+#endif // __STARPU_MPI_COMM_H__

+ 124 - 0
nmad/src/mpi/starpu_mpi_early_data.c

@@ -0,0 +1,124 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2009, 2010-2014, 2017  Université de Bordeaux
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#include <stdlib.h>
+#include <starpu_mpi.h>
+#include <mpi/starpu_mpi_early_data.h>
+#include <starpu_mpi_private.h>
+#include <common/uthash.h>
+
+#ifdef STARPU_USE_MPI_MPI
+
+struct _starpu_mpi_early_data_handle_hashlist
+{
+	struct _starpu_mpi_early_data_handle_list list;
+	UT_hash_handle hh;
+	struct _starpu_mpi_node_tag node_tag;
+};
+
+/** stores data which have been received by MPI but have not been requested by the application */
+static starpu_pthread_mutex_t _starpu_mpi_early_data_handle_mutex;
+static struct _starpu_mpi_early_data_handle_hashlist *_starpu_mpi_early_data_handle_hashmap = NULL;
+static int _starpu_mpi_early_data_handle_hashmap_count = 0;
+
+void _starpu_mpi_early_data_init(void)
+{
+	_starpu_mpi_early_data_handle_hashmap = NULL;
+	_starpu_mpi_early_data_handle_hashmap_count = 0;
+	STARPU_PTHREAD_MUTEX_INIT(&_starpu_mpi_early_data_handle_mutex, NULL);
+}
+
+void _starpu_mpi_early_data_check_termination(void)
+{
+	STARPU_ASSERT_MSG(_starpu_mpi_early_data_handle_hashmap_count == 0, "Number of unexpected received messages left is not zero (but %d), did you forget to post a receive corresponding to a send?", _starpu_mpi_early_data_handle_hashmap_count);
+}
+
+void _starpu_mpi_early_data_shutdown(void)
+{
+	struct _starpu_mpi_early_data_handle_hashlist *current, *tmp;
+	HASH_ITER(hh, _starpu_mpi_early_data_handle_hashmap, current, tmp)
+	{
+		STARPU_ASSERT(_starpu_mpi_early_data_handle_list_empty(&current->list));
+		HASH_DEL(_starpu_mpi_early_data_handle_hashmap, current);
+		free(current);
+	}
+	STARPU_PTHREAD_MUTEX_DESTROY(&_starpu_mpi_early_data_handle_mutex);
+}
+
+struct _starpu_mpi_early_data_handle *_starpu_mpi_early_data_create(struct _starpu_mpi_envelope *envelope, int source, MPI_Comm comm)
+{
+	struct _starpu_mpi_early_data_handle* early_data_handle;
+	_STARPU_MPI_CALLOC(early_data_handle, 1, sizeof(struct _starpu_mpi_early_data_handle));
+	STARPU_PTHREAD_MUTEX_INIT(&early_data_handle->req_mutex, NULL);
+	STARPU_PTHREAD_COND_INIT(&early_data_handle->req_cond, NULL);
+	early_data_handle->env = envelope;
+	early_data_handle->node_tag.comm = comm;
+	early_data_handle->node_tag.rank = source;
+	early_data_handle->node_tag.data_tag = envelope->data_tag;
+	return early_data_handle;
+}
+
+struct _starpu_mpi_early_data_handle *_starpu_mpi_early_data_find(struct _starpu_mpi_node_tag *node_tag)
+{
+	struct _starpu_mpi_early_data_handle_hashlist *hashlist;
+	struct _starpu_mpi_early_data_handle *early_data_handle;
+
+	STARPU_PTHREAD_MUTEX_LOCK(&_starpu_mpi_early_data_handle_mutex);
+	_STARPU_MPI_DEBUG(60, "Looking for early_data_handle with comm %ld source %d tag %d\n", (long int)node_tag->comm, node_tag->rank, node_tag->data_tag);
+	HASH_FIND(hh, _starpu_mpi_early_data_handle_hashmap, node_tag, sizeof(struct _starpu_mpi_node_tag), hashlist);
+	if (hashlist == NULL)
+	{
+		early_data_handle = NULL;
+	}
+	else
+	{
+		if (_starpu_mpi_early_data_handle_list_empty(&hashlist->list))
+		{
+			early_data_handle = NULL;
+		}
+		else
+		{
+			_starpu_mpi_early_data_handle_hashmap_count --;
+			early_data_handle = _starpu_mpi_early_data_handle_list_pop_front(&hashlist->list);
+		}
+	}
+	_STARPU_MPI_DEBUG(60, "Found early_data_handle %p with comm %ld source %d tag %d\n", early_data_handle, (long int)node_tag->comm, node_tag->rank, node_tag->data_tag);
+	STARPU_PTHREAD_MUTEX_UNLOCK(&_starpu_mpi_early_data_handle_mutex);
+	return early_data_handle;
+}
+
+void _starpu_mpi_early_data_add(struct _starpu_mpi_early_data_handle *early_data_handle)
+{
+	STARPU_PTHREAD_MUTEX_LOCK(&_starpu_mpi_early_data_handle_mutex);
+	_STARPU_MPI_DEBUG(60, "Trying to add early_data_handle %p with comm %ld source %d tag %d\n", early_data_handle, (long int)early_data_handle->node_tag.comm,
+			  early_data_handle->node_tag.rank, early_data_handle->node_tag.data_tag);
+
+	struct _starpu_mpi_early_data_handle_hashlist *hashlist;
+	HASH_FIND(hh, _starpu_mpi_early_data_handle_hashmap, &early_data_handle->node_tag, sizeof(struct _starpu_mpi_node_tag), hashlist);
+	if (hashlist == NULL)
+	{
+		_STARPU_MPI_MALLOC(hashlist, sizeof(struct _starpu_mpi_early_data_handle_hashlist));
+		_starpu_mpi_early_data_handle_list_init(&hashlist->list);
+		hashlist->node_tag = early_data_handle->node_tag;
+		HASH_ADD(hh, _starpu_mpi_early_data_handle_hashmap, node_tag, sizeof(hashlist->node_tag), hashlist);
+	}
+	_starpu_mpi_early_data_handle_list_push_back(&hashlist->list, early_data_handle);
+	_starpu_mpi_early_data_handle_hashmap_count ++;
+	STARPU_PTHREAD_MUTEX_UNLOCK(&_starpu_mpi_early_data_handle_mutex);
+}
+
+#endif // STARPU_USE_MPI_MPI

+ 59 - 0
nmad/src/mpi/starpu_mpi_early_data.h

@@ -0,0 +1,59 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2009, 2010-2014, 2016  Université de Bordeaux
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#ifndef __STARPU_MPI_EARLY_DATA_H__
+#define __STARPU_MPI_EARLY_DATA_H__
+
+#include <starpu.h>
+#include <stdlib.h>
+#include <mpi.h>
+#include <common/config.h>
+#include <common/list.h>
+#include <starpu_mpi_private.h>
+
+#ifdef STARPU_USE_MPI_MPI
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+LIST_TYPE(_starpu_mpi_early_data_handle,
+	  starpu_data_handle_t handle;
+	  struct _starpu_mpi_envelope *env;
+	  struct _starpu_mpi_req *req;
+	  void *buffer;
+	  int req_ready;
+	  struct _starpu_mpi_node_tag node_tag;
+	  starpu_pthread_mutex_t req_mutex;
+	  starpu_pthread_cond_t req_cond;
+);
+
+void _starpu_mpi_early_data_init(void);
+void _starpu_mpi_early_data_check_termination(void);
+void _starpu_mpi_early_data_shutdown(void);
+
+struct _starpu_mpi_early_data_handle *_starpu_mpi_early_data_create(struct _starpu_mpi_envelope *envelope, int source, MPI_Comm comm) STARPU_ATTRIBUTE_MALLOC;
+struct _starpu_mpi_early_data_handle *_starpu_mpi_early_data_find(struct _starpu_mpi_node_tag *node_tag);
+void _starpu_mpi_early_data_add(struct _starpu_mpi_early_data_handle *early_data_handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*  STARPU_USE_MPI_MPI */
+#endif /* __STARPU_MPI_EARLY_DATA_H__ */

+ 121 - 0
nmad/src/mpi/starpu_mpi_early_request.c

@@ -0,0 +1,121 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2009, 2010-2014, 2016-2017  Université de Bordeaux
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#include <stdlib.h>
+#include <starpu_mpi.h>
+#include <starpu_mpi_private.h>
+#include <mpi/starpu_mpi_early_request.h>
+#include <common/uthash.h>
+
+#ifdef STARPU_USE_MPI_MPI
+
+/** stores application requests for which data have not been received yet */
+struct _starpu_mpi_early_request_hashlist
+{
+	struct _starpu_mpi_req_list list;
+	UT_hash_handle hh;
+	struct _starpu_mpi_node_tag node_tag;
+};
+
+static starpu_pthread_mutex_t _starpu_mpi_early_request_mutex;
+struct _starpu_mpi_early_request_hashlist *_starpu_mpi_early_request_hash;
+int _starpu_mpi_early_request_hash_count;
+
+void _starpu_mpi_early_request_init()
+{
+	_starpu_mpi_early_request_hash = NULL;
+	_starpu_mpi_early_request_hash_count = 0;
+	STARPU_PTHREAD_MUTEX_INIT(&_starpu_mpi_early_request_mutex, NULL);
+}
+
+void _starpu_mpi_early_request_shutdown()
+{
+	struct _starpu_mpi_early_request_hashlist *entry, *tmp;
+	HASH_ITER(hh, _starpu_mpi_early_request_hash, entry, tmp)
+	{
+		STARPU_ASSERT(_starpu_mpi_req_list_empty(&entry->list));
+		HASH_DEL(_starpu_mpi_early_request_hash, entry);
+		free(entry);
+	}
+	STARPU_PTHREAD_MUTEX_DESTROY(&_starpu_mpi_early_request_mutex);
+}
+
+int _starpu_mpi_early_request_count()
+{
+	return _starpu_mpi_early_request_hash_count;
+}
+
+void _starpu_mpi_early_request_check_termination()
+{
+	STARPU_ASSERT_MSG(_starpu_mpi_early_request_count() == 0, "Number of early requests left is not zero");
+}
+
+struct _starpu_mpi_req* _starpu_mpi_early_request_dequeue(int data_tag, int source, MPI_Comm comm)
+{
+	struct _starpu_mpi_node_tag node_tag;
+	struct _starpu_mpi_req *found;
+	struct _starpu_mpi_early_request_hashlist *hashlist;
+
+	STARPU_PTHREAD_MUTEX_LOCK(&_starpu_mpi_early_request_mutex);
+	memset(&node_tag, 0, sizeof(struct _starpu_mpi_node_tag));
+	node_tag.comm = comm;
+	node_tag.rank = source;
+	node_tag.data_tag = data_tag;
+
+	_STARPU_MPI_DEBUG(100, "Looking for early_request with comm %ld source %d tag %d\n", (long int)node_tag.comm, node_tag.rank, node_tag.data_tag);
+	HASH_FIND(hh, _starpu_mpi_early_request_hash, &node_tag, sizeof(struct _starpu_mpi_node_tag), hashlist);
+	if (hashlist == NULL)
+	{
+		found = NULL;
+	}
+	else
+	{
+		if (_starpu_mpi_req_list_empty(&hashlist->list))
+		{
+			found = NULL;
+		}
+		else
+		{
+			found = _starpu_mpi_req_list_pop_front(&hashlist->list);
+			_starpu_mpi_early_request_hash_count --;
+		}
+	}
+	_STARPU_MPI_DEBUG(100, "Found early_request %p with comm %ld source %d tag %d\n", found, (long int)node_tag.comm, node_tag.rank, node_tag.data_tag);
+	STARPU_PTHREAD_MUTEX_UNLOCK(&_starpu_mpi_early_request_mutex);
+	return found;
+}
+
+void _starpu_mpi_early_request_enqueue(struct _starpu_mpi_req *req)
+{
+	STARPU_PTHREAD_MUTEX_LOCK(&_starpu_mpi_early_request_mutex);
+	_STARPU_MPI_DEBUG(100, "Adding request %p with comm %ld source %d tag %d in the application request hashmap\n", req, (long int)req->node_tag.comm, req->node_tag.rank, req->node_tag.data_tag);
+
+	struct _starpu_mpi_early_request_hashlist *hashlist;
+	HASH_FIND(hh, _starpu_mpi_early_request_hash, &req->node_tag, sizeof(struct _starpu_mpi_node_tag), hashlist);
+	if (hashlist == NULL)
+	{
+		_STARPU_MPI_MALLOC(hashlist, sizeof(struct _starpu_mpi_early_request_hashlist));
+		_starpu_mpi_req_list_init(&hashlist->list);
+		hashlist->node_tag = req->node_tag;
+		HASH_ADD(hh, _starpu_mpi_early_request_hash, node_tag, sizeof(hashlist->node_tag), hashlist);
+	}
+	_starpu_mpi_req_list_push_back(&hashlist->list, req);
+	_starpu_mpi_early_request_hash_count ++;
+	STARPU_PTHREAD_MUTEX_UNLOCK(&_starpu_mpi_early_request_mutex);
+}
+
+#endif // STARPU_USE_MPI_MPI

+ 47 - 0
nmad/src/mpi/starpu_mpi_early_request.h

@@ -0,0 +1,47 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2009, 2010-2014  Université de Bordeaux
+ * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#ifndef __STARPU_MPI_EARLY_REQUEST_H__
+#define __STARPU_MPI_EARLY_REQUEST_H__
+
+#include <starpu.h>
+#include <stdlib.h>
+#include <mpi.h>
+#include <common/config.h>
+#include <common/list.h>
+
+#ifdef STARPU_USE_MPI_MPI
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+void _starpu_mpi_early_request_init(void);
+void _starpu_mpi_early_request_shutdown(void);
+int _starpu_mpi_early_request_count(void);
+void _starpu_mpi_early_request_check_termination(void);
+
+void _starpu_mpi_early_request_enqueue(struct _starpu_mpi_req *req);
+struct _starpu_mpi_req* _starpu_mpi_early_request_dequeue(int data_tag, int source, MPI_Comm comm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STARPU_USE_MPI_MPI */
+#endif /* __STARPU_MPI_EARLY_REQUEST_H__ */

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1640 - 0
nmad/src/mpi/starpu_mpi_mpi.c


+ 153 - 0
nmad/src/mpi/starpu_mpi_sync_data.c

@@ -0,0 +1,153 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2015, 2016, 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#include <stdlib.h>
+#include <starpu_mpi.h>
+#include <mpi/starpu_mpi_sync_data.h>
+#include <starpu_mpi_private.h>
+#include <common/uthash.h>
+
+#ifdef STARPU_USE_MPI_MPI
+
+struct _starpu_mpi_sync_data_handle_hashlist
+{
+	struct _starpu_mpi_req_list list;
+	UT_hash_handle hh;
+	struct _starpu_mpi_node_tag node_tag;
+};
+
+/** stores data which have been received by MPI but have not been requested by the application */
+static starpu_pthread_mutex_t _starpu_mpi_sync_data_handle_mutex;
+static struct _starpu_mpi_sync_data_handle_hashlist *_starpu_mpi_sync_data_handle_hashmap = NULL;
+static int _starpu_mpi_sync_data_handle_hashmap_count = 0;
+
+void _starpu_mpi_sync_data_init(void)
+{
+	_starpu_mpi_sync_data_handle_hashmap = NULL;
+	STARPU_PTHREAD_MUTEX_INIT(&_starpu_mpi_sync_data_handle_mutex, NULL);
+	_starpu_mpi_sync_data_handle_hashmap_count = 0;
+}
+
+void _starpu_mpi_sync_data_shutdown(void)
+{
+	struct _starpu_mpi_sync_data_handle_hashlist *current, *tmp;
+	HASH_ITER(hh, _starpu_mpi_sync_data_handle_hashmap, current, tmp)
+	{
+		STARPU_ASSERT(_starpu_mpi_req_list_empty(&current->list));
+		HASH_DEL(_starpu_mpi_sync_data_handle_hashmap, current);
+		free(current);
+	}
+	STARPU_PTHREAD_MUTEX_DESTROY(&_starpu_mpi_sync_data_handle_mutex);
+}
+
+#ifdef STARPU_VERBOSE
+static
+void _starpu_mpi_sync_data_handle_display_hash(struct _starpu_mpi_node_tag *node_tag)
+{
+	struct _starpu_mpi_sync_data_handle_hashlist *hashlist;
+	HASH_FIND(hh, _starpu_mpi_sync_data_handle_hashmap, node_tag, sizeof(struct _starpu_mpi_node_tag), hashlist);
+
+	if (hashlist == NULL)
+	{
+		_STARPU_MPI_DEBUG(60, "Hashlist for comm %ld source %d and tag %d does not exist\n", (long int)node_tag->comm, node_tag->rank, node_tag->data_tag);
+	}
+	else if (_starpu_mpi_req_list_empty(&hashlist->list))
+	{
+		_STARPU_MPI_DEBUG(60, "Hashlist for comm %ld source %d and tag %d is empty\n", (long int)node_tag->comm, node_tag->rank, node_tag->data_tag);
+	}
+	else
+	{
+		struct _starpu_mpi_req *cur;
+		for (cur = _starpu_mpi_req_list_begin(&hashlist->list) ;
+		     cur != _starpu_mpi_req_list_end(&hashlist->list);
+		     cur = _starpu_mpi_req_list_next(cur))
+		{
+			_STARPU_MPI_DEBUG(60, "Element for comm %ld source %d and tag %d: %p\n", (long int)node_tag->comm, node_tag->rank, node_tag->data_tag, cur);
+		}
+	}
+}
+#endif
+
+void _starpu_mpi_sync_data_check_termination(void)
+{
+	STARPU_ASSERT_MSG(_starpu_mpi_sync_data_handle_hashmap_count == 0, "Number of sync received messages left is not zero, did you forget to post a receive corresponding to a send?");
+}
+
+int _starpu_mpi_sync_data_count(void)
+{
+	return _starpu_mpi_sync_data_handle_hashmap_count;
+}
+
+struct _starpu_mpi_req *_starpu_mpi_sync_data_find(int data_tag, int source, MPI_Comm comm)
+{
+	struct _starpu_mpi_req *req;
+	struct _starpu_mpi_node_tag node_tag;
+	struct _starpu_mpi_sync_data_handle_hashlist *found;
+
+	memset(&node_tag, 0, sizeof(struct _starpu_mpi_node_tag));
+	node_tag.comm = comm;
+	node_tag.rank = source;
+	node_tag.data_tag = data_tag;
+
+	_STARPU_MPI_DEBUG(60, "Looking for sync_data_handle with comm %ld source %d tag %d in the hashmap\n", (long int)comm, source, data_tag);
+
+	STARPU_PTHREAD_MUTEX_LOCK(&_starpu_mpi_sync_data_handle_mutex);
+	HASH_FIND(hh, _starpu_mpi_sync_data_handle_hashmap, &node_tag, sizeof(struct _starpu_mpi_node_tag), found);
+	if (found == NULL)
+	{
+		req = NULL;
+	}
+	else
+	{
+		if (_starpu_mpi_req_list_empty(&found->list))
+		{
+			req = NULL;
+		}
+		else
+		{
+			req = _starpu_mpi_req_list_pop_front(&found->list);
+			_starpu_mpi_sync_data_handle_hashmap_count --;
+		}
+	}
+	STARPU_PTHREAD_MUTEX_UNLOCK(&_starpu_mpi_sync_data_handle_mutex);
+	_STARPU_MPI_DEBUG(60, "Found sync_data_handle %p with comm %ld source %d tag %d in the hashmap\n", req, (long int)comm, source, data_tag);
+	return req;
+}
+
+void _starpu_mpi_sync_data_add(struct _starpu_mpi_req *sync_req)
+{
+	struct _starpu_mpi_sync_data_handle_hashlist *hashlist;
+
+	_STARPU_MPI_DEBUG(2000, "Adding sync_req %p with comm %ld source %d tag %d in the hashmap\n", sync_req, (long int)sync_req->node_tag.comm, sync_req->node_tag.rank, sync_req->node_tag.data_tag);
+
+	STARPU_PTHREAD_MUTEX_LOCK(&_starpu_mpi_sync_data_handle_mutex);
+	HASH_FIND(hh, _starpu_mpi_sync_data_handle_hashmap, &sync_req->node_tag, sizeof(struct _starpu_mpi_node_tag), hashlist);
+	if (hashlist == NULL)
+	{
+		_STARPU_MPI_MALLOC(hashlist, sizeof(struct _starpu_mpi_sync_data_handle_hashlist));
+		_starpu_mpi_req_list_init(&hashlist->list);
+		hashlist->node_tag = sync_req->node_tag;
+		HASH_ADD(hh, _starpu_mpi_sync_data_handle_hashmap, node_tag, sizeof(hashlist->node_tag), hashlist);
+	}
+	_starpu_mpi_req_list_push_back(&hashlist->list, sync_req);
+	_starpu_mpi_sync_data_handle_hashmap_count ++;
+	STARPU_PTHREAD_MUTEX_UNLOCK(&_starpu_mpi_sync_data_handle_mutex);
+#ifdef STARPU_VERBOSE
+	_starpu_mpi_sync_data_handle_display_hash(&sync_req->node_tag);
+#endif
+}
+
+#endif // STARPU_USE_MPI_MPI

+ 46 - 0
nmad/src/mpi/starpu_mpi_sync_data.h

@@ -0,0 +1,46 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2015, 2016, 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#ifndef __STARPU_MPI_SYNC_DATA_H__
+#define __STARPU_MPI_SYNC_DATA_H__
+
+#include <starpu.h>
+#include <stdlib.h>
+#include <mpi.h>
+#include <common/config.h>
+#include <common/list.h>
+
+#ifdef STARPU_USE_MPI_MPI
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+void _starpu_mpi_sync_data_init(void);
+void _starpu_mpi_sync_data_check_termination(void);
+void _starpu_mpi_sync_data_shutdown(void);
+
+struct _starpu_mpi_req *_starpu_mpi_sync_data_find(int data_tag, int source, MPI_Comm comm);
+void _starpu_mpi_sync_data_add(struct _starpu_mpi_req *req);
+int _starpu_mpi_sync_data_count();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STARPU_USE_MPI_MPI */
+#endif /* __STARPU_MPI_SYNC_DATA_H__ */

+ 122 - 0
nmad/src/mpi/starpu_mpi_tag.c

@@ -0,0 +1,122 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017  CNRS
+ * Copyright (C) 2011-2015, 2017  Université de Bordeaux
+ * Copyright (C) 2014 INRIA
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#include <starpu.h>
+#include <starpu_mpi.h>
+#include <starpu_mpi_private.h>
+#include <common/uthash.h>
+#include <common/starpu_spinlock.h>
+#include <datawizard/coherency.h>
+
+#ifdef STARPU_USE_MPI_MPI
+
+/* Entry in the `registered_tag_handles' hash table.  */
+struct handle_tag_entry
+{
+	UT_hash_handle hh;
+	int tag;
+	starpu_data_handle_t handle;
+};
+
+/* Hash table mapping host tags to data handles.  */
+static struct handle_tag_entry *registered_tag_handles;
+static struct _starpu_spinlock    registered_tag_handles_lock;
+
+void _starpu_mpi_tag_init(void)
+{
+	_starpu_spin_init(&registered_tag_handles_lock);
+}
+
+void _starpu_mpi_tag_shutdown(void)
+{
+     	struct handle_tag_entry *tag_entry, *tag_tmp;
+
+	_starpu_spin_destroy(&registered_tag_handles_lock);
+
+	HASH_ITER(hh, registered_tag_handles, tag_entry, tag_tmp)
+	{
+		HASH_DEL(registered_tag_handles, tag_entry);
+		free(tag_entry);
+	}
+
+	registered_tag_handles = NULL;
+}
+
+starpu_data_handle_t _starpu_mpi_tag_get_data_handle_from_tag(int tag)
+{
+	struct handle_tag_entry *ret;
+
+	_starpu_spin_lock(&registered_tag_handles_lock);
+	HASH_FIND_INT(registered_tag_handles, &tag, ret);
+	_starpu_spin_unlock(&registered_tag_handles_lock);
+
+	if (ret)
+	{
+		return ret->handle;
+	}
+	else
+	{
+		return NULL;
+	}
+}
+
+void _starpu_mpi_tag_data_register(starpu_data_handle_t handle, int tag)
+{
+	struct handle_tag_entry *entry;
+	if (tag == -1)
+		/* No tag for this data, probably a temporary data not to be communicated */
+		return;
+	_STARPU_MPI_MALLOC(entry, sizeof(*entry));
+
+	STARPU_ASSERT_MSG(!(_starpu_mpi_tag_get_data_handle_from_tag(tag)),
+			  "There is already a data handle %p registered with the tag %d\n", _starpu_mpi_tag_get_data_handle_from_tag(tag), tag);
+
+	_STARPU_MPI_DEBUG(42, "Adding handle %p with tag %d in hashtable\n", handle, tag);
+
+	entry->handle = handle;
+	entry->tag = tag;
+
+	_starpu_spin_lock(&registered_tag_handles_lock);
+	HASH_ADD_INT(registered_tag_handles, tag, entry);
+	_starpu_spin_unlock(&registered_tag_handles_lock);
+}
+
+int _starpu_mpi_tag_data_release(starpu_data_handle_t handle)
+{
+	int tag = starpu_mpi_data_get_tag(handle);
+
+	_STARPU_MPI_DEBUG(42, "Removing handle %p with tag %d from hashtable\n", handle, tag);
+
+	if (tag != -1)
+	{
+		struct handle_tag_entry *tag_entry;
+
+		_starpu_spin_lock(&registered_tag_handles_lock);
+		HASH_FIND_INT(registered_tag_handles, &(((struct _starpu_mpi_data *)(handle->mpi_data))->node_tag.data_tag), tag_entry);
+		STARPU_ASSERT_MSG((tag_entry != NULL),"Data handle %p with tag %d isn't in the hashmap !",handle,tag);
+
+		HASH_DEL(registered_tag_handles, tag_entry);
+
+		_starpu_spin_unlock(&registered_tag_handles_lock);
+
+		free(tag_entry);
+	}
+	return 0;
+}
+
+#endif // STARPU_USE_MPI_MPI

+ 43 - 0
nmad/src/mpi/starpu_mpi_tag.h

@@ -0,0 +1,43 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2015, 2016, 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#ifndef __STARPU_MPI_TAG_H__
+#define __STARPU_MPI_TAG_H__
+
+#include <starpu.h>
+#include <stdlib.h>
+#include <mpi.h>
+
+#ifdef STARPU_USE_MPI_MPI
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+void _starpu_mpi_tag_init(void);
+void _starpu_mpi_tag_shutdown(void);
+
+void _starpu_mpi_tag_data_register(starpu_data_handle_t handle, int tag);
+int _starpu_mpi_tag_data_release(starpu_data_handle_t handle);
+starpu_data_handle_t _starpu_mpi_tag_get_data_handle_from_tag(int tag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // STARPU_USE_MPI_MPI
+#endif // __STARPU_MPI_TAG_H__

+ 6 - 2
nmad/src/nmad/starpu_mpi_nmad.c

@@ -29,11 +29,14 @@
 #include <common/config.h>
 #include <common/thread.h>
 #include <datawizard/coherency.h>
-#include <nm_sendrecv_interface.h>
-#include <nm_mpi_nmad.h>
 #include <core/task.h>
 #include <core/topology.h>
 
+#ifdef STARPU_USE_MPI_NMAD
+
+#include <nm_sendrecv_interface.h>
+#include <nm_mpi_nmad.h>
+
 static void _starpu_mpi_handle_request_termination(struct _starpu_mpi_req *req,nm_sr_event_t event);
 #ifdef STARPU_VERBOSE
 static char *_starpu_mpi_request_type(enum _starpu_mpi_request_type request_type);
@@ -761,3 +764,4 @@ void _starpu_mpi_progress_shutdown(int *value)
         STARPU_PTHREAD_COND_DESTROY(&progress_cond);
 }
 
+#endif /* STARPU_USE_MPI_NMAD*/

+ 8 - 3
nmad/src/starpu_mpi.c

@@ -36,6 +36,11 @@
 #include <core/topology.h>
 #include <core/workers.h>
 
+#if defined(STARPU_USE_MPI_MPI)
+#include <mpi/starpu_mpi_comm.h>
+#include <mpi/starpu_mpi_tag.h>
+#endif
+
 static struct _starpu_mpi_req *_starpu_mpi_isend_common(starpu_data_handle_t data_handle,
 							int dest, int data_tag, MPI_Comm comm,
 							unsigned detached, unsigned sync, int prio, void (*callback)(void *), void *arg,
@@ -211,7 +216,7 @@ int starpu_mpi_barrier(MPI_Comm comm)
 
 void _starpu_mpi_data_clear(starpu_data_handle_t data_handle)
 {
-#if defined(STARPU_MPI_MPI)
+#if defined(STARPU_USE_MPI_MPI)
 	_starpu_mpi_tag_data_release(data_handle);
 #endif
 	_starpu_mpi_cache_data_clear(data_handle);
@@ -233,7 +238,7 @@ void starpu_mpi_data_register_comm(starpu_data_handle_t data_handle, int tag, in
 		mpi_data->node_tag.rank = -1;
 		mpi_data->node_tag.comm = MPI_COMM_WORLD;
 		data_handle->mpi_data = mpi_data;
-#if defined(STARPU_MPI_MPI)
+#if defined(STARPU_USE_MPI_MPI)
 		_starpu_mpi_tag_data_register(data_handle, tag);
 #endif
 		_starpu_mpi_cache_data_init(data_handle);
@@ -249,7 +254,7 @@ void starpu_mpi_data_register_comm(starpu_data_handle_t data_handle, int tag, in
 		_STARPU_MPI_TRACE_DATA_SET_RANK(data_handle, rank);
 		mpi_data->node_tag.rank = rank;
 		mpi_data->node_tag.comm = comm;
-#if defined(STARPU_MPI_MPI)
+#if defined(STARPU_USE_MPI_MPI)
 		_starpu_mpi_comm_register(comm);
 #endif
 	}

+ 6 - 1
nmad/src/starpu_mpi_init.c

@@ -32,6 +32,11 @@
 #include <core/simgrid.h>
 #include <core/task.h>
 
+#if defined(STARPU_USE_MPI_MPI)
+#include <mpi/starpu_mpi_comm.h>
+#include <mpi/starpu_mpi_tag.h>
+#endif
+
 #ifdef STARPU_SIMGRID
 static int _mpi_world_size;
 static int _mpi_world_rank;
@@ -177,7 +182,7 @@ int starpu_mpi_shutdown(void)
 	_starpu_mpi_comm_amounts_display(stderr, rank);
 	_starpu_mpi_comm_amounts_shutdown();
 	_starpu_mpi_cache_shutdown(world_size);
-#if defined(STARPU_MPI_MPI)
+#if defined(STARPU_USE_MPI_MPI)
 	_starpu_mpi_tag_shutdown();
 	_starpu_mpi_comm_shutdown();
 #endif

+ 11 - 11
nmad/src/starpu_mpi_private.h

@@ -26,7 +26,7 @@
 #include <common/list.h>
 #include <common/prio_list.h>
 #include <core/simgrid.h>
-#if defined(STARPU_MPI_NMAD)
+#if defined(STARPU_USE_MPI_NMAD)
 #include <pioman.h>
 #include <nm_sendrecv_interface.h>
 #include <nm_session_interface.h>
@@ -157,7 +157,7 @@ int _starpu_debug_rank;
 #  define _STARPU_MPI_LOG_OUT()
 #endif
 
-#if defined(STARPU_MPI_MPI)
+#if defined(STARPU_USE_MPI_MPI)
 extern int _starpu_mpi_tag;
 #define _STARPU_MPI_TAG_ENVELOPE  _starpu_mpi_tag
 #define _STARPU_MPI_TAG_DATA      _starpu_mpi_tag+1
@@ -173,7 +173,7 @@ struct _starpu_mpi_envelope
 	int data_tag;
 	unsigned sync;
 };
-#endif /* STARPU_MPI_MPI */
+#endif /* STARPU_USE_MPI_MPI */
 
 enum _starpu_mpi_request_type
 {
@@ -217,7 +217,7 @@ LIST_TYPE(_starpu_mpi_req,
 
 	/* who are we talking to ? */
 	struct _starpu_mpi_node_tag node_tag;
-#if defined(STARPU_MPI_NMAD)
+#if defined(STARPU_USE_MPI_NMAD)
 	nm_gate_t gate;
 	nm_session_t session;
 #endif
@@ -225,10 +225,10 @@ LIST_TYPE(_starpu_mpi_req,
 	void (*func)(struct _starpu_mpi_req *);
 
 	MPI_Status *status;
-#if defined(STARPU_MPI_NMAD)
+#if defined(STARPU_USE_MPI_NMAD)
 	nm_sr_request_t data_request;
 	int waited;
-#elif defined(STARPU_MPI_MPI)
+#elif defined(STARPU_USE_MPI_MPI)
 	MPI_Request data_request;
 #endif
 
@@ -236,9 +236,9 @@ LIST_TYPE(_starpu_mpi_req,
 	unsigned sync;
 
 	int ret;
-#if defined(STARPU_MPI_NMAD)
+#if defined(STARPU_USE_MPI_NMAD)
 	piom_cond_t req_cond;
-#elif defined(STARPU_MPI_MPI)
+#elif defined(STARPU_USE_MPI_MPI)
 	starpu_pthread_mutex_t req_mutex;
 	starpu_pthread_cond_t req_cond;
 	starpu_pthread_mutex_t posted_mutex;
@@ -260,13 +260,13 @@ LIST_TYPE(_starpu_mpi_req,
 	void (*callback)(void *);
 
         /* in the case of user-defined datatypes, we need to send the size of the data */
-#if defined(STARPU_MPI_NMAD)
+#if defined(STARPU_USE_MPI_NMAD)
 	nm_sr_request_t size_req;
-#elif defined(STARPU_MPI_MPI)
+#elif defined(STARPU_USE_MPI_MPI)
 	MPI_Request size_req;
 #endif
 
-#if defined(STARPU_MPI_MPI)
+#if defined(STARPU_USE_MPI_MPI)
 	struct _starpu_mpi_envelope* envelope;
 
 	unsigned is_internal_req:1;

+ 8 - 3
nmad/tests/Makefile.am

@@ -101,7 +101,7 @@ AM_LDFLAGS = $(STARPU_OPENCL_LDFLAGS) $(STARPU_CUDA_LDFLAGS) $(FXT_LDFLAGS) $(ST
 
 if BUILD_TESTS
 
-starpu_mpi_TESTS =				
+starpu_mpi_TESTS =
 
 starpu_mpi_TESTS +=				\
 	cache					\
@@ -157,6 +157,11 @@ starpu_mpi_TESTS +=				\
 	gather					\
 	gather2
 
+if STARPU_USE_MPI_MPI
+starpu_mpi_TESTS +=				\
+	load_balancer
+endif
+
 # Expected to fail
 starpu_mpi_TESTS +=				\
 	policy_register_toomany			\
@@ -216,8 +221,8 @@ noinst_PROGRAMS =				\
 	policy_selection			\
 	policy_selection2			\
 	early_request				\
-	starpu_redefine
-
+	starpu_redefine				\
+	load_balancer
 
 XFAIL_TESTS=					\
 	policy_register_toomany			\

+ 75 - 0
nmad/tests/load_balancer.c

@@ -0,0 +1,75 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2017  CNRS
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+
+#include <starpu_mpi.h>
+#include <starpu_mpi_lb.h>
+#include "helper.h"
+
+#if !defined(STARPU_HAVE_UNSETENV) || !defined(STARPU_USE_MPI_MPI)
+
+#warning unsetenv is not defined. Skipping test
+int main(int argc, char **argv)
+{
+	return STARPU_TEST_SKIPPED;
+}
+#else
+
+void get_neighbors(int **neighbor_ids, int *nneighbors)
+{
+	int rank, size;
+	starpu_mpi_comm_rank(MPI_COMM_WORLD, &rank);
+	starpu_mpi_comm_size(MPI_COMM_WORLD, &size);
+	*nneighbors = 1;
+	*neighbor_ids = malloc(sizeof(int));
+	*neighbor_ids[0] = rank==size-1?0:rank+1;
+}
+
+void get_data_unit_to_migrate(starpu_data_handle_t **handle_unit, int *nhandles, int dst_node)
+{
+	*nhandles = 0;
+}
+
+int main(int argc, char **argv)
+{
+	int ret;
+	struct starpu_mpi_lb_conf itf;
+	int mpi_init;
+
+	itf.get_neighbors = get_neighbors;
+	itf.get_data_unit_to_migrate = get_data_unit_to_migrate;
+
+	MPI_INIT_THREAD(&argc, &argv, MPI_THREAD_SERIALIZED, &mpi_init);
+	ret = starpu_init(NULL);
+	STARPU_CHECK_RETURN_VALUE(ret, "starpu_init");
+	ret = starpu_mpi_init(NULL, NULL, mpi_init);
+	STARPU_CHECK_RETURN_VALUE(ret, "starpu_mpi_init");
+
+	unsetenv("STARPU_MPI_LB");
+	starpu_mpi_lb_init(NULL, NULL);
+	starpu_mpi_lb_shutdown();
+
+	starpu_mpi_lb_init("heat", &itf);
+	starpu_mpi_lb_shutdown();
+
+	starpu_mpi_shutdown();
+	starpu_shutdown();
+	if (!mpi_init)
+		MPI_Finalize();
+
+	return 0;
+}
+
+#endif