1 /* Copyright (c) 2004-2013. The SimGrid Team.
2 * All rights reserved. */
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. */
7 #include "surf_private.h"
8 #include "xbt/module.h"
10 #include "simix/smx_host_private.h"
11 #include "surf/surf_resource.h"
12 #include "xbt/xbt_os_thread.h"
13 #include "simgrid/sg_config.h"
17 XBT_LOG_NEW_CATEGORY(surf, "All SURF categories");
18 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_kernel, surf,
19 "Logging specific to SURF (kernel)");
21 /* Additional declarations for Windows portability. */
29 static const char *disk_drives_letter_table[MAX_DRIVE] = {
57 #endif /* #ifdef _XBT_WIN32 */
60 * Returns the initial path. On Windows the initial path is
61 * the current directory for the current process in the other
62 * case the function returns "./" that represents the current
63 * directory on Unix/Linux platforms.
66 const char *__surf_get_initial_path(void)
71 char current_directory[MAX_PATH + 1] = { 0 };
72 unsigned int len = GetCurrentDirectory(MAX_PATH + 1, current_directory);
78 strncpy(root, current_directory, 3);
80 for (i = 0; i < MAX_DRIVE; i++) {
81 if (toupper(root[0]) == disk_drives_letter_table[i][0])
82 return disk_drives_letter_table[i];
91 /* The __surf_is_absolute_file_path() returns 1 if
92 * file_path is a absolute file path, in the other
93 * case the function returns 0.
95 int __surf_is_absolute_file_path(const char *file_path)
98 WIN32_FIND_DATA wfd = { 0 };
99 HANDLE hFile = FindFirstFile(file_path, &wfd);
101 if (INVALID_HANDLE_VALUE == hFile)
107 return (file_path[0] == '/');
113 /* model_list_invoke contains only surf_workstation and surf_vm_workstation.
114 * The callback functions of cpu_model and network_model will be called from
115 * those of these workstation models. */
116 xbt_dynar_t model_list = NULL; /* for destroying all models correctly */
117 xbt_dynar_t model_list_invoke = NULL; /* for invoking callbacks */
118 tmgr_history_t history = NULL;
119 lmm_system_t maxmin_system = NULL;
120 xbt_dynar_t surf_path = NULL;
121 xbt_dynar_t host_that_restart = NULL;
122 xbt_dict_t watched_hosts_lib;
124 /* Don't forget to update the option description in smx_config when you change this */
125 s_surf_model_description_t surf_network_model_description[] = {
127 "Realistic network analytic model (slow-start modeled by multiplying latency by 10.4, bandwidth by .92; bottleneck sharing uses a payload of S=8775 for evaluating RTT). ",
128 surf_network_model_init_LegrandVelho},
130 "Simplistic network model where all communication take a constant time (one second). This model provides the lowest realism, but is (marginally) faster.",
131 surf_network_model_init_Constant},
133 "Realistic network model specifically tailored for HPC settings (accurate modeling of slow start with correction factors on three intervals: < 1KiB, < 64 KiB, >= 64 KiB)",
134 surf_network_model_init_SMPI},
136 "Legacy network analytic model (Very similar to LV08, but without corrective factors. The timings of small messages are thus poorly modeled).",
137 surf_network_model_init_CM02},
140 "Network pseudo-model using the GTNets simulator instead of an analytic model",
141 surf_network_model_init_GTNETS},
145 "Network pseudo-model using the NS3 tcp model instead of an analytic model",
146 surf_network_model_init_NS3},
149 "Model from Steven H. Low using lagrange_solve instead of lmm_solve (experts only; check the code for more info).",
150 surf_network_model_init_Reno},
152 "Model from Steven H. Low using lagrange_solve instead of lmm_solve (experts only; check the code for more info).",
153 surf_network_model_init_Reno2},
155 "Model from Steven H. Low using lagrange_solve instead of lmm_solve (experts only; check the code for more info).",
156 surf_network_model_init_Vegas},
157 {NULL, NULL, NULL} /* this array must be NULL terminated */
160 s_surf_model_description_t surf_cpu_model_description[] = {
162 "Simplistic CPU model (time=size/power).",
163 surf_cpu_model_init_Cas01},
164 {NULL, NULL, NULL} /* this array must be NULL terminated */
167 s_surf_model_description_t surf_workstation_model_description[] = {
169 "Default workstation model. Currently, CPU:Cas01 and network:LV08 (with cross traffic enabled)",
170 surf_workstation_model_init_current_default},
172 "Workstation model that is automatically chosen if you change the network and CPU models",
173 surf_workstation_model_init_compound},
174 {"ptask_L07", "Workstation model somehow similar to Cas01+CM02 but allowing parallel tasks",
175 surf_workstation_model_init_ptask_L07},
176 {NULL, NULL, NULL} /* this array must be NULL terminated */
179 s_surf_model_description_t surf_optimization_mode_description[] = {
181 "Lazy action management (partial invalidation in lmm + heap in action remaining).",
184 "Trace integration. Highly optimized mode when using availability traces (only available for the Cas01 CPU model for now).",
187 "Full update of remaining and variables. Slow but may be useful when debugging.",
189 {NULL, NULL, NULL} /* this array must be NULL terminated */
192 s_surf_model_description_t surf_storage_model_description[] = {
194 "Simplistic storage model.",
195 surf_storage_model_init_default},
196 {NULL, NULL, NULL} /* this array must be NULL terminated */
199 /* ********************************************************************* */
200 /* TUTORIAL: New model */
201 s_surf_model_description_t surf_new_model_description[] = {
204 surf_new_model_init_default},
205 {NULL, NULL, NULL} /* this array must be NULL terminated */
207 /* ********************************************************************* */
209 #ifdef CONTEXT_THREADS
210 static xbt_parmap_t surf_parmap = NULL; /* parallel map on models */
213 static double *surf_mins = NULL; /* return value of share_resources for each model */
214 static int surf_min_index; /* current index in surf_mins */
215 static double min; /* duration determined by surf_solve */
217 static void surf_share_resources(surf_model_t model);
218 static void surf_update_actions_state(surf_model_t model);
220 /** Displays the long description of all registered models, and quit */
221 void model_help(const char *category, s_surf_model_description_t * table)
224 printf("Long description of the %s models accepted by this simulator:\n",
226 for (i = 0; table[i].name; i++)
227 printf(" %s: %s\n", table[i].name, table[i].description);
230 int find_model_description(s_surf_model_description_t * table,
234 char *name_list = NULL;
236 for (i = 0; table[i].name; i++)
237 if (!strcmp(name, table[i].name)) {
241 xbt_die("No model is valid! This is a bug.");
242 name_list = xbt_strdup(table[0].name);
243 for (i = 1; table[i].name; i++) {
245 xbt_realloc(name_list,
246 strlen(name_list) + strlen(table[i].name) + 3);
247 strcat(name_list, ", ");
248 strcat(name_list, table[i].name);
250 xbt_die("Model '%s' is invalid! Valid models are: %s.", name, name_list);
254 double generic_maxmin_share_resources(xbt_swag_t running_actions,
257 void (*solve) (lmm_system_t))
259 surf_action_t action = NULL;
262 #define VARIABLE(action) (*((lmm_variable_t*)(((char *) (action)) + (offset))))
266 xbt_swag_foreach(action, running_actions) {
267 value = lmm_variable_getvalue(VARIABLE(action));
268 if ((value > 0) || (action->max_duration >= 0))
276 if (action->remains > 0)
277 min = action->remains / value;
280 if ((action->max_duration >= 0) && (action->max_duration < min))
281 min = action->max_duration;
283 min = action->max_duration;
286 for (action = xbt_swag_getNext(action, running_actions->offset);
288 action = xbt_swag_getNext(action, running_actions->offset)) {
289 value = lmm_variable_getvalue(VARIABLE(action));
291 if (action->remains > 0)
292 value = action->remains / value;
297 XBT_DEBUG("Updating min (value) with %p: %f", action, min);
300 if ((action->max_duration >= 0) && (action->max_duration < min)) {
301 min = action->max_duration;
302 XBT_DEBUG("Updating min (duration) with %p: %f", action, min);
305 XBT_DEBUG("min value : %f", min);
311 double generic_share_resources_lazy(double now, surf_model_t model)
313 surf_action_lmm_t action = NULL;
318 ("Before share resources, the size of modified actions set is %d",
319 xbt_swag_size(model->model_private->modified_set));
321 lmm_solve(model->model_private->maxmin_system);
324 ("After share resources, The size of modified actions set is %d",
325 xbt_swag_size(model->model_private->modified_set));
327 while((action = xbt_swag_extract(model->model_private->modified_set))) {
328 int max_dur_flag = 0;
330 if (action->generic_action.state_set !=
331 model->states.running_action_set)
334 /* bogus priority, skip it */
335 if (action->generic_action.priority <= 0)
338 generic_update_action_remaining_lazy(action,now);
341 value = lmm_variable_getvalue(action->variable);
343 if (action->generic_action.remains > 0) {
344 value = action->generic_action.remains / value;
352 if ((action->generic_action.max_duration != NO_MAX_DURATION)
354 || action->generic_action.start +
355 action->generic_action.max_duration < min)) {
356 min = action->generic_action.start +
357 action->generic_action.max_duration;
361 XBT_DEBUG("Action(%p) Start %f Finish %f Max_duration %f", action,
362 action->generic_action.start, now + value,
363 action->generic_action.max_duration);
366 surf_action_lmm_heap_remove(model->model_private->action_heap,action);
367 surf_action_lmm_heap_insert(model->model_private->action_heap,action, min, max_dur_flag ? MAX_DURATION : NORMAL);
368 XBT_DEBUG("Insert at heap action(%p) min %f now %f", action, min,
370 } else DIE_IMPOSSIBLE;
373 //hereafter must have already the min value for this resource model
374 if (xbt_heap_size(model->model_private->action_heap) > 0)
375 min = xbt_heap_maxkey(model->model_private->action_heap) - now;
379 XBT_DEBUG("The minimum with the HEAP %f", min);
383 static XBT_INLINE void routing_asr_host_free(void *p)
385 sg_routing_edge_t elm = p;
390 static XBT_INLINE void routing_asr_prop_free(void *p)
396 void sg_version(int *ver_major,int *ver_minor,int *ver_patch) {
397 *ver_major = SIMGRID_VERSION_MAJOR;
398 *ver_minor = SIMGRID_VERSION_MINOR;
399 *ver_patch = SIMGRID_VERSION_PATCH;
402 void surf_init(int *argc, char **argv)
404 XBT_DEBUG("Create all Libs");
405 host_lib = xbt_lib_new();
406 link_lib = xbt_lib_new();
407 as_router_lib = xbt_lib_new();
408 storage_lib = xbt_lib_new();
409 storage_type_lib = xbt_lib_new();
410 watched_hosts_lib = xbt_dict_new_homogeneous(NULL);
412 XBT_DEBUG("Add routing levels");
413 ROUTING_HOST_LEVEL = xbt_lib_add_level(host_lib,routing_asr_host_free);
414 ROUTING_ASR_LEVEL = xbt_lib_add_level(as_router_lib,routing_asr_host_free);
415 ROUTING_PROP_ASR_LEVEL = xbt_lib_add_level(as_router_lib,routing_asr_prop_free);
417 XBT_DEBUG("Add SURF levels");
418 SURF_CPU_LEVEL = xbt_lib_add_level(host_lib,surf_resource_free);
419 SURF_WKS_LEVEL = xbt_lib_add_level(host_lib,surf_resource_free);
420 SURF_LINK_LEVEL = xbt_lib_add_level(link_lib,surf_resource_free);
422 xbt_init(argc, argv);
424 model_list = xbt_dynar_new(sizeof(surf_model_private_t), NULL);
425 if (!model_list_invoke)
426 model_list_invoke = xbt_dynar_new(sizeof(surf_model_private_t), NULL);
428 history = tmgr_history_new();
431 TRACE_add_start_function(TRACE_surf_alloc);
432 TRACE_add_end_function(TRACE_surf_release);
435 sg_config_init(argc, argv);
443 # define FILE_DELIM "\\"
445 # define FILE_DELIM "/" /* FIXME: move to better location */
448 FILE *surf_fopen(const char *name, const char *mode)
451 char *path_elm = NULL;
457 if (__surf_is_absolute_file_path(name)) /* don't mess with absolute file names */
458 return fopen(name, mode);
460 /* search relative files in the path */
461 xbt_dynar_foreach(surf_path, cpt, path_elm) {
462 buff = bprintf("%s" FILE_DELIM "%s", path_elm, name);
463 file = fopen(buff, mode);
475 surf_model_t model = NULL;
478 TRACE_end(); /* Just in case it was not called by the upper
479 * layer (or there is no upper layer) */
482 sg_config_finalize();
484 xbt_dynar_foreach(model_list, iter, model)
485 model->model_private->finalize(model);
486 xbt_dynar_free(&model_list);
488 xbt_dynar_free(&model_list_invoke);
493 lmm_system_free(maxmin_system);
494 maxmin_system = NULL;
497 tmgr_history_free(history);
502 #ifdef CONTEXT_THREADS
503 xbt_parmap_destroy(surf_parmap);
507 xbt_dynar_free(&host_that_restart);
508 xbt_dynar_free(&surf_path);
510 xbt_lib_free(&host_lib);
511 xbt_lib_free(&link_lib);
512 xbt_lib_free(&as_router_lib);
513 xbt_lib_free(&storage_lib);
514 xbt_lib_free(&storage_type_lib);
516 xbt_dict_free(&watched_hosts_lib);
519 surf_parse_lex_destroy();
520 surf_parse_free_callbacks();
522 NOW = 0; /* Just in case the user plans to restart the simulation afterward */
525 void surf_presolve(void)
527 double next_event_date = -1.0;
528 tmgr_trace_event_t event = NULL;
530 surf_resource_t resource = NULL;
531 surf_model_t model = NULL;
535 ("First Run! Let's \"purge\" events and put models in the right state");
536 while ((next_event_date = tmgr_history_next_date(history)) != -1.0) {
537 if (next_event_date > NOW)
540 tmgr_history_get_next_event_leq(history, next_event_date,
542 (void **) &resource))) {
544 resource->model->model_private->update_resource_state(resource,
551 /* FIXME: see what is check_update_action_state(). if necessary, use model_list_invoke. */
552 xbt_dynar_foreach(model_list, iter, model)
553 model->model_private->update_actions_state(model, NOW, 0.0);
556 double surf_solve(double max_date)
559 min = -1.0; /* duration */
560 double next_event_date = -1.0;
561 double model_next_action_end = -1.0;
563 surf_resource_t resource = NULL;
564 surf_model_t model = NULL;
565 tmgr_trace_event_t event = NULL;
568 if(!host_that_restart)
569 host_that_restart = xbt_dynar_new(sizeof(char*), NULL);
571 if (max_date != -1.0 && max_date != NOW) {
572 min = max_date - NOW;
575 XBT_DEBUG("Looking for next action end for all models except NS3");
577 if (surf_mins == NULL) {
578 surf_mins = xbt_new(double, xbt_dynar_length(model_list_invoke));
582 /* sequential version */
583 xbt_dynar_foreach(model_list_invoke, iter, model) {
584 surf_share_resources(model);
587 for (i = 0; i < xbt_dynar_length(model_list_invoke); i++) {
588 if ((min < 0.0 || surf_mins[i] < min)
589 && surf_mins[i] >= 0.0) {
594 XBT_DEBUG("Min for resources (remember that NS3 don't update that value) : %f", min);
596 XBT_DEBUG("Looking for next trace event");
599 XBT_DEBUG("Next TRACE event : %f", next_event_date);
601 next_event_date = tmgr_history_next_date(history);
603 if(surf_network_model->name && !strcmp(surf_network_model->name,"network NS3")){
604 if(next_event_date!=-1.0 && min!=-1.0) {
605 min = MIN(next_event_date - NOW, min);
607 min = MAX(next_event_date - NOW, min);
610 XBT_DEBUG("Run for network at most %f", min);
611 // run until min or next flow
612 model_next_action_end = surf_network_model->model_private->share_resources(surf_network_model, min);
614 XBT_DEBUG("Min for network : %f", model_next_action_end);
615 if(model_next_action_end>=0.0)
616 min = model_next_action_end;
619 if (next_event_date < 0.0) {
620 XBT_DEBUG("no next TRACE event. Stop searching for it");
624 if ((min == -1.0) || (next_event_date > NOW + min)) break;
626 XBT_DEBUG("Updating models (min = %g, NOW = %g, next_event_date = %g)",min, NOW, next_event_date);
628 tmgr_history_get_next_event_leq(history, next_event_date,
630 (void **) &resource))) {
631 if (resource->model->model_private->resource_used(resource) ||
632 xbt_dict_get_or_null(watched_hosts_lib,resource->name)
634 min = next_event_date - NOW;
636 ("This event will modify model state. Next event set to %f",
639 /* update state of model_obj according to new value. Does not touch lmm.
640 It will be modified if needed when updating actions */
641 XBT_DEBUG("Calling update_resource_state for resource %s with min %f",
642 resource->name, min);
644 resource->model->model_private->update_resource_state(resource,
650 /* FIXME: Moved this test to here to avoid stopping simulation if there are actions running on cpus and all cpus are with availability = 0.
651 * This may cause an infinite loop if one cpu has a trace with periodicity = 0 and the other a trace with periodicity > 0.
652 * The options are: all traces with same periodicity(0 or >0) or we need to change the way how the events are managed */
654 XBT_DEBUG("No next event at all. Bail out now.");
658 XBT_DEBUG("Duration set to %f", min);
661 /* FIXME: model_list or model_list_invoke? revisit here later */
662 /* sequential version */
663 xbt_dynar_foreach(model_list, iter, model) {
664 surf_update_actions_state(model);
668 TRACE_paje_dump_buffer (0);
674 XBT_INLINE double surf_get_clock(void)
679 static void surf_share_resources(surf_model_t model)
681 double next_action_end = -1.0;
682 int i = __sync_fetch_and_add(&surf_min_index, 1);
683 if (strcmp(model->name,"network NS3")) {
684 XBT_DEBUG("Running for Resource [%s]", model->name);
685 next_action_end = model->model_private->share_resources(model, NOW);
686 XBT_DEBUG("Resource [%s] : next action end = %f",
687 model->name, next_action_end);
689 surf_mins[i] = next_action_end;
692 static void surf_update_actions_state(surf_model_t model)
694 model->model_private->update_actions_state(model, NOW, min);