Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Remove unused typedefs.
[simgrid.git] / src / surf / cpu_ti.cpp
1 /* Copyright (c) 2013-2017. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include "cpu_ti.hpp"
8 #include "src/surf/trace_mgr.hpp"
9 #include "xbt/utility.hpp"
10 #include <algorithm>
11
12 #ifndef SURF_MODEL_CPUTI_H_
13 #define SURF_MODEL_CPUTI_H_
14
15 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_cpu_ti, surf_cpu, "Logging specific to the SURF CPU TRACE INTEGRATION module");
16
17 namespace simgrid {
18 namespace surf {
19
20 /*********
21  * Trace *
22  *********/
23
24 CpuTiTrace::CpuTiTrace(tmgr_trace_t speedTrace)
25 {
26   double integral = 0;
27   double time = 0;
28   int i = 0;
29   nbPoints_ = speedTrace->event_list.size() + 1;
30   timePoints_ = new double[nbPoints_];
31   integral_ =  new double[nbPoints_];
32   for (auto const& val : speedTrace->event_list) {
33     timePoints_[i] = time;
34     integral_[i] = integral;
35     integral += val.date_ * val.value_;
36     time += val.date_;
37     i++;
38   }
39   timePoints_[i] = time;
40   integral_[i] = integral;
41 }
42
43 CpuTiTrace::~CpuTiTrace()
44 {
45   delete [] timePoints_;
46   delete [] integral_;
47 }
48
49 CpuTiTgmr::~CpuTiTgmr()
50 {
51   if (trace_)
52     delete trace_;
53 }
54
55 /**
56 * \brief Integrate trace
57 *
58 * Wrapper around surf_cpu_integrate_trace_simple() to get
59 * the cyclic effect.
60 *
61 * \param a      Begin of interval
62 * \param b      End of interval
63 * \return the integrate value. -1 if an error occurs.
64 */
65 double CpuTiTgmr::integrate(double a, double b)
66 {
67   int a_index;
68
69   if ((a < 0.0) || (a > b)) {
70     xbt_die("Error, invalid integration interval [%.2f,%.2f]. "
71         "You probably have a task executing with negative computation amount. Check your code.", a, b);
72   }
73   if (fabs(a -b) < EPSILON)
74     return 0.0;
75
76   if (type_ == TRACE_FIXED) {
77     return ((b - a) * value_);
78   }
79
80   if (fabs(ceil(a / lastTime_) - a / lastTime_) < EPSILON)
81     a_index = 1 + static_cast<int>(ceil(a / lastTime_));
82   else
83     a_index = static_cast<int> (ceil(a / lastTime_));
84
85   int b_index = static_cast<int> (floor(b / lastTime_));
86
87   if (a_index > b_index) {      /* Same chunk */
88     return trace_->integrateSimple(a - (a_index - 1) * lastTime_, b - (b_index) * lastTime_);
89   }
90
91   double first_chunk = trace_->integrateSimple(a - (a_index - 1) * lastTime_, lastTime_);
92   double middle_chunk = (b_index - a_index) * total_;
93   double last_chunk = trace_->integrateSimple(0.0, b - (b_index) * lastTime_);
94
95   XBT_DEBUG("first_chunk=%.2f  middle_chunk=%.2f  last_chunk=%.2f\n", first_chunk, middle_chunk, last_chunk);
96
97   return (first_chunk + middle_chunk + last_chunk);
98 }
99
100 /**
101  * \brief Auxiliary function to compute the integral between a and b.
102  *     It simply computes the integrals at point a and b and returns the difference between them.
103  * \param a  Initial point
104  * \param b  Final point
105 */
106 double CpuTiTrace::integrateSimple(double a, double b)
107 {
108   return integrateSimplePoint(b) - integrateSimplePoint(a);
109 }
110
111 /**
112  * \brief Auxiliary function to compute the integral at point a.
113  * \param a        point
114  */
115 double CpuTiTrace::integrateSimplePoint(double a)
116 {
117   double integral = 0;
118   double a_aux = a;
119   int ind = binarySearch(timePoints_, a, 0, nbPoints_ - 1);
120   integral += integral_[ind];
121
122   XBT_DEBUG("a %f ind %d integral %f ind + 1 %f ind %f time +1 %f time %f",
123        a, ind, integral, integral_[ind + 1], integral_[ind], timePoints_[ind + 1], timePoints_[ind]);
124   double_update(&a_aux, timePoints_[ind], sg_maxmin_precision*sg_surf_precision);
125   if (a_aux > 0)
126     integral += ((integral_[ind + 1] - integral_[ind]) / (timePoints_[ind + 1] - timePoints_[ind])) *
127                 (a - timePoints_[ind]);
128   XBT_DEBUG("Integral a %f = %f", a, integral);
129
130   return integral;
131 }
132
133 /**
134 * \brief Computes the time needed to execute "amount" on cpu.
135 *
136 * Here, amount can span multiple trace periods
137 *
138 * \param a        Initial time
139 * \param amount  Amount to be executed
140 * \return  End time
141 */
142 double CpuTiTgmr::solve(double a, double amount)
143 {
144   /* Fix very small negative numbers */
145   if ((a < 0.0) && (a > -EPSILON)) {
146     a = 0.0;
147   }
148   if ((amount < 0.0) && (amount > -EPSILON)) {
149     amount = 0.0;
150   }
151
152   /* Sanity checks */
153   if ((a < 0.0) || (amount < 0.0)) {
154     XBT_CRITICAL ("Error, invalid parameters [a = %.2f, amount = %.2f]. "
155         "You probably have a task executing with negative computation amount. Check your code.", a, amount);
156     xbt_abort();
157   }
158
159   /* At this point, a and amount are positive */
160   if (amount < EPSILON)
161     return a;
162
163   /* Is the trace fixed ? */
164   if (type_ == TRACE_FIXED) {
165     return (a + (amount / value_));
166   }
167
168   XBT_DEBUG("amount %f total %f", amount, total_);
169   /* Reduce the problem to one where amount <= trace_total */
170   int quotient = static_cast<int>(floor(amount / total_));
171   double reduced_amount = (total_) * ((amount / total_) - floor(amount / total_));
172   double reduced_a = a - (lastTime_) * static_cast<int>(floor(a / lastTime_));
173
174   XBT_DEBUG("Quotient: %d reduced_amount: %f reduced_a: %f", quotient, reduced_amount, reduced_a);
175
176   /* Now solve for new_amount which is <= trace_total */
177   double reduced_b = solveSomewhatSimple(reduced_a, reduced_amount);
178
179 /* Re-map to the original b and amount */
180   double b = (lastTime_) * static_cast<int>(floor(a / lastTime_)) + (quotient * lastTime_) + reduced_b;
181   return b;
182 }
183
184 /**
185 * \brief Auxiliary function to solve integral
186 *
187 * Here, amount is <= trace->total
188 * and a <=trace->last_time
189 *
190 */
191 double CpuTiTgmr::solveSomewhatSimple(double a, double amount)
192 {
193   double b;
194
195   XBT_DEBUG("Solve integral: [%.2f, amount=%.2f]", a, amount);
196   double amount_till_end = integrate(a, lastTime_);
197
198   if (amount_till_end > amount) {
199     b = trace_->solveSimple(a, amount);
200   } else {
201     b = lastTime_ + trace_->solveSimple(0.0, amount - amount_till_end);
202   }
203   return b;
204 }
205
206 /**
207  * \brief Auxiliary function to solve integral.
208  *  It returns the date when the requested amount of flops is available
209  * \param a        Initial point
210  * \param amount  Amount of flops
211  * \return The date when amount is available.
212 */
213 double CpuTiTrace::solveSimple(double a, double amount)
214 {
215   double integral_a = integrateSimplePoint(a);
216   int ind = binarySearch(integral_, integral_a + amount, 0, nbPoints_ - 1);
217   double time = timePoints_[ind];
218   time += (integral_a + amount - integral_[ind]) /
219            ((integral_[ind + 1] - integral_[ind]) / (timePoints_[ind + 1] - timePoints_[ind]));
220
221   return time;
222 }
223
224 /**
225 * \brief Auxiliary function to update the CPU speed scale.
226 *
227 *  This function uses the trace structure to return the speed scale at the determined time a.
228 * \param a        Time
229 * \return CPU speed scale
230 */
231 double CpuTiTgmr::getPowerScale(double a)
232 {
233   double reduced_a = a - floor(a / lastTime_) * lastTime_;
234   int point = trace_->binarySearch(trace_->timePoints_, reduced_a, 0, trace_->nbPoints_ - 1);
235   trace_mgr::DatedValue val = speedTrace_->event_list.at(point);
236   return val.value_;
237 }
238
239 /**
240 * \brief Creates a new integration trace from a tmgr_trace_t
241 *
242 * \param  speedTrace    CPU availability trace
243 * \param  value          Percentage of CPU speed available (useful to fixed tracing)
244 * \return  Integration trace structure
245 */
246 CpuTiTgmr::CpuTiTgmr(tmgr_trace_t speedTrace, double value) :
247     speedTrace_(speedTrace)
248 {
249   double total_time = 0.0;
250   trace_ = 0;
251
252 /* no availability file, fixed trace */
253   if (not speedTrace) {
254     type_ = TRACE_FIXED;
255     value_ = value;
256     XBT_DEBUG("No availability trace. Constant value = %f", value);
257     return;
258   }
259
260   /* only one point available, fixed trace */
261   if (speedTrace->event_list.size() == 1) {
262     trace_mgr::DatedValue val = speedTrace->event_list.front();
263     type_ = TRACE_FIXED;
264     value_                    = val.value_;
265     return;
266   }
267
268   type_ = TRACE_DYNAMIC;
269
270   /* count the total time of trace file */
271   for (auto const& val : speedTrace->event_list)
272     total_time += val.date_;
273
274   trace_ = new CpuTiTrace(speedTrace);
275   lastTime_ = total_time;
276   total_ = trace_->integrateSimple(0, total_time);
277
278   XBT_DEBUG("Total integral %f, last_time %f ", total_, lastTime_);
279 }
280
281 /**
282  * \brief Binary search in array.
283  *  It returns the first point of the interval in which "a" is.
284  * \param array    Array
285  * \param a        Value to search
286  * \param low     Low bound to search in array
287  * \param high    Upper bound to search in array
288  * \return Index of point
289 */
290 int CpuTiTrace::binarySearch(double *array, double a, int low, int high)
291 {
292   xbt_assert(low < high, "Wrong parameters: low (%d) should be smaller than high (%d)", low, high);
293
294   do {
295     int mid = low + (high - low) / 2;
296     XBT_DEBUG("a %f low %d high %d mid %d value %f", a, low, high, mid, array[mid]);
297
298     if (array[mid] > a)
299       high = mid;
300     else
301       low = mid;
302   }
303   while (low < high - 1);
304
305   return low;
306 }
307
308 }
309 }
310
311 /*********
312  * Model *
313  *********/
314
315 void surf_cpu_model_init_ti()
316 {
317   xbt_assert(not surf_cpu_model_pm, "CPU model already initialized. This should not happen.");
318   xbt_assert(not surf_cpu_model_vm, "CPU model already initialized. This should not happen.");
319
320   surf_cpu_model_pm = new simgrid::surf::CpuTiModel();
321   all_existing_models->push_back(surf_cpu_model_pm);
322
323   surf_cpu_model_vm = new simgrid::surf::CpuTiModel();
324   all_existing_models->push_back(surf_cpu_model_vm);
325 }
326
327 namespace simgrid {
328 namespace surf {
329
330 CpuTiModel::~CpuTiModel()
331 {
332   surf_cpu_model_pm = nullptr;
333 }
334
335 Cpu *CpuTiModel::createCpu(simgrid::s4u::Host *host, std::vector<double>* speedPerPstate, int core)
336 {
337   return new CpuTi(this, host, speedPerPstate, core);
338 }
339
340 double CpuTiModel::nextOccuringEvent(double now)
341 {
342   double min_action_duration = -1;
343
344   /* iterates over modified cpus to update share resources */
345   for (auto it = std::begin(modifiedCpu_); it != std::end(modifiedCpu_);) {
346     CpuTi& ti = *it;
347     ++it; // increment iterator here since the following call to ti.updateActionsFinishTime() may invalidate it
348     ti.updateActionsFinishTime(now);
349   }
350
351   /* get the min next event if heap not empty */
352   if (not actionHeapIsEmpty())
353     min_action_duration = actionHeapTopDate() - now;
354
355   XBT_DEBUG("Share resources, min next event date: %f", min_action_duration);
356
357   return min_action_duration;
358 }
359
360 void CpuTiModel::updateActionsState(double now, double /*delta*/)
361 {
362   while (not actionHeapIsEmpty() && actionHeapTopDate() <= now) {
363     CpuTiAction* action = static_cast<CpuTiAction*>(actionHeapPop());
364     XBT_DEBUG("Action %p: finish", action);
365     action->finish(Action::State::done);
366     /* set the remains to 0 due to precision problems when updating the remaining amount */
367     action->setRemains(0);
368     /* update remaining amount of all actions */
369     action->cpu_->updateRemainingAmount(surf_get_clock());
370   }
371 }
372
373 /************
374  * Resource *
375  ************/
376 CpuTi::CpuTi(CpuTiModel *model, simgrid::s4u::Host *host, std::vector<double> *speedPerPstate, int core)
377   : Cpu(model, host, speedPerPstate, core)
378 {
379   xbt_assert(core==1,"Multi-core not handled by this model yet");
380   coresAmount_ = core;
381
382   speed_.peak = speedPerPstate->front();
383   XBT_DEBUG("CPU create: peak=%f", speed_.peak);
384
385   speedIntegratedTrace_ = new CpuTiTgmr(nullptr, 1/*scale*/);
386 }
387
388 CpuTi::~CpuTi()
389 {
390   modified(false);
391   delete speedIntegratedTrace_;
392 }
393 void CpuTi::setSpeedTrace(tmgr_trace_t trace)
394 {
395   if (speedIntegratedTrace_)
396     delete speedIntegratedTrace_;
397
398   speedIntegratedTrace_ = new CpuTiTgmr(trace, speed_.scale);
399
400   /* add a fake trace event if periodicity == 0 */
401   if (trace && trace->event_list.size() > 1) {
402     trace_mgr::DatedValue val = trace->event_list.back();
403     if (val.date_ < 1e-12)
404       speed_.event = future_evt_set->add_trace(new simgrid::trace_mgr::trace(), this);
405   }
406 }
407
408 void CpuTi::apply_event(tmgr_trace_event_t event, double value)
409 {
410   if (event == speed_.event) {
411     tmgr_trace_t speedTrace;
412     CpuTiTgmr *trace;
413
414     XBT_DEBUG("Finish trace date: value %f", value);
415     /* update remaining of actions and put in modified cpu list */
416     updateRemainingAmount(surf_get_clock());
417
418     modified(true);
419
420     speedTrace = speedIntegratedTrace_->speedTrace_;
421     trace_mgr::DatedValue val = speedTrace->event_list.back();
422     delete speedIntegratedTrace_;
423     speed_.scale = val.value_;
424
425     trace = new CpuTiTgmr(TRACE_FIXED, val.value_);
426     XBT_DEBUG("value %f", val.value_);
427
428     speedIntegratedTrace_ = trace;
429
430     tmgr_trace_event_unref(&speed_.event);
431
432   } else if (event == stateEvent_) {
433     if (value > 0) {
434       if(isOff())
435         host_that_restart.push_back(getHost());
436       turnOn();
437     } else {
438       turnOff();
439       double date = surf_get_clock();
440
441       /* put all action running on cpu to failed */
442       for (CpuTiAction& action : actionSet_) {
443         if (action.getState() == Action::State::running || action.getState() == Action::State::ready ||
444             action.getState() == Action::State::not_in_the_system) {
445           action.setFinishTime(date);
446           action.setState(Action::State::failed);
447           action.heapRemove(model()->getActionHeap());
448         }
449       }
450     }
451     tmgr_trace_event_unref(&stateEvent_);
452
453   } else {
454     xbt_die("Unknown event!\n");
455   }
456 }
457
458 void CpuTi::updateActionsFinishTime(double now)
459 {
460   double sum_priority = 0.0;
461   double total_area;
462
463   /* update remaining amount of actions */
464   updateRemainingAmount(now);
465
466   for (CpuTiAction const& action : actionSet_) {
467     /* action not running, skip it */
468     if (action.getStateSet() != surf_cpu_model_pm->getRunningActionSet())
469       continue;
470
471     /* bogus priority, skip it */
472     if (action.getPriority() <= 0)
473       continue;
474
475     /* action suspended, skip it */
476     if (action.suspended_ != Action::SuspendStates::not_suspended)
477       continue;
478
479     sum_priority += 1.0 / action.getPriority();
480   }
481   sumPriority_ = sum_priority;
482
483   for (CpuTiAction& action : actionSet_) {
484     double min_finish = -1;
485     /* action not running, skip it */
486     if (action.getStateSet() != surf_cpu_model_pm->getRunningActionSet())
487       continue;
488
489     /* verify if the action is really running on cpu */
490     if (action.suspended_ == Action::SuspendStates::not_suspended && action.getPriority() > 0) {
491       /* total area needed to finish the action. Used in trace integration */
492       total_area = (action.getRemains()) * sum_priority * action.getPriority();
493
494       total_area /= speed_.peak;
495
496       action.setFinishTime(speedIntegratedTrace_->solve(now, total_area));
497       /* verify which event will happen before (max_duration or finish time) */
498       if (action.getMaxDuration() > NO_MAX_DURATION &&
499           action.getStartTime() + action.getMaxDuration() < action.getFinishTime())
500         min_finish = action.getStartTime() + action.getMaxDuration();
501       else
502         min_finish = action.getFinishTime();
503     } else {
504       /* put the max duration time on heap */
505       if (action.getMaxDuration() > NO_MAX_DURATION)
506         min_finish = action.getStartTime() + action.getMaxDuration();
507     }
508     /* add in action heap */
509     if (min_finish > NO_MAX_DURATION)
510       action.heapUpdate(model()->getActionHeap(), min_finish, NOTSET);
511     else
512       action.heapRemove(model()->getActionHeap());
513
514     XBT_DEBUG("Update finish time: Cpu(%s) Action: %p, Start Time: %f Finish Time: %f Max duration %f", getCname(),
515               &action, action.getStartTime(), action.getFinishTime(), action.getMaxDuration());
516   }
517   /* remove from modified cpu */
518   modified(false);
519 }
520
521 bool CpuTi::isUsed()
522 {
523   return not actionSet_.empty();
524 }
525
526 double CpuTi::getAvailableSpeed()
527 {
528   speed_.scale = speedIntegratedTrace_->getPowerScale(surf_get_clock());
529   return Cpu::getAvailableSpeed();
530 }
531
532 /** @brief Update the remaining amount of actions */
533 void CpuTi::updateRemainingAmount(double now)
534 {
535
536   /* already updated */
537   if (lastUpdate_ >= now)
538     return;
539
540   /* compute the integration area */
541   double area_total = speedIntegratedTrace_->integrate(lastUpdate_, now) * speed_.peak;
542   XBT_DEBUG("Flops total: %f, Last update %f", area_total, lastUpdate_);
543   for (CpuTiAction& action : actionSet_) {
544     /* action not running, skip it */
545     if (action.getStateSet() != model()->getRunningActionSet())
546       continue;
547
548     /* bogus priority, skip it */
549     if (action.getPriority() <= 0)
550       continue;
551
552     /* action suspended, skip it */
553     if (action.suspended_ != Action::SuspendStates::not_suspended)
554       continue;
555
556     /* action don't need update */
557     if (action.getStartTime() >= now)
558       continue;
559
560     /* skip action that are finishing now */
561     if (action.getFinishTime() >= 0 && action.getFinishTime() <= now)
562       continue;
563
564     /* update remaining */
565     action.updateRemains(area_total / (sumPriority_ * action.getPriority()));
566     XBT_DEBUG("Update remaining action(%p) remaining %f", &action, action.getRemainsNoUpdate());
567   }
568   lastUpdate_ = now;
569 }
570
571 CpuAction *CpuTi::execution_start(double size)
572 {
573   XBT_IN("(%s,%g)", getCname(), size);
574   CpuTiAction* action = new CpuTiAction(static_cast<CpuTiModel*>(model()), size, isOff(), this);
575
576   actionSet_.push_back(*action);
577
578   XBT_OUT();
579   return action;
580 }
581
582
583 CpuAction *CpuTi::sleep(double duration)
584 {
585   if (duration > 0)
586     duration = std::max(duration, sg_surf_precision);
587
588   XBT_IN("(%s,%g)", getCname(), duration);
589   CpuTiAction* action = new CpuTiAction(static_cast<CpuTiModel*>(model()), 1.0, isOff(), this);
590
591   action->setMaxDuration(duration);
592   action->suspended_ = Action::SuspendStates::sleeping;
593   if (duration == NO_MAX_DURATION) {
594     /* Move to the *end* of the corresponding action set. This convention is used to speed up update_resource_state */
595     simgrid::xbt::intrusive_erase(*action->getStateSet(), *action);
596     action->stateSet_ = &static_cast<CpuTiModel*>(model())->runningActionSetThatDoesNotNeedBeingChecked_;
597     action->getStateSet()->push_back(*action);
598   }
599
600   actionSet_.push_back(*action);
601
602   XBT_OUT();
603   return action;
604 }
605
606 void CpuTi::modified(bool modified){
607   CpuTiList& modifiedCpu = static_cast<CpuTiModel*>(model())->modifiedCpu_;
608   if (modified) {
609     if (not cpu_ti_hook.is_linked()) {
610       modifiedCpu.push_back(*this);
611     }
612   } else {
613     if (cpu_ti_hook.is_linked())
614       simgrid::xbt::intrusive_erase(modifiedCpu, *this);
615   }
616 }
617
618 /**********
619  * Action *
620  **********/
621
622 CpuTiAction::CpuTiAction(CpuTiModel *model_, double cost, bool failed, CpuTi *cpu)
623  : CpuAction(model_, cost, failed)
624  , cpu_(cpu)
625 {
626   cpu_->modified(true);
627 }
628
629 void CpuTiAction::setState(Action::State state)
630 {
631   CpuAction::setState(state);
632   cpu_->modified(true);
633 }
634
635 int CpuTiAction::unref()
636 {
637   refcount_--;
638   if (not refcount_) {
639     if (action_hook.is_linked())
640       simgrid::xbt::intrusive_erase(*getStateSet(), *this);
641     /* remove from action_set */
642     if (action_ti_hook.is_linked())
643       simgrid::xbt::intrusive_erase(cpu_->actionSet_, *this);
644     /* remove from heap */
645     heapRemove(getModel()->getActionHeap());
646     cpu_->modified(true);
647     delete this;
648     return 1;
649   }
650   return 0;
651 }
652
653 void CpuTiAction::cancel()
654 {
655   this->setState(Action::State::failed);
656   heapRemove(getModel()->getActionHeap());
657   cpu_->modified(true);
658 }
659
660 void CpuTiAction::suspend()
661 {
662   XBT_IN("(%p)", this);
663   if (suspended_ != Action::SuspendStates::sleeping) {
664     suspended_ = Action::SuspendStates::suspended;
665     heapRemove(getModel()->getActionHeap());
666     cpu_->modified(true);
667   }
668   XBT_OUT();
669 }
670
671 void CpuTiAction::resume()
672 {
673   XBT_IN("(%p)", this);
674   if (suspended_ != Action::SuspendStates::sleeping) {
675     suspended_ = Action::SuspendStates::not_suspended;
676     cpu_->modified(true);
677   }
678   XBT_OUT();
679 }
680
681 void CpuTiAction::setMaxDuration(double duration)
682 {
683   double min_finish;
684
685   XBT_IN("(%p,%g)", this, duration);
686
687   Action::setMaxDuration(duration);
688
689   if (duration >= 0)
690     min_finish = (getStartTime() + getMaxDuration()) < getFinishTime() ?
691                  (getStartTime() + getMaxDuration()) : getFinishTime();
692   else
693     min_finish = getFinishTime();
694
695   /* add in action heap */
696   heapUpdate(getModel()->getActionHeap(), min_finish, NOTSET);
697
698   XBT_OUT();
699 }
700
701 void CpuTiAction::setSharingWeight(double priority)
702 {
703   XBT_IN("(%p,%g)", this, priority);
704   setSharingWeightNoUpdate(priority);
705   cpu_->modified(true);
706   XBT_OUT();
707 }
708
709 double CpuTiAction::getRemains()
710 {
711   XBT_IN("(%p)", this);
712   cpu_->updateRemainingAmount(surf_get_clock());
713   XBT_OUT();
714   return getRemainsNoUpdate();
715 }
716
717 }
718 }
719
720 #endif /* SURF_MODEL_CPUTI_H_ */