1 /* Copyright (c) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011. 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. */
9 #include "surf_private.h"
10 #include "xbt/module.h"
12 #include "surf/surf_resource.h"
13 #include "xbt/xbt_os_thread.h"
15 XBT_LOG_NEW_CATEGORY(surf, "All SURF categories");
16 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_kernel, surf,
17 "Logging specific to SURF (kernel)");
19 /* Additional declarations for Windows portability. */
27 static const char *disk_drives_letter_table[MAX_DRIVE] = {
55 #endif /* #ifdef _XBT_WIN32 */
58 * Returns the initial path. On Windows the initial path is
59 * the current directory for the current process in the other
60 * case the function returns "./" that represents the current
61 * directory on Unix/Linux platforms.
64 const char *__surf_get_initial_path(void)
69 char current_directory[MAX_PATH + 1] = { 0 };
70 unsigned int len = GetCurrentDirectory(MAX_PATH + 1, current_directory);
76 strncpy(root, current_directory, 3);
78 for (i = 0; i < MAX_DRIVE; i++) {
79 if (toupper(root[0]) == disk_drives_letter_table[i][0])
80 return disk_drives_letter_table[i];
89 /* The __surf_is_absolute_file_path() returns 1 if
90 * file_path is a absolute file path, in the other
91 * case the function returns 0.
93 int __surf_is_absolute_file_path(const char *file_path)
96 WIN32_FIND_DATA wfd = { 0 };
97 HANDLE hFile = FindFirstFile(file_path, &wfd);
99 if (INVALID_HANDLE_VALUE == hFile)
105 return (file_path[0] == '/');
111 xbt_dynar_t model_list = NULL;
112 tmgr_history_t history = NULL;
113 lmm_system_t maxmin_system = NULL;
114 xbt_dynar_t surf_path = NULL;
116 /* Don't forget to update the option description in smx_config when you change this */
117 s_surf_model_description_t surf_network_model_description[] = {
119 "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). ",
120 surf_network_model_init_LegrandVelho},
122 "Simplistic network model where all communication take a constant time (one second). This model provides the lowest realism, but is (marginally) faster.",
123 surf_network_model_init_Constant},
125 "Realistic network model specifically tailored for HPC settings (accurate modeling of slow start with correction factors on three intervals: < 1KiB, < 64 KiB, >= 64 KiB)",
126 surf_network_model_init_SMPI},
128 "Legacy network analytic model (Very similar to LV08, but without corrective factors. The timings of small messages are thus poorly modeled).",
129 surf_network_model_init_CM02},
132 "Network pseudo-model using the GTNets simulator instead of an analytic model",
133 surf_network_model_init_GTNETS},
137 "Network pseudo-model using the NS3 tcp model instead of an analytic model",
138 surf_network_model_init_NS3},
141 "Model from Steven H. Low using lagrange_solve instead of lmm_solve (experts only; check the code for more info).",
142 surf_network_model_init_Reno},
144 "Model from Steven H. Low using lagrange_solve instead of lmm_solve (experts only; check the code for more info).",
145 surf_network_model_init_Reno2},
147 "Model from Steven H. Low using lagrange_solve instead of lmm_solve (experts only; check the code for more info).",
148 surf_network_model_init_Vegas},
149 {NULL, NULL, NULL} /* this array must be NULL terminated */
152 s_surf_model_description_t surf_cpu_model_description[] = {
154 "Simplistic CPU model (time=size/power).",
155 surf_cpu_model_init_Cas01},
156 {NULL, NULL, NULL} /* this array must be NULL terminated */
159 s_surf_model_description_t surf_workstation_model_description[] = {
161 "Default workstation model. Currently, CPU:Cas01 and network:LV08 (with cross traffic enabled)",
162 surf_workstation_model_init_current_default},
164 "Workstation model that is automatically chosen if you change the network and CPU models",
165 surf_workstation_model_init_compound},
166 {"ptask_L07", "Workstation model somehow similar to Cas01+CM02 but allowing parallel tasks",
167 surf_workstation_model_init_ptask_L07},
168 {NULL, NULL, NULL} /* this array must be NULL terminated */
171 s_surf_model_description_t surf_optimization_mode_description[] = {
173 "Lazy action management (partial invalidation in lmm + heap in action remaining).",
176 "Trace integration. Highly optimized mode when using availability traces (only available for the Cas01 CPU model for now).",
179 "Full update of remaining and variables. Slow but may be useful when debugging.",
181 {NULL, NULL, NULL} /* this array must be NULL terminated */
184 s_surf_model_description_t surf_storage_model_description[] = {
186 "Simplistic storage model.",
187 surf_storage_model_init_default},
188 {NULL, NULL, NULL} /* this array must be NULL terminated */
191 #ifdef CONTEXT_THREADS
192 static xbt_parmap_t surf_parmap = NULL; /* parallel map on models */
195 static int surf_nthreads = 1; /* number of threads of the parmap (1 means no parallelism) */
196 static double *surf_mins = NULL; /* return value of share_resources for each model */
197 static int surf_min_index; /* current index in surf_mins */
198 static double min; /* duration determined by surf_solve */
200 static void surf_share_resources(surf_model_t model);
201 static void surf_update_actions_state(surf_model_t model);
203 /** Displays the long description of all registered models, and quit */
204 void model_help(const char *category, s_surf_model_description_t * table)
207 printf("Long description of the %s models accepted by this simulator:\n",
209 for (i = 0; table[i].name; i++)
210 printf(" %s: %s\n", table[i].name, table[i].description);
213 int find_model_description(s_surf_model_description_t * table,
217 char *name_list = NULL;
219 for (i = 0; table[i].name; i++)
220 if (!strcmp(name, table[i].name)) {
223 name_list = strdup(table[0].name);
224 for (i = 1; table[i].name; i++) {
226 xbt_realloc(name_list,
227 strlen(name_list) + strlen(table[i].name) + 3);
228 strcat(name_list, ", ");
229 strcat(name_list, table[i].name);
231 xbt_die("Model '%s' is invalid! Valid models are: %s.", name, name_list);
235 double generic_maxmin_share_resources(xbt_swag_t running_actions,
238 void (*solve) (lmm_system_t))
240 surf_action_t action = NULL;
243 #define VARIABLE(action) (*((lmm_variable_t*)(((char *) (action)) + (offset))))
247 xbt_swag_foreach(action, running_actions) {
248 value = lmm_variable_getvalue(VARIABLE(action));
249 if ((value > 0) || (action->max_duration >= 0))
257 if (action->remains > 0)
258 min = action->remains / value;
261 if ((action->max_duration >= 0) && (action->max_duration < min))
262 min = action->max_duration;
264 min = action->max_duration;
267 for (action = xbt_swag_getNext(action, running_actions->offset);
269 action = xbt_swag_getNext(action, running_actions->offset)) {
270 value = lmm_variable_getvalue(VARIABLE(action));
272 if (action->remains > 0)
273 value = action->remains / value;
278 XBT_DEBUG("Updating min (value) with %p: %f", action, min);
281 if ((action->max_duration >= 0) && (action->max_duration < min)) {
282 min = action->max_duration;
283 XBT_DEBUG("Updating min (duration) with %p: %f", action, min);
286 XBT_DEBUG("min value : %f", min);
292 double generic_share_resources_lazy(double now, surf_model_t model)
294 surf_action_lmm_t action = NULL;
299 ("Before share resources, the size of modified actions set is %d",
300 xbt_swag_size(model->model_private->modified_set));
302 lmm_solve(model->model_private->maxmin_system);
305 ("After share resources, The size of modified actions set is %d",
306 xbt_swag_size(model->model_private->modified_set));
308 while((action = xbt_swag_extract(model->model_private->modified_set))) {
309 int max_dur_flag = 0;
311 if (action->generic_action.state_set !=
312 model->states.running_action_set)
315 /* bogus priority, skip it */
316 if (action->generic_action.priority <= 0)
319 generic_update_action_remaining_lazy(action,now);
322 value = lmm_variable_getvalue(action->variable);
324 if (action->generic_action.remains > 0) {
325 value = action->generic_action.remains / value;
333 if ((action->generic_action.max_duration != NO_MAX_DURATION)
335 || action->generic_action.start +
336 action->generic_action.max_duration < min)) {
337 min = action->generic_action.start +
338 action->generic_action.max_duration;
342 XBT_DEBUG("Action(%p) Start %lf Finish %lf Max_duration %lf", action,
343 action->generic_action.start, now + value,
344 action->generic_action.max_duration);
347 surf_action_lmm_heap_remove(model->model_private->action_heap,action);
348 surf_action_lmm_heap_insert(model->model_private->action_heap,action, min, max_dur_flag ? MAX_DURATION : NORMAL);
349 XBT_DEBUG("Insert at heap action(%p) min %lf now %lf", action, min,
351 } else DIE_IMPOSSIBLE;
354 //hereafter must have already the min value for this resource model
355 if (xbt_heap_size(model->model_private->action_heap) > 0)
356 min = xbt_heap_maxkey(model->model_private->action_heap) - now;
360 XBT_DEBUG("The minimum with the HEAP %lf", min);
364 static XBT_INLINE void routing_asr_host_free(void *p)
366 sg_routing_edge_t elm = p;
371 void sg_version(int *ver_major,int *ver_minor,int *ver_patch) {
372 *ver_major = SIMGRID_VERSION_MAJOR;
373 *ver_minor = SIMGRID_VERSION_MINOR;
374 *ver_patch = SIMGRID_VERSION_PATCH;
377 void surf_init(int *argc, char **argv)
379 XBT_DEBUG("Create all Libs");
380 host_lib = xbt_lib_new();
381 link_lib = xbt_lib_new();
382 as_router_lib = xbt_lib_new();
383 storage_lib = xbt_lib_new();
384 storage_type_lib = xbt_lib_new();
385 watched_hosts_lib = xbt_dict_new();
387 XBT_DEBUG("Add routing levels");
388 ROUTING_HOST_LEVEL = xbt_lib_add_level(host_lib,routing_asr_host_free);
389 ROUTING_ASR_LEVEL = xbt_lib_add_level(as_router_lib,routing_asr_host_free);
391 XBT_DEBUG("Add SURF levels");
392 SURF_CPU_LEVEL = xbt_lib_add_level(host_lib,surf_resource_free);
393 SURF_WKS_LEVEL = xbt_lib_add_level(host_lib,surf_resource_free);
394 SURF_LINK_LEVEL = xbt_lib_add_level(link_lib,surf_resource_free);
396 xbt_init(argc, argv);
398 model_list = xbt_dynar_new(sizeof(surf_model_private_t), NULL);
400 history = tmgr_history_new();
402 surf_config_init(argc, argv);
409 # define FILE_DELIM "\\"
411 # define FILE_DELIM "/" /* FIXME: move to better location */
414 FILE *surf_fopen(const char *name, const char *mode)
417 char *path_elm = NULL;
423 if (__surf_is_absolute_file_path(name)) /* don't mess with absolute file names */
424 return fopen(name, mode);
426 /* search relative files in the path */
427 xbt_dynar_foreach(surf_path, cpt, path_elm) {
428 buff = bprintf("%s" FILE_DELIM "%s", path_elm, name);
429 file = fopen(buff, mode);
441 surf_model_t model = NULL;
443 surf_config_finalize();
445 xbt_dynar_foreach(model_list, iter, model)
446 model->model_private->finalize();
447 xbt_dynar_free(&model_list);
451 lmm_system_free(maxmin_system);
452 maxmin_system = NULL;
455 tmgr_history_free(history);
460 #ifdef CONTEXT_THREADS
461 xbt_parmap_destroy(surf_parmap);
466 xbt_dynar_free(&surf_path);
468 xbt_lib_free(&host_lib);
469 xbt_lib_free(&link_lib);
470 xbt_lib_free(&as_router_lib);
471 xbt_lib_free(&storage_lib);
472 xbt_lib_free(&storage_type_lib);
474 xbt_dict_free(&watched_hosts_lib);
477 surf_parse_lex_destroy();
478 surf_parse_free_callbacks();
480 NOW = 0; /* Just in case the user plans to restart the simulation afterward */
483 void surf_presolve(void)
485 double next_event_date = -1.0;
486 tmgr_trace_event_t event = NULL;
488 surf_resource_t resource = NULL;
489 surf_model_t model = NULL;
493 ("First Run! Let's \"purge\" events and put models in the right state");
494 while ((next_event_date = tmgr_history_next_date(history)) != -1.0) {
495 if (next_event_date > NOW)
498 tmgr_history_get_next_event_leq(history, next_event_date,
500 (void **) &resource))) {
501 resource->model->model_private->update_resource_state(resource,
506 xbt_dynar_foreach(model_list, iter, model)
507 model->model_private->update_actions_state(NOW, 0.0);
510 double surf_solve(double max_date)
512 min = -1.0; /* duration */
513 double next_event_date = -1.0;
514 double model_next_action_end = -1.0;
516 surf_resource_t resource = NULL;
517 surf_model_t model = NULL;
518 tmgr_trace_event_t event = NULL;
521 if (max_date != -1.0 && max_date != NOW) {
522 min = max_date - NOW;
525 XBT_DEBUG("Looking for next action end for all models except NS3");
527 if (surf_mins == NULL) {
528 surf_mins = xbt_new(double, xbt_dynar_length(model_list));
533 if (surf_get_nthreads() > 1) {
534 /* parallel version */
535 #ifdef CONTEXT_THREADS
536 xbt_parmap_apply(surf_parmap, (void_f_pvoid_t) surf_share_resources, model_list);
538 xbt_die("Asked to run in parallel, but no thread at hand...");
542 /* sequential version */
543 xbt_dynar_foreach(model_list, iter, model) {
544 surf_share_resources(model);
549 for (i = 0; i < xbt_dynar_length(model_list); i++) {
550 if ((min < 0.0 || surf_mins[i] < min)
551 && surf_mins[i] >= 0.0) {
556 XBT_DEBUG("Min for resources (remember that NS3 don't update that value) : %f", min);
558 XBT_DEBUG("Looking for next trace event");
561 XBT_DEBUG("Next TRACE event : %f", next_event_date);
563 next_event_date = tmgr_history_next_date(history);
565 if(surf_network_model->name && !strcmp(surf_network_model->name,"network NS3")){
566 if(next_event_date!=-1.0 && min!=-1.0) {
567 min = MIN(next_event_date - NOW, min);
569 min = MAX(next_event_date - NOW, min);
572 XBT_DEBUG("Run for NS3 at most %f", min);
573 // run until min or next flow
574 model_next_action_end = surf_network_model->model_private->share_resources(min);
576 XBT_DEBUG("Min for NS3 : %f", model_next_action_end);
577 if(model_next_action_end>=0.0)
578 min = model_next_action_end;
581 if (next_event_date == -1.0) {
582 XBT_DEBUG("no next TRACE event. Stop searching for it");
586 if ((min != -1.0) && (next_event_date > NOW + min)) break;
588 XBT_DEBUG("Updating models");
590 tmgr_history_get_next_event_leq(history, next_event_date,
592 (void **) &resource))) {
593 if (resource->model->model_private->resource_used(resource)) {
594 min = next_event_date - NOW;
596 ("This event will modify model state. Next event set to %f",
599 /* update state of model_obj according to new value. Does not touch lmm.
600 It will be modified if needed when updating actions */
601 XBT_DEBUG("Calling update_resource_state for resource %s with min %lf",
602 resource->model->name, min);
603 resource->model->model_private->update_resource_state(resource,
609 /* FIXME: Moved this test to here to avoid stopping simulation if there are actions running on cpus and all cpus are with availability = 0.
610 * This may cause an infinite loop if one cpu has a trace with periodicity = 0 and the other a trace with periodicity > 0.
611 * The options are: all traces with same periodicity(0 or >0) or we need to change the way how the events are managed */
613 XBT_DEBUG("No next event at all. Bail out now.");
617 XBT_DEBUG("Duration set to %f", min);
621 if (surf_get_nthreads() > 1) {
622 /* parallel version */
623 #ifdef CONTEXT_THREADS
624 xbt_parmap_apply(surf_parmap, (void_f_pvoid_t) surf_update_actions_state, model_list);
628 /* sequential version */
629 xbt_dynar_foreach(model_list, iter, model) {
630 surf_update_actions_state(model);
635 TRACE_paje_dump_buffer (0);
641 XBT_INLINE double surf_get_clock(void)
646 static void surf_share_resources(surf_model_t model)
648 double next_action_end = -1.0;
649 int i = __sync_fetch_and_add(&surf_min_index, 1);
650 if (strcmp(model->name,"network NS3")) {
651 XBT_DEBUG("Running for Resource [%s]", model->name);
652 next_action_end = model->model_private->share_resources(NOW);
653 XBT_DEBUG("Resource [%s] : next action end = %f",
654 model->name, next_action_end);
656 surf_mins[i] = next_action_end;
659 static void surf_update_actions_state(surf_model_t model)
661 model->model_private->update_actions_state(NOW, min);
665 * \brief Returns the number of parallel threads used to update the models.
666 * \return the number of threads (1 means no parallelism)
668 int surf_get_nthreads(void) {
669 return surf_nthreads;
673 * \brief Sets the number of parallel threads used to update the models.
675 * A value of 1 means no parallelism.
677 * \param nb_threads the number of threads to use
679 void surf_set_nthreads(int nthreads) {
682 nthreads = xbt_os_get_numcores();
683 XBT_INFO("Auto-setting surf/nthreads to %d",nthreads);
686 #ifdef CONTEXT_THREADS
687 xbt_parmap_destroy(surf_parmap);
692 #ifdef CONTEXT_THREADS
693 surf_parmap = xbt_parmap_new(nthreads, XBT_PARMAP_DEFAULT);
695 THROWF(arg_error, 0, "Cannot activate parallel threads in Surf: your architecture does not support threads");
699 surf_nthreads = nthreads;
702 void surf_watched_hosts(void)
706 xbt_dict_cursor_t cursor;
708 XBT_DEBUG("Check for host SURF_RESOURCE_ON on watched_hosts_lib");
709 xbt_dict_foreach(watched_hosts_lib,cursor,key,host)
711 if(SIMIX_host_get_state(host) == SURF_RESOURCE_ON){
712 XBT_DEBUG("See SURF_RESOURCE_ON on host: %s",SIMIX_host_get_name(host));
713 // TODO need to restart all processes on host->auto_restart_processes
714 XBT_INFO("Should call SIMIX restart host here for '%s'",SIMIX_host_get_name(host));
715 // TODO be sure having remove the wake up host
716 //xbt_dict_remove(watched_hosts_lib,key);
719 XBT_DEBUG("See SURF_RESOURCE_OFF on host: %s",key);