Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
ae5613b800c6a7528323926dc688809ae0be7627
[simgrid.git] / doc / doxygen / uhood.doc
1 /*! @page uhood Under the Hood
2
3 \tableofcontents
4
5 TBD
6
7  - Simulation Loop, LMM, sharing -> papers
8  - Context Switching, privatization -> papers
9  - @subpage inside
10
11 \section simgrid_uhood_s4u S4U
12
13 S4U classes are designed to be user process interfaces to Maestro resources.
14 We provide an uniform interface to them:
15
16 * automatic reference count with intrusive smart pointers `simgrid::s4u::FooPtr`
17   (also called `simgrid::s4u::Foo::Ptr`);
18
19 * manual reference count with `intrusive_ptr_add_ref(p)`,
20   `intrusive_ptr_release(p)` (which is the interface used by
21   [`boost::intrusive_ptr`](http://www.boost.org/doc/libs/1_61_0/libs/smart_ptr/intrusive_ptr.html));
22
23 * delegation of the operations to a opaque `pimpl` (which is the Maestro object);
24
25 * the Maestro object and the corresponding S4U object have the same lifetime
26   (and share the same reference count).
27
28 The ability to manipulate thge objects thought pointers and have the ability
29 to use explicite reference count management is useful for creating C wrappers
30 to the S4U and should play nicely with other language bindings (such as
31 SWIG-based ones).
32
33 Some objects currently live for the whole duration of the simulation and do
34 not have refertence counts. We still provide dummy `intrusive_ptr_add_ref(p)`,
35 `intrusive_ptr_release(p)` and `FooPtr` for consistency.
36
37 In many cases, we try to have a API which is consistent with the API or
38 corresponding C++ standard classes. For example, the methods of
39 `simgrid::s4u::Mutex` are based on [`std::mutex`](http://en.cppreference.com/w/cpp/thread/mutex).
40 This has several benefits:
41
42  * we use a proven interface with a well defined and documented semantic;
43
44  * the interface is easy to understand and remember for people used to the C++
45    standard interface;
46
47  * we can use some standard C++ algorithms and helper classes with our types
48    (`simgrid::s4u::Mutex` can be used with
49    [`std::lock`](http://en.cppreference.com/w/cpp/thread/lock),
50    [`std::unique_lock`](http://en.cppreference.com/w/cpp/thread/unique_lock),
51    etc.).
52
53 Example of `simgris::s4u::Actor`:
54
55 ~~~
56 class Actor {
57   // This is the corresponding maestro object:
58   friend simgrid::simix::Process;
59   simgrid::simix::Process* pimpl_ = nullptr;
60 public:
61
62   Actor(simgrid::simix::Process* pimpl) : pimpl_(pimpl) {}
63   Actor(Actor const&) = delete;
64   Actor& operator=(Actor const&) = delete;
65
66   // Reference count is delegated to the S4u object:
67   friend void intrusive_ptr_add_ref(Actor* actor)
68   {
69     xbt_assert(actor != nullptr);
70     SIMIX_process_ref(actor->pimpl_);
71   }
72   friend void intrusive_ptr_release(Actor* actor)
73   {
74     xbt_assert(actor != nullptr);
75     SIMIX_process_unref(actor->pimpl_);
76   }
77   using Ptr = boost::intrusive_ptr<Actor>;
78
79   // Create processes:
80   static Ptr createActor(const char* name, s4u::Host *host, double killTime, std::function<void()> code);
81
82   // [...]
83 };
84
85 using ActorPtr = Actor::Ptr;
86 ~~~
87
88 It uses the `simgrid::simix::Process` as a opaque pimple:
89
90 ~~~
91 class Process {
92 private:
93   std::atomic_int_fast32_t refcount_ { 1 };
94   // The lifetime of the s4u::Actor is bound to the lifetime of the Process:
95   simgrid::s4u::Actor actor_;
96 public:
97   Process() : actor_(this) {}
98
99   // Reference count:
100   friend void intrusive_ptr_add_ref(Process* process)
101   {
102     // Atomic operation! Do not split in two instructions!
103     auto previous = (process->refcount_)++;
104     xbt_assert(previous != 0);
105     (void) previous;
106   }
107   friend void intrusive_ptr_release(Process* process)
108   {
109     // Atomic operation! Do not split in two instructions!
110     auto count = --(process->refcount_);
111     if (count == 0)
112       delete process;
113   }
114
115   // [...]
116 };
117
118 smx_process_t SIMIX_process_ref(smx_process_t process)
119 {
120   if (process != nullptr)
121     intrusive_ptr_add_ref(process);
122   return process;
123 }
124
125 /** Decrease the refcount for this process */
126 void SIMIX_process_unref(smx_process_t process)
127 {
128   if (process != nullptr)
129     intrusive_ptr_release(process);
130 }
131 ~~~
132
133 \section simgrid_uhood_async Asynchronous operations
134
135 \subsection simgrid_uhood_futures Futures
136
137 The `simgrid::kernel::Future` class has been added to SimGrid as an abstraction
138 to represent asynchronous operations in the SimGrid maestro. Its API is based
139 on `std::experimental::future` from the [C++ Extensions for Concurrency Technical
140 Specification](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0159r0.html):
141
142  - `simgrid::kernel::Future<T>` represents the result an asynchronous operations
143     in the simulation inside the SimGrid maestro/kernel;
144
145  - `simgrid::kernel::Promise<T>` can be used to set the value of an assocaiated
146    `simgrid::kernel::Future<T>`.
147
148 The expected way to work with `simgrid::kernel::Future<T>` is to add a
149 completion handler/continuation:
150
151 ~~~
152 // This code is executed in the maestro context, we cannot block for the result
153 // to be ready:
154 simgrid::kernel::Future<std::vector<char>> result = simgrid::kernel::readFile(file);
155
156 // Add a completion handler:
157 result.then([file](simgrid::kernel::Future<std::vector<char>> result) {
158   // At this point, the operation is complete and we can safely call .get():
159   xbt_assert(result.is_ready());
160   try {
161     std::vector<char> data = result.get();
162     XBT_DEBUG("Finished reading file %s: length %zu", file.c_str(), data.size());
163   }
164   // If the operation failed, .get() throws an exception:
165   catch (std::runtime_error& e) {
166     XBT_ERROR("Could not read file %s", file.c_str());
167   }
168 });
169 ~~~
170
171 The SimGrid kernel cannot block so calling `.get()` or `.wait()` on a
172 `simgrid::kernel::Future<T>` which is not ready will deadlock. In practice, the
173 simulator detects this and aborts after reporting an error.
174
175 In order to generate your own future, you might need to use a
176 `simgrid::kernel::Promise<T>`. The promise is a one-way channel which can be
177 used to set the result of an associated `simgrid::kernel::Future<T>`
178 (with either `.set_value()` or `.set_exception()`):
179
180 ~~~
181 simgrid::kernel::Future<void> kernel_wait_until(double date)
182 {
183   auto promise = std::make_shared<simgrid::kernel::Promise<void>>();
184   auto future = promise->get_future();
185   SIMIX_timer_set(date, [promise] {
186     promise->set_value();
187   });
188   return future;
189 }
190 ~~~
191
192 Like the experimental futures, we support chaining `.then()` methods with
193 automatic future unwrapping.
194 You might want to look at some [tutorial on C++ futures](https://www.youtube.com/watch?v=mPxIegd9J3w&list=PLHTh1InhhwT75gykhs7pqcR_uSiG601oh&index=43)
195 for more details and examples. Some operations of the proposed experimental
196 futures are currently not implemented in our futures however such as
197 `.wait_for()`, `.wait_until()`,
198 [`shared_future`](http://en.cppreference.com/w/cpp/thread/shared_future),
199 [`when_any()`](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0159r0.html#futures.when_any).
200
201 \subsection simgrid_uhood_timer Timers
202
203 \section simgrid_uhood_mc Model Checker
204
205 The current implementation of the model-checker uses two distinct processes:
206
207  - the SimGrid model-checker (`simgrid-mc`) itself lives in the parent process;
208
209  - it spaws a child process for the SimGrid simulator/mastro and the simulated
210    processes.
211
212 They communicate using a `AF_UNIX` `SOCK_DGRAM` socket and exchange messages
213 defined in `mc_protocol.h`. The `SIMGRID_MC_SOCKET_FD` environment variable it
214 set to the file descriptor of this socket in the child process.
215
216 The model-checker analyzes, saves and restores the state of the model-checked
217 process using the following techniques:
218
219 * the model-checker reads and writes in the model-checked address space;
220
221 * the model-cheker `ptrace()`s the model-checked process and is thus able to
222   know the state of the model-checked process if it crashes;
223
224 * DWARF debug informations are used to unwind the stack and identify local
225   variables;
226
227 * a custom heap is enabled in the model-checked process which allows the model
228   checker to know which chunks are allocated and which are freed.
229
230 \subsection simgrid_uhood_mc_address_space Address space
231
232 The `AddressSpace` is a base class used for both the model-checked process
233 and its snapshots and has methods to read in the corresponding address space:
234
235  - the `Process` class is a subclass representing the model-checked process;
236
237  - the `Snapshot` class is a subclass representing a snapshot of the process.
238
239 Additional helper class include:
240
241  - `Remote<T>` is the result of reading a `T` in a remote AddressSpace. For
242     trivial types (int, etc.), it is convertible t o `T`;
243
244  - `RemotePtr<T>` represents the address of an object of type `T` in some
245     remote `AddressSpace` (it could be an alias to `Remote<T*>`).
246
247 \subsection simgrid_uhood_mc_address_elf_dwarf ELF and DWARF
248
249 [ELF](http://refspecs.linuxbase.org/elf/elf.pdf) is a standard executable file
250 and dynamic libraries file format.
251 [DWARF](http://dwarfstd.org/) is a standard for debug informations.
252 Both are used on GNU/Linux systems and exploited by the model-checker to
253 understand the model-checked process:
254
255  - `ObjectInformation` represents the informations about a given ELF module
256    (executable or shared-object);
257
258  - `Frame` represents a subprogram scope (either a subprogram or a scope within
259     the subprogram);
260
261  - `Type` represents a type (eg. `char*`, `int`, `std::string`) and is referenced
262     by variables (global, variables, parameters), functions (return type),
263     and other types (type of a `struct` field, etc.);
264
265  - `LocationList` and `DwarfExpression` are used to describe the location of
266     variables.
267
268 */