Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
We may want to use this function in examples.
[simgrid.git] / src / surf / cpu.c
1 /* Copyright (c) 2004, 2005, 2006, 2007, 2008, 2009, 2010. 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 "surf_private.h"
8
9 typedef s_surf_action_lmm_t s_surf_action_cpu_Cas01_t,
10     *surf_action_cpu_Cas01_t;
11
12 typedef struct cpu_Cas01 {
13   s_surf_resource_t generic_resource;
14   double power_peak;
15   double power_scale;
16   int core;
17   tmgr_trace_event_t power_event;
18   e_surf_resource_state_t state_current;
19   tmgr_trace_event_t state_event;
20   lmm_constraint_t constraint;
21 } s_cpu_Cas01_t, *cpu_Cas01_t;
22
23 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_cpu, surf,
24                                 "Logging specific to the SURF CPU module");
25
26
27
28 surf_model_t surf_cpu_model = NULL;
29 lmm_system_t cpu_maxmin_system = NULL;
30
31
32 static xbt_swag_t cpu_running_action_set_that_does_not_need_being_checked =
33     NULL;
34
35 static cpu_Cas01_t cpu_new(char *name, double power_peak,
36                            double power_scale,
37                            tmgr_trace_t power_trace,
38                            int core,
39                            e_surf_resource_state_t state_initial,
40                            tmgr_trace_t state_trace,
41                            xbt_dict_t cpu_properties)
42 {
43   cpu_Cas01_t cpu = xbt_new0(s_cpu_Cas01_t, 1);
44   xbt_assert1(!surf_model_resource_by_name(surf_cpu_model, name),
45               "Host '%s' declared several times in the platform file",
46               name);
47   cpu->generic_resource.model = surf_cpu_model;
48   cpu->generic_resource.name = name;
49   cpu->generic_resource.properties = cpu_properties;
50   cpu->power_peak = power_peak;
51   xbt_assert0(cpu->power_peak > 0, "Power has to be >0");
52   cpu->power_scale = power_scale;
53   cpu->core = core;
54   xbt_assert1(core>0,"Invalid number of cores %d",core);
55   if (power_trace)
56     cpu->power_event =
57         tmgr_history_add_trace(history, power_trace, 0.0, 0, cpu);
58
59   cpu->state_current = state_initial;
60   if (state_trace)
61     cpu->state_event =
62         tmgr_history_add_trace(history, state_trace, 0.0, 0, cpu);
63
64   cpu->constraint =
65       lmm_constraint_new(cpu_maxmin_system, cpu,
66                          cpu->core * cpu->power_scale * cpu->power_peak);
67
68   xbt_dict_set(surf_model_resource_set(surf_cpu_model), name, cpu,
69                surf_resource_free);
70
71   return cpu;
72 }
73
74
75 static void parse_cpu_init(void)
76 {
77   double power_peak = 0.0;
78   double power_scale = 0.0;
79   int core = 0;
80   tmgr_trace_t power_trace = NULL;
81   e_surf_resource_state_t state_initial = SURF_RESOURCE_OFF;
82   tmgr_trace_t state_trace = NULL;
83
84   power_peak = get_cpu_power(A_surfxml_host_power);
85   surf_parse_get_double(&power_scale, A_surfxml_host_availability);
86   power_trace = tmgr_trace_new(A_surfxml_host_availability_file);
87   surf_parse_get_int(&core, A_surfxml_host_core);
88
89   xbt_assert0((A_surfxml_host_state == A_surfxml_host_state_ON) ||
90               (A_surfxml_host_state == A_surfxml_host_state_OFF),
91               "Invalid state");
92   if (A_surfxml_host_state == A_surfxml_host_state_ON)
93     state_initial = SURF_RESOURCE_ON;
94   if (A_surfxml_host_state == A_surfxml_host_state_OFF)
95     state_initial = SURF_RESOURCE_OFF;
96   state_trace = tmgr_trace_new(A_surfxml_host_state_file);
97
98   cpu_new(xbt_strdup(A_surfxml_host_id), power_peak, power_scale,
99           power_trace, core, state_initial, state_trace, current_property_set);
100   current_property_set = NULL;
101 }
102
103 static void add_traces_cpu(void)
104 {
105   xbt_dict_cursor_t cursor = NULL;
106   char *trace_name, *elm;
107
108   static int called = 0;
109
110   if (called)
111     return;
112   called = 1;
113
114
115   /* connect all traces relative to hosts */
116   xbt_dict_foreach(trace_connect_list_host_avail, cursor, trace_name, elm) {
117     tmgr_trace_t trace = xbt_dict_get_or_null(traces_set_list, trace_name);
118     cpu_Cas01_t host = surf_model_resource_by_name(surf_cpu_model, elm);
119
120     xbt_assert1(host, "Host %s undefined", elm);
121     xbt_assert1(trace, "Trace %s undefined", trace_name);
122
123     host->state_event =
124         tmgr_history_add_trace(history, trace, 0.0, 0, host);
125   }
126
127   xbt_dict_foreach(trace_connect_list_power, cursor, trace_name, elm) {
128     tmgr_trace_t trace = xbt_dict_get_or_null(traces_set_list, trace_name);
129     cpu_Cas01_t host = surf_model_resource_by_name(surf_cpu_model, elm);
130
131     xbt_assert1(host, "Host %s undefined", elm);
132     xbt_assert1(trace, "Trace %s undefined", trace_name);
133
134     host->power_event =
135         tmgr_history_add_trace(history, trace, 0.0, 0, host);
136   }
137 }
138
139 static void cpu_define_callbacks(const char *file)
140 {
141   surfxml_add_callback(ETag_surfxml_host_cb_list, parse_cpu_init);
142   surfxml_add_callback(ETag_surfxml_platform_cb_list, &add_traces_cpu);
143 }
144
145 static int cpu_resource_used(void *resource_id)
146 {
147   return lmm_constraint_used(cpu_maxmin_system,
148                              ((cpu_Cas01_t) resource_id)->constraint);
149 }
150
151 static int cpu_action_unref(surf_action_t action)
152 {
153   action->refcount--;
154   if (!action->refcount) {
155     xbt_swag_remove(action, action->state_set);
156     if (((surf_action_cpu_Cas01_t) action)->variable)
157       lmm_variable_free(cpu_maxmin_system,
158                         ((surf_action_cpu_Cas01_t) action)->variable);
159 #ifdef HAVE_TRACING
160     if (action->category)
161       xbt_free(action->category);
162 #endif
163     surf_action_free(&action);
164     return 1;
165   }
166   return 0;
167 }
168
169 static void cpu_action_cancel(surf_action_t action)
170 {
171   surf_action_state_set(action, SURF_ACTION_FAILED);
172   return;
173 }
174
175 static void cpu_action_state_set(surf_action_t action,
176                                  e_surf_action_state_t state)
177 {
178 /*   if((state==SURF_ACTION_DONE) || (state==SURF_ACTION_FAILED)) */
179 /*     if(((surf_action_cpu_Cas01_t)action)->variable) { */
180 /*       lmm_variable_disable(cpu_maxmin_system, ((surf_action_cpu_Cas01_t)action)->variable); */
181 /*       ((surf_action_cpu_Cas01_t)action)->variable = NULL; */
182 /*     } */
183
184   surf_action_state_set(action, state);
185   return;
186 }
187
188 static double cpu_share_resources(double now)
189 {
190   s_surf_action_cpu_Cas01_t action;
191   return generic_maxmin_share_resources(surf_cpu_model->
192                                         states.running_action_set,
193                                         xbt_swag_offset(action, variable),
194                                         cpu_maxmin_system, lmm_solve);
195 }
196
197 static void cpu_update_actions_state(double now, double delta)
198 {
199   surf_action_cpu_Cas01_t action = NULL;
200   surf_action_cpu_Cas01_t next_action = NULL;
201   xbt_swag_t running_actions = surf_cpu_model->states.running_action_set;
202
203   xbt_swag_foreach_safe(action, next_action, running_actions) {
204 #ifdef HAVE_TRACING
205     cpu_Cas01_t x =
206         lmm_constraint_id(lmm_get_cnst_from_var
207                           (cpu_maxmin_system, action->variable, 0));
208
209     TRACE_surf_host_set_utilization(x->generic_resource.name,
210                                     action->generic_action.data,
211                                     (surf_action_t) action,
212                                     lmm_variable_getvalue
213                                     (action->variable), now - delta,
214                                     delta);
215     TRACE_last_timestamp_to_dump = now-delta;
216 #endif
217     double_update(&(action->generic_action.remains),
218                   lmm_variable_getvalue(action->variable) * delta);
219     if (action->generic_action.max_duration != NO_MAX_DURATION)
220       double_update(&(action->generic_action.max_duration), delta);
221     if ((action->generic_action.remains <= 0) &&
222         (lmm_get_variable_weight(action->variable) > 0)) {
223       action->generic_action.finish = surf_get_clock();
224       cpu_action_state_set((surf_action_t) action, SURF_ACTION_DONE);
225     } else if ((action->generic_action.max_duration != NO_MAX_DURATION) &&
226                (action->generic_action.max_duration <= 0)) {
227       action->generic_action.finish = surf_get_clock();
228       cpu_action_state_set((surf_action_t) action, SURF_ACTION_DONE);
229     }
230   }
231
232   return;
233 }
234
235 static void cpu_update_resource_state(void *id,
236                                       tmgr_trace_event_t event_type,
237                                       double value, double date)
238 {
239   cpu_Cas01_t cpu = id;
240   lmm_variable_t var = NULL;
241   lmm_element_t elem = NULL;
242
243   if (event_type == cpu->power_event) {
244     cpu->power_scale = value;
245     lmm_update_constraint_bound(cpu_maxmin_system, cpu->constraint,
246                                 cpu->core * cpu->power_scale * cpu->power_peak);
247 #ifdef HAVE_TRACING
248     TRACE_surf_host_set_power(date, cpu->generic_resource.name,
249                               cpu->core * cpu->power_scale * cpu->power_peak);
250 #endif
251     while ((var = lmm_get_var_from_cnst
252             (cpu_maxmin_system, cpu->constraint, &elem))) {
253         surf_action_cpu_Cas01_t action = lmm_variable_id(var);
254         lmm_update_variable_bound(cpu_maxmin_system, action->variable,
255                                   cpu->power_scale * cpu->power_peak);
256     }
257     if (tmgr_trace_event_free(event_type))
258       cpu->power_event = NULL;
259   } else if (event_type == cpu->state_event) {
260     if (value > 0)
261       cpu->state_current = SURF_RESOURCE_ON;
262     else {
263       lmm_constraint_t cnst = cpu->constraint;
264       lmm_variable_t var = NULL;
265       lmm_element_t elem = NULL;
266
267       cpu->state_current = SURF_RESOURCE_OFF;
268
269       while ((var = lmm_get_var_from_cnst(cpu_maxmin_system, cnst, &elem))) {
270         surf_action_t action = lmm_variable_id(var);
271
272         if (surf_action_state_get(action) == SURF_ACTION_RUNNING ||
273             surf_action_state_get(action) == SURF_ACTION_READY ||
274             surf_action_state_get(action) ==
275             SURF_ACTION_NOT_IN_THE_SYSTEM) {
276           action->finish = date;
277           cpu_action_state_set(action, SURF_ACTION_FAILED);
278         }
279       }
280     }
281     if (tmgr_trace_event_free(event_type))
282       cpu->state_event = NULL;
283   } else {
284     XBT_CRITICAL("Unknown event ! \n");
285     xbt_abort();
286   }
287
288   return;
289 }
290
291 static surf_action_t cpu_execute(void *cpu, double size)
292 {
293   surf_action_cpu_Cas01_t action = NULL;
294   cpu_Cas01_t CPU = cpu;
295
296   XBT_IN("(%s,%g)", surf_resource_name(CPU), size);
297   action =
298       surf_action_new(sizeof(s_surf_action_cpu_Cas01_t), size,
299                       surf_cpu_model,
300                       CPU->state_current != SURF_RESOURCE_ON);
301
302   action->suspended = 0;        /* Should be useless because of the
303                                    calloc but it seems to help valgrind... */
304
305   action->variable = lmm_variable_new(cpu_maxmin_system, action,
306                                       action->generic_action.priority,
307                                       CPU->power_scale * CPU->power_peak, 1);
308   lmm_expand(cpu_maxmin_system, CPU->constraint, action->variable, 1.0);
309   XBT_OUT();
310   return (surf_action_t) action;
311 }
312
313 static surf_action_t cpu_action_sleep(void *cpu, double duration)
314 {
315   surf_action_cpu_Cas01_t action = NULL;
316
317   if (duration > 0)
318     duration = MAX(duration, MAXMIN_PRECISION);
319
320   XBT_IN("(%s,%g)", surf_resource_name(cpu), duration);
321   action = (surf_action_cpu_Cas01_t) cpu_execute(cpu, 1.0);
322   action->generic_action.max_duration = duration;
323   action->suspended = 2;
324   if (duration == NO_MAX_DURATION) {
325     /* Move to the *end* of the corresponding action set. This convention
326        is used to speed up update_resource_state  */
327     xbt_swag_remove(action, ((surf_action_t) action)->state_set);
328     ((surf_action_t) action)->state_set =
329         cpu_running_action_set_that_does_not_need_being_checked;
330     xbt_swag_insert(action, ((surf_action_t) action)->state_set);
331   }
332
333   lmm_update_variable_weight(cpu_maxmin_system, action->variable, 0.0);
334   XBT_OUT();
335   return (surf_action_t) action;
336 }
337
338 static void cpu_action_suspend(surf_action_t action)
339 {
340   XBT_IN("(%p)", action);
341   if (((surf_action_cpu_Cas01_t) action)->suspended != 2) {
342     lmm_update_variable_weight(cpu_maxmin_system,
343                                ((surf_action_cpu_Cas01_t)
344                                 action)->variable, 0.0);
345     ((surf_action_cpu_Cas01_t) action)->suspended = 1;
346   }
347   XBT_OUT();
348 }
349
350 static void cpu_action_resume(surf_action_t action)
351 {
352   XBT_IN("(%p)", action);
353   if (((surf_action_cpu_Cas01_t) action)->suspended != 2) {
354     lmm_update_variable_weight(cpu_maxmin_system,
355                                ((surf_action_cpu_Cas01_t)
356                                 action)->variable, action->priority);
357     ((surf_action_cpu_Cas01_t) action)->suspended = 0;
358   }
359   XBT_OUT();
360 }
361
362 static int cpu_action_is_suspended(surf_action_t action)
363 {
364   return (((surf_action_cpu_Cas01_t) action)->suspended == 1);
365 }
366
367 static void cpu_action_set_max_duration(surf_action_t action,
368                                         double duration)
369 {
370   XBT_IN("(%p,%g)", action, duration);
371   action->max_duration = duration;
372   XBT_OUT();
373 }
374
375 static void cpu_action_set_priority(surf_action_t action, double priority)
376 {
377   XBT_IN("(%p,%g)", action, priority);
378   action->priority = priority;
379   lmm_update_variable_weight(cpu_maxmin_system,
380                              ((surf_action_cpu_Cas01_t) action)->variable,
381                              priority);
382
383   XBT_OUT();
384 }
385
386 #ifdef HAVE_TRACING
387 static void cpu_action_set_category(surf_action_t action, const char *category)
388 {
389   XBT_IN("(%p,%s)", action, category);
390   action->category = xbt_strdup (category);
391   XBT_OUT();
392 }
393 #endif
394
395 static double cpu_action_get_remains(surf_action_t action)
396 {
397   XBT_IN("(%p)", action);
398   return action->remains;
399   XBT_OUT();
400 }
401
402 static e_surf_resource_state_t cpu_get_state(void *cpu)
403 {
404   return ((cpu_Cas01_t) cpu)->state_current;
405 }
406
407 static double cpu_get_speed(void *cpu, double load)
408 {
409   return load * (((cpu_Cas01_t) cpu)->power_peak);
410 }
411
412 static double cpu_get_available_speed(void *cpu)
413 {
414   /* number between 0 and 1 */
415   return ((cpu_Cas01_t) cpu)->power_scale;
416 }
417
418 static void cpu_create_resource(char *name, double power_peak,
419                                 double power_scale,
420                                 tmgr_trace_t power_trace,
421                                 int core,
422                                 e_surf_resource_state_t state_initial,
423                                 tmgr_trace_t state_trace,
424                                 xbt_dict_t cpu_properties)
425 {
426   cpu_new(name, power_peak, power_scale, power_trace, core,
427           state_initial, state_trace, cpu_properties);
428 }
429
430 static void cpu_finalize(void)
431 {
432   lmm_system_free(cpu_maxmin_system);
433   cpu_maxmin_system = NULL;
434
435   surf_model_exit(surf_cpu_model);
436   surf_cpu_model = NULL;
437
438   xbt_swag_free(cpu_running_action_set_that_does_not_need_being_checked);
439   cpu_running_action_set_that_does_not_need_being_checked = NULL;
440 }
441
442 static void surf_cpu_model_init_internal(void)
443 {
444   s_surf_action_t action;
445
446   surf_cpu_model = surf_model_init();
447
448   cpu_running_action_set_that_does_not_need_being_checked =
449       xbt_swag_new(xbt_swag_offset(action, state_hookup));
450
451   surf_cpu_model->name = "CPU";
452
453   surf_cpu_model->action_unref = cpu_action_unref;
454   surf_cpu_model->action_cancel = cpu_action_cancel;
455   surf_cpu_model->action_state_set = cpu_action_state_set;
456
457   surf_cpu_model->model_private->resource_used = cpu_resource_used;
458   surf_cpu_model->model_private->share_resources = cpu_share_resources;
459   surf_cpu_model->model_private->update_actions_state =
460       cpu_update_actions_state;
461   surf_cpu_model->model_private->update_resource_state =
462       cpu_update_resource_state;
463   surf_cpu_model->model_private->finalize = cpu_finalize;
464
465   surf_cpu_model->suspend = cpu_action_suspend;
466   surf_cpu_model->resume = cpu_action_resume;
467   surf_cpu_model->is_suspended = cpu_action_is_suspended;
468   surf_cpu_model->set_max_duration = cpu_action_set_max_duration;
469   surf_cpu_model->set_priority = cpu_action_set_priority;
470 #ifdef HAVE_TRACING
471   surf_cpu_model->set_category = cpu_action_set_category;
472 #endif
473   surf_cpu_model->get_remains = cpu_action_get_remains;
474
475   surf_cpu_model->extension.cpu.execute = cpu_execute;
476   surf_cpu_model->extension.cpu.sleep = cpu_action_sleep;
477
478   surf_cpu_model->extension.cpu.get_state = cpu_get_state;
479   surf_cpu_model->extension.cpu.get_speed = cpu_get_speed;
480   surf_cpu_model->extension.cpu.get_available_speed =
481       cpu_get_available_speed;
482   surf_cpu_model->extension.cpu.create_resource = cpu_create_resource;
483   surf_cpu_model->extension.cpu.add_traces = add_traces_cpu;
484
485   if (!cpu_maxmin_system)
486     cpu_maxmin_system = lmm_system_new();
487 }
488
489 /*********************************************************************/
490 /* Basic sharing model for CPU: that is where all this started... ;) */
491 /*********************************************************************/
492 /* @InProceedings{casanova01simgrid, */
493 /*   author =       "H. Casanova", */
494 /*   booktitle =    "Proceedings of the IEEE Symposium on Cluster Computing */
495 /*                  and the Grid (CCGrid'01)", */
496 /*   publisher =    "IEEE Computer Society", */
497 /*   title =        "Simgrid: {A} Toolkit for the Simulation of Application */
498 /*                  Scheduling", */
499 /*   year =         "2001", */
500 /*   month =        may, */
501 /*   note =         "Available at */
502 /*                  \url{http://grail.sdsc.edu/papers/simgrid_ccgrid01.ps.gz}." */
503 /* } */
504 void surf_cpu_model_init_Cas01(const char *filename)
505 {
506   if (surf_cpu_model)
507     return;
508   surf_cpu_model_init_internal();
509   cpu_define_callbacks(filename);
510   xbt_dynar_push(model_list, &surf_cpu_model);
511 }