Logo AND Algorithmique Numérique Distribuée

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