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 "simix/smx_host_private.h"
13 #include "surf/surf_resource.h"
14 #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 */
59 * Returns the initial path. On Windows the initial path is
60 * the current directory for the current process in the other
61 * case the function returns "./" that represents the current
62 * directory on Unix/Linux platforms.
65 const char *__surf_get_initial_path(void)
70 char current_directory[MAX_PATH + 1] = { 0 };
71 unsigned int len = GetCurrentDirectory(MAX_PATH + 1, current_directory);
77 strncpy(root, current_directory, 3);
79 for (i = 0; i < MAX_DRIVE; i++) {
80 if (toupper(root[0]) == disk_drives_letter_table[i][0])
81 return disk_drives_letter_table[i];
90 /* The __surf_is_absolute_file_path() returns 1 if
91 * file_path is a absolute file path, in the other
92 * case the function returns 0.
94 int __surf_is_absolute_file_path(const char *file_path)
97 WIN32_FIND_DATA wfd = { 0 };
98 HANDLE hFile = FindFirstFile(file_path, &wfd);
100 if (INVALID_HANDLE_VALUE == hFile)
106 return (file_path[0] == '/');
112 xbt_dynar_t model_list = NULL;
113 tmgr_history_t history = NULL;
114 lmm_system_t maxmin_system = NULL;
115 xbt_dynar_t surf_path = NULL;
117 /* Don't forget to update the option description in smx_config when you change this */
118 s_surf_model_description_t surf_network_model_description[] = {
120 "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). ",
121 surf_network_model_init_LegrandVelho},
123 "Simplistic network model where all communication take a constant time (one second). This model provides the lowest realism, but is (marginally) faster.",
124 surf_network_model_init_Constant},
126 "Realistic network model specifically tailored for HPC settings (accurate modeling of slow start with correction factors on three intervals: < 1KiB, < 64 KiB, >= 64 KiB)",
127 surf_network_model_init_SMPI},
129 "Legacy network analytic model (Very similar to LV08, but without corrective factors. The timings of small messages are thus poorly modeled).",
130 surf_network_model_init_CM02},
133 "Network pseudo-model using the GTNets simulator instead of an analytic model",
134 surf_network_model_init_GTNETS},
138 "Network pseudo-model using the NS3 tcp model instead of an analytic model",
139 surf_network_model_init_NS3},
142 "Model from Steven H. Low using lagrange_solve instead of lmm_solve (experts only; check the code for more info).",
143 surf_network_model_init_Reno},
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_Reno2},
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_Vegas},
150 {NULL, NULL, NULL} /* this array must be NULL terminated */
153 s_surf_model_description_t surf_cpu_model_description[] = {
155 "Simplistic CPU model (time=size/power).",
156 surf_cpu_model_init_Cas01},
157 {NULL, NULL, NULL} /* this array must be NULL terminated */
160 s_surf_model_description_t surf_workstation_model_description[] = {
162 "Default workstation model. Currently, CPU:Cas01 and network:LV08 (with cross traffic enabled)",
163 surf_workstation_model_init_current_default},
165 "Workstation model that is automatically chosen if you change the network and CPU models",
166 surf_workstation_model_init_compound},
167 {"ptask_L07", "Workstation model somehow similar to Cas01+CM02 but allowing parallel tasks",
168 surf_workstation_model_init_ptask_L07},
169 {NULL, NULL, NULL} /* this array must be NULL terminated */
172 s_surf_model_description_t surf_optimization_mode_description[] = {
174 "Lazy action management (partial invalidation in lmm + heap in action remaining).",
177 "Trace integration. Highly optimized mode when using availability traces (only available for the Cas01 CPU model for now).",
180 "Full update of remaining and variables. Slow but may be useful when debugging.",
182 {NULL, NULL, NULL} /* this array must be NULL terminated */
185 s_surf_model_description_t surf_storage_model_description[] = {
187 "Simplistic storage model.",
188 surf_storage_model_init_default},
189 {NULL, NULL, NULL} /* this array must be NULL terminated */
192 #ifdef CONTEXT_THREADS
193 static xbt_parmap_t surf_parmap = NULL; /* parallel map on models */
196 static int surf_nthreads = 1; /* number of threads of the parmap (1 means no parallelism) */
197 static double *surf_mins = NULL; /* return value of share_resources for each model */
198 static int surf_min_index; /* current index in surf_mins */
199 static double min; /* duration determined by surf_solve */
201 static void surf_share_resources(surf_model_t model);
202 static void surf_update_actions_state(surf_model_t model);
204 /** Displays the long description of all registered models, and quit */
205 void model_help(const char *category, s_surf_model_description_t * table)
208 printf("Long description of the %s models accepted by this simulator:\n",
210 for (i = 0; table[i].name; i++)
211 printf(" %s: %s\n", table[i].name, table[i].description);
214 int find_model_description(s_surf_model_description_t * table,
218 char *name_list = NULL;
220 for (i = 0; table[i].name; i++)
221 if (!strcmp(name, table[i].name)) {
224 name_list = strdup(table[0].name);
225 for (i = 1; table[i].name; i++) {
227 xbt_realloc(name_list,
228 strlen(name_list) + strlen(table[i].name) + 3);
229 strcat(name_list, ", ");
230 strcat(name_list, table[i].name);
232 xbt_die("Model '%s' is invalid! Valid models are: %s.", name, name_list);
236 double generic_maxmin_share_resources(xbt_swag_t running_actions,
239 void (*solve) (lmm_system_t))
241 surf_action_t action = NULL;
244 #define VARIABLE(action) (*((lmm_variable_t*)(((char *) (action)) + (offset))))
248 xbt_swag_foreach(action, running_actions) {
249 value = lmm_variable_getvalue(VARIABLE(action));
250 if ((value > 0) || (action->max_duration >= 0))
258 if (action->remains > 0)
259 min = action->remains / value;
262 if ((action->max_duration >= 0) && (action->max_duration < min))
263 min = action->max_duration;
265 min = action->max_duration;
268 for (action = xbt_swag_getNext(action, running_actions->offset);
270 action = xbt_swag_getNext(action, running_actions->offset)) {
271 value = lmm_variable_getvalue(VARIABLE(action));
273 if (action->remains > 0)
274 value = action->remains / value;
279 XBT_DEBUG("Updating min (value) with %p: %f", action, min);
282 if ((action->max_duration >= 0) && (action->max_duration < min)) {
283 min = action->max_duration;
284 XBT_DEBUG("Updating min (duration) with %p: %f", action, min);
287 XBT_DEBUG("min value : %f", min);
293 double generic_share_resources_lazy(double now, surf_model_t model)
295 surf_action_lmm_t action = NULL;
300 ("Before share resources, the size of modified actions set is %d",
301 xbt_swag_size(model->model_private->modified_set));
303 lmm_solve(model->model_private->maxmin_system);
306 ("After share resources, The size of modified actions set is %d",
307 xbt_swag_size(model->model_private->modified_set));
309 while((action = xbt_swag_extract(model->model_private->modified_set))) {
310 int max_dur_flag = 0;
312 if (action->generic_action.state_set !=
313 model->states.running_action_set)
316 /* bogus priority, skip it */
317 if (action->generic_action.priority <= 0)
320 generic_update_action_remaining_lazy(action,now);
323 value = lmm_variable_getvalue(action->variable);
325 if (action->generic_action.remains > 0) {
326 value = action->generic_action.remains / value;
334 if ((action->generic_action.max_duration != NO_MAX_DURATION)
336 || action->generic_action.start +
337 action->generic_action.max_duration < min)) {
338 min = action->generic_action.start +
339 action->generic_action.max_duration;
343 XBT_DEBUG("Action(%p) Start %lf Finish %lf Max_duration %lf", action,
344 action->generic_action.start, now + value,
345 action->generic_action.max_duration);
348 surf_action_lmm_heap_remove(model->model_private->action_heap,action);
349 surf_action_lmm_heap_insert(model->model_private->action_heap,action, min, max_dur_flag ? MAX_DURATION : NORMAL);
350 XBT_DEBUG("Insert at heap action(%p) min %lf now %lf", action, min,
352 } else DIE_IMPOSSIBLE;
355 //hereafter must have already the min value for this resource model
356 if (xbt_heap_size(model->model_private->action_heap) > 0)
357 min = xbt_heap_maxkey(model->model_private->action_heap) - now;
361 XBT_DEBUG("The minimum with the HEAP %lf", min);
365 static XBT_INLINE void routing_asr_host_free(void *p)
367 sg_routing_edge_t elm = p;
372 static XBT_INLINE void routing_asr_prop_free(void *p)
378 void sg_version(int *ver_major,int *ver_minor,int *ver_patch) {
379 *ver_major = SIMGRID_VERSION_MAJOR;
380 *ver_minor = SIMGRID_VERSION_MINOR;
381 *ver_patch = SIMGRID_VERSION_PATCH;
384 void surf_init(int *argc, char **argv)
386 XBT_DEBUG("Create all Libs");
387 host_lib = xbt_lib_new();
388 link_lib = xbt_lib_new();
389 as_router_lib = xbt_lib_new();
390 storage_lib = xbt_lib_new();
391 storage_type_lib = xbt_lib_new();
392 watched_hosts_lib = xbt_dict_new();
394 XBT_DEBUG("Add routing levels");
395 ROUTING_HOST_LEVEL = xbt_lib_add_level(host_lib,routing_asr_host_free);
396 ROUTING_ASR_LEVEL = xbt_lib_add_level(as_router_lib,routing_asr_host_free);
397 ROUTING_PROP_ASR_LEVEL = xbt_lib_add_level(as_router_lib,routing_asr_prop_free);
399 XBT_DEBUG("Add SURF levels");
400 SURF_CPU_LEVEL = xbt_lib_add_level(host_lib,surf_resource_free);
401 SURF_WKS_LEVEL = xbt_lib_add_level(host_lib,surf_resource_free);
402 SURF_LINK_LEVEL = xbt_lib_add_level(link_lib,surf_resource_free);
404 xbt_init(argc, argv);
406 model_list = xbt_dynar_new(sizeof(surf_model_private_t), NULL);
408 history = tmgr_history_new();
410 surf_config_init(argc, argv);
417 # define FILE_DELIM "\\"
419 # define FILE_DELIM "/" /* FIXME: move to better location */
422 FILE *surf_fopen(const char *name, const char *mode)
425 char *path_elm = NULL;
431 if (__surf_is_absolute_file_path(name)) /* don't mess with absolute file names */
432 return fopen(name, mode);
434 /* search relative files in the path */
435 xbt_dynar_foreach(surf_path, cpt, path_elm) {
436 buff = bprintf("%s" FILE_DELIM "%s", path_elm, name);
437 file = fopen(buff, mode);
449 surf_model_t model = NULL;
451 surf_config_finalize();
453 xbt_dynar_foreach(model_list, iter, model)
454 model->model_private->finalize();
455 xbt_dynar_free(&model_list);
459 lmm_system_free(maxmin_system);
460 maxmin_system = NULL;
463 tmgr_history_free(history);
468 #ifdef CONTEXT_THREADS
469 xbt_parmap_destroy(surf_parmap);
474 xbt_dynar_free(&surf_path);
476 xbt_lib_free(&host_lib);
477 xbt_lib_free(&link_lib);
478 xbt_lib_free(&as_router_lib);
479 xbt_lib_free(&storage_lib);
480 xbt_lib_free(&storage_type_lib);
482 xbt_dict_free(&watched_hosts_lib);
485 surf_parse_lex_destroy();
486 surf_parse_free_callbacks();
488 NOW = 0; /* Just in case the user plans to restart the simulation afterward */
491 void surf_presolve(void)
493 double next_event_date = -1.0;
494 tmgr_trace_event_t event = NULL;
496 surf_resource_t resource = NULL;
497 surf_model_t model = NULL;
501 ("First Run! Let's \"purge\" events and put models in the right state");
502 while ((next_event_date = tmgr_history_next_date(history)) != -1.0) {
503 if (next_event_date > NOW)
506 tmgr_history_get_next_event_leq(history, next_event_date,
508 (void **) &resource))) {
509 resource->model->model_private->update_resource_state(resource,
514 xbt_dynar_foreach(model_list, iter, model)
515 model->model_private->update_actions_state(NOW, 0.0);
518 double surf_solve(double max_date)
520 min = -1.0; /* duration */
521 double next_event_date = -1.0;
522 double model_next_action_end = -1.0;
524 surf_resource_t resource = NULL;
525 surf_model_t model = NULL;
526 tmgr_trace_event_t event = NULL;
529 if (max_date != -1.0 && max_date != NOW) {
530 min = max_date - NOW;
533 XBT_DEBUG("Looking for next action end for all models except NS3");
535 if (surf_mins == NULL) {
536 surf_mins = xbt_new(double, xbt_dynar_length(model_list));
541 if (surf_get_nthreads() > 1) {
542 /* parallel version */
543 #ifdef CONTEXT_THREADS
544 xbt_parmap_apply(surf_parmap, (void_f_pvoid_t) surf_share_resources, model_list);
546 xbt_die("Asked to run in parallel, but no thread at hand...");
550 /* sequential version */
551 xbt_dynar_foreach(model_list, iter, model) {
552 surf_share_resources(model);
557 for (i = 0; i < xbt_dynar_length(model_list); i++) {
558 if ((min < 0.0 || surf_mins[i] < min)
559 && surf_mins[i] >= 0.0) {
564 XBT_DEBUG("Min for resources (remember that NS3 don't update that value) : %f", min);
566 XBT_DEBUG("Looking for next trace event");
569 XBT_DEBUG("Next TRACE event : %f", next_event_date);
571 next_event_date = tmgr_history_next_date(history);
573 if(surf_network_model->name && !strcmp(surf_network_model->name,"network NS3")){
574 if(next_event_date!=-1.0 && min!=-1.0) {
575 min = MIN(next_event_date - NOW, min);
577 min = MAX(next_event_date - NOW, min);
580 XBT_DEBUG("Run for NS3 at most %f", min);
581 // run until min or next flow
582 model_next_action_end = surf_network_model->model_private->share_resources(min);
584 XBT_DEBUG("Min for NS3 : %f", model_next_action_end);
585 if(model_next_action_end>=0.0)
586 min = model_next_action_end;
589 if (next_event_date == -1.0) {
590 XBT_DEBUG("no next TRACE event. Stop searching for it");
594 if ((min != -1.0) && (next_event_date > NOW + min)) break;
596 XBT_DEBUG("Updating models");
598 tmgr_history_get_next_event_leq(history, next_event_date,
600 (void **) &resource))) {
601 if (resource->model->model_private->resource_used(resource)) {
602 min = next_event_date - NOW;
604 ("This event will modify model state. Next event set to %f",
607 /* update state of model_obj according to new value. Does not touch lmm.
608 It will be modified if needed when updating actions */
609 XBT_DEBUG("Calling update_resource_state for resource %s with min %lf",
610 resource->model->name, min);
611 resource->model->model_private->update_resource_state(resource,
617 /* FIXME: Moved this test to here to avoid stopping simulation if there are actions running on cpus and all cpus are with availability = 0.
618 * This may cause an infinite loop if one cpu has a trace with periodicity = 0 and the other a trace with periodicity > 0.
619 * The options are: all traces with same periodicity(0 or >0) or we need to change the way how the events are managed */
621 XBT_DEBUG("No next event at all. Bail out now.");
625 XBT_DEBUG("Duration set to %f", min);
629 if (surf_get_nthreads() > 1) {
630 /* parallel version */
631 #ifdef CONTEXT_THREADS
632 xbt_parmap_apply(surf_parmap, (void_f_pvoid_t) surf_update_actions_state, model_list);
636 /* sequential version */
637 xbt_dynar_foreach(model_list, iter, model) {
638 surf_update_actions_state(model);
643 TRACE_paje_dump_buffer (0);
649 XBT_INLINE double surf_get_clock(void)
654 static void surf_share_resources(surf_model_t model)
656 double next_action_end = -1.0;
657 int i = __sync_fetch_and_add(&surf_min_index, 1);
658 if (strcmp(model->name,"network NS3")) {
659 XBT_DEBUG("Running for Resource [%s]", model->name);
660 next_action_end = model->model_private->share_resources(NOW);
661 XBT_DEBUG("Resource [%s] : next action end = %f",
662 model->name, next_action_end);
664 surf_mins[i] = next_action_end;
667 static void surf_update_actions_state(surf_model_t model)
669 model->model_private->update_actions_state(NOW, min);
673 * \brief Returns the number of parallel threads used to update the models.
674 * \return the number of threads (1 means no parallelism)
676 int surf_get_nthreads(void) {
677 return surf_nthreads;
681 * \brief Sets the number of parallel threads used to update the models.
683 * A value of 1 means no parallelism.
685 * \param nb_threads the number of threads to use
687 void surf_set_nthreads(int nthreads) {
690 nthreads = xbt_os_get_numcores();
691 XBT_INFO("Auto-setting surf/nthreads to %d",nthreads);
694 #ifdef CONTEXT_THREADS
695 xbt_parmap_destroy(surf_parmap);
700 #ifdef CONTEXT_THREADS
701 surf_parmap = xbt_parmap_new(nthreads, XBT_PARMAP_DEFAULT);
703 THROWF(arg_error, 0, "Cannot activate parallel threads in Surf: your architecture does not support threads");
707 surf_nthreads = nthreads;
710 void surf_watched_hosts(void)
714 xbt_dict_cursor_t cursor;
716 XBT_DEBUG("Check for host SURF_RESOURCE_ON on watched_hosts_lib");
717 xbt_dict_foreach(watched_hosts_lib,cursor,key,host)
719 if(SIMIX_host_get_state(host) == SURF_RESOURCE_ON){
720 XBT_INFO("Restart processes on host: %s",SIMIX_host_get_name(host));
721 SIMIX_host_autorestart(host);
722 xbt_dict_remove(watched_hosts_lib,key);
725 XBT_DEBUG("See SURF_RESOURCE_OFF on host: %s",key);