4 /* Copyright (c) 2004 Arnaud Legrand. All rights reserved. */
6 /* This program is free software; you can redistribute it and/or modify it
7 * under the terms of the license (GNU LGPL) which comes with this package. */
9 #include "surf_private.h"
10 #include "trace_mgr_private.h"
11 #include "cpu_ti_private.h"
15 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_cpu_ti, surf,
16 "Logging specific to the SURF CPU TRACE INTEGRATION module");
19 static xbt_swag_t running_action_set_that_does_not_need_being_checked = NULL;
20 static xbt_swag_t modified_cpu = NULL;
21 static xbt_heap_t action_heap;
23 /* prototypes of new trace functions */
24 static double surf_cpu_integrate_trace(surf_cpu_ti_tgmr_t trace, double a,
26 static double surf_cpu_integrate_trace_simple(surf_cpu_ti_tgmr_t trace,
30 static double surf_cpu_solve_trace(surf_cpu_ti_tgmr_t trace, double a,
32 static double surf_cpu_solve_trace_somewhat_simple(surf_cpu_ti_tgmr_t trace,
33 double a, double amount);
34 static double surf_cpu_solve_trace_simple(surf_cpu_ti_tgmr_t trace, double a,
37 static void surf_cpu_free_trace(surf_cpu_ti_tgmr_t trace);
38 static void surf_cpu_free_time_series(surf_cpu_ti_timeSeries_t timeSeries);
39 static double surf_cpu_integrate_exactly(surf_cpu_ti_tgmr_t trace, int index,
41 static double surf_cpu_solve_exactly(surf_cpu_ti_tgmr_t trace, int index,
42 double a, double amount);
45 static void surf_cpu_free_time_series(surf_cpu_ti_timeSeries_t timeSeries)
47 xbt_free(timeSeries->values);
48 xbt_free(timeSeries->trace_index);
49 xbt_free(timeSeries->trace_value);
53 static void surf_cpu_free_trace(surf_cpu_ti_tgmr_t trace)
57 for (i = 0; i < trace->nb_levels; i++)
58 surf_cpu_free_time_series(trace->levels[i]);
60 xbt_free(trace->levels);
64 static surf_cpu_ti_timeSeries_t surf_cpu_ti_time_series_new(tmgr_trace_t
69 surf_cpu_ti_timeSeries_t series;
70 double time = 0.0, value = 0.0, sum_delta = 0.0;
71 double previous_time = 0.0, old_time = 0.0;
72 int event_lost = 0, next_index = 0;
73 double next_time = 0.0;
78 series = xbt_new0(s_surf_cpu_ti_timeSeries_t, 1);
79 series->spacing = spacing;
80 series->power_trace = power_trace;
82 /* alloc memory only once, it's faster than doing realloc each time */
83 total_alloc = (int) ceil((total_time / spacing));
84 series->values = xbt_malloc0(sizeof(double) * total_alloc);
85 series->trace_index = xbt_malloc0(sizeof(int) * total_alloc);
86 series->trace_value = xbt_malloc0(sizeof(double) * total_alloc);
88 xbt_dynar_foreach(power_trace->event_list, cpt, val) {
89 /* delta = the next trace event
90 * value = state until next event */
93 /* ignore events until next spacing */
94 if (time < (series->nb_points + 1) * spacing) {
95 value += val.value * val.delta;
96 sum_delta += val.delta;
102 /* update value and sum_delta with the space between last point in trace(old_time) and next spacing */
103 value += val.value * ((series->nb_points + 1) * spacing - old_time);
104 sum_delta += ((series->nb_points + 1) * spacing - old_time);
105 /* calcule the value to next spacing */
108 while (previous_time + spacing <= time) {
109 /* update first spacing with mean of points.
110 * others with the right value */
112 series->values[series->nb_points] = value;
113 series->trace_index[series->nb_points] = next_index;
114 series->trace_value[series->nb_points] = next_time;
117 series->trace_index[series->nb_points] = -1;
118 series->values[series->nb_points] = val.value;
120 (series->nb_points)++;
121 previous_time += spacing;
123 /* update value and sum_delta, interval: [time, next spacing] */
124 value = (time - previous_time) * val.value;
125 sum_delta = (time - previous_time);
127 next_index = (int) cpt + 1;
132 * ignore small amount at end */
133 double_update(&time, (series->nb_points) * spacing);
135 /* here the value is divided by spacing in order to have exactly the value of last chunk (independently of its size). After, when we calcule the integral, we multiply by actual_last_time insted of last_time */
137 series->values[series->nb_points] = value;
138 /* update first spacing with mean of points
139 * others with the right value */
141 series->trace_index[series->nb_points] = next_index;
142 series->trace_value[series->nb_points] = next_time;
144 series->trace_index[series->nb_points] = -1;
145 (series->nb_points)++;
151 * \brief Create new levels of points.
153 * This function assumes that the input series is
154 * evenly spaces, starting at time 0. That is the sort
155 * of series produced by surf_cpu_ti_time_series_new()
157 * \param original Original timeSeries structure
158 * \param factor New factor to spacing
159 * \return New timeSeries structure with spacing*factor
161 static surf_cpu_ti_timeSeries_t
162 surf_cpu_ti_time_series_coarsen(surf_cpu_ti_timeSeries_t original, int factor)
164 surf_cpu_ti_timeSeries_t series;
166 double dfactor = (double) (factor);
169 if (original->nb_points <= factor) {
170 DEBUG0("Warning: Not enough data points to coarsen time series");
174 series = xbt_new0(s_surf_cpu_ti_timeSeries_t, 1);
175 series->spacing = (original->spacing) * dfactor;
177 while (i + factor <= original->nb_points) {
180 for (j = i; j < i + factor; j++) {
181 ave += original->values[j];
185 series->values = xbt_realloc(series->values,
186 (series->nb_points + 1) * sizeof(double));
187 series->values[(series->nb_points)++] = ave;
195 * \brief Create a new integration trace from a tmgr_trace_t
197 * \param power_trace CPU availability trace
198 * \param value Percentage of CPU power disponible (usefull to fixed tracing)
199 * \param spacing Initial spacing
200 * \return Integration trace structure
202 static surf_cpu_ti_tgmr_t cpu_ti_parse_trace(tmgr_trace_t power_trace,
205 surf_cpu_ti_tgmr_t trace;
206 surf_cpu_ti_timeSeries_t series;
208 double total_time = 0.0;
211 trace = xbt_new0(s_surf_cpu_ti_tgmr_t, 1);
213 /* no availability file, fixed trace */
215 trace->type = TRACE_FIXED;
216 trace->value = value;
217 DEBUG1("No availabily trace. Constant value = %lf", value);
221 /* only one point available, fixed trace */
222 if (xbt_dynar_length(power_trace->event_list) == 1) {
223 xbt_dynar_get_cpy(power_trace->event_list, 0, &val);
224 trace->type = TRACE_FIXED;
225 trace->value = val.value;
229 /* count the total time of trace file */
230 xbt_dynar_foreach(power_trace->event_list, cpt, val) {
231 total_time += val.delta;
233 trace->actual_last_time = total_time;
235 DEBUG2("Value %lf, Spacing %lf", value, power_trace->timestep);
237 surf_cpu_ti_time_series_new(power_trace, power_trace->timestep,
242 trace->type = TRACE_DYNAMIC;
244 trace->levels = xbt_new0(surf_cpu_ti_timeSeries_t, 1);
245 trace->levels[(trace->nb_levels)++] = series;
247 /* Do the coarsening with some arbitrary factors */
248 for (i = 1; i < TRACE_NB_LEVELS; i++) {
249 series = surf_cpu_ti_time_series_coarsen(trace->levels[i - 1], 4 * i);
251 if (series) { /* If coarsening was possible, add it */
252 trace->levels = xbt_realloc(trace->levels,
254 1) * sizeof(s_surf_cpu_ti_timeSeries_t));
255 trace->levels[(trace->nb_levels)++] = series;
256 } else { /* otherwise stop */
260 /* calcul of initial integrate */
262 power_trace->timestep * ((double) (trace->levels[0]->nb_points));
265 surf_cpu_integrate_trace(trace, 0.0, trace->actual_last_time);
267 DEBUG3("Total integral %lf, last_time %lf actual_last_time %lf",
268 trace->total, trace->last_time, trace->actual_last_time);
274 static cpu_ti_t cpu_new(char *name, double power_peak,
276 tmgr_trace_t power_trace,
277 e_surf_resource_state_t state_initial,
278 tmgr_trace_t state_trace, xbt_dict_t cpu_properties)
280 tmgr_trace_t empty_trace;
282 cpu_ti_t cpu = xbt_new0(s_cpu_ti_t, 1);
283 s_surf_action_cpu_ti_t ti_action;
284 xbt_assert1(!surf_model_resource_by_name(surf_cpu_model, name),
285 "Host '%s' declared several times in the platform file", name);
286 cpu->action_set = xbt_swag_new(xbt_swag_offset(ti_action, cpu_list_hookup));
287 cpu->generic_resource.model = surf_cpu_model;
288 cpu->generic_resource.name = name;
289 cpu->generic_resource.properties = cpu_properties;
290 cpu->power_peak = power_peak;
291 xbt_assert0(cpu->power_peak > 0, "Power has to be >0");
292 DEBUG1("power scale %lf", power_scale);
293 cpu->power_scale = power_scale;
294 cpu->avail_trace = cpu_ti_parse_trace(power_trace, power_scale);
295 cpu->state_current = state_initial;
298 tmgr_history_add_trace(history, state_trace, 0.0, 0, cpu);
299 if (power_trace && xbt_dynar_length(power_trace->event_list) > 1) {
300 /* add a fake trace event if periodicity == 0 */
301 xbt_dynar_get_cpy(power_trace->event_list,
302 xbt_dynar_length(power_trace->event_list) - 1, &val);
303 if (val.delta == 0) {
304 empty_trace = tmgr_empty_trace_new();
306 tmgr_history_add_trace(history, empty_trace,
307 cpu->avail_trace->actual_last_time, 0, cpu);
310 xbt_dict_set(surf_model_resource_set(surf_cpu_model), name, cpu,
317 static void parse_cpu_init(void)
319 double power_peak = 0.0;
320 double power_scale = 0.0;
321 tmgr_trace_t power_trace = NULL;
322 e_surf_resource_state_t state_initial = SURF_RESOURCE_OFF;
323 tmgr_trace_t state_trace = NULL;
325 power_peak = get_cpu_power(A_surfxml_host_power);
326 surf_parse_get_double(&power_scale, A_surfxml_host_availability);
327 power_trace = tmgr_trace_new(A_surfxml_host_availability_file);
329 xbt_assert0((A_surfxml_host_state == A_surfxml_host_state_ON) ||
330 (A_surfxml_host_state == A_surfxml_host_state_OFF),
332 if (A_surfxml_host_state == A_surfxml_host_state_ON)
333 state_initial = SURF_RESOURCE_ON;
334 if (A_surfxml_host_state == A_surfxml_host_state_OFF)
335 state_initial = SURF_RESOURCE_OFF;
336 state_trace = tmgr_trace_new(A_surfxml_host_state_file);
338 current_property_set = xbt_dict_new();
339 cpu_new(xbt_strdup(A_surfxml_host_id), power_peak, power_scale,
340 power_trace, state_initial, state_trace, current_property_set);
344 static void add_traces_cpu(void)
346 xbt_dict_cursor_t cursor = NULL;
347 char *trace_name, *elm;
349 static int called = 0;
355 /* connect all traces relative to hosts */
356 xbt_dict_foreach(trace_connect_list_host_avail, cursor, trace_name, elm) {
357 tmgr_trace_t trace = xbt_dict_get_or_null(traces_set_list, trace_name);
358 cpu_ti_t cpu = surf_model_resource_by_name(surf_cpu_model, elm);
360 xbt_assert1(cpu, "Host %s undefined", elm);
361 xbt_assert1(trace, "Trace %s undefined", trace_name);
363 if (cpu->state_event) {
364 DEBUG1("Trace already configured for this CPU(%s), ignoring it", elm);
367 DEBUG2("Add state trace: %s to CPU(%s)", trace_name, elm);
368 cpu->state_event = tmgr_history_add_trace(history, trace, 0.0, 0, cpu);
371 xbt_dict_foreach(trace_connect_list_power, cursor, trace_name, elm) {
372 tmgr_trace_t trace = xbt_dict_get_or_null(traces_set_list, trace_name);
373 cpu_ti_t cpu = surf_model_resource_by_name(surf_cpu_model, elm);
375 xbt_assert1(cpu, "Host %s undefined", elm);
376 xbt_assert1(trace, "Trace %s undefined", trace_name);
378 DEBUG2("Add power trace: %s to CPU(%s)", trace_name, elm);
379 if (cpu->avail_trace)
380 surf_cpu_free_trace(cpu->avail_trace);
382 cpu->avail_trace = cpu_ti_parse_trace(trace, cpu->power_scale);
386 static void define_callbacks(const char *file)
388 surf_parse_reset_parser();
389 surfxml_add_callback(STag_surfxml_host_cb_list, parse_cpu_init);
390 surfxml_add_callback(ETag_surfxml_platform_cb_list, &add_traces_cpu);
393 static int resource_used(void *resource_id)
395 cpu_ti_t cpu = resource_id;
396 return xbt_swag_size(cpu->action_set);
399 static int action_unref(surf_action_t action)
402 if (!action->refcount) {
403 xbt_swag_remove(action, action->state_set);
404 /* remove from action_set */
405 xbt_swag_remove(action, ACTION_GET_CPU(action)->action_set);
406 /* remove from heap */
407 xbt_heap_remove(action_heap, ((surf_action_cpu_ti_t) action)->index_heap);
408 xbt_swag_insert(ACTION_GET_CPU(action), modified_cpu);
415 static void action_cancel(surf_action_t action)
417 surf_action_state_set(action, SURF_ACTION_FAILED);
418 xbt_heap_remove(action_heap, ((surf_action_cpu_ti_t) action)->index_heap);
419 xbt_swag_insert(ACTION_GET_CPU(action), modified_cpu);
423 static void cpu_action_state_set(surf_action_t action,
424 e_surf_action_state_t state)
426 surf_action_state_set(action, state);
427 xbt_swag_insert(ACTION_GET_CPU(action), modified_cpu);
432 * \brief Update the remaning amount of actions
434 * \param cpu Cpu on which the actions are running
435 * \param now Current time
437 static void cpu_update_remaining_amount(cpu_ti_t cpu, double now)
439 #define GENERIC_ACTION(action) action->generic_action
441 surf_action_cpu_ti_t action;
443 /* already updated */
444 if (cpu->last_update >= now)
447 /* calcule the surface */
449 surf_cpu_integrate_trace(cpu->avail_trace, cpu->last_update,
450 now) * cpu->power_peak;
451 DEBUG2("Flops total: %lf, Last update %lf", area_total, cpu->last_update);
453 xbt_swag_foreach(action, cpu->action_set) {
454 /* action not running, skip it */
455 if (GENERIC_ACTION(action).state_set !=
456 surf_cpu_model->states.running_action_set)
459 /* bogus priority, skip it */
460 if (GENERIC_ACTION(action).priority <= 0)
463 /* action suspended, skip it */
464 if (action->suspended != 0)
467 /* action don't need update */
468 if (GENERIC_ACTION(action).start >= now)
471 /* skip action that are finishing now */
472 if (GENERIC_ACTION(action).finish >= 0
473 && GENERIC_ACTION(action).finish <= now)
476 /* update remaining */
477 double_update(&(GENERIC_ACTION(action).remains),
478 area_total / (cpu->sum_priority *
479 GENERIC_ACTION(action).priority));
480 DEBUG2("Update remaining action(%p) remaining %lf", action,
481 GENERIC_ACTION(action).remains);
483 cpu->last_update = now;
484 #undef GENERIC_ACTION
488 * \brief Update the finish date of action if necessary
490 * \param cpu Cpu on which the actions are running
491 * \param now Current time
493 static void cpu_update_action_finish_date(cpu_ti_t cpu, double now)
495 #define GENERIC_ACTION(action) action->generic_action
496 surf_action_cpu_ti_t action;
497 double sum_priority = 0.0, total_area, min_finish = -1;
499 /* update remaning amount of actions */
500 cpu_update_remaining_amount(cpu, now);
502 xbt_swag_foreach(action, cpu->action_set) {
503 /* action not running, skip it */
504 if (GENERIC_ACTION(action).state_set !=
505 surf_cpu_model->states.running_action_set)
508 /* bogus priority, skip it */
509 if (GENERIC_ACTION(action).priority <= 0)
512 /* action suspended, skip it */
513 if (action->suspended != 0)
516 sum_priority += 1.0 / GENERIC_ACTION(action).priority;
518 cpu->sum_priority = sum_priority;
520 xbt_swag_foreach(action, cpu->action_set) {
521 /* action not running, skip it */
522 if (GENERIC_ACTION(action).state_set !=
523 surf_cpu_model->states.running_action_set)
526 /* verify if the action is really running on cpu */
527 if (action->suspended == 0 && GENERIC_ACTION(action).priority > 0) {
528 /* total area needed to finish the action. Used in trace integration */
530 (GENERIC_ACTION(action).remains) * sum_priority *
531 GENERIC_ACTION(action).priority;
533 total_area /= cpu->power_peak;
535 GENERIC_ACTION(action).finish =
536 surf_cpu_solve_trace(cpu->avail_trace, now, total_area);
537 /* verify which event will happen before (max_duration or finish time) */
538 if ((GENERIC_ACTION(action).max_duration != NO_MAX_DURATION) &&
539 (GENERIC_ACTION(action).start +
540 GENERIC_ACTION(action).max_duration <
541 GENERIC_ACTION(action).finish))
542 min_finish = GENERIC_ACTION(action).start +
543 GENERIC_ACTION(action).max_duration;
545 min_finish = GENERIC_ACTION(action).finish;
547 /* put the max duration time on heap */
548 if (GENERIC_ACTION(action).max_duration != NO_MAX_DURATION)
550 (GENERIC_ACTION(action).start +
551 GENERIC_ACTION(action).max_duration);
553 /* add in action heap */
554 DEBUG2("action(%p) index %d", action, action->index_heap);
555 if (action->index_heap >= 0) {
556 surf_action_cpu_ti_t heap_act =
557 xbt_heap_remove(action_heap, action->index_heap);
558 if (heap_act != action)
561 if (min_finish != NO_MAX_DURATION)
562 xbt_heap_push(action_heap, action, min_finish);
565 ("Update finish time: Cpu(%s) Action: %p, Start Time: %lf Finish Time: %lf Max duration %lf",
566 cpu->generic_resource.name, action, GENERIC_ACTION(action).start,
567 GENERIC_ACTION(action).finish, GENERIC_ACTION(action).max_duration);
569 /* remove from modified cpu */
570 xbt_swag_remove(cpu, modified_cpu);
571 #undef GENERIC_ACTION
574 static double share_resources(double now)
576 cpu_ti_t cpu, cpu_next;
577 double min_action_duration = -1;
579 /* iterates over modified cpus to update share resources */
580 xbt_swag_foreach_safe(cpu, cpu_next, modified_cpu) {
581 cpu_update_action_finish_date(cpu, now);
583 /* get the min next event if heap not empty */
584 if (xbt_heap_size(action_heap) > 0)
585 min_action_duration = xbt_heap_maxkey(action_heap) - now;
587 DEBUG1("Share resources, min next event date: %lf", min_action_duration);
589 return min_action_duration;
592 static void update_actions_state(double now, double delta)
594 #define GENERIC_ACTION(action) action->generic_action
595 surf_action_cpu_ti_t action;
596 while ((xbt_heap_size(action_heap) > 0)
597 && (xbt_heap_maxkey(action_heap) <= now)) {
598 action = xbt_heap_pop(action_heap);
599 DEBUG1("Action %p: finish", action);
600 GENERIC_ACTION(action).finish = surf_get_clock();
601 /* set the remains to 0 due to precision problems when updating the remaining amount */
602 GENERIC_ACTION(action).remains = 0;
603 cpu_action_state_set((surf_action_t) action, SURF_ACTION_DONE);
604 /* update remaining amout of all actions */
605 cpu_update_remaining_amount(action->cpu, surf_get_clock());
607 #undef GENERIC_ACTION
610 static void update_resource_state(void *id,
611 tmgr_trace_event_t event_type,
612 double value, double date)
615 surf_action_cpu_ti_t action;
617 if (event_type == cpu->power_event) {
618 tmgr_trace_t power_trace;
619 surf_cpu_ti_tgmr_t trace;
622 DEBUG3("Finish trace date: %lf value %lf date %lf", surf_get_clock(),
624 /* update remaining of actions and put in modified cpu swag */
625 cpu_update_remaining_amount(cpu, date);
626 xbt_swag_insert(cpu, modified_cpu);
628 power_trace = cpu->avail_trace->levels[0]->power_trace;
629 xbt_dynar_get_cpy(power_trace->event_list,
630 xbt_dynar_length(power_trace->event_list) - 1, &val);
632 surf_cpu_free_trace(cpu->avail_trace);
633 cpu->power_scale = val.value;
635 trace = xbt_new0(s_surf_cpu_ti_tgmr_t, 1);
636 trace->type = TRACE_FIXED;
637 trace->value = val.value;
638 DEBUG1("value %lf", val.value);
640 cpu->avail_trace = trace;
642 if (tmgr_trace_event_free(event_type))
643 cpu->power_event = NULL;
644 } else if (event_type == cpu->state_event) {
646 cpu->state_current = SURF_RESOURCE_ON;
648 cpu->state_current = SURF_RESOURCE_OFF;
650 /* put all action running on cpu to failed */
651 xbt_swag_foreach(action, cpu->action_set) {
652 if (surf_action_state_get((surf_action_t) action) ==
654 || surf_action_state_get((surf_action_t) action) ==
656 || surf_action_state_get((surf_action_t) action) ==
657 SURF_ACTION_NOT_IN_THE_SYSTEM) {
658 action->generic_action.finish = date;
659 cpu_action_state_set((surf_action_t) action, SURF_ACTION_FAILED);
660 if (action->index_heap >= 0) {
661 surf_action_cpu_ti_t heap_act =
662 xbt_heap_remove(action_heap, action->index_heap);
663 if (heap_act != action)
669 if (tmgr_trace_event_free(event_type))
670 cpu->state_event = NULL;
672 CRITICAL0("Unknown event ! \n");
679 static surf_action_t execute(void *cpu, double size)
681 surf_action_cpu_ti_t action = NULL;
684 XBT_IN2("(%s,%g)", surf_resource_name(CPU), size);
686 surf_action_new(sizeof(s_surf_action_cpu_ti_t), size, surf_cpu_model,
687 CPU->state_current != SURF_RESOURCE_ON);
689 action->index_heap = -1;
691 xbt_swag_insert(CPU, modified_cpu);
693 xbt_swag_insert(action, CPU->action_set);
695 action->suspended = 0; /* Should be useless because of the
696 calloc but it seems to help valgrind... */
699 return (surf_action_t) action;
702 static void action_update_index_heap(void *action, int i)
704 ((surf_action_cpu_ti_t) action)->index_heap = i;
707 static surf_action_t action_sleep(void *cpu, double duration)
709 surf_action_cpu_ti_t action = NULL;
712 duration = MAX(duration, MAXMIN_PRECISION);
714 XBT_IN2("(%s,%g)", surf_resource_name(cpu), duration);
715 action = (surf_action_cpu_ti_t) execute(cpu, 1.0);
716 action->generic_action.max_duration = duration;
717 action->suspended = 2;
718 if (duration == NO_MAX_DURATION) {
719 /* Move to the *end* of the corresponding action set. This convention
720 is used to speed up update_resource_state */
721 xbt_swag_remove(action, ((surf_action_t) action)->state_set);
722 ((surf_action_t) action)->state_set =
723 running_action_set_that_does_not_need_being_checked;
724 xbt_swag_insert(action, ((surf_action_t) action)->state_set);
727 return (surf_action_t) action;
730 static void action_suspend(surf_action_t action)
732 XBT_IN1("(%p)", action);
733 if (((surf_action_cpu_ti_t) action)->suspended != 2) {
734 ((surf_action_cpu_ti_t) action)->suspended = 1;
735 xbt_swag_insert(ACTION_GET_CPU(action), modified_cpu);
740 static void action_resume(surf_action_t action)
742 XBT_IN1("(%p)", action);
743 if (((surf_action_cpu_ti_t) action)->suspended != 2) {
744 ((surf_action_cpu_ti_t) action)->suspended = 0;
745 xbt_swag_insert(ACTION_GET_CPU(action), modified_cpu);
750 static int action_is_suspended(surf_action_t action)
752 return (((surf_action_cpu_ti_t) action)->suspended == 1);
755 static void action_set_max_duration(surf_action_t action, double duration)
757 surf_action_cpu_ti_t ACT = (surf_action_cpu_ti_t) action;
760 XBT_IN2("(%p,%g)", action, duration);
762 action->max_duration = duration;
766 (action->start + action->max_duration) <
767 action->finish ? (action->start +
768 action->max_duration) : action->finish;
770 min_finish = action->finish;
772 /* add in action heap */
773 if (ACT->index_heap >= 0) {
774 surf_action_cpu_ti_t heap_act =
775 xbt_heap_remove(action_heap, ACT->index_heap);
779 xbt_heap_push(action_heap, ACT, min_finish);
784 static void action_set_priority(surf_action_t action, double priority)
786 XBT_IN2("(%p,%g)", action, priority);
787 action->priority = priority;
788 xbt_swag_insert(ACTION_GET_CPU(action), modified_cpu);
792 static double action_get_remains(surf_action_t action)
794 XBT_IN1("(%p)", action);
795 cpu_update_remaining_amount((cpu_ti_t) ((surf_action_cpu_ti_t) action)->cpu,
797 return action->remains;
801 static e_surf_resource_state_t get_state(void *cpu)
803 return ((cpu_ti_t) cpu)->state_current;
806 static double get_speed(void *cpu, double load)
808 return load * (((cpu_ti_t) cpu)->power_peak);
812 * \brief Auxiliar function to update the cpu power scale.
814 * This function uses the trace structure to return the power scale at the determined time a.
815 * \param trace Trace structure to search the updated power scale
817 * \return Cpu power scale
819 static double surf_cpu_get_power_scale(surf_cpu_ti_tgmr_t trace, double a)
824 reduced_a = a - floor(a / trace->last_time) * trace->last_time;
825 point = (int) (reduced_a / trace->levels[0]->spacing);
826 return trace->levels[0]->values[point];
829 static double get_available_speed(void *cpu)
833 surf_cpu_get_power_scale(CPU->avail_trace, surf_get_clock());
834 /* number between 0 and 1 */
835 return CPU->power_scale;
838 static void finalize(void)
841 xbt_dict_cursor_t cursor;
843 xbt_dict_foreach(surf_model_resource_set(surf_cpu_model), cursor, key, cpu) {
845 xbt_swag_free(CPU->action_set);
846 surf_cpu_free_trace(CPU->avail_trace);
849 surf_model_exit(surf_cpu_model);
850 surf_cpu_model = NULL;
852 xbt_swag_free(running_action_set_that_does_not_need_being_checked);
853 xbt_swag_free(modified_cpu);
854 running_action_set_that_does_not_need_being_checked = NULL;
855 xbt_heap_free(action_heap);
858 static void surf_cpu_model_init_internal(void)
860 s_surf_action_t action;
863 surf_cpu_model = surf_model_init();
865 running_action_set_that_does_not_need_being_checked =
866 xbt_swag_new(xbt_swag_offset(action, state_hookup));
868 modified_cpu = xbt_swag_new(xbt_swag_offset(cpu, modified_cpu_hookup));
870 surf_cpu_model->name = "CPU_TI";
872 surf_cpu_model->action_unref = action_unref;
873 surf_cpu_model->action_cancel = action_cancel;
874 surf_cpu_model->action_state_set = cpu_action_state_set;
876 surf_cpu_model->model_private->resource_used = resource_used;
877 surf_cpu_model->model_private->share_resources = share_resources;
878 surf_cpu_model->model_private->update_actions_state = update_actions_state;
879 surf_cpu_model->model_private->update_resource_state =
880 update_resource_state;
881 surf_cpu_model->model_private->finalize = finalize;
883 surf_cpu_model->suspend = action_suspend;
884 surf_cpu_model->resume = action_resume;
885 surf_cpu_model->is_suspended = action_is_suspended;
886 surf_cpu_model->set_max_duration = action_set_max_duration;
887 surf_cpu_model->set_priority = action_set_priority;
888 surf_cpu_model->get_remains = action_get_remains;
890 surf_cpu_model->extension.cpu.execute = execute;
891 surf_cpu_model->extension.cpu.sleep = action_sleep;
893 surf_cpu_model->extension.cpu.get_state = get_state;
894 surf_cpu_model->extension.cpu.get_speed = get_speed;
895 surf_cpu_model->extension.cpu.get_available_speed = get_available_speed;
897 action_heap = xbt_heap_new(8, NULL);
898 xbt_heap_set_update_callback(action_heap, action_update_index_heap);
902 void surf_cpu_model_init_ti(const char *filename)
906 surf_cpu_model_init_internal();
907 define_callbacks(filename);
908 xbt_dynar_push(model_list, &surf_cpu_model);
912 ///////////////// BEGIN INTEGRAL //////////////
915 * \brief Integrate trace
917 * Wrapper around surf_cpu_integrate_trace_simple() to get
920 * \param trace Trace structure.
921 * \param a Begin of interval
922 * \param b End of interval
923 * \return the integrate value. -1 if an error occurs.
925 static double surf_cpu_integrate_trace(surf_cpu_ti_tgmr_t trace, double a,
931 int a_index, b_index;
933 if ((a < 0.0) || (a > b)) {
935 ("Error, invalid integration interval [%.2f,%.2f]. You probably have a task executing with negative computation amount. Check your code.",
942 if (trace->type == TRACE_FIXED) {
943 return ((b - a) * trace->value);
946 if (ceil(a / trace->last_time) == a / trace->last_time)
947 a_index = 1 + (int) (ceil(a / trace->last_time));
949 a_index = (int) (ceil(a / trace->last_time));
951 b_index = (int) (floor(b / trace->last_time));
953 if (a_index > b_index) { /* Same chunk */
954 return surf_cpu_integrate_trace_simple(trace,
956 1) * trace->last_time,
957 b - (b_index) * trace->last_time);
960 first_chunk = surf_cpu_integrate_trace_simple(trace,
962 1) * trace->last_time,
964 middle_chunk = (b_index - a_index) * trace->total;
965 last_chunk = surf_cpu_integrate_trace_simple(trace,
968 (b_index) * trace->last_time);
970 DEBUG3("first_chunk=%.2f middle_chunk=%.2f last_chunk=%.2f\n",
971 first_chunk, middle_chunk, last_chunk);
973 return (first_chunk + middle_chunk + last_chunk);
977 * \brief Integrate the trace between a and b.
979 * integrates without taking cyclic-traces into account.
980 * [a,b] \subset [0,last_time]
982 * \param trace Trace structure.
983 * \param a Begin of interval
984 * \param b End of interval
985 * \return the integrate value. -1 if an error occurs.
987 static double surf_cpu_integrate_trace_simple(surf_cpu_ti_tgmr_t trace,
990 double integral = 0.0;
994 long l_bounds[TRACE_NB_LEVELS];
995 long u_bounds[TRACE_NB_LEVELS];
996 double a_divided_by_spacing;
997 double current_spacing;
998 DEBUG2("Computing simple integral on [%.2f , %.2f]\n", a, b);
1001 if ((a < 0.0) || (b < a) || (a > trace->last_time)
1002 || (b > trace->last_time)) {
1004 ("Error, invalid integration interval [%.2f,%.2f]. You probably have a task executing with negative computation amount. Check your code.",
1012 for (i = 0; i < trace->nb_levels; i++) {
1013 a_divided_by_spacing = a / trace->levels[i]->spacing;
1014 if (ceil(a_divided_by_spacing) == a_divided_by_spacing)
1015 l_bounds[i] = 1 + (long) ceil(a_divided_by_spacing);
1017 l_bounds[i] = (long) (ceil(a_divided_by_spacing));
1018 if (b == trace->last_time) {
1019 u_bounds[i] = (long) (floor(b / trace->levels[i]->spacing)) - 1;
1021 u_bounds[i] = (long) (floor(b / trace->levels[i]->spacing));
1023 DEBUG3("level %d: l%ld u%ld\n", i, l_bounds[i], u_bounds[i]);
1025 if (l_bounds[i] <= u_bounds[i])
1028 DEBUG1("top_level=%d\n", top_level);
1030 /* Are a and b BOTH in the same chunk of level 0 ? */
1031 if (l_bounds[0] > u_bounds[0]) {
1032 return surf_cpu_integrate_exactly(trace, u_bounds[0], a, b);
1034 return (b - a) * (trace->levels[0]->values[u_bounds[0]]);
1038 /* first sub-level amount */
1039 integral += ((l_bounds[0]) * (trace->levels[0]->spacing) - a) *
1040 (trace->levels[0]->values[l_bounds[0] - 1]);
1042 DEBUG1("Initial level 0 amount is %.2f\n", integral);
1044 /* first n-1 levels */
1045 for (i = 0; i < top_level; i++) {
1047 if (l_bounds[i] >= u_bounds[i])
1050 current_spacing = trace->levels[i]->spacing;
1051 index = l_bounds[i];
1055 while (double_positive
1056 (l_bounds[i + 1] * trace->levels[i + 1]->spacing -
1057 index * current_spacing)) {
1058 integral += current_spacing * trace->levels[i]->values[index];
1059 DEBUG2("%.2f->%.2f|",
1060 index * (trace->levels[i]->spacing),
1061 (index + 1) * (trace->levels[i]->spacing));
1068 DEBUG1("After going up: %.2f\n", integral);
1071 current_spacing = trace->levels[top_level]->spacing;
1072 index = l_bounds[top_level];
1074 DEBUG1("L%d:", top_level);
1076 while (index < u_bounds[top_level]) {
1077 integral += current_spacing * trace->levels[top_level]->values[index];
1079 DEBUG2("%.2f->%.2f|",
1080 index * (trace->levels[top_level]->spacing),
1081 (index + 1) * (trace->levels[top_level]->spacing));
1087 DEBUG1("After steady : %.2f\n", integral);
1089 /* And going back down */
1090 for (i = top_level - 1; i >= 0; i--) {
1091 if (l_bounds[i] > u_bounds[i])
1094 current_spacing = trace->levels[i]->spacing;
1095 index = rint(u_bounds[i + 1] * (trace->levels[i + 1]->spacing /
1098 while (double_positive
1099 ((u_bounds[i]) * current_spacing - index * current_spacing)) {
1100 integral += current_spacing * trace->levels[i]->values[index];
1101 DEBUG2("%.2f->%.2f|",
1102 index * (trace->levels[i]->spacing),
1103 (index + 1) * (trace->levels[i]->spacing));
1108 DEBUG1("After going down : %.2f", integral);
1111 /* Little piece at the end */
1113 integral += (b - u_bounds[0] * (trace->levels[0]->spacing)) *
1114 (trace->levels[0]->values[u_bounds[0]]);
1117 surf_cpu_integrate_exactly(trace, u_bounds[0],
1118 u_bounds[0] * (trace->levels[0]->spacing), b);
1119 DEBUG1("After last bit : %.2f", integral);
1126 * \brief Calcul the time needed to execute "amount" on cpu.
1128 * Here, amount can span multiple trace periods
1130 * \param trace CPU trace structure
1131 * \param a Initial time
1132 * \param amount Amount of calcul to be executed
1135 static double surf_cpu_solve_trace(surf_cpu_ti_tgmr_t trace, double a,
1140 double reduced_amount;
1144 /* Fix very small negative numbers */
1145 if ((a < 0.0) && (a > -EPSILON)) {
1148 if ((amount < 0.0) && (amount > -EPSILON)) {
1153 if ((a < 0.0) || (amount < 0.0)) {
1155 ("Error, invalid parameters [a = %.2f, amount = %.2f]. You probably have a task executing with negative computation amount. Check your code.",
1160 /* At this point, a and amount are positive */
1162 if (amount < EPSILON)
1165 /* Is the trace fixed ? */
1166 if (trace->type == TRACE_FIXED) {
1167 return (a + (amount / trace->value));
1170 DEBUG2("amount %lf total %lf", amount, trace->total);
1171 /* Reduce the problem to one where amount <= trace_total */
1172 quotient = (int) (floor(amount / trace->total));
1173 reduced_amount = (trace->total) * ((amount / trace->total) -
1174 floor(amount / trace->total));
1175 reduced_a = a - (trace->last_time) * (int) (floor(a / trace->last_time));
1177 DEBUG3("Quotient: %d reduced_amount: %lf reduced_a: %lf", quotient,
1178 reduced_amount, reduced_a);
1180 /* Now solve for new_amount which is <= trace_total */
1182 fprintf(stderr,"reduced_a = %.2f\n",reduced_a);
1183 fprintf(stderr,"reduced_amount = %.2f\n",reduced_amount);
1186 surf_cpu_solve_trace_somewhat_simple(trace, reduced_a, reduced_amount);
1188 /* Re-map to the original b and amount */
1189 b = (trace->last_time) * (int) (floor(a / trace->last_time)) +
1190 (quotient * trace->actual_last_time) + reduced_b;
1195 * \brief Auxiliar function to solve integral
1197 * Here, amount is <= trace->total
1198 * and a <=trace->last_time
1201 static double surf_cpu_solve_trace_somewhat_simple(surf_cpu_ti_tgmr_t trace,
1202 double a, double amount)
1204 double amount_till_end;
1207 DEBUG2("Solve integral: [%.2f, amount=%.2f]", a, amount);
1209 amount_till_end = surf_cpu_integrate_trace(trace, a, trace->last_time);
1211 fprintf(stderr,"amount_till_end=%.2f\n",amount_till_end);
1214 if (amount_till_end > amount) {
1215 b = surf_cpu_solve_trace_simple(trace, a, amount);
1217 b = trace->last_time +
1218 surf_cpu_solve_trace_simple(trace, 0.0, amount - amount_till_end);
1225 * \brief Auxiliar function to solve integral
1226 * surf_cpu_solve_trace_simple()
1228 * solve for the upper bound without taking
1229 * cyclic-traces into account.
1231 * [a,y] \subset [0,last_time]
1234 static double surf_cpu_solve_trace_simple(surf_cpu_ti_tgmr_t trace, double a,
1244 long l_bounds[TRACE_NB_LEVELS]; /* May be too bgi for this trace */
1245 double a_divided_by_spacing;
1246 double current_spacing;
1248 DEBUG2("Solving simple integral [x=%.2f,amount=%.2f]", a, amount);
1251 if ((a < 0.0) || (amount < 0.0) || (a > trace->last_time)) {
1253 ("Error, invalid parameters [a = %.2f, amount = %.2f]. You probably have a task executing with negative computation amount. Check your code.",
1257 if (amount == 0.0) {
1258 /* fprintf(stderr,"Warning: trivial integral solve\n"); */
1262 for (i = 0; i < trace->nb_levels; i++) {
1263 a_divided_by_spacing = a / trace->levels[i]->spacing;
1264 if (ceil(a_divided_by_spacing) == a_divided_by_spacing)
1265 l_bounds[i] = 1 + (long) ceil(a_divided_by_spacing);
1267 l_bounds[i] = (long) (ceil(a_divided_by_spacing));
1269 if ((l_bounds[i] + 1) * trace->levels[i]->spacing > trace->last_time)
1272 DEBUG2("level %d: l%ld", i, l_bounds[i]);
1274 if (i == trace->nb_levels)
1275 top_level = trace->nb_levels - 1;
1281 /* first sub-level amount */
1282 /* old code, keep here for a while */
1284 next_chunk = ((l_bounds[0]) * (trace->levels[0]->spacing) - a) *
1285 (trace->levels[0]->values[l_bounds[0] - 1]);
1288 surf_cpu_integrate_exactly(trace, l_bounds[0] - 1, a,
1289 (l_bounds[0]) * (trace->levels[0]->spacing));
1291 if (remains - next_chunk < 0.0) {
1293 b = a + (amount / trace->levels[0]->values[l_bounds[0] - 1]);
1295 b = a + surf_cpu_solve_exactly(trace, l_bounds[0] - 1, a, amount);
1296 DEBUG1("Returning sub-level[0] result %.2f", b);
1300 b = (l_bounds[0]) * (trace->levels[0]->spacing);
1301 remains -= next_chunk;
1303 DEBUG2("After sub-0 stuff: remains %.2f (b=%.2f)", remains, b);
1305 /* first n-1 levels */
1306 DEBUG0("Going up levels");
1309 for (i = 0; i < top_level; i++) {
1311 current_spacing = trace->levels[i]->spacing;
1312 index = l_bounds[i];
1316 while (double_positive
1317 (l_bounds[i + 1] * trace->levels[i + 1]->spacing -
1318 index * current_spacing)
1319 && ((index + 1) * (current_spacing) < trace->last_time)) {
1321 next_chunk = current_spacing * trace->levels[i]->values[index];
1323 DEBUG3("%.2f next_chunk= %.2f remains=%.2f",
1324 (index + 1) * (trace->levels[i]->spacing), next_chunk, remains);
1326 if (remains - next_chunk < 0.0) { /* Too far */
1329 } else { /* Keep going */
1330 DEBUG2("%.2f->%.2f|",
1331 index * (trace->levels[i]->spacing),
1332 (index + 1) * (trace->levels[i]->spacing));
1334 remains -= next_chunk;
1335 b = (index + 1) * (current_spacing);
1340 /* found chunk, fix the index to top level */
1350 current_spacing = trace->levels[top_level]->spacing;
1351 index = l_bounds[top_level];
1353 DEBUG1("L%d:", top_level);
1355 /* iterate over the last level only if it hasn't found the chunk where the amount is */
1357 while (index < trace->levels[top_level]->nb_points) {
1358 next_chunk = current_spacing * trace->levels[top_level]->values[index];
1359 if (remains - next_chunk <= 0.0) { /* Too far */
1362 DEBUG2("%.2f->%.2f|",
1363 index * (trace->levels[top_level]->spacing),
1364 (index + 1) * (trace->levels[top_level]->spacing));
1366 remains -= next_chunk;
1367 b = (index + 1) * (current_spacing);
1372 DEBUG2("remains = %.2f b=%.2f", remains, b);
1374 /* And going back down */
1375 DEBUG0("Going back down");
1376 for (i = top_level - 1; i >= 0; i--) {
1378 current_spacing = trace->levels[i]->spacing;
1379 /* use rint to trunc index due to precision problems */
1380 index = rint(b / trace->levels[i]->spacing);
1384 while (index < trace->levels[i]->nb_points) {
1385 next_chunk = current_spacing * trace->levels[i]->values[index];
1386 DEBUG3("remains %lf nextchu %lf value %lf", remains, next_chunk,
1387 trace->levels[i]->values[index]);
1388 if (remains - next_chunk <= 0.0) { /* Too far */
1391 DEBUG3("%.2f->%.2f| b %lf",
1392 index * (current_spacing), (index + 1) * (current_spacing), b);
1394 remains -= next_chunk;
1395 b += current_spacing;
1401 DEBUG2("remains = %.2f b=%.2f\n", remains, b);
1402 DEBUG1("Last bit index=%ld\n", index);
1404 /* Little piece at the end */
1406 b += (remains) / (trace->levels[0]->values[index]);
1408 b += surf_cpu_solve_exactly(trace, index, b, remains);
1409 DEBUG1("Total b %lf", b);
1414 * \brief This function calcules the exactly value of integral between a and b. It uses directly the tmgr_trace_t strucure.
1415 * It works only if the two points are in the same timestep.
1416 * \param trace Trace structure
1417 * \param index Index of timestep where the points are located
1418 * \param a First point of interval
1419 * \param b Second point
1420 * \return the integral value
1422 static double surf_cpu_integrate_exactly(surf_cpu_ti_tgmr_t trace, int index,
1426 double integral = 0.0;
1429 s_tmgr_event_t elem;
1431 /* already at the end */
1432 if (index >= trace->levels[0]->nb_points && !double_positive(b - a))
1434 tmgr_index = trace->levels[0]->trace_index[index];
1435 tmgr_date = trace->levels[0]->trace_value[index];
1438 ("Start time: %lf End time: %lf index %d tmgr_index %d tmgr_date %lf value %lf",
1439 a, b, index, tmgr_index, tmgr_date, trace->levels[0]->values[index]);
1442 return (b - a) * (trace->levels[0]->values[index]);
1444 while (a > tmgr_date) {
1445 xbt_dynar_get_cpy(trace->levels[0]->power_trace->event_list, tmgr_index,
1447 tmgr_date += elem.delta;
1450 /* sum first slice [a, tmgr_date[ */
1451 if (a < tmgr_date) {
1452 xbt_dynar_get_cpy(trace->levels[0]->power_trace->event_list,
1453 tmgr_index - 1, &elem);
1454 if (b < tmgr_date) {
1455 return (b - a) * elem.value;
1458 integral = (tmgr_date - a) * elem.value;
1463 xbt_dynar_length(trace->levels[0]->power_trace->event_list)) {
1464 xbt_dynar_get_cpy(trace->levels[0]->power_trace->event_list, tmgr_index,
1466 if (b <= time + elem.delta) {
1467 integral += (b - time) * elem.value;
1470 integral += elem.delta * elem.value;
1479 * \brief This function calcules the exactly time needed to compute amount flops. It uses directly the tmgr_trace_t structure.
1480 * It works only if the two points are in the same timestep.
1481 * \param trace Trace structure
1482 * \param index Index of timestep where the points are located
1483 * \param a Start time
1484 * \param amount Total amount
1485 * \return number of seconds needed to compute amount flops
1487 static double surf_cpu_solve_exactly(surf_cpu_ti_tgmr_t trace, int index,
1488 double a, double amount)
1492 double time, tmgr_date;
1493 double slice_amount;
1494 s_tmgr_event_t elem;
1497 tmgr_index = trace->levels[0]->trace_index[index];
1498 tmgr_date = trace->levels[0]->trace_value[index];
1503 ("Start time: %lf Amount: %lf index %d tmgr_index %d tmgr_date %lf value %lf",
1504 a, amount, index, tmgr_index, tmgr_date,
1505 trace->levels[0]->values[index]);
1507 return amount / (trace->levels[0]->values[index]);
1509 while (a > tmgr_date) {
1510 xbt_dynar_get_cpy(trace->levels[0]->power_trace->event_list, tmgr_index,
1512 tmgr_date += elem.delta;
1515 /* sum first slice [a, tmgr_date[ */
1516 if (a < tmgr_date) {
1517 xbt_dynar_get_cpy(trace->levels[0]->power_trace->event_list,
1518 tmgr_index - 1, &elem);
1519 slice_amount = (tmgr_date - a) * elem.value;
1520 DEBUG5("slice amount %lf a %lf tmgr_date %lf elem_value %lf delta %lf",
1521 slice_amount, a, tmgr_date, elem.value, elem.delta);
1522 if (remains <= slice_amount) {
1523 return (remains / elem.value);
1526 remains -= (tmgr_date - a) * elem.value;
1531 xbt_dynar_get_cpy(trace->levels[0]->power_trace->event_list, tmgr_index,
1533 slice_amount = elem.delta * elem.value;
1534 DEBUG5("slice amount %lf a %lf tmgr_date %lf elem_value %lf delta %lf",
1535 slice_amount, a, tmgr_date, elem.value, elem.delta);
1536 if (remains <= slice_amount) {
1537 time += remains / elem.value;
1541 remains -= elem.delta * elem.value;
1548 //////////// END INTEGRAL /////////////////