Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
6645e768ba5129863d4fd7b00a4ea181eddd1153
[simgrid.git] / src / kernel / activity / ExecImpl.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 "src/kernel/activity/ExecImpl.hpp"
7 #include "simgrid/Exception.hpp"
8 #include "simgrid/modelchecker.h"
9 #include "src/mc/mc_replay.hpp"
10 #include "src/simix/smx_host_private.hpp"
11 #include "src/surf/cpu_interface.hpp"
12 #include "src/surf/surf_interface.hpp"
13
14 #include "simgrid/s4u/Host.hpp"
15
16 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(simix_process);
17
18 void simcall_HANDLER_execution_wait(smx_simcall_t simcall, simgrid::kernel::activity::ExecImpl* synchro)
19 {
20   XBT_DEBUG("Wait for execution of synchro %p, state %d", synchro, (int)synchro->state_);
21
22   /* Associate this simcall to the synchro */
23   synchro->simcalls_.push_back(simcall);
24   simcall->issuer->waiting_synchro = synchro;
25
26   /* set surf's synchro */
27   if (MC_is_active() || MC_record_replay_is_active()) {
28     synchro->state_ = SIMIX_DONE;
29     synchro->finish();
30     return;
31   }
32
33   /* If the synchro is already finished then perform the error handling */
34   if (synchro->state_ != SIMIX_RUNNING)
35     synchro->finish();
36 }
37
38 void simcall_HANDLER_execution_test(smx_simcall_t simcall, simgrid::kernel::activity::ExecImpl* synchro)
39 {
40   int res = (synchro->state_ != SIMIX_WAITING && synchro->state_ != SIMIX_RUNNING);
41   if (res) {
42     synchro->simcalls_.push_back(simcall);
43     synchro->finish();
44   } else {
45     SIMIX_simcall_answer(simcall);
46   }
47   simcall_execution_test__set__result(simcall, res);
48 }
49
50 namespace simgrid {
51 namespace kernel {
52 namespace activity {
53
54 ExecImpl::ExecImpl(std::string name, std::string tracing_category, s4u::Host* host)
55     : ActivityImpl(std::move(name)), host_(host)
56 {
57   this->state_ = SIMIX_RUNNING;
58   this->set_category(std::move(tracing_category));
59
60   XBT_DEBUG("Create exec %p", this);
61 }
62
63 ExecImpl::ExecImpl(std::string name, std::string tracing_category, s4u::Host* host, double timeout)
64     : ExecImpl(std::move(name), std::move(tracing_category), nullptr)
65 {
66   if (timeout > 0 && not MC_is_active() && not MC_record_replay_is_active()) {
67     timeout_detector_ = host->pimpl_cpu->sleep(timeout);
68     timeout_detector_->set_data(this);
69   }
70   XBT_DEBUG("Create exec %p", this);
71 }
72
73 ExecImpl::~ExecImpl()
74 {
75   if (surf_action_)
76     surf_action_->unref();
77   if (timeout_detector_)
78     timeout_detector_->unref();
79   XBT_DEBUG("Destroy exec %p", this);
80 }
81
82 ExecImpl* ExecImpl::start(double flops_amount, double priority, double bound)
83 {
84   if (not MC_is_active() && not MC_record_replay_is_active()) {
85     surf_action_ = host_->pimpl_cpu->execution_start(flops_amount);
86     surf_action_->set_data(this);
87     surf_action_->set_priority(priority);
88     if (bound > 0)
89       surf_action_->set_bound(bound);
90   }
91
92   XBT_DEBUG("Create execute synchro %p: %s", this, get_cname());
93   ExecImpl::on_creation(this);
94   return this;
95 }
96
97 void ExecImpl::cancel()
98 {
99   XBT_VERB("This exec %p is canceled", this);
100   if (surf_action_ != nullptr)
101     surf_action_->cancel();
102 }
103
104 double ExecImpl::get_remaining()
105 {
106   xbt_assert(host_ != nullptr, "Calling remains() on a parallel execution is not allowed. "
107                                "We would need to return a vector instead of a scalar. "
108                                "Did you mean remainingRatio() instead?");
109   return surf_action_ ? surf_action_->get_remains() : 0;
110 }
111
112 double ExecImpl::get_remaining_ratio()
113 {
114   if (host_ ==
115       nullptr) // parallel task: their remain is already between 0 and 1 (see comment in ExecImpl::get_remaining())
116     return (surf_action_ == nullptr) ? 0 : surf_action_->get_remains();
117   else // Actually compute the ratio for sequential tasks
118     return (surf_action_ == nullptr) ? 0 : surf_action_->get_remains() / surf_action_->get_cost();
119 }
120
121 void ExecImpl::set_bound(double bound)
122 {
123   if (surf_action_)
124     surf_action_->set_bound(bound);
125 }
126 void ExecImpl::set_priority(double priority)
127 {
128   if (surf_action_)
129     surf_action_->set_priority(priority);
130 }
131
132 void ExecImpl::post()
133 {
134   if (host_ && not host_->is_on()) { /* FIXME: handle resource failure for parallel tasks too */
135     /* If the host running the synchro failed, notice it. This way, the asking
136      * process can be killed if it runs on that host itself */
137     state_ = SIMIX_FAILED;
138   } else if (surf_action_ && surf_action_->get_state() == resource::Action::State::FAILED) {
139     /* If the host running the synchro didn't fail, then the synchro was canceled */
140     state_ = SIMIX_CANCELED;
141   } else if (timeout_detector_ && timeout_detector_->get_state() == resource::Action::State::FINISHED) {
142     state_ = SIMIX_TIMEOUT;
143   } else {
144     state_ = SIMIX_DONE;
145   }
146
147   on_completion(this);
148
149   if (surf_action_) {
150     surf_action_->unref();
151     surf_action_ = nullptr;
152   }
153   if (timeout_detector_) {
154     timeout_detector_->unref();
155     timeout_detector_ = nullptr;
156   }
157
158   /* If there are simcalls associated with the synchro, then answer them */
159   if (not simcalls_.empty())
160     finish();
161 }
162
163 void ExecImpl::finish()
164 {
165   while (not simcalls_.empty()) {
166     smx_simcall_t simcall = simcalls_.front();
167     simcalls_.pop_front();
168     switch (state_) {
169
170       case SIMIX_DONE:
171         /* do nothing, synchro done */
172         XBT_DEBUG("ExecImpl::finish(): execution successful");
173         break;
174
175       case SIMIX_FAILED:
176         XBT_DEBUG("ExecImpl::finish(): host '%s' failed", simcall->issuer->get_host()->get_cname());
177         simcall->issuer->context_->iwannadie = true;
178         if (simcall->issuer->get_host()->is_on())
179           simcall->issuer->exception_ =
180               std::make_exception_ptr(simgrid::HostFailureException(XBT_THROW_POINT, "Host failed"));
181         /* else, the actor will be killed with no possibility to survive */
182         break;
183
184       case SIMIX_CANCELED:
185         XBT_DEBUG("ExecImpl::finish(): execution canceled");
186         simcall->issuer->exception_ =
187             std::make_exception_ptr(simgrid::CancelException(XBT_THROW_POINT, "Execution Canceled"));
188         break;
189
190       case SIMIX_TIMEOUT:
191         XBT_DEBUG("ExecImpl::finish(): execution timeouted");
192         simcall->issuer->exception_ = std::make_exception_ptr(simgrid::TimeoutError(XBT_THROW_POINT, "Timeouted"));
193         break;
194
195       default:
196         xbt_die("Internal error in ExecImpl::finish(): unexpected synchro state %d", static_cast<int>(state_));
197     }
198
199     simcall->issuer->waiting_synchro = nullptr;
200     simcall_execution_wait__set__result(simcall, state_);
201
202     /* Fail the process if the host is down */
203     if (simcall->issuer->get_host()->is_on())
204       SIMIX_simcall_answer(simcall);
205     else
206       simcall->issuer->context_->iwannadie = true;
207   }
208 }
209
210 ActivityImpl* ExecImpl::migrate(simgrid::s4u::Host* to)
211 {
212   if (not MC_is_active() && not MC_record_replay_is_active()) {
213     resource::Action* old_action = this->surf_action_;
214     resource::Action* new_action = to->pimpl_cpu->execution_start(old_action->get_cost());
215     new_action->set_remains(old_action->get_remains());
216     new_action->set_data(this);
217     new_action->set_priority(old_action->get_priority());
218
219     // FIXME: the user-defined bound seem to not be kept by LMM, that seem to overwrite it for the multi-core modeling.
220     // I hope that the user did not provide any.
221
222     old_action->set_data(nullptr);
223     old_action->cancel();
224     old_action->unref();
225     this->surf_action_ = new_action;
226   }
227
228   on_migration(this, to);
229   return this;
230 }
231
232 /*************
233  * Callbacks *
234  *************/
235 xbt::signal<void(ExecImplPtr)> ExecImpl::on_creation;
236 xbt::signal<void(ExecImplPtr)> ExecImpl::on_completion;
237 xbt::signal<void(ExecImplPtr, s4u::Host*)> ExecImpl::on_migration;
238
239 } // namespace activity
240 } // namespace kernel
241 } // namespace simgrid