Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
kill an unused parameter in the trace_mgr
[simgrid.git] / src / surf / trace_mgr.cpp
1 /* Copyright (c) 2004-2005, 2007, 2009-2014. 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 "xbt/sysdep.h"
8 #include "xbt/log.h"
9 #include "xbt/str.h"
10 #include "xbt/dict.h"
11 #include "src/surf/trace_mgr.hpp"
12 #include "surf_private.h"
13 #include "xbt/RngStream.h"
14 #include <math.h>
15
16 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_trace, surf, "Surf trace management");
17
18 static xbt_dict_t trace_list = NULL;
19
20 simgrid::trace_mgr::future_evt_set::future_evt_set() {
21 }
22
23 simgrid::trace_mgr::future_evt_set::~future_evt_set()
24 {
25   xbt_heap_free(p_heap);
26 }
27
28
29 /**
30  * \brief Create a #tmgr_trace_t from probabilist generators
31  *
32  * This trace will generate an infinite set of events.
33  * It needs two #probabilist_event_generator_t. The date when the event are
34  * triggered is directed by date_generator, and will be interpreted as seconds.
35  * The value of the event is set by value_generator. The value should be between
36  * 0 and 1.
37  *
38  * \param id The name of the trace
39  * \param date_generator The #probabilist_event_generator_t which generates the time
40  *        between two events
41  * \param generator2 The #probabilist_event_generator_t which generates the value
42  *        of each events.
43  * \return The new #tmgr_trace_t
44  */
45 tmgr_trace_t tmgr_trace_generator_value(const char *id,
46                                   probabilist_event_generator_t date_generator,
47                                   probabilist_event_generator_t value_generator)
48 {
49   tmgr_trace_t trace = NULL;
50
51   trace = xbt_new0(s_tmgr_trace_t, 1);
52   trace->type = e_trace_probabilist;
53
54   trace->s_probabilist.event_generator[0] = date_generator;
55   trace->s_probabilist.event_generator[1] = value_generator;
56   trace->s_probabilist.is_state_trace = 0;
57
58   return trace;
59 }
60
61 /**
62  * \brief Create a #tmgr_trace_t from probabilist generators
63  *
64  * This trace will generate an infinite set of events. Value of the events
65  * will be alternatively 0 and 1, so this should be used as a state trace.
66  *
67  * \param id The name of the trace
68  * \param date_generator The #probabilist_event_generator_t which generates the time
69  *        between two events
70  * \param first_event_value Set the first event value
71  * \return The new #tmgr_trace_t
72  */
73 tmgr_trace_t tmgr_trace_generator_state(const char *id,
74                                   probabilist_event_generator_t date_generator,
75                                   int first_event_hostIsOn)
76 {
77   tmgr_trace_t trace = NULL;
78
79   trace = xbt_new0(s_tmgr_trace_t, 1);
80   trace->type = e_trace_probabilist;
81
82   trace->s_probabilist.event_generator[0] = date_generator;
83   trace->s_probabilist.event_generator[1] = date_generator;
84   trace->s_probabilist.is_state_trace = 1;
85   trace->s_probabilist.next_event = first_event_hostIsOn;
86
87   return trace;
88 }
89
90 /**
91  * \brief Create a #tmgr_trace_t from probabilist generators
92  *
93  * This trace will generate an infinite set of events. Value of the events
94  * will be alternatively 0 and 1, so this should be used as a state trace.
95  *
96  * \param id The name of the trace
97  * \param avail_duration_generator The #probabilist_event_generator_t which
98  *        set the duration of the available state, (ie 1 value)
99  * \param unavail_duration_generator The #probabilist_event_generator_t which
100  *        set the duration of the unavailable state, (ie 0 value)
101  * \param first_event_value Set the first event value
102  * \return The new #tmgr_trace_t
103  */
104 tmgr_trace_t tmgr_trace_generator_avail_unavail(const char *id,
105                                 probabilist_event_generator_t avail_duration_generator,
106                                 probabilist_event_generator_t unavail_duration_generator,
107                                 int first_event_hostIsOn)
108 {
109   tmgr_trace_t trace = NULL;
110
111   trace = xbt_new0(s_tmgr_trace_t, 1);
112   trace->type = e_trace_probabilist;
113
114   trace->s_probabilist.event_generator[0] = unavail_duration_generator;
115   trace->s_probabilist.event_generator[1] = avail_duration_generator;
116   trace->s_probabilist.is_state_trace = 1;
117   trace->s_probabilist.next_event = first_event_hostIsOn;
118
119   return trace;
120 }
121
122 /**
123  * \brief Create a new #probabilist_event_generator_t following the uniform distribution
124  *
125  * This generator will generate uniformly distributed random values between min and max
126  * The id is important : it controls the seed of the generator. So, generators with the
127  * same id and the same parameters will generate the same values.
128  *
129  * \param id The name of the generator
130  * \param min The minimal generated value
131  * \param max The maximal generated value
132  * \return a new #probabilist_event_generator_t
133  */
134 probabilist_event_generator_t tmgr_event_generator_new_uniform(const char* id,
135                                                                double min,
136                                                                double max)
137 {
138   probabilist_event_generator_t event_generator = NULL;
139   RngStream rng_stream = NULL;
140
141   rng_stream = sg_platf_rng_stream_get(id);
142
143   event_generator = xbt_new0(s_probabilist_event_generator_t, 1);
144   event_generator->type = e_generator_uniform;
145   event_generator->s_uniform_parameters.min = min;
146   event_generator->s_uniform_parameters.max = max;
147   event_generator->rng_stream = rng_stream;
148
149   tmgr_event_generator_next_value(event_generator);
150
151   return event_generator;
152 }
153
154
155 /**
156  * \brief Create a new #probabilist_event_generator_t following the exponential distribution
157  *
158  * This generator will generate random values following the exponential distribution.
159  * The mean value is 1/rate .
160  * The id is important : it controls the seed of the generator. So, generators with the
161  * same id and the same parameters will generate the same values.
162  *
163  * \param id The name of the generator
164  * \param rate The rate parameter
165  * \return a new #probabilist_event_generator_t
166  */
167 probabilist_event_generator_t tmgr_event_generator_new_exponential(const char* id,
168                                                                    double rate)
169 {
170   probabilist_event_generator_t event_generator = NULL;
171   RngStream rng_stream = NULL;
172
173   rng_stream = sg_platf_rng_stream_get(id);
174
175   event_generator = xbt_new0(s_probabilist_event_generator_t, 1);
176   event_generator->type = e_generator_exponential;
177   event_generator->s_exponential_parameters.rate = rate;
178   event_generator->rng_stream = rng_stream;
179
180   tmgr_event_generator_next_value(event_generator);
181
182   return event_generator;
183 }
184
185 /**
186  * \brief Create a new #probabilist_event_generator_t following the weibull distribution
187  *
188  * This generator will generate random values following the weibull distribution.
189  * The id is important : it controls the seed of the generator. So, generators with the
190  * same id and the same parameters will generate the same values.
191  *
192  * \param id The name of the generator
193  * \param scale The scale parameter
194  * \param shape The shape parameter
195  * \return a new #probabilist_event_generator_t
196  */
197 probabilist_event_generator_t tmgr_event_generator_new_weibull(const char* id,
198                                                                double scale,
199                                                                double shape)
200 {
201   probabilist_event_generator_t event_generator = NULL;
202   RngStream rng_stream = NULL;
203
204   rng_stream = sg_platf_rng_stream_get(id);
205
206   event_generator = xbt_new0(s_probabilist_event_generator_t, 1);
207   event_generator->type = e_generator_weibull;
208   event_generator->s_weibull_parameters.scale = scale;
209   event_generator->s_weibull_parameters.shape = shape;
210   event_generator->rng_stream = rng_stream;
211
212   tmgr_event_generator_next_value(event_generator);
213
214   return event_generator;
215 }
216 /**
217  * \brief Get the next random value of a #probabilist_event_generator_t
218  * \param generator The #probabilist_event_generator_t
219  * \return the next random value
220  */
221 double tmgr_event_generator_next_value(probabilist_event_generator_t generator)
222 {
223
224   switch(generator->type) {
225     case e_generator_uniform:
226       generator->next_value = (RngStream_RandU01(generator->rng_stream)
227                   * (generator->s_uniform_parameters.max - generator->s_uniform_parameters.min))
228                   + generator->s_uniform_parameters.min;
229       break;
230     case e_generator_exponential:
231       generator->next_value = -log(RngStream_RandU01(generator->rng_stream))
232                               / generator->s_exponential_parameters.rate;
233       break;
234     case e_generator_weibull:
235       generator->next_value = generator->s_weibull_parameters.scale
236                               * pow( -log(RngStream_RandU01(generator->rng_stream)),
237                                     1.0 / generator->s_weibull_parameters.shape );
238   }
239
240   return generator->next_value;
241 }
242
243 tmgr_trace_t tmgr_trace_new_from_string(const char *id, const char *input,
244                                         double periodicity)
245 {
246   tmgr_trace_t trace = NULL;
247   int linecount = 0;
248   s_tmgr_event_t event;
249   tmgr_event_t last_event = NULL;
250   xbt_dynar_t list;
251   unsigned int cpt;
252   char *val;
253
254   if (trace_list) {
255     trace = (tmgr_trace_t)xbt_dict_get_or_null(trace_list, id);
256     if (trace) {
257       XBT_WARN("Ignoring redefinition of trace %s", id);
258       return trace;
259     }
260   }
261
262   xbt_assert(periodicity >= 0,
263               "Invalid periodicity %g (must be positive)", periodicity);
264
265   trace = xbt_new0(s_tmgr_trace_t, 1);
266   trace->type = e_trace_list;
267   trace->s_list.event_list = xbt_dynar_new(sizeof(s_tmgr_event_t), NULL);
268
269   list = xbt_str_split(input, "\n\r");
270
271   xbt_dynar_foreach(list, cpt, val) {
272     linecount++;
273     xbt_str_trim(val, " \t\n\r\x0B");
274     if (val[0] == '#' || val[0] == '\0' || val[0] == '%')
275       continue;
276
277     if (sscanf(val, "PERIODICITY " "%lg" "\n", &periodicity) == 1)
278       continue;
279
280     if (sscanf(val, "%lg" " " "%lg" "\n", &event.delta, &event.value) != 2)
281       xbt_die("%s:%d: Syntax error in trace\n%s", id, linecount, input);
282
283     if (last_event) {
284       if (last_event->delta > event.delta) {
285         xbt_die("%s:%d: Invalid trace: Events must be sorted, "
286                 "but time %g > time %g.\n%s",
287                 id, linecount, last_event->delta, event.delta, input);
288       }
289       last_event->delta = event.delta - last_event->delta;
290     } else {
291       if(event.delta > 0.0){
292         s_tmgr_event_t first_event;
293         first_event.delta=event.delta;
294         first_event.value=-1.0;
295         xbt_dynar_push(trace->s_list.event_list, &first_event);
296       }
297     }
298     xbt_dynar_push(trace->s_list.event_list, &event);
299     last_event = (tmgr_event_t)xbt_dynar_get_ptr(trace->s_list.event_list, xbt_dynar_length(trace->s_list.event_list) - 1);
300   }
301   if (last_event)
302     last_event->delta = periodicity;
303
304   if (!trace_list)
305     trace_list = xbt_dict_new_homogeneous((void (*)(void *)) tmgr_trace_free);
306
307   xbt_dict_set(trace_list, id, (void *) trace, NULL);
308
309   xbt_dynar_free(&list);
310   return trace;
311 }
312
313 tmgr_trace_t tmgr_trace_new_from_file(const char *filename)
314 {
315   char *tstr = NULL;
316   FILE *f = NULL;
317   tmgr_trace_t trace = NULL;
318
319   if ((!filename) || (strcmp(filename, "") == 0))
320     return NULL;
321
322   if (trace_list) {
323     trace = (tmgr_trace_t)xbt_dict_get_or_null(trace_list, filename);
324     if (trace) {
325       XBT_WARN("Ignoring redefinition of trace %s", filename);
326       return trace;
327     }
328   }
329
330   f = surf_fopen(filename, "r");
331   if (f == NULL)
332     xbt_die("Cannot open file '%s' (path=%s)", filename,
333             xbt_str_join(surf_path, ":"));
334
335   tstr = xbt_str_from_file(f);
336   fclose(f);
337   trace = tmgr_trace_new_from_string(filename, tstr, 0.);
338   xbt_free(tstr);
339
340   return trace;
341 }
342
343 tmgr_trace_t tmgr_empty_trace_new(void)
344 {
345   tmgr_trace_t trace = NULL;
346   s_tmgr_event_t event;
347
348   trace = xbt_new0(s_tmgr_trace_t, 1);
349   trace->type = e_trace_list;
350   trace->s_list.event_list = xbt_dynar_new(sizeof(s_tmgr_event_t), NULL);
351
352   event.delta = 0.0;
353   event.value = 0.0;
354   xbt_dynar_push(trace->s_list.event_list, &event);
355
356   return trace;
357 }
358
359 void tmgr_trace_free(tmgr_trace_t trace)
360 {
361   if (!trace)
362     return;
363
364   switch(trace->type) {
365     case e_trace_list:
366       xbt_dynar_free(&(trace->s_list.event_list));
367       break;
368     case e_trace_probabilist:
369       THROW_UNIMPLEMENTED;
370       break;
371   }
372   free(trace);
373 }
374
375 tmgr_trace_iterator_t simgrid::trace_mgr::future_evt_set::add_trace(
376     tmgr_trace_t trace,
377     double start_time,
378     void *resource)
379 {
380   tmgr_trace_iterator_t trace_iterator = NULL;
381
382   trace_iterator = xbt_new0(s_tmgr_trace_event_t, 1);
383   trace_iterator->trace = trace;
384   trace_iterator->idx = 0;
385   trace_iterator->resource = resource;
386
387   if(trace->type == e_trace_list) {
388     xbt_assert((trace_iterator->idx < xbt_dynar_length(trace->s_list.event_list)),
389               "You're referring to an event that does not exist!");
390   }
391
392   xbt_heap_push(p_heap, trace_iterator, start_time);
393
394   return trace_iterator;
395 }
396
397 double simgrid::trace_mgr::future_evt_set::next_date()
398 {
399   if (xbt_heap_size(p_heap))
400     return (xbt_heap_maxkey(p_heap));
401   else
402     return -1.0;
403 }
404
405 tmgr_trace_iterator_t simgrid::trace_mgr::future_evt_set::pop_leq(
406     double date,
407     double *value,
408     void** resource)
409 {
410   double event_date = next_date();
411   tmgr_trace_iterator_t trace_iterator = NULL;
412   tmgr_event_t event = NULL;
413   tmgr_trace_t trace = NULL;
414   double event_delta;
415
416   if (event_date > date)
417     return NULL;
418
419   if (!(trace_iterator = (tmgr_trace_iterator_t)xbt_heap_pop(p_heap)))
420     return NULL;
421
422   trace = trace_iterator->trace;
423   *resource = trace_iterator->resource;
424
425   switch(trace->type) {
426     case e_trace_list:
427
428       event = (tmgr_event_t)xbt_dynar_get_ptr(trace->s_list.event_list, trace_iterator->idx);
429
430       *value = event->value;
431
432       if (trace_iterator->idx < xbt_dynar_length(trace->s_list.event_list) - 1) {
433         xbt_heap_push(p_heap, trace_iterator, event_date + event->delta);
434         trace_iterator->idx++;
435       } else if (event->delta > 0) {        /* Last element, checking for periodicity */
436         xbt_heap_push(p_heap, trace_iterator, event_date + event->delta);
437         trace_iterator->idx = 1; /* not 0 as the first event is a placeholder to handle when events really start */
438       } else {                      /* We don't need this trace_event anymore */
439         trace_iterator->free_me = 1;
440       }
441       break;
442
443     case e_trace_probabilist:
444
445       //FIXME : not tested yet
446       if(trace->s_probabilist.is_state_trace) {
447         *value = (double) trace->s_probabilist.next_event;
448         if(trace->s_probabilist.next_event == 0) {
449           event_delta = tmgr_event_generator_next_value(trace->s_probabilist.event_generator[0]);
450           trace->s_probabilist.next_event = 1;
451         } else {
452           event_delta = tmgr_event_generator_next_value(trace->s_probabilist.event_generator[1]);
453           trace->s_probabilist.next_event = 0;
454         }
455       } else {
456         event_delta = tmgr_event_generator_next_value(trace->s_probabilist.event_generator[0]);
457         *value = tmgr_event_generator_next_value(trace->s_probabilist.event_generator[1]);
458       }
459       xbt_heap_push(p_heap, trace_iterator, event_date + event_delta);
460       XBT_DEBUG("Generating a new event at date %f, with value %f", event_date + event_delta, *value);
461
462       break;
463   }
464
465   return trace_iterator;
466 }
467
468 void tmgr_finalize(void)
469 {
470   xbt_dict_free(&trace_list);
471 }
472
473 int tmgr_trace_event_free(tmgr_trace_iterator_t trace_event)
474 {
475   if (trace_event->free_me) {
476     xbt_free(trace_event);
477     return 1;
478   }
479   return 0;
480 }