Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of git+ssh://scm.gforge.inria.fr//gitroot/simgrid/simgrid
[simgrid.git] / src / simdag / sd_workstation.c
1 /* Copyright (c) 2006-2011. 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 "private.h"
8 #include "simdag/simdag.h"
9 #include "xbt/dict.h"
10 #include "xbt/lib.h"
11 #include "xbt/sysdep.h"
12 #include "surf/surf.h"
13 #include "surf/surf_resource.h"
14
15
16
17 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(sd_workstation, sd,
18                                 "Logging specific to SimDag (workstation)");
19
20 /* Creates a workstation and registers it in SD.
21  */
22 SD_workstation_t __SD_workstation_create(void *surf_workstation,
23                                          void *data)
24 {
25
26   SD_workstation_priv_t workstation;
27   const char *name;
28
29   workstation = xbt_new(s_SD_workstation_priv_t, 1);
30   workstation->data = data;     /* user data */
31   workstation->access_mode = SD_WORKSTATION_SHARED_ACCESS;      /* default mode is shared */
32   workstation->task_fifo = NULL;
33   workstation->current_task = NULL;
34
35   name = surf_resource_name(surf_workstation);
36   xbt_lib_set(host_lib,name,SD_HOST_LEVEL,workstation);
37   return xbt_lib_get_elm_or_null(host_lib,name);
38 }
39
40 /* Creates a storage and registers it in SD.
41  */
42 SD_storage_t __SD_storage_create(void *surf_storage, void *data)
43 {
44
45   SD_storage_priv_t storage;
46   const char *name;
47
48   storage = xbt_new(s_SD_storage_priv_t, 1);
49   storage->data = data;     /* user data */
50
51   name = surf_resource_name(surf_storage);
52   xbt_lib_set(storage_lib,name, SD_STORAGE_LEVEL, storage);
53   return xbt_lib_get_elm_or_null(storage_lib, name);
54 }
55
56 /* Destroys a storage.
57  */
58 void __SD_storage_destroy(void *storage)
59 {
60   xbt_free(storage);
61 }
62
63 /**
64  * \brief Returns a workstation given its name
65  *
66  * If there is no such workstation, the function returns \c NULL.
67  *
68  * \param name workstation name
69  * \return the workstation, or \c NULL if there is no such workstation
70  */
71 SD_workstation_t SD_workstation_get_by_name(const char *name)
72 {
73   return xbt_lib_get_elm_or_null(host_lib, name);
74 }
75
76 /**
77  * \brief Returns the workstation list
78  *
79  * Use SD_workstation_get_number() to know the array size.
80  *
81  * \return an array of \ref SD_workstation_t containing all workstations
82  * \see SD_workstation_get_number()
83  */
84 const SD_workstation_t *SD_workstation_get_list(void)
85 {
86
87   xbt_lib_cursor_t cursor;
88   char *key;
89   void **data;
90   int i;
91
92   xbt_assert(SD_workstation_get_number() > 0, "There is no workstation!");
93
94   if (sd_global->workstation_list == NULL) {    /* this is the first time the function is called */
95     sd_global->workstation_list =
96       xbt_new(SD_workstation_t, xbt_lib_length(host_lib));
97
98     i = 0;
99     xbt_lib_foreach(host_lib, cursor, key, data) {
100       if(data[SD_HOST_LEVEL])
101         sd_global->workstation_list[i++] = xbt_dict_cursor_get_elm(cursor);
102     }
103   }
104   return sd_global->workstation_list;
105 }
106
107 /**
108  * \brief Returns the number of workstations
109  *
110  * \return the number of existing workstations
111  * \see SD_workstation_get_list()
112  */
113 int SD_workstation_get_number(void)
114 {
115   return xbt_lib_length(host_lib);
116 }
117
118 /**
119  * \brief Returns the user data of a workstation
120  *
121  * \param workstation a workstation
122  * \return the user data associated with this workstation (can be \c NULL)
123  * \see SD_workstation_set_data()
124  */
125 void *SD_workstation_get_data(SD_workstation_t workstation)
126 {
127   return SD_workstation_priv(workstation)->data;
128 }
129
130 /**
131  * \brief Sets the user data of a workstation
132  *
133  * The new data can be \c NULL. The old data should have been freed first
134  * if it was not \c NULL.
135  *
136  * \param workstation a workstation
137  * \param data the new data you want to associate with this workstation
138  * \see SD_workstation_get_data()
139  */
140 void SD_workstation_set_data(SD_workstation_t workstation, void *data)
141 {
142   SD_workstation_priv(workstation)->data = data;
143 }
144
145 /**
146  * \brief Returns the name of a workstation
147  *
148  * \param workstation a workstation
149  * \return the name of this workstation (cannot be \c NULL)
150  */
151 const char *SD_workstation_get_name(SD_workstation_t workstation)
152 {
153   return sg_host_name(workstation);
154 }
155
156 /**
157  * \brief Returns the value of a given workstation property
158  *
159  * \param ws a workstation
160  * \param name a property name
161  * \return value of a property (or NULL if property not set)
162  */
163 const char *SD_workstation_get_property_value(SD_workstation_t ws,
164                                               const char *name)
165 {
166   return xbt_dict_get_or_null(SD_workstation_get_properties(ws), name);
167 }
168
169
170 /**
171  * \brief Returns a #xbt_dict_t consisting of the list of properties assigned to this workstation
172  *
173  * \param workstation a workstation
174  * \return the dictionary containing the properties associated with the workstation
175  */
176 xbt_dict_t SD_workstation_get_properties(SD_workstation_t workstation)
177 {
178   return surf_workstation_model->extension.
179       workstation.get_properties(surf_workstation_resource_priv(workstation));
180 }
181
182
183 /** @brief Displays debugging informations about a workstation */
184 void SD_workstation_dump(SD_workstation_t ws)
185 {
186   xbt_dict_t props;
187   xbt_dict_cursor_t cursor=NULL;
188   char *key,*data;
189   SD_task_t task = NULL;
190   
191   XBT_INFO("Displaying workstation %s", SD_workstation_get_name(ws));
192   XBT_INFO("  - power: %.0f", SD_workstation_get_power(ws));
193   XBT_INFO("  - available power: %.2f", SD_workstation_get_available_power(ws));
194   switch (SD_workstation_priv(ws)->access_mode){
195   case SD_WORKSTATION_SHARED_ACCESS:
196       XBT_INFO("  - access mode: Space shared");
197       break;
198   case SD_WORKSTATION_SEQUENTIAL_ACCESS:
199       XBT_INFO("  - access mode: Exclusive");
200     task = SD_workstation_get_current_task(ws);
201     if(task)
202       XBT_INFO("    current running task: %s",
203                SD_task_get_name(task));
204     else
205       XBT_INFO("    no task running");
206       break;
207   default: break;
208   }
209   props = SD_workstation_get_properties(ws);
210   
211   if (!xbt_dict_is_empty(props)){
212     XBT_INFO("  - properties:");
213
214     xbt_dict_foreach(props,cursor,key,data) {
215       XBT_INFO("    %s->%s",key,data);
216     }
217   }
218 }
219
220 /**
221  * \brief Returns the route between two workstations
222  *
223  * Use SD_route_get_size() to know the array size.
224  *
225  * \param src a workstation
226  * \param dst another workstation
227  * \return a new array of \ref SD_link_t representating the route between these two workstations
228  * \see SD_route_get_size(), SD_link_t
229  */
230 const SD_link_t *SD_route_get_list(SD_workstation_t src,
231                                    SD_workstation_t dst)
232 {
233   void *surf_src;
234   void *surf_dst;
235   xbt_dynar_t surf_route;
236   const char *link_name;
237   void *surf_link;
238   unsigned int cpt;
239
240   if (sd_global->recyclable_route == NULL) {
241     /* first run */
242     sd_global->recyclable_route = xbt_new(SD_link_t, SD_link_get_number());
243   }
244
245   surf_src = src;
246   surf_dst = dst;
247   surf_route =
248       surf_workstation_model->extension.workstation.get_route(surf_src,
249                                                               surf_dst);
250
251   xbt_dynar_foreach(surf_route, cpt, surf_link) {
252     link_name = surf_resource_name(surf_link);
253     sd_global->recyclable_route[cpt] =
254         xbt_lib_get_or_null(link_lib, link_name, SD_LINK_LEVEL);
255   }
256   return sd_global->recyclable_route;
257 }
258
259 /**
260  * \brief Returns the number of links on the route between two workstations
261  *
262  * \param src a workstation
263  * \param dst another workstation
264  * \return the number of links on the route between these two workstations
265  * \see SD_route_get_list()
266  */
267 int SD_route_get_size(SD_workstation_t src, SD_workstation_t dst)
268 {
269   return xbt_dynar_length(surf_workstation_model->extension.
270                           workstation.get_route(src, dst));
271 }
272
273 /**
274  * \brief Returns the total power of a workstation
275  *
276  * \param workstation a workstation
277  * \return the total power of this workstation
278  * \see SD_workstation_get_available_power()
279  */
280 double SD_workstation_get_power(SD_workstation_t workstation)
281 {
282   return surf_workstation_model->extension.workstation.
283       get_speed(workstation, 1.0);
284 }
285
286 /**
287  * \brief Returns the proportion of available power in a workstation
288  *
289  * \param workstation a workstation
290  * \return the proportion of power currently available in this workstation (normally a number between 0 and 1)
291  * \see SD_workstation_get_power()
292  */
293 double SD_workstation_get_available_power(SD_workstation_t workstation)
294 {
295   return surf_workstation_model->extension.
296       workstation.get_available_speed(workstation);
297 }
298
299 /**
300  * \brief Returns an approximative estimated time for the given computation amount on a workstation
301  *
302  * \param workstation a workstation
303  * \param computation_amount the computation amount you want to evaluate (in flops)
304  * \return an approximative estimated computation time for the given computation amount on this workstation (in seconds)
305  */
306 double SD_workstation_get_computation_time(SD_workstation_t workstation,
307                                            double computation_amount)
308 {
309   xbt_assert(computation_amount >= 0,
310               "computation_amount must be greater than or equal to zero");
311   return computation_amount / SD_workstation_get_power(workstation);
312 }
313
314 /**
315  * \brief Returns the latency of the route between two workstations, i.e. the sum of all link latencies
316  * between the workstations.
317  *
318  * \param src the first workstation
319  * \param dst the second workstation
320  * \return the latency of the route between the two workstations (in seconds)
321  * \see SD_route_get_current_bandwidth()
322  */
323 double SD_route_get_current_latency(SD_workstation_t src,
324                                     SD_workstation_t dst)
325 {
326
327   const SD_link_t *links;
328   int nb_links;
329   double latency;
330   int i;
331
332   links = SD_route_get_list(src, dst);
333   nb_links = SD_route_get_size(src, dst);
334   latency = 0.0;
335
336   for (i = 0; i < nb_links; i++) {
337     latency += SD_link_get_current_latency(links[i]);
338   }
339
340   return latency;
341 }
342
343 /**
344  * \brief Returns the bandwidth of the route between two workstations, i.e. the minimum link bandwidth of all
345  * between the workstations.
346  *
347  * \param src the first workstation
348  * \param dst the second workstation
349  * \return the bandwidth of the route between the two workstations (in bytes/second)
350  * \see SD_route_get_current_latency()
351  */
352 double SD_route_get_current_bandwidth(SD_workstation_t src,
353                                       SD_workstation_t dst)
354 {
355
356   const SD_link_t *links;
357   int nb_links;
358   double bandwidth;
359   double min_bandwidth;
360   int i;
361
362   links = SD_route_get_list(src, dst);
363   nb_links = SD_route_get_size(src, dst);
364   bandwidth = min_bandwidth = -1.0;
365
366
367   for (i = 0; i < nb_links; i++) {
368     bandwidth = SD_link_get_current_bandwidth(links[i]);
369     if (bandwidth < min_bandwidth || min_bandwidth == -1.0)
370       min_bandwidth = bandwidth;
371   }
372
373   return min_bandwidth;
374 }
375
376 /**
377  * \brief Returns an approximative estimated time for the given
378  * communication amount between two workstations
379  *
380  * \param src the first workstation
381  * \param dst the second workstation
382  * \param communication_amount the communication amount you want to evaluate (in bytes)
383  * \return an approximative estimated computation time for the given communication amount
384  * between the workstations (in seconds)
385  */
386 double SD_route_get_communication_time(SD_workstation_t src,
387                                        SD_workstation_t dst,
388                                        double communication_amount)
389 {
390
391
392   /* total time = latency + transmission time of the slowest link
393      transmission time of a link = communication amount / link bandwidth */
394
395   const SD_link_t *links;
396   int nb_links;
397   double bandwidth, min_bandwidth;
398   double latency;
399   int i;
400
401   xbt_assert(communication_amount >= 0,
402               "communication_amount must be greater than or equal to zero");
403
404
405
406   if (communication_amount == 0.0)
407     return 0.0;
408
409   links = SD_route_get_list(src, dst);
410   nb_links = SD_route_get_size(src, dst);
411   min_bandwidth = -1.0;
412   latency = 0;
413
414   for (i = 0; i < nb_links; i++) {
415     latency += SD_link_get_current_latency(links[i]);
416     bandwidth = SD_link_get_current_bandwidth(links[i]);
417     if (bandwidth < min_bandwidth || min_bandwidth == -1.0)
418       min_bandwidth = bandwidth;
419   }
420
421   return latency + (communication_amount / min_bandwidth);
422 }
423
424 /**
425  * \brief Returns the access mode of this workstation.
426  *
427  * \param workstation a workstation
428  * \return the access mode for the tasks running on this workstation:
429  * SD_WORKSTATION_SHARED_ACCESS or SD_WORKSTATION_SEQUENTIAL_ACCESS
430  *
431  * \see SD_workstation_set_access_mode(), e_SD_workstation_access_mode_t
432  */
433 e_SD_workstation_access_mode_t
434 SD_workstation_get_access_mode(SD_workstation_t workstation)
435 {
436   return SD_workstation_priv(workstation)->access_mode;
437 }
438
439 /**
440  * \brief Sets the access mode for the tasks that will be executed on a workstation
441  *
442  * By default, a workstation model is shared, i.e. several tasks
443  * can be executed at the same time on a workstation. The CPU power of
444  * the workstation is shared between the running tasks on the workstation.
445  * In sequential mode, only one task can use the workstation, and the other
446  * tasks wait in a FIFO.
447  *
448  * \param workstation a workstation
449  * \param access_mode the access mode you want to set to this workstation:
450  * SD_WORKSTATION_SHARED_ACCESS or SD_WORKSTATION_SEQUENTIAL_ACCESS
451  *
452  * \see SD_workstation_get_access_mode(), e_SD_workstation_access_mode_t
453  */
454 void SD_workstation_set_access_mode(SD_workstation_t workstation,
455                                     e_SD_workstation_access_mode_t
456                                     access_mode)
457 {
458   xbt_assert(access_mode != SD_WORKSTATION_SEQUENTIAL_ACCESS ||
459              access_mode != SD_WORKSTATION_SHARED_ACCESS,
460              "Trying to set an invalid access mode");
461
462   if (access_mode == SD_workstation_priv(workstation)->access_mode) {
463     return;                     // nothing is changed
464   }
465
466   SD_workstation_priv(workstation)->access_mode = access_mode;
467
468   if (access_mode == SD_WORKSTATION_SHARED_ACCESS) {
469     xbt_fifo_free(SD_workstation_priv(workstation)->task_fifo);
470     SD_workstation_priv(workstation)->task_fifo = NULL;
471   } else {
472     SD_workstation_priv(workstation)->task_fifo = xbt_fifo_new();
473   }
474 }
475
476 /**
477  * \brief Return the list of mounted storages on a workstation.
478  *
479  * \param workstation a workstation
480  * \return a dynar containing all mounted storages on the workstation
481  */
482 xbt_dynar_t SD_workstation_get_storage_list(SD_workstation_t workstation){
483   return surf_workstation_model->extension.workstation.get_storage_list(workstation);
484 }
485
486 /* Returns whether a task can start now on a workstation*/
487 /*
488   int __SD_workstation_can_start(SD_workstation_t workstation, SD_task_t task) {
489   SD_CHECK_INIT_DONE();
490   xbt_assert(workstation != NULL && task != NULL, "Invalid parameter");
491
492   return !__SD_workstation_is_busy(workstation) &&
493   (xbt_fifo_size(workstation->task_fifo) == 0) || xbt_fifo_get_first_item(workstation->task_fifo) == task);
494   }
495 */
496
497 /* Returns whether a workstation is busy. A workstation is busy is it is
498  * in sequential mode and a task is running on it or the fifo is not empty.
499  */
500 int __SD_workstation_is_busy(SD_workstation_t workstation)
501 {
502   XBT_DEBUG
503       ("Workstation '%s' access mode: '%s', current task: %s, fifo size: %d",
504        SD_workstation_get_name(workstation),
505        (SD_workstation_priv(workstation)->access_mode ==
506         SD_WORKSTATION_SHARED_ACCESS) ? "SHARED" : "FIFO",
507        (SD_workstation_priv(workstation)->current_task ?
508         SD_task_get_name(SD_workstation_priv(workstation)->current_task)
509         : "none"),
510        (SD_workstation_priv(workstation)->task_fifo ? xbt_fifo_size(SD_workstation_priv(workstation)->task_fifo) :
511         0));
512
513   return SD_workstation_priv(workstation)->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS &&
514       (SD_workstation_priv(workstation)->current_task != NULL
515        || xbt_fifo_size(SD_workstation_priv(workstation)->task_fifo) > 0);
516 }
517
518 /* Destroys a workstation.
519  */
520 void __SD_workstation_destroy(void *workstation)
521 {
522
523   SD_workstation_priv_t w;
524
525   /* workstation->surf_workstation is freed by surf_exit and workstation->data is freed by the user */
526
527   w = (SD_workstation_priv_t) workstation;
528
529   if (w->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS) {
530     xbt_fifo_free(w->task_fifo);
531   }
532   xbt_free(w);
533 }
534
535 /** 
536  * \brief Returns the kind of the task currently running on a workstation
537  * Only call this with sequential access mode set
538  * \param workstation a workstation */
539 SD_task_t SD_workstation_get_current_task(SD_workstation_t workstation)
540 {
541   xbt_assert(SD_workstation_priv(workstation)->access_mode == SD_WORKSTATION_SEQUENTIAL_ACCESS,
542               "Access mode must be set to SD_WORKSTATION_SEQUENTIAL_ACCESS"
543               " to use this function");
544
545   return (SD_workstation_priv(workstation)->current_task);
546 }
547
548 /**
549  * \brief Returns a #xbt_dict_t consisting of the list of properties assigned to the AS
550  * or router
551  *
552  * \param AS, router name
553  * \return the xbt_dict_t properties of the AS
554  */
555 xbt_dict_t SD_as_router_get_properties(const char *asr)
556 {
557   return get_as_router_properties(asr);
558 }
559 /**
560  * \brief Returns a #xbt_dict_t consisting of the list of properties assigned to the AS
561  * or router
562  *
563  * \param AS, router name
564  * \param The name of a properties
565  * \return value of the properties
566  */
567 const char* SD_as_router_get_property_value(const char *asr, const char *name)
568 {
569   xbt_dict_t dict = get_as_router_properties(asr);
570   if(!dict) return NULL;
571   return xbt_dict_get_or_null(dict,name);
572 }