Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
fix dist
[simgrid.git] / src / mc / mc_smx.cpp
1 /* Copyright (c) 2015-2017. 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 <cassert>
7 #include <cstddef>
8 #include <cstdlib>
9
10 #include <memory>
11 #include <type_traits>
12 #include <utility>
13 #include <vector>
14
15 #include <xbt/log.h>
16 #include <xbt/str.h>
17 #include <xbt/swag.h>
18
19 #include <simgrid/s4u/host.hpp>
20
21 #include "src/simix/smx_private.h"
22 #include "src/mc/mc_smx.h"
23 #include "src/mc/ModelChecker.hpp"
24
25 using simgrid::mc::remote;
26
27 /** HACK, Statically "upcast" a s_smx_actor_t into a ActorInformation
28  *
29  *  This gets 'actorInfo' from '&actorInfo->copy'. It upcasts in the
30  *  sense that we could achieve the same thing by having ActorInformation
31  *  inherit from s_smx_actor_t but we don't really want to do that.
32  */
33 static inline simgrid::mc::ActorInformation* actor_info_cast(smx_actor_t actor)
34 {
35   simgrid::mc::ActorInformation temp;
36   std::size_t offset = (char*) temp.copy.getBuffer() - (char*)&temp;
37
38   simgrid::mc::ActorInformation* process_info = (simgrid::mc::ActorInformation*)((char*)actor - offset);
39   return process_info;
40 }
41
42 /** Load the remote swag of processes into a vector
43  *
44  *  @param process     MCed process
45  *  @param target      Local vector (to be filled with copies of `s_smx_actor_t`)
46  *  @param remote_swag Address of the process SWAG in the remote list
47  */
48 static void MC_process_refresh_simix_process_list(simgrid::mc::Process* process,
49                                                   std::vector<simgrid::mc::ActorInformation>& target,
50                                                   simgrid::mc::RemotePtr<s_xbt_swag_t> remote_swag)
51 {
52   target.clear();
53
54   // swag = REMOTE(*simix_global->process_list)
55   s_xbt_swag_t swag;
56   process->read_bytes(&swag, sizeof(swag), remote_swag);
57
58   // Load each element of the vector from the MCed process:
59   int i = 0;
60   for (smx_actor_t p = (smx_actor_t) swag.head; p; ++i) {
61
62     simgrid::mc::ActorInformation info;
63     info.address = p;
64     info.hostname = nullptr;
65     process->read_bytes(&info.copy, sizeof(info.copy), remote(p));
66     target.push_back(std::move(info));
67
68     // Lookup next process address:
69     p = (smx_actor_t) xbt_swag_getNext(&info.copy, swag.offset);
70   }
71   assert(i == swag.count);
72 }
73
74 static void MC_process_refresh_simix_actor_dynar(simgrid::mc::Process* process,
75                                                  std::vector<simgrid::mc::ActorInformation>& target,
76                                                  simgrid::mc::RemotePtr<s_xbt_dynar_t> remote_dynar)
77 {
78   target.clear();
79
80   s_xbt_dynar_t dynar;
81   process->read_bytes(&dynar, sizeof(dynar), remote_dynar);
82
83   smx_actor_t* data = (smx_actor_t*)malloc(dynar.elmsize * dynar.used);
84   process->read_bytes(data, dynar.elmsize * dynar.used, dynar.data);
85
86   // Load each element of the vector from the MCed process:
87   for (unsigned int i = 0; i < dynar.used; ++i) {
88
89     simgrid::mc::ActorInformation info;
90     info.address  = data[i];
91     info.hostname = nullptr;
92     process->read_bytes(&info.copy, sizeof(info.copy), remote(data[i]));
93     target.push_back(std::move(info));
94   }
95   free(data);
96 }
97 namespace simgrid {
98 namespace mc {
99
100 void Process::refresh_simix()
101 {
102   if (this->cache_flags_ & Process::cache_simix_processes)
103     return;
104
105   // TODO, avoid to reload `&simix_global`, `simix_global`, `*simix_global`
106
107   static_assert(std::is_same<
108       std::unique_ptr<simgrid::simix::Global>,
109       decltype(simix_global)
110     >::value, "Unexpected type for simix_global");
111   static_assert(sizeof(simix_global) == sizeof(simgrid::simix::Global*),
112     "Bad size for simix_global");
113
114   // simix_global_p = REMOTE(simix_global.get());
115   RemotePtr<simgrid::simix::Global> simix_global_p =
116     this->read_variable<simgrid::simix::Global*>("simix_global");
117
118   // simix_global = REMOTE(*simix_global)
119   Remote<simgrid::simix::Global> simix_global =
120     this->read<simgrid::simix::Global>(simix_global_p);
121
122   MC_process_refresh_simix_actor_dynar(this, this->smx_actors_infos, remote(simix_global.getBuffer()->actors_vector));
123   MC_process_refresh_simix_process_list(this, this->smx_dead_actors_infos,
124                                         remote(simix_global.getBuffer()->process_to_destroy));
125
126   this->cache_flags_ |= Process::cache_simix_processes;
127 }
128
129 }
130 }
131
132 /** Get the issuer of a simcall (`req->issuer`)
133  *
134  *  In split-process mode, it does the black magic necessary to get an address
135  *  of a (shallow) copy of the data structure the issuer SIMIX actor in the local
136  *  address space.
137  *
138  *  @param process the MCed process
139  *  @param req     the simcall (copied in the local process)
140  */
141 smx_actor_t MC_smx_simcall_get_issuer(s_smx_simcall_t const* req)
142 {
143   xbt_assert(mc_model_checker != nullptr);
144
145   // This is the address of the smx_actor in the MCed process:
146   auto address = simgrid::mc::remote(req->issuer);
147
148   // Lookup by address:
149   for (auto& actor : mc_model_checker->process().actors())
150     if (actor.address == address)
151       return actor.copy.getBuffer();
152   for (auto& actor : mc_model_checker->process().dead_actors())
153     if (actor.address == address)
154       return actor.copy.getBuffer();
155
156   xbt_die("Issuer not found");
157 }
158
159 const char* MC_smx_actor_get_host_name(smx_actor_t actor)
160 {
161   if (mc_model_checker == nullptr)
162     return actor->host->cname();
163
164   simgrid::mc::Process* process = &mc_model_checker->process();
165
166   /* HACK, Horrible hack to find the offset of the id in the simgrid::s4u::Host.
167
168      Offsetof is not supported for non-POD types but this should
169      work in practice for the targets currently supported by the MC
170      as long as we do not add funny features to the Host class
171      (such as virtual base).
172
173      We are using a (C++11) unrestricted union in order to avoid
174      any construction/destruction of the simgrid::s4u::Host.
175   */
176   union fake_host {
177     simgrid::s4u::Host host;
178     fake_host() {}
179     ~fake_host() {}
180   };
181   fake_host foo;
182   const size_t offset = (char*) &foo.host.name() - (char*) &foo.host;
183
184   // Read the simgrid::xbt::string in the MCed process:
185   simgrid::mc::ActorInformation* info     = actor_info_cast(actor);
186   auto remote_string_address              = remote((simgrid::xbt::string_data*)((char*)actor->host + offset));
187   simgrid::xbt::string_data remote_string = process->read(remote_string_address);
188   char hostname[remote_string.len];
189   process->read_bytes(hostname, remote_string.len + 1, remote(remote_string.data));
190   info->hostname = mc_model_checker->get_host_name(hostname).c_str();
191   return info->hostname;
192 }
193
194 const char* MC_smx_actor_get_name(smx_actor_t actor)
195 {
196   simgrid::mc::Process* process = &mc_model_checker->process();
197   if (mc_model_checker == nullptr)
198     return actor->name.c_str();
199
200   simgrid::mc::ActorInformation* info = actor_info_cast(actor);
201   if (info->name.empty()) {
202     simgrid::xbt::string_data string_data = (simgrid::xbt::string_data&)actor->name;
203     info->name = process->read_string(remote(string_data.data), string_data.len);
204   }
205   return info->name.c_str();
206 }
207
208 #if HAVE_SMPI
209 int MC_smpi_process_count(void)
210 {
211   if (mc_model_checker == nullptr)
212     return smpi_process_count();
213   int res;
214   mc_model_checker->process().read_variable("process_count",
215     &res, sizeof(res));
216   return res;
217 }
218 #endif
219
220 unsigned long MC_smx_get_maxpid(void)
221 {
222   unsigned long maxpid;
223   mc_model_checker->process().read_variable("simix_process_maxpid",
224     &maxpid, sizeof(maxpid));
225   return maxpid;
226 }