Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of https://framagit.org/simgrid/simgrid
[simgrid.git] / src / smpi / bindings / smpi_pmpi.cpp
1 /* Copyright (c) 2007-2019. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include "private.hpp"
7 #include "simgrid/instr.h"
8 #include "simgrid/s4u/Engine.hpp"
9 #include "simgrid/s4u/Host.hpp"
10 #include "smpi_comm.hpp"
11 #include "smpi_datatype_derived.hpp"
12 #include "smpi_status.hpp"
13 #include "src/kernel/actor/ActorImpl.hpp"
14 #include "src/smpi/include/smpi_actor.hpp"
15
16 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_pmpi, smpi, "Logging specific to SMPI (pmpi)");
17
18 //this function need to be here because of the calls to smpi_bench
19 void TRACE_smpi_set_category(const char *category)
20 {
21   //need to end bench otherwise categories for execution tasks are wrong
22   smpi_bench_end();
23   if (category != nullptr) {
24     // declare category
25     TRACE_category(category);
26     smpi_process()->set_tracing_category(category);
27   }
28   //begin bench after changing process's category
29   smpi_bench_begin();
30 }
31
32 /* PMPI User level calls */
33
34 int PMPI_Init(int*, char***)
35 {
36   xbt_assert(simgrid::s4u::Engine::is_initialized(),
37              "Your MPI program was not properly initialized. The easiest is to use smpirun to start it.");
38
39   // Init is called only once per SMPI process
40   if (not smpi_process()->initializing()){
41     simgrid::smpi::ActorExt::init();
42   }
43   if (not smpi_process()->initialized()){
44     int rank_traced = simgrid::s4u::this_actor::get_pid();
45     TRACE_smpi_init(rank_traced);
46     TRACE_smpi_comm_in(rank_traced, __func__, new simgrid::instr::NoOpTIData("init"));
47     TRACE_smpi_comm_out(rank_traced);
48     TRACE_smpi_computing_init(rank_traced);
49     TRACE_smpi_sleeping_init(rank_traced);
50     smpi_bench_begin();
51     smpi_process()->mark_as_initialized();
52   }
53
54   smpi_mpi_init();
55
56   return MPI_SUCCESS;
57 }
58
59 int PMPI_Finalize()
60 {
61   smpi_bench_end();
62   int rank_traced = simgrid::s4u::this_actor::get_pid();
63   TRACE_smpi_comm_in(rank_traced, __func__, new simgrid::instr::NoOpTIData("finalize"));
64
65   smpi_process()->finalize();
66
67   TRACE_smpi_comm_out(rank_traced);
68   TRACE_smpi_finalize(rank_traced);
69   return MPI_SUCCESS;
70 }
71
72 int PMPI_Finalized(int* flag)
73 {
74   *flag=smpi_process()!=nullptr ? smpi_process()->finalized() : 0;
75   return MPI_SUCCESS;
76 }
77
78 int PMPI_Get_version (int *version,int *subversion){
79   *version = MPI_VERSION;
80   *subversion= MPI_SUBVERSION;
81   return MPI_SUCCESS;
82 }
83
84 int PMPI_Get_library_version (char *version,int *len){
85   smpi_bench_end();
86   snprintf(version, MPI_MAX_LIBRARY_VERSION_STRING, "SMPI Version %d.%d. Copyright The Simgrid Team 2007-2019",
87            SIMGRID_VERSION_MAJOR, SIMGRID_VERSION_MINOR);
88   *len = strlen(version) > MPI_MAX_LIBRARY_VERSION_STRING ? MPI_MAX_LIBRARY_VERSION_STRING : strlen(version);
89   smpi_bench_begin();
90   return MPI_SUCCESS;
91 }
92
93 int PMPI_Init_thread(int* argc, char*** argv, int /*required*/, int* provided)
94 {
95   if (provided != nullptr) {
96     *provided = MPI_THREAD_SINGLE;
97   }
98   return MPI_Init(argc, argv);
99 }
100
101 int PMPI_Query_thread(int *provided)
102 {
103   if (provided == nullptr) {
104     return MPI_ERR_ARG;
105   } else {
106     *provided = MPI_THREAD_SINGLE;
107     return MPI_SUCCESS;
108   }
109 }
110
111 int PMPI_Is_thread_main(int *flag)
112 {
113   // FIXME: The MPI standard seems to say that fatal errors need to be triggered
114   // if MPI has been finalized or not yet been initialized
115   if (flag == nullptr) {
116     return MPI_ERR_ARG;
117   } else {
118     *flag = simgrid::s4u::this_actor::get_pid() ==
119             1; // FIXME: I don't think this is correct: This just returns true if the process ID is 1,
120                // regardless of whether this process called MPI_Thread_Init() or not.
121     return MPI_SUCCESS;
122   }
123 }
124
125 int PMPI_Abort(MPI_Comm /*comm*/, int /*errorcode*/)
126 {
127   smpi_bench_end();
128   // FIXME: should kill all processes in comm instead
129   smx_actor_t actor = SIMIX_process_self();
130   simgrid::simix::simcall([actor] { actor->exit(); });
131   return MPI_SUCCESS;
132 }
133
134 double PMPI_Wtime()
135 {
136   return smpi_mpi_wtime();
137 }
138
139 extern double sg_maxmin_precision;
140 double PMPI_Wtick()
141 {
142   return sg_maxmin_precision;
143 }
144
145 int PMPI_Address(const void* location, MPI_Aint* address)
146 {
147   if (address==nullptr) {
148     return MPI_ERR_ARG;
149   } else {
150     *address = reinterpret_cast<MPI_Aint>(location);
151     return MPI_SUCCESS;
152   }
153 }
154
155 int PMPI_Get_address(const void *location, MPI_Aint * address)
156 {
157   return PMPI_Address(location, address);
158 }
159
160 int PMPI_Get_processor_name(char *name, int *resultlen)
161 {
162   strncpy(name, sg_host_self()->get_cname(),
163           strlen(sg_host_self()->get_cname()) < MPI_MAX_PROCESSOR_NAME - 1 ? strlen(sg_host_self()->get_cname()) + 1
164                                                                            : MPI_MAX_PROCESSOR_NAME - 1);
165   *resultlen = strlen(name) > MPI_MAX_PROCESSOR_NAME ? MPI_MAX_PROCESSOR_NAME : strlen(name);
166
167   return MPI_SUCCESS;
168 }
169
170 int PMPI_Get_count(const MPI_Status * status, MPI_Datatype datatype, int *count)
171 {
172   if (status == nullptr || count == nullptr) {
173     return MPI_ERR_ARG;
174   } else if (not datatype->is_valid()) {
175     return MPI_ERR_TYPE;
176   } else {
177     size_t size = datatype->size();
178     if (size == 0) {
179       *count = 0;
180       return MPI_SUCCESS;
181     } else if (status->count % size != 0) {
182       return MPI_UNDEFINED;
183     } else {
184       *count = simgrid::smpi::Status::get_count(status, datatype);
185       return MPI_SUCCESS;
186     }
187   }
188 }
189
190 int PMPI_Initialized(int* flag) {
191    *flag=(smpi_process()!=nullptr && smpi_process()->initialized());
192    return MPI_SUCCESS;
193 }
194
195 int PMPI_Alloc_mem(MPI_Aint size, MPI_Info /*info*/, void* baseptr)
196 {
197   void *ptr = xbt_malloc(size);
198   if(ptr==nullptr)
199     return MPI_ERR_NO_MEM;
200   else {
201     *static_cast<void**>(baseptr) = ptr;
202     return MPI_SUCCESS;
203   }
204 }
205
206 int PMPI_Free_mem(void *baseptr){
207   xbt_free(baseptr);
208   return MPI_SUCCESS;
209 }
210
211 int PMPI_Error_class(int errorcode, int* errorclass) {
212   // assume smpi uses only standard mpi error codes
213   *errorclass=errorcode;
214   return MPI_SUCCESS;
215 }
216
217 int PMPI_Error_string(int errorcode, char* string, int* resultlen)
218 {
219   static const char* smpi_error_string[] = {FOREACH_ERROR(GENERATE_STRING)};
220   constexpr int nerrors                  = (sizeof smpi_error_string) / (sizeof smpi_error_string[0]);
221   if (errorcode < 0 || errorcode >= nerrors || string == nullptr)
222     return MPI_ERR_ARG;
223
224   int len    = snprintf(string, MPI_MAX_ERROR_STRING, "%s", smpi_error_string[errorcode]);
225   *resultlen = std::min(len, MPI_MAX_ERROR_STRING - 1);
226   return MPI_SUCCESS;
227 }
228
229 int PMPI_Keyval_create(MPI_Copy_function* copy_fn, MPI_Delete_function* delete_fn, int* keyval, void* extra_state) {
230   smpi_copy_fn _copy_fn={copy_fn,nullptr,nullptr,nullptr,nullptr,nullptr};
231   smpi_delete_fn _delete_fn={delete_fn,nullptr,nullptr,nullptr,nullptr,nullptr};
232   return simgrid::smpi::Keyval::keyval_create<simgrid::smpi::Comm>(_copy_fn, _delete_fn, keyval, extra_state);
233 }
234
235 int PMPI_Keyval_free(int* keyval) {
236   return simgrid::smpi::Keyval::keyval_free<simgrid::smpi::Comm>(keyval);
237 }