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. */
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"
16 XBT_LOG_NEW_CATEGORY(surf, "All SURF categories");
17 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_kernel, surf,
18 "Logging specific to SURF (kernel)");
20 /* Additional declarations for Windows portability. */
28 static const char *disk_drives_letter_table[MAX_DRIVE] = {
56 #endif /* #ifdef _XBT_WIN32 */
58 int surf_cfg_get_int(const char* name)
60 return xbt_cfg_get_int(_surf_cfg_set,name);
62 double surf_cfg_get_double(const char* name)
64 return xbt_cfg_get_double(_surf_cfg_set,name);
66 char* surf_cfg_get_string(const char* name)
68 return xbt_cfg_get_string(_surf_cfg_set,name);
70 void surf_cfg_get_peer(const char *name, char **peer, int *port)
72 xbt_cfg_get_peer(_surf_cfg_set,name, peer, port);
74 xbt_dynar_t surf_cfg_get_dynar(const char* name)
76 return xbt_cfg_get_dynar(_surf_cfg_set,name);
79 * Returns the initial path. On Windows the initial path is
80 * the current directory for the current process in the other
81 * case the function returns "./" that represents the current
82 * directory on Unix/Linux platforms.
85 const char *__surf_get_initial_path(void)
90 char current_directory[MAX_PATH + 1] = { 0 };
91 unsigned int len = GetCurrentDirectory(MAX_PATH + 1, current_directory);
97 strncpy(root, current_directory, 3);
99 for (i = 0; i < MAX_DRIVE; i++) {
100 if (toupper(root[0]) == disk_drives_letter_table[i][0])
101 return disk_drives_letter_table[i];
110 /* The __surf_is_absolute_file_path() returns 1 if
111 * file_path is a absolute file path, in the other
112 * case the function returns 0.
114 int __surf_is_absolute_file_path(const char *file_path)
117 WIN32_FIND_DATA wfd = { 0 };
118 HANDLE hFile = FindFirstFile(file_path, &wfd);
120 if (INVALID_HANDLE_VALUE == hFile)
126 return (file_path[0] == '/');
132 xbt_dynar_t model_list = NULL;
133 tmgr_history_t history = NULL;
134 lmm_system_t maxmin_system = NULL;
135 xbt_dynar_t surf_path = NULL;
137 /* Don't forget to update the option description in smx_config when you change this */
138 s_surf_model_description_t surf_network_model_description[] = {
140 "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). ",
141 surf_network_model_init_LegrandVelho},
143 "Simplistic network model where all communication take a constant time (one second). This model provides the lowest realism, but is (marginally) faster.",
144 surf_network_model_init_Constant},
146 "Realistic network model specifically tailored for HPC settings (accurate modeling of slow start with correction factors on three intervals: < 1KiB, < 64 KiB, >= 64 KiB)",
147 surf_network_model_init_SMPI},
149 "Legacy network analytic model (Very similar to LV08, but without corrective factors. The timings of small messages are thus poorly modeled).",
150 surf_network_model_init_CM02},
153 "Network pseudo-model using the GTNets simulator instead of an analytic model",
154 surf_network_model_init_GTNETS},
158 "Network pseudo-model using the NS3 tcp model instead of an analytic model",
159 surf_network_model_init_NS3},
162 "Model from Steven H. Low using lagrange_solve instead of lmm_solve (experts only; check the code for more info).",
163 surf_network_model_init_Reno},
165 "Model from Steven H. Low using lagrange_solve instead of lmm_solve (experts only; check the code for more info).",
166 surf_network_model_init_Reno2},
168 "Model from Steven H. Low using lagrange_solve instead of lmm_solve (experts only; check the code for more info).",
169 surf_network_model_init_Vegas},
170 {NULL, NULL, NULL} /* this array must be NULL terminated */
173 s_surf_model_description_t surf_cpu_model_description[] = {
175 "Simplistic CPU model (time=size/power).",
176 surf_cpu_model_init_Cas01},
177 {NULL, NULL, NULL} /* this array must be NULL terminated */
180 s_surf_model_description_t surf_workstation_model_description[] = {
182 "Default workstation model. Currently, CPU:Cas01 and network:LV08 (with cross traffic enabled)",
183 surf_workstation_model_init_current_default},
185 "Workstation model that is automatically chosen if you change the network and CPU models",
186 surf_workstation_model_init_compound},
187 {"ptask_L07", "Workstation model somehow similar to Cas01+CM02 but allowing parallel tasks",
188 surf_workstation_model_init_ptask_L07},
189 {NULL, NULL, NULL} /* this array must be NULL terminated */
192 s_surf_model_description_t surf_optimization_mode_description[] = {
194 "Lazy action management (partial invalidation in lmm + heap in action remaining).",
197 "Trace integration. Highly optimized mode when using availability traces (only available for the Cas01 CPU model for now).",
200 "Full update of remaining and variables. Slow but may be useful when debugging.",
202 {NULL, NULL, NULL} /* this array must be NULL terminated */
205 s_surf_model_description_t surf_storage_model_description[] = {
207 "Simplistic storage model.",
208 surf_storage_model_init_default},
209 {NULL, NULL, NULL} /* this array must be NULL terminated */
212 /* ********************************************************************* */
213 /* TUTORIAL: New model */
214 s_surf_model_description_t surf_new_model_description[] = {
217 surf_new_model_init_default},
218 {NULL, NULL, NULL} /* this array must be NULL terminated */
220 /* ********************************************************************* */
222 #ifdef CONTEXT_THREADS
223 static xbt_parmap_t surf_parmap = NULL; /* parallel map on models */
226 static int surf_nthreads = 1; /* number of threads of the parmap (1 means no parallelism) */
227 static double *surf_mins = NULL; /* return value of share_resources for each model */
228 static int surf_min_index; /* current index in surf_mins */
229 static double min; /* duration determined by surf_solve */
231 static void surf_share_resources(surf_model_t model);
232 static void surf_update_actions_state(surf_model_t model);
234 /** Displays the long description of all registered models, and quit */
235 void model_help(const char *category, s_surf_model_description_t * table)
238 printf("Long description of the %s models accepted by this simulator:\n",
240 for (i = 0; table[i].name; i++)
241 printf(" %s: %s\n", table[i].name, table[i].description);
244 int find_model_description(s_surf_model_description_t * table,
248 char *name_list = NULL;
250 for (i = 0; table[i].name; i++)
251 if (!strcmp(name, table[i].name)) {
254 name_list = strdup(table[0].name);
255 for (i = 1; table[i].name; i++) {
257 xbt_realloc(name_list,
258 strlen(name_list) + strlen(table[i].name) + 3);
259 strcat(name_list, ", ");
260 strcat(name_list, table[i].name);
262 xbt_die("Model '%s' is invalid! Valid models are: %s.", name, name_list);
266 double generic_maxmin_share_resources(xbt_swag_t running_actions,
269 void (*solve) (lmm_system_t))
271 surf_action_t action = NULL;
274 #define VARIABLE(action) (*((lmm_variable_t*)(((char *) (action)) + (offset))))
278 xbt_swag_foreach(action, running_actions) {
279 value = lmm_variable_getvalue(VARIABLE(action));
280 if ((value > 0) || (action->max_duration >= 0))
288 if (action->remains > 0)
289 min = action->remains / value;
292 if ((action->max_duration >= 0) && (action->max_duration < min))
293 min = action->max_duration;
295 min = action->max_duration;
298 for (action = xbt_swag_getNext(action, running_actions->offset);
300 action = xbt_swag_getNext(action, running_actions->offset)) {
301 value = lmm_variable_getvalue(VARIABLE(action));
303 if (action->remains > 0)
304 value = action->remains / value;
309 XBT_DEBUG("Updating min (value) with %p: %f", action, min);
312 if ((action->max_duration >= 0) && (action->max_duration < min)) {
313 min = action->max_duration;
314 XBT_DEBUG("Updating min (duration) with %p: %f", action, min);
317 XBT_DEBUG("min value : %f", min);
323 double generic_share_resources_lazy(double now, surf_model_t model)
325 surf_action_lmm_t action = NULL;
330 ("Before share resources, the size of modified actions set is %d",
331 xbt_swag_size(model->model_private->modified_set));
333 lmm_solve(model->model_private->maxmin_system);
336 ("After share resources, The size of modified actions set is %d",
337 xbt_swag_size(model->model_private->modified_set));
339 while((action = xbt_swag_extract(model->model_private->modified_set))) {
340 int max_dur_flag = 0;
342 if (action->generic_action.state_set !=
343 model->states.running_action_set)
346 /* bogus priority, skip it */
347 if (action->generic_action.priority <= 0)
350 generic_update_action_remaining_lazy(action,now);
353 value = lmm_variable_getvalue(action->variable);
355 if (action->generic_action.remains > 0) {
356 value = action->generic_action.remains / value;
364 if ((action->generic_action.max_duration != NO_MAX_DURATION)
366 || action->generic_action.start +
367 action->generic_action.max_duration < min)) {
368 min = action->generic_action.start +
369 action->generic_action.max_duration;
373 XBT_DEBUG("Action(%p) Start %lf Finish %lf Max_duration %lf", action,
374 action->generic_action.start, now + value,
375 action->generic_action.max_duration);
378 surf_action_lmm_heap_remove(model->model_private->action_heap,action);
379 surf_action_lmm_heap_insert(model->model_private->action_heap,action, min, max_dur_flag ? MAX_DURATION : NORMAL);
380 XBT_DEBUG("Insert at heap action(%p) min %lf now %lf", action, min,
382 } else DIE_IMPOSSIBLE;
385 //hereafter must have already the min value for this resource model
386 if (xbt_heap_size(model->model_private->action_heap) > 0)
387 min = xbt_heap_maxkey(model->model_private->action_heap) - now;
391 XBT_DEBUG("The minimum with the HEAP %lf", min);
395 static XBT_INLINE void routing_asr_host_free(void *p)
397 sg_routing_edge_t elm = p;
402 static XBT_INLINE void routing_asr_prop_free(void *p)
408 void sg_version(int *ver_major,int *ver_minor,int *ver_patch) {
409 *ver_major = SIMGRID_VERSION_MAJOR;
410 *ver_minor = SIMGRID_VERSION_MINOR;
411 *ver_patch = SIMGRID_VERSION_PATCH;
414 xbt_dynar_t sg_cmdline = NULL;
416 extern char *xbt_os_procname_data;
419 void surf_init(int *argc, char **argv)
421 xbt_os_procname_data = argv[0];
423 XBT_DEBUG("Create all Libs");
424 host_lib = xbt_lib_new();
425 link_lib = xbt_lib_new();
426 as_router_lib = xbt_lib_new();
427 storage_lib = xbt_lib_new();
428 storage_type_lib = xbt_lib_new();
429 watched_hosts_lib = xbt_dict_new();
431 XBT_DEBUG("Add routing levels");
432 ROUTING_HOST_LEVEL = xbt_lib_add_level(host_lib,routing_asr_host_free);
433 ROUTING_ASR_LEVEL = xbt_lib_add_level(as_router_lib,routing_asr_host_free);
434 ROUTING_PROP_ASR_LEVEL = xbt_lib_add_level(as_router_lib,routing_asr_prop_free);
436 XBT_DEBUG("Add SURF levels");
437 SURF_CPU_LEVEL = xbt_lib_add_level(host_lib,surf_resource_free);
438 SURF_WKS_LEVEL = xbt_lib_add_level(host_lib,surf_resource_free);
439 SURF_LINK_LEVEL = xbt_lib_add_level(link_lib,surf_resource_free);
441 sg_cmdline = xbt_dynar_new(sizeof(char*),NULL);
443 for (i=0;i<*argc;i++) {
444 xbt_dynar_push(sg_cmdline,&(argv[i]));
446 xbt_init(argc, argv);
448 model_list = xbt_dynar_new(sizeof(surf_model_private_t), NULL);
450 history = tmgr_history_new();
452 surf_config_init(argc, argv);
460 # define FILE_DELIM "\\"
462 # define FILE_DELIM "/" /* FIXME: move to better location */
465 FILE *surf_fopen(const char *name, const char *mode)
468 char *path_elm = NULL;
474 if (__surf_is_absolute_file_path(name)) /* don't mess with absolute file names */
475 return fopen(name, mode);
477 /* search relative files in the path */
478 xbt_dynar_foreach(surf_path, cpt, path_elm) {
479 buff = bprintf("%s" FILE_DELIM "%s", path_elm, name);
480 file = fopen(buff, mode);
492 surf_model_t model = NULL;
494 surf_config_finalize();
496 xbt_dynar_foreach(model_list, iter, model)
497 model->model_private->finalize();
498 xbt_dynar_free(&model_list);
502 lmm_system_free(maxmin_system);
503 maxmin_system = NULL;
506 tmgr_history_free(history);
511 #ifdef CONTEXT_THREADS
512 xbt_parmap_destroy(surf_parmap);
517 xbt_dynar_free(&surf_path);
518 xbt_dynar_free(&sg_cmdline);
520 xbt_lib_free(&host_lib);
521 xbt_lib_free(&link_lib);
522 xbt_lib_free(&as_router_lib);
523 xbt_lib_free(&storage_lib);
524 xbt_lib_free(&storage_type_lib);
526 xbt_dict_free(&watched_hosts_lib);
529 surf_parse_lex_destroy();
530 surf_parse_free_callbacks();
532 NOW = 0; /* Just in case the user plans to restart the simulation afterward */
535 void surf_presolve(void)
537 double next_event_date = -1.0;
538 tmgr_trace_event_t event = NULL;
540 surf_resource_t resource = NULL;
541 surf_model_t model = NULL;
545 ("First Run! Let's \"purge\" events and put models in the right state");
546 while ((next_event_date = tmgr_history_next_date(history)) != -1.0) {
547 if (next_event_date > NOW)
550 tmgr_history_get_next_event_leq(history, next_event_date,
552 (void **) &resource))) {
553 resource->model->model_private->update_resource_state(resource,
558 xbt_dynar_foreach(model_list, iter, model)
559 model->model_private->update_actions_state(NOW, 0.0);
562 double surf_solve(double max_date)
564 min = -1.0; /* duration */
565 double next_event_date = -1.0;
566 double model_next_action_end = -1.0;
568 surf_resource_t resource = NULL;
569 surf_model_t model = NULL;
570 tmgr_trace_event_t event = NULL;
573 if (max_date != -1.0 && max_date != NOW) {
574 min = max_date - NOW;
577 XBT_DEBUG("Looking for next action end for all models except NS3");
579 if (surf_mins == NULL) {
580 surf_mins = xbt_new(double, xbt_dynar_length(model_list));
585 if (surf_get_nthreads() > 1) {
586 /* parallel version */
587 #ifdef CONTEXT_THREADS
588 xbt_parmap_apply(surf_parmap, (void_f_pvoid_t) surf_share_resources, model_list);
590 xbt_die("Asked to run in parallel, but no thread at hand...");
594 /* sequential version */
595 xbt_dynar_foreach(model_list, iter, model) {
596 surf_share_resources(model);
601 for (i = 0; i < xbt_dynar_length(model_list); i++) {
602 if ((min < 0.0 || surf_mins[i] < min)
603 && surf_mins[i] >= 0.0) {
608 XBT_DEBUG("Min for resources (remember that NS3 don't update that value) : %f", min);
610 XBT_DEBUG("Looking for next trace event");
613 XBT_DEBUG("Next TRACE event : %f", next_event_date);
615 next_event_date = tmgr_history_next_date(history);
617 if(surf_network_model->name && !strcmp(surf_network_model->name,"network NS3")){
618 if(next_event_date!=-1.0 && min!=-1.0) {
619 min = MIN(next_event_date - NOW, min);
621 min = MAX(next_event_date - NOW, min);
624 XBT_DEBUG("Run for NS3 at most %f", min);
625 // run until min or next flow
626 model_next_action_end = surf_network_model->model_private->share_resources(min);
628 XBT_DEBUG("Min for NS3 : %f", model_next_action_end);
629 if(model_next_action_end>=0.0)
630 min = model_next_action_end;
633 if (next_event_date == -1.0) {
634 XBT_DEBUG("no next TRACE event. Stop searching for it");
638 if ((min != -1.0) && (next_event_date > NOW + min)) break;
640 XBT_DEBUG("Updating models");
642 tmgr_history_get_next_event_leq(history, next_event_date,
644 (void **) &resource))) {
645 if (resource->model->model_private->resource_used(resource)) {
646 min = next_event_date - NOW;
648 ("This event will modify model state. Next event set to %f",
651 /* update state of model_obj according to new value. Does not touch lmm.
652 It will be modified if needed when updating actions */
653 XBT_DEBUG("Calling update_resource_state for resource %s with min %lf",
654 resource->model->name, min);
655 resource->model->model_private->update_resource_state(resource,
661 /* FIXME: Moved this test to here to avoid stopping simulation if there are actions running on cpus and all cpus are with availability = 0.
662 * This may cause an infinite loop if one cpu has a trace with periodicity = 0 and the other a trace with periodicity > 0.
663 * The options are: all traces with same periodicity(0 or >0) or we need to change the way how the events are managed */
665 XBT_DEBUG("No next event at all. Bail out now.");
669 XBT_DEBUG("Duration set to %f", min);
673 if (surf_get_nthreads() > 1) {
674 /* parallel version */
675 #ifdef CONTEXT_THREADS
676 xbt_parmap_apply(surf_parmap, (void_f_pvoid_t) surf_update_actions_state, model_list);
680 /* sequential version */
681 xbt_dynar_foreach(model_list, iter, model) {
682 surf_update_actions_state(model);
687 TRACE_paje_dump_buffer (0);
693 XBT_INLINE double surf_get_clock(void)
698 static void surf_share_resources(surf_model_t model)
700 double next_action_end = -1.0;
701 int i = __sync_fetch_and_add(&surf_min_index, 1);
702 if (strcmp(model->name,"network NS3")) {
703 XBT_DEBUG("Running for Resource [%s]", model->name);
704 next_action_end = model->model_private->share_resources(NOW);
705 XBT_DEBUG("Resource [%s] : next action end = %f",
706 model->name, next_action_end);
708 surf_mins[i] = next_action_end;
711 static void surf_update_actions_state(surf_model_t model)
713 model->model_private->update_actions_state(NOW, min);
717 * \brief Returns the number of parallel threads used to update the models.
718 * \return the number of threads (1 means no parallelism)
720 int surf_get_nthreads(void) {
721 return surf_nthreads;
725 * \brief Sets the number of parallel threads used to update the models.
727 * A value of 1 means no parallelism.
729 * \param nb_threads the number of threads to use
731 void surf_set_nthreads(int nthreads) {
734 nthreads = xbt_os_get_numcores();
735 XBT_INFO("Auto-setting surf/nthreads to %d",nthreads);
738 #ifdef CONTEXT_THREADS
739 xbt_parmap_destroy(surf_parmap);
744 #ifdef CONTEXT_THREADS
745 surf_parmap = xbt_parmap_new(nthreads, XBT_PARMAP_DEFAULT);
747 THROWF(arg_error, 0, "Cannot activate parallel threads in Surf: your architecture does not support threads");
751 surf_nthreads = nthreads;
754 void surf_watched_hosts(void)
758 xbt_dict_cursor_t cursor;
760 XBT_DEBUG("Check for host SURF_RESOURCE_ON on watched_hosts_lib");
761 xbt_dict_foreach(watched_hosts_lib,cursor,key,host)
763 if(SIMIX_host_get_state(host) == SURF_RESOURCE_ON){
764 XBT_INFO("Restart processes on host: %s",SIMIX_host_get_name(host));
765 SIMIX_host_autorestart(host);
766 xbt_dict_remove(watched_hosts_lib,key);
769 XBT_DEBUG("See SURF_RESOURCE_OFF on host: %s",key);