Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Exposing a pointer to internals is not considered as good OOP practices
[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 #if 0 /* probabilistic dead code. Should be reimplemented, not killed (please) */
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 #endif /* probabilistic dead code */
243
244 tmgr_trace_t tmgr_trace_new_from_string(const char *id, const char *input,
245                                         double periodicity)
246 {
247   tmgr_trace_t trace = NULL;
248   int linecount = 0;
249   s_tmgr_event_t event;
250   tmgr_event_t last_event = NULL;
251   xbt_dynar_t list;
252   unsigned int cpt;
253   char *val;
254
255   if (trace_list) {
256     trace = (tmgr_trace_t)xbt_dict_get_or_null(trace_list, id);
257     if (trace) {
258       XBT_WARN("Ignoring redefinition of trace %s", id);
259       return trace;
260     }
261   }
262
263   xbt_assert(periodicity >= 0,
264               "Invalid periodicity %g (must be positive)", periodicity);
265
266   trace = xbt_new0(s_tmgr_trace_t, 1);
267   trace->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->event_list, &first_event);
296       }
297     }
298     xbt_dynar_push(trace->event_list, &event);
299     last_event = (tmgr_event_t)xbt_dynar_get_ptr(trace->event_list, xbt_dynar_length(trace->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   tmgr_trace_t trace = NULL;
316
317   if ((!filename) || (strcmp(filename, "") == 0))
318     return NULL;
319
320   if (trace_list) {
321     trace = (tmgr_trace_t)xbt_dict_get_or_null(trace_list, filename);
322     if (trace) {
323       XBT_WARN("Ignoring redefinition of trace %s", filename);
324       return trace;
325     }
326   }
327
328   FILE *f = surf_fopen(filename, "r");
329   xbt_assert(f != NULL,
330       "Cannot open file '%s' (path=%s)", filename, xbt_str_join(surf_path, ":"));
331
332   char *tstr = xbt_str_from_file(f);
333   fclose(f);
334   trace = tmgr_trace_new_from_string(filename, tstr, 0.);
335   xbt_free(tstr);
336
337   return trace;
338 }
339
340 tmgr_trace_t tmgr_empty_trace_new(void)
341 {
342   tmgr_trace_t trace = NULL;
343   s_tmgr_event_t event;
344
345   trace = xbt_new0(s_tmgr_trace_t, 1);
346   trace->event_list = xbt_dynar_new(sizeof(s_tmgr_event_t), NULL);
347
348   event.delta = 0.0;
349   event.value = 0.0;
350   xbt_dynar_push(trace->event_list, &event);
351
352   return trace;
353 }
354
355 void tmgr_trace_free(tmgr_trace_t trace)
356 {
357   if (!trace)
358     return;
359
360   xbt_dynar_free(&(trace->event_list));
361   free(trace);
362 }
363
364 /** @brief Registers a new trace into the future event set, and get an iterator over the integrated trace  */
365 tmgr_trace_iterator_t simgrid::trace_mgr::future_evt_set::add_trace(
366     tmgr_trace_t trace, double start_time, surf::Resource *resource)
367 {
368   tmgr_trace_iterator_t trace_iterator = NULL;
369
370   trace_iterator = xbt_new0(s_tmgr_trace_event_t, 1);
371   trace_iterator->trace = trace;
372   trace_iterator->idx = 0;
373   trace_iterator->resource = resource;
374
375   xbt_assert((trace_iterator->idx < xbt_dynar_length(trace->event_list)),
376       "Your trace should have at least one event!");
377
378   xbt_heap_push(p_heap, trace_iterator, start_time);
379
380   return trace_iterator;
381 }
382
383 /** @brief returns the date of the next occurring event (pure function) */
384 double simgrid::trace_mgr::future_evt_set::next_date() const
385 {
386   if (xbt_heap_size(p_heap))
387     return (xbt_heap_maxkey(p_heap));
388   else
389     return -1.0;
390 }
391
392 /** @brief Retrieves the next occurring event, or NULL if none happens before #date */
393 tmgr_trace_iterator_t simgrid::trace_mgr::future_evt_set::pop_leq(
394     double date, double *value, simgrid::surf::Resource **resource)
395 {
396   double event_date = next_date();
397   if (event_date > date)
398     return NULL;
399
400   tmgr_trace_iterator_t trace_iterator = (tmgr_trace_iterator_t)xbt_heap_pop(p_heap);
401   if (trace_iterator == NULL)
402     return NULL;
403
404   tmgr_trace_t trace = trace_iterator->trace;
405   *resource = trace_iterator->resource;
406
407   tmgr_event_t event = (tmgr_event_t)xbt_dynar_get_ptr(trace->event_list, trace_iterator->idx);
408
409   *value = event->value;
410
411   if (trace_iterator->idx < xbt_dynar_length(trace->event_list) - 1) {
412     xbt_heap_push(p_heap, trace_iterator, event_date + event->delta);
413     trace_iterator->idx++;
414   } else if (event->delta > 0) {        /* Last element, checking for periodicity */
415     xbt_heap_push(p_heap, trace_iterator, event_date + event->delta);
416     trace_iterator->idx = 1; /* not 0 as the first event is a placeholder to handle when events really start */
417   } else {                      /* We don't need this trace_event anymore */
418     trace_iterator->free_me = 1;
419   }
420
421   return trace_iterator;
422 }
423
424 void tmgr_finalize(void)
425 {
426   xbt_dict_free(&trace_list);
427 }
428
429 void tmgr_trace_event_unref(tmgr_trace_iterator_t *trace_event)
430 {
431   if ((*trace_event)->free_me) {
432     xbt_free(*trace_event);
433     *trace_event = nullptr;
434   }
435 }