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 xbt_dynar_t model_list = NULL;
114 tmgr_history_t history = NULL;
115 lmm_system_t maxmin_system = NULL;
116 xbt_dynar_t surf_path = NULL;
117 xbt_dynar_t host_that_restart = NULL;
118 xbt_dict_t watched_hosts_lib;
120 /* Don't forget to update the option description in smx_config when you change this */
121 s_surf_model_description_t surf_network_model_description[] = {
123 "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). ",
124 surf_network_model_init_LegrandVelho},
126 "Simplistic network model where all communication take a constant time (one second). This model provides the lowest realism, but is (marginally) faster.",
127 surf_network_model_init_Constant},
129 "Realistic network model specifically tailored for HPC settings (accurate modeling of slow start with correction factors on three intervals: < 1KiB, < 64 KiB, >= 64 KiB)",
130 surf_network_model_init_SMPI},
132 "Legacy network analytic model (Very similar to LV08, but without corrective factors. The timings of small messages are thus poorly modeled).",
133 surf_network_model_init_CM02},
136 "Network pseudo-model using the GTNets simulator instead of an analytic model",
137 surf_network_model_init_GTNETS},
141 "Network pseudo-model using the NS3 tcp model instead of an analytic model",
142 surf_network_model_init_NS3},
145 "Model from Steven H. Low using lagrange_solve instead of lmm_solve (experts only; check the code for more info).",
146 surf_network_model_init_Reno},
148 "Model from Steven H. Low using lagrange_solve instead of lmm_solve (experts only; check the code for more info).",
149 surf_network_model_init_Reno2},
151 "Model from Steven H. Low using lagrange_solve instead of lmm_solve (experts only; check the code for more info).",
152 surf_network_model_init_Vegas},
153 {NULL, NULL, NULL} /* this array must be NULL terminated */
156 s_surf_model_description_t surf_cpu_model_description[] = {
158 "Simplistic CPU model (time=size/power).",
159 surf_cpu_model_init_Cas01},
160 {NULL, NULL, NULL} /* this array must be NULL terminated */
163 s_surf_model_description_t surf_workstation_model_description[] = {
165 "Default workstation model. Currently, CPU:Cas01 and network:LV08 (with cross traffic enabled)",
166 surf_workstation_model_init_current_default},
168 "Workstation model that is automatically chosen if you change the network and CPU models",
169 surf_workstation_model_init_compound},
170 {"ptask_L07", "Workstation model somehow similar to Cas01+CM02 but allowing parallel tasks",
171 surf_workstation_model_init_ptask_L07},
172 {NULL, NULL, NULL} /* this array must be NULL terminated */
175 s_surf_model_description_t surf_optimization_mode_description[] = {
177 "Lazy action management (partial invalidation in lmm + heap in action remaining).",
180 "Trace integration. Highly optimized mode when using availability traces (only available for the Cas01 CPU model for now).",
183 "Full update of remaining and variables. Slow but may be useful when debugging.",
185 {NULL, NULL, NULL} /* this array must be NULL terminated */
188 s_surf_model_description_t surf_storage_model_description[] = {
190 "Simplistic storage model.",
191 surf_storage_model_init_default},
192 {NULL, NULL, NULL} /* this array must be NULL terminated */
195 /* ********************************************************************* */
196 /* TUTORIAL: New model */
197 s_surf_model_description_t surf_new_model_description[] = {
200 surf_new_model_init_default},
201 {NULL, NULL, NULL} /* this array must be NULL terminated */
203 /* ********************************************************************* */
205 #ifdef CONTEXT_THREADS
206 static xbt_parmap_t surf_parmap = NULL; /* parallel map on models */
209 static int surf_nthreads = 1; /* number of threads of the parmap (1 means no parallelism) */
210 static int surf_parallel_threshold = 1; /* minimal number of pending actions to
211 * update Surf models in parallel */
212 static double *surf_mins = NULL; /* return value of share_resources for each model */
213 static int surf_min_index; /* current index in surf_mins */
214 static double min; /* duration determined by surf_solve */
216 static void surf_share_resources(surf_model_t model);
217 static void surf_update_actions_state(surf_model_t model);
219 /** Displays the long description of all registered models, and quit */
220 void model_help(const char *category, s_surf_model_description_t * table)
223 printf("Long description of the %s models accepted by this simulator:\n",
225 for (i = 0; table[i].name; i++)
226 printf(" %s: %s\n", table[i].name, table[i].description);
229 int find_model_description(s_surf_model_description_t * table,
233 char *name_list = NULL;
235 for (i = 0; table[i].name; i++)
236 if (!strcmp(name, table[i].name)) {
240 xbt_die("No model is valid! This is a bug.");
241 name_list = xbt_strdup(table[0].name);
242 for (i = 1; table[i].name; i++) {
244 xbt_realloc(name_list,
245 strlen(name_list) + strlen(table[i].name) + 3);
246 strcat(name_list, ", ");
247 strcat(name_list, table[i].name);
249 xbt_die("Model '%s' is invalid! Valid models are: %s.", name, name_list);
253 double generic_maxmin_share_resources(xbt_swag_t running_actions,
256 void (*solve) (lmm_system_t))
258 surf_action_t action = NULL;
261 #define VARIABLE(action) (*((lmm_variable_t*)(((char *) (action)) + (offset))))
265 xbt_swag_foreach(action, running_actions) {
266 value = lmm_variable_getvalue(VARIABLE(action));
267 if ((value > 0) || (action->max_duration >= 0))
275 if (action->remains > 0)
276 min = action->remains / value;
279 if ((action->max_duration >= 0) && (action->max_duration < min))
280 min = action->max_duration;
282 min = action->max_duration;
285 for (action = xbt_swag_getNext(action, running_actions->offset);
287 action = xbt_swag_getNext(action, running_actions->offset)) {
288 value = lmm_variable_getvalue(VARIABLE(action));
290 if (action->remains > 0)
291 value = action->remains / value;
296 XBT_DEBUG("Updating min (value) with %p: %f", action, min);
299 if ((action->max_duration >= 0) && (action->max_duration < min)) {
300 min = action->max_duration;
301 XBT_DEBUG("Updating min (duration) with %p: %f", action, min);
304 XBT_DEBUG("min value : %f", min);
310 double generic_share_resources_lazy(double now, surf_model_t model)
312 surf_action_lmm_t action = NULL;
317 ("Before share resources, the size of modified actions set is %d",
318 xbt_swag_size(model->model_private->modified_set));
320 lmm_solve(model->model_private->maxmin_system);
323 ("After share resources, The size of modified actions set is %d",
324 xbt_swag_size(model->model_private->modified_set));
326 while((action = xbt_swag_extract(model->model_private->modified_set))) {
327 int max_dur_flag = 0;
329 if (action->generic_action.state_set !=
330 model->states.running_action_set)
333 /* bogus priority, skip it */
334 if (action->generic_action.priority <= 0)
337 generic_update_action_remaining_lazy(action,now);
340 value = lmm_variable_getvalue(action->variable);
342 if (action->generic_action.remains > 0) {
343 value = action->generic_action.remains / value;
351 if ((action->generic_action.max_duration != NO_MAX_DURATION)
353 || action->generic_action.start +
354 action->generic_action.max_duration < min)) {
355 min = action->generic_action.start +
356 action->generic_action.max_duration;
360 XBT_DEBUG("Action(%p) Start %f Finish %f Max_duration %f", action,
361 action->generic_action.start, now + value,
362 action->generic_action.max_duration);
365 surf_action_lmm_heap_remove(model->model_private->action_heap,action);
366 surf_action_lmm_heap_insert(model->model_private->action_heap,action, min, max_dur_flag ? MAX_DURATION : NORMAL);
367 XBT_DEBUG("Insert at heap action(%p) min %f now %f", action, min,
369 } else DIE_IMPOSSIBLE;
372 //hereafter must have already the min value for this resource model
373 if (xbt_heap_size(model->model_private->action_heap) > 0)
374 min = xbt_heap_maxkey(model->model_private->action_heap) - now;
378 XBT_DEBUG("The minimum with the HEAP %f", min);
382 static XBT_INLINE void routing_asr_host_free(void *p)
384 sg_routing_edge_t elm = p;
389 static XBT_INLINE void routing_asr_prop_free(void *p)
395 void sg_version(int *ver_major,int *ver_minor,int *ver_patch) {
396 *ver_major = SIMGRID_VERSION_MAJOR;
397 *ver_minor = SIMGRID_VERSION_MINOR;
398 *ver_patch = SIMGRID_VERSION_PATCH;
401 void surf_init(int *argc, char **argv)
403 XBT_DEBUG("Create all Libs");
404 host_lib = xbt_lib_new();
405 link_lib = xbt_lib_new();
406 as_router_lib = xbt_lib_new();
407 storage_lib = xbt_lib_new();
408 storage_type_lib = xbt_lib_new();
409 watched_hosts_lib = xbt_dict_new_homogeneous(NULL);
411 XBT_DEBUG("Add routing levels");
412 ROUTING_HOST_LEVEL = xbt_lib_add_level(host_lib,routing_asr_host_free);
413 ROUTING_ASR_LEVEL = xbt_lib_add_level(as_router_lib,routing_asr_host_free);
414 ROUTING_PROP_ASR_LEVEL = xbt_lib_add_level(as_router_lib,routing_asr_prop_free);
416 XBT_DEBUG("Add SURF levels");
417 SURF_CPU_LEVEL = xbt_lib_add_level(host_lib,surf_resource_free);
418 SURF_WKS_LEVEL = xbt_lib_add_level(host_lib,surf_resource_free);
419 SURF_LINK_LEVEL = xbt_lib_add_level(link_lib,surf_resource_free);
421 xbt_init(argc, argv);
423 model_list = xbt_dynar_new(sizeof(surf_model_private_t), NULL);
425 history = tmgr_history_new();
428 TRACE_add_start_function(TRACE_surf_alloc);
429 TRACE_add_end_function(TRACE_surf_release);
432 sg_config_init(argc, argv);
440 # define FILE_DELIM "\\"
442 # define FILE_DELIM "/" /* FIXME: move to better location */
445 FILE *surf_fopen(const char *name, const char *mode)
448 char *path_elm = NULL;
454 if (__surf_is_absolute_file_path(name)) /* don't mess with absolute file names */
455 return fopen(name, mode);
457 /* search relative files in the path */
458 xbt_dynar_foreach(surf_path, cpt, path_elm) {
459 buff = bprintf("%s" FILE_DELIM "%s", path_elm, name);
460 file = fopen(buff, mode);
472 surf_model_t model = NULL;
475 TRACE_end(); /* Just in case it was not called by the upper
476 * layer (or there is no upper layer) */
479 sg_config_finalize();
481 xbt_dynar_foreach(model_list, iter, model)
482 model->model_private->finalize();
483 xbt_dynar_free(&model_list);
487 lmm_system_free(maxmin_system);
488 maxmin_system = NULL;
491 tmgr_history_free(history);
496 #ifdef CONTEXT_THREADS
497 xbt_parmap_destroy(surf_parmap);
501 xbt_dynar_free(&host_that_restart);
502 xbt_dynar_free(&surf_path);
504 xbt_lib_free(&host_lib);
505 xbt_lib_free(&link_lib);
506 xbt_lib_free(&as_router_lib);
507 xbt_lib_free(&storage_lib);
508 xbt_lib_free(&storage_type_lib);
510 xbt_dict_free(&watched_hosts_lib);
513 surf_parse_lex_destroy();
514 surf_parse_free_callbacks();
516 NOW = 0; /* Just in case the user plans to restart the simulation afterward */
519 void surf_presolve(void)
521 double next_event_date = -1.0;
522 tmgr_trace_event_t event = NULL;
524 surf_resource_t resource = NULL;
525 surf_model_t model = NULL;
529 ("First Run! Let's \"purge\" events and put models in the right state");
530 while ((next_event_date = tmgr_history_next_date(history)) != -1.0) {
531 if (next_event_date > NOW)
534 tmgr_history_get_next_event_leq(history, next_event_date,
536 (void **) &resource))) {
538 resource->model->model_private->update_resource_state(resource,
544 xbt_dynar_foreach(model_list, iter, model)
545 model->model_private->update_actions_state(NOW, 0.0);
548 /* Returns 1 if there is at least two models with more than
549 * surf/parallel_threshold actions */
550 static int surf_do_par(void)
552 const int thres = surf_get_parallel_threshold();
557 xbt_dynar_foreach(model_list, iter, model) {
558 if (xbt_swag_size(model->states.ready_action_set)
559 + xbt_swag_size(model->states.running_action_set)
560 + xbt_swag_size(model->states.failed_action_set)
561 + xbt_swag_size(model->states.done_action_set) >= thres
568 double surf_solve(double max_date)
570 min = -1.0; /* duration */
571 double next_event_date = -1.0;
572 double model_next_action_end = -1.0;
574 surf_resource_t resource = NULL;
575 surf_model_t model = NULL;
576 tmgr_trace_event_t event = NULL;
579 if(!host_that_restart)
580 host_that_restart = xbt_dynar_new(sizeof(char*), NULL);
582 if (max_date != -1.0 && max_date != NOW) {
583 min = max_date - NOW;
586 XBT_DEBUG("Looking for next action end for all models except NS3");
588 if (surf_mins == NULL) {
589 surf_mins = xbt_new(double, xbt_dynar_length(model_list));
593 if (surf_get_nthreads() > 1 && surf_do_par()) {
594 /* parallel version */
595 #ifdef CONTEXT_THREADS
596 xbt_parmap_apply(surf_parmap, (void_f_pvoid_t) surf_share_resources, model_list);
598 xbt_die("Asked to run in parallel, but no thread at hand...");
602 /* sequential version */
603 xbt_dynar_foreach(model_list, iter, model) {
604 surf_share_resources(model);
609 for (i = 0; i < xbt_dynar_length(model_list); i++) {
610 if ((min < 0.0 || surf_mins[i] < min)
611 && surf_mins[i] >= 0.0) {
616 XBT_DEBUG("Min for resources (remember that NS3 don't update that value) : %f", min);
618 XBT_DEBUG("Looking for next trace event");
621 XBT_DEBUG("Next TRACE event : %f", next_event_date);
623 next_event_date = tmgr_history_next_date(history);
625 if(surf_network_model->name && !strcmp(surf_network_model->name,"network NS3")){
626 if(next_event_date!=-1.0 && min!=-1.0) {
627 min = MIN(next_event_date - NOW, min);
629 min = MAX(next_event_date - NOW, min);
632 XBT_DEBUG("Run for network at most %f", min);
633 // run until min or next flow
634 model_next_action_end = surf_network_model->model_private->share_resources(min);
636 XBT_DEBUG("Min for network : %f", model_next_action_end);
637 if(model_next_action_end>=0.0)
638 min = model_next_action_end;
641 if (next_event_date < 0.0) {
642 XBT_DEBUG("no next TRACE event. Stop searching for it");
646 if ((min == -1.0) || (next_event_date > NOW + min)) break;
648 XBT_DEBUG("Updating models (min = %g, NOW = %g, next_event_date = %g)",min, NOW, next_event_date);
650 tmgr_history_get_next_event_leq(history, next_event_date,
652 (void **) &resource))) {
653 if (resource->model->model_private->resource_used(resource) ||
654 xbt_dict_get_or_null(watched_hosts_lib,resource->name)
656 min = next_event_date - NOW;
658 ("This event will modify model state. Next event set to %f",
661 /* update state of model_obj according to new value. Does not touch lmm.
662 It will be modified if needed when updating actions */
663 XBT_DEBUG("Calling update_resource_state for resource %s with min %f",
664 resource->name, min);
666 resource->model->model_private->update_resource_state(resource,
672 /* FIXME: Moved this test to here to avoid stopping simulation if there are actions running on cpus and all cpus are with availability = 0.
673 * This may cause an infinite loop if one cpu has a trace with periodicity = 0 and the other a trace with periodicity > 0.
674 * The options are: all traces with same periodicity(0 or >0) or we need to change the way how the events are managed */
676 XBT_DEBUG("No next event at all. Bail out now.");
680 XBT_DEBUG("Duration set to %f", min);
684 if (surf_get_nthreads() > 1 && surf_do_par()) {
685 /* parallel version */
686 #ifdef CONTEXT_THREADS
687 xbt_parmap_apply(surf_parmap, (void_f_pvoid_t) surf_update_actions_state, model_list);
691 /* sequential version */
692 xbt_dynar_foreach(model_list, iter, model) {
693 surf_update_actions_state(model);
698 TRACE_paje_dump_buffer (0);
704 XBT_INLINE double surf_get_clock(void)
709 static void surf_share_resources(surf_model_t model)
711 double next_action_end = -1.0;
712 int i = __sync_fetch_and_add(&surf_min_index, 1);
713 if (strcmp(model->name,"network NS3")) {
714 XBT_DEBUG("Running for Resource [%s]", model->name);
715 next_action_end = model->model_private->share_resources(NOW);
716 XBT_DEBUG("Resource [%s] : next action end = %f",
717 model->name, next_action_end);
719 surf_mins[i] = next_action_end;
722 static void surf_update_actions_state(surf_model_t model)
724 model->model_private->update_actions_state(NOW, min);
728 * \brief Returns the number of parallel threads used to update the models.
729 * \return the number of threads (1 means no parallelism)
731 int surf_get_nthreads(void) {
732 return surf_nthreads;
736 * \brief Sets the number of parallel threads used to update the models.
738 * A value of 1 means no parallelism.
740 * \param nb_threads the number of threads to use
742 void surf_set_nthreads(int nthreads) {
745 nthreads = xbt_os_get_numcores();
746 XBT_INFO("Auto-setting surf/nthreads to %d",nthreads);
749 #ifdef CONTEXT_THREADS
750 xbt_parmap_destroy(surf_parmap);
755 #ifdef CONTEXT_THREADS
756 surf_parmap = xbt_parmap_new(nthreads, XBT_PARMAP_DEFAULT);
758 THROWF(arg_error, 0, "Cannot activate parallel threads in Surf: your architecture does not support threads");
762 surf_nthreads = nthreads;
765 int surf_get_parallel_threshold(void)
767 return surf_parallel_threshold;
770 void surf_set_parallel_threshold(int threshold)
772 surf_parallel_threshold = threshold;