Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
b33f3950fd879dfaaab676084419b570e69003cb
[simgrid.git] / src / surf / surf.c
1 /* Copyright (c) 2004, 2005, 2006, 2007, 2008, 2009, 2010. The SimGrid Team.
2  * All rights reserved.                                                     */
3
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. */
6
7 #include <ctype.h>
8
9 #include "surf_private.h"
10 #include "xbt/module.h"
11
12 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_kernel, surf,
13                                 "Logging specific to SURF (kernel)");
14
15 /* Additional declarations for Windows potability. */
16
17 #ifndef MAX_DRIVE
18 #define MAX_DRIVE 26
19 #endif
20
21 #ifdef _WIN32
22 #include <windows.h>
23 static const char *disk_drives_letter_table[MAX_DRIVE] = {
24   "A:\\",
25   "B:\\",
26   "C:\\",
27   "D:\\",
28   "E:\\",
29   "F:\\",
30   "G:\\",
31   "H:\\",
32   "I:\\",
33   "J:\\",
34   "K:\\",
35   "L:\\",
36   "M:\\",
37   "N:\\",
38   "O:\\",
39   "P:\\",
40   "Q:\\",
41   "R:\\",
42   "S:\\",
43   "T:\\",
44   "U:\\",
45   "V:\\",
46   "W:\\",
47   "X:\\",
48   "Y:\\",
49   "Z:\\"
50 };
51 #endif /* #ifdef _WIN32 */
52
53 /*
54  * Returns the initial path. On Windows the initial path is
55  * the current directory for the current process in the other
56  * case the function returns "./" that represents the current
57  * directory on Unix/Linux platforms.
58  */
59
60 const char *__surf_get_initial_path(void)
61 {
62
63 #ifdef _WIN32
64   unsigned i;
65   char current_directory[MAX_PATH + 1] = { 0 };
66   unsigned int len = GetCurrentDirectory(MAX_PATH + 1, current_directory);
67   char root[4] = { 0 };
68
69   if (!len)
70     return NULL;
71
72   strncpy(root, current_directory, 3);
73
74   for (i = 0; i < MAX_DRIVE; i++) {
75     if (toupper(root[0]) == disk_drives_letter_table[i][0])
76       return disk_drives_letter_table[i];
77   }
78
79   return NULL;
80 #else
81   return "./";
82 #endif
83 }
84
85 /* The __surf_is_absolute_file_path() returns 1 if
86  * file_path is a absolute file path, in the other
87  * case the function returns 0.
88  */
89 int __surf_is_absolute_file_path(const char *file_path)
90 {
91 #ifdef _WIN32
92   WIN32_FIND_DATA wfd = { 0 };
93   HANDLE hFile = FindFirstFile(file_path, &wfd);
94
95   if (INVALID_HANDLE_VALUE == hFile)
96     return 0;
97
98   FindClose(hFile);
99   return 1;
100 #else
101   return (file_path[0] == '/');
102 #endif
103 }
104
105 static double NOW = 0;
106
107 xbt_dynar_t model_list = NULL;
108 tmgr_history_t history = NULL;
109 lmm_system_t maxmin_system = NULL;
110 xbt_dynar_t surf_path = NULL;
111
112 /* Don't forget to update the option description in smx_config when you change this */
113 s_surf_model_description_t surf_network_model_description[] = {
114     {"Constant", "Simplistic network model where all communication take a constant time (one second)", NULL, surf_network_model_init_Constant},
115     {"Vivaldi", "Scalable network model using the Vivaldi coordinate ideas", NULL, surf_network_model_init_Vivaldi},
116   {"CM02", "Realistic network model with lmm_solve and no correction factors", NULL, surf_network_model_init_CM02},
117   {"LV08", "Realistic network model with lmm_solve and these correction factors: latency*=10.4, bandwidth*=.92, S=8775" , NULL, surf_network_model_init_LegrandVelho},
118 #ifdef HAVE_GTNETS
119   {"GTNets", "Network Pseudo-model using the GTNets simulator instead of an analytic model", NULL, surf_network_model_init_GTNETS},
120 #endif
121   {"Reno", "Model using lagrange_solve instead of lmm_solve (experts only)", NULL, surf_network_model_init_Reno},
122   {"Reno2", "Model using lagrange_solve instead of lmm_solve (experts only)", NULL, surf_network_model_init_Reno2},
123   {"Vegas", "Model using lagrange_solve instead of lmm_solve (experts only)", NULL, surf_network_model_init_Vegas},
124   {NULL, NULL, NULL, NULL}            /* this array must be NULL terminated */
125 };
126
127 s_surf_model_description_t surf_cpu_model_description[] = {
128   {"Cas01_fullupdate", "CPU classical model time=size/power", NULL, surf_cpu_model_init_Cas01},
129   {"Cas01", "Variation of Cas01_fullupdate with partial invalidation optimization of lmm system. Should produce the same values, only faster", NULL, surf_cpu_model_init_Cas01_im},
130   {"CpuTI", "Variation of Cas01 with also trace integration. Should produce the same values, only faster if you use availability traces", NULL, surf_cpu_model_init_ti},
131   {NULL, NULL, NULL, NULL}            /* this array must be NULL terminated */
132 };
133
134 s_surf_model_description_t surf_workstation_model_description[] = {
135   {"CLM03", "Default workstation model, using LV08 and CM02 as network and CPU", NULL, surf_workstation_model_init_CLM03, create_workstations},
136   {"compound", "Workstation model allowing you to use other network and CPU models", NULL, surf_workstation_model_init_compound, create_workstations},
137   {"ptask_L07", "Workstation model with better parallel task modeling", NULL, surf_workstation_model_init_ptask_L07, NULL},
138   {NULL, NULL, NULL, NULL}            /* this array must be NULL terminated */
139 };
140
141 void update_model_description(s_surf_model_description_t * table,
142                               const char *name, surf_model_t model)
143 {
144   int i = find_model_description(table, name);
145   table[i].model = model;
146 }
147
148 /** Displays the long description of all registered models, and quit */
149 void model_help(const char* category, s_surf_model_description_t * table) {
150   int i;
151   printf("Long description of the %s models accepted by this simulator:\n",category);
152   for (i = 0; table[i].name; i++)
153     printf("  %s: %s\n", table[i].name, table[i].description);
154 }
155
156 int find_model_description(s_surf_model_description_t * table,
157                            const char *name)
158 {
159   int i;
160   char *name_list = NULL;
161
162   for (i = 0; table[i].name; i++)
163     if (!strcmp(name, table[i].name)) {
164       return i;
165     }
166   name_list = strdup(table[0].name);
167   for (i = 1; table[i].name; i++) {
168     name_list =
169       xbt_realloc(name_list, strlen(name_list) + strlen(table[i].name) + 2);
170     strcat(name_list, ", ");
171     strcat(name_list, table[i].name);
172   }
173   xbt_assert2(0, "Model '%s' is invalid! Valid models are: %s.", name,
174               name_list);
175 }
176
177 double generic_maxmin_share_resources(xbt_swag_t running_actions,
178                                       size_t offset,
179                                       lmm_system_t sys,
180                                       void (*solve) (lmm_system_t))
181 {
182   surf_action_t action = NULL;
183   double min = -1;
184   double value = -1;
185 #define VARIABLE(action) (*((lmm_variable_t*)(((char *) (action)) + (offset))))
186
187   xbt_assert0(solve, "Give me a real solver function!");
188   solve(sys);
189
190   xbt_swag_foreach(action, running_actions) {
191     value = lmm_variable_getvalue(VARIABLE(action));
192     if ((value > 0) || (action->max_duration >= 0))
193       break;
194   }
195
196   if (!action)
197     return -1.0;
198
199   if (value > 0) {
200     if (action->remains > 0)
201       min = action->remains / value;
202     else
203       min = 0.0;
204     if ((action->max_duration >= 0) && (action->max_duration < min))
205       min = action->max_duration;
206   } else
207     min = action->max_duration;
208
209
210   for (action = xbt_swag_getNext(action, running_actions->offset);
211        action; action = xbt_swag_getNext(action, running_actions->offset)) {
212     value = lmm_variable_getvalue(VARIABLE(action));
213     if (value > 0) {
214       if (action->remains > 0)
215         value = action->remains / value;
216       else
217         value = 0.0;
218       if (value < min) {
219         min = value;
220         DEBUG2("Updating min (value) with %p: %f", action, min);
221       }
222     }
223     if ((action->max_duration >= 0) && (action->max_duration < min)) {
224       min = action->max_duration;
225       DEBUG2("Updating min (duration) with %p: %f", action, min);
226     }
227   }
228   DEBUG1("min value : %f", min);
229
230 #undef VARIABLE
231   return min;
232 }
233
234
235 XBT_LOG_EXTERNAL_CATEGORY(surf_cpu);
236 XBT_LOG_EXTERNAL_CATEGORY(surf_kernel);
237 XBT_LOG_EXTERNAL_CATEGORY(surf_lagrange);
238 XBT_LOG_EXTERNAL_CATEGORY(surf_lagrange_dichotomy);
239 XBT_LOG_EXTERNAL_CATEGORY(surf_maxmin);
240 XBT_LOG_EXTERNAL_CATEGORY(surf_network);
241 XBT_LOG_EXTERNAL_CATEGORY(surf_trace);
242 XBT_LOG_EXTERNAL_CATEGORY(surf_parse);
243 XBT_LOG_EXTERNAL_CATEGORY(surf_timer);
244 XBT_LOG_EXTERNAL_CATEGORY(surf_workstation);
245 XBT_LOG_EXTERNAL_CATEGORY(surf_config);
246 XBT_LOG_EXTERNAL_CATEGORY(surf_routing);
247
248
249 #ifdef HAVE_GTNETS
250 XBT_LOG_EXTERNAL_CATEGORY(surf_network_gtnets);
251 #endif
252
253 void surf_init(int *argc, char **argv)
254 {
255   /* Connect our log channels: that must be done manually under windows */
256   XBT_LOG_CONNECT(surf_cpu, surf);
257   XBT_LOG_CONNECT(surf_kernel, surf);
258   XBT_LOG_CONNECT(surf_lagrange, surf);
259   XBT_LOG_CONNECT(surf_lagrange_dichotomy, surf_lagrange);
260   XBT_LOG_CONNECT(surf_maxmin, surf);
261   XBT_LOG_CONNECT(surf_network, surf);
262   XBT_LOG_CONNECT(surf_trace, surf);
263   XBT_LOG_CONNECT(surf_parse, surf);
264   XBT_LOG_CONNECT(surf_timer, surf);
265   XBT_LOG_CONNECT(surf_workstation, surf);
266   XBT_LOG_CONNECT(surf_config, surf);
267   XBT_LOG_CONNECT(surf_routing, surf);
268
269 #ifdef HAVE_GTNETS
270   XBT_LOG_CONNECT(surf_network_gtnets, surf);
271 #endif
272
273   xbt_init(argc, argv);
274   if (!model_list)
275     model_list = xbt_dynar_new(sizeof(surf_model_private_t), NULL);
276   if (!history)
277     history = tmgr_history_new();
278
279   surf_config_init(argc, argv);
280 }
281
282 #ifdef WIN32
283 # define FILE_DELIM "\\"
284 #else
285 # define FILE_DELIM "/"         /* FIXME: move to better location */
286 #endif
287
288 FILE *surf_fopen(const char *name, const char *mode)
289 {
290   unsigned int cpt;
291   char *path_elm = NULL;
292   char *buff;
293   FILE *file = NULL;
294
295   xbt_assert(name);
296
297   if (__surf_is_absolute_file_path(name))       /* don't mess with absolute file names */
298     return fopen(name, mode);
299
300   /* search relative files in the path */
301   xbt_dynar_foreach(surf_path, cpt, path_elm) {
302     buff = bprintf("%s" FILE_DELIM "%s", path_elm, name);
303     file = fopen(buff, mode);
304     free(buff);
305
306     if (file)
307       return file;
308   }
309   return NULL;
310 }
311
312 void surf_exit(void)
313 {
314   unsigned int iter;
315   surf_model_t model = NULL;
316
317   surf_config_finalize();
318
319   xbt_dynar_foreach(model_list, iter, model)
320     model->model_private->finalize();
321   xbt_dynar_free(&model_list);
322
323   if (maxmin_system) {
324     lmm_system_free(maxmin_system);
325     maxmin_system = NULL;
326   }
327   if (history) {
328     tmgr_history_free(history);
329     history = NULL;
330   }
331
332   if (surf_path)
333     xbt_dynar_free(&surf_path);
334
335   tmgr_finalize();
336   surf_parse_lex_destroy();
337   surf_parse_free_callbacks();
338   xbt_dict_free(&route_table);
339   NOW = 0;                      /* Just in case the user plans to restart the simulation afterward */
340   xbt_exit();
341 }
342
343 void surf_presolve(void)
344 {
345   double next_event_date = -1.0;
346   tmgr_trace_event_t event = NULL;
347   double value = -1.0;
348   surf_resource_t resource = NULL;
349   surf_model_t model = NULL;
350   unsigned int iter;
351
352   DEBUG0
353     ("First Run! Let's \"purge\" events and put models in the right state");
354   while ((next_event_date = tmgr_history_next_date(history)) != -1.0) {
355     if (next_event_date > NOW)
356       break;
357     while ((event =
358             tmgr_history_get_next_event_leq(history, next_event_date,
359                                             &value, (void **) &resource))) {
360       resource->model->model_private->update_resource_state(resource,
361                                                             event, value,
362                                                             NOW);
363     }
364   }
365   xbt_dynar_foreach(model_list, iter, model)
366     model->model_private->update_actions_state(NOW, 0.0);
367 }
368
369 double surf_solve(void)
370 {
371   double min = -1.0;
372   double next_event_date = -1.0;
373   double model_next_action_end = -1.0;
374   double value = -1.0;
375   surf_resource_t resource = NULL;
376   surf_model_t model = NULL;
377   tmgr_trace_event_t event = NULL;
378   unsigned int iter;
379
380   min = -1.0;
381
382   DEBUG0("Looking for next action end");
383   xbt_dynar_foreach(model_list, iter, model) {
384     DEBUG1("Running for Resource [%s]", model->name);
385     model_next_action_end = model->model_private->share_resources(NOW);
386     DEBUG2("Resource [%s] : next action end = %f",
387            model->name, model_next_action_end);
388     if (((min < 0.0) || (model_next_action_end < min))
389         && (model_next_action_end >= 0.0))
390       min = model_next_action_end;
391   }
392   DEBUG1("Next action end : %f", min);
393
394   DEBUG0("Looking for next event");
395   while ((next_event_date = tmgr_history_next_date(history)) != -1.0) {
396     DEBUG1("Next TRACE event : %f", next_event_date);
397     if ((min != -1.0) && (next_event_date > NOW + min))
398       break;
399     DEBUG0("Updating models");
400     while ((event =
401             tmgr_history_get_next_event_leq(history, next_event_date,
402                                             &value, (void **) &resource))) {
403       if (resource->model->model_private->resource_used(resource)) {
404         min = next_event_date - NOW;
405         DEBUG1
406           ("This event will modify model state. Next event set to %f", min);
407       }
408       /* update state of model_obj according to new value. Does not touch lmm.
409          It will be modified if needed when updating actions */
410       DEBUG2("Calling update_resource_state for resource %s with min %lf",
411              resource->model->name, min);
412       resource->model->model_private->update_resource_state(resource, event,
413                                                             value, NOW + min);
414     }
415   }
416
417   /* FIXME: Moved this test to here to avoid stoping simulation if there are actions running on cpus and all cpus are with availability = 0. 
418    * This may cause an infinite loop if one cpu has a trace with periodicity = 0 and the other a trace with periodicity > 0.
419    * The options are: all traces with same periodicity(0 or >0) or we need to change the way how the events are managed */
420   if (min < 0.0)
421     return -1.0;
422
423   DEBUG1("Duration set to %f", min);
424
425   NOW = NOW + min;
426
427   xbt_dynar_foreach(model_list, iter, model)
428     model->model_private->update_actions_state(NOW, min);
429
430   return min;
431 }
432
433 double surf_get_clock(void)
434 {
435   return NOW;
436 }