1 /* Copyright (c) 2004, 2005, 2007, 2009, 2010. 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. */
7 #include "xbt/sysdep.h"
11 #include "trace_mgr_private.h"
12 #include "surf_private.h"
13 #include "xbt/RngStream.h"
16 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_trace, surf, "Surf trace management");
18 static xbt_dict_t trace_list = NULL;
20 XBT_INLINE tmgr_history_t tmgr_history_new(void)
24 h = xbt_new0(s_tmgr_history_t, 1);
26 h->heap = xbt_heap_new(8, xbt_free_f); /* Why 8 ? Well, why not... */
31 XBT_INLINE void tmgr_history_free(tmgr_history_t h)
33 xbt_heap_free(h->heap);
39 * \brief Create a #tmgr_trace_t from probabilist generators
41 * This trace will generate an infinite set of events.
42 * It needs two #probabilist_event_generator_t. For regular events, the first one is
43 * used as a date generator, the second as a value generator. For a state trace, the
44 * event values are 0 or 1. The first generator rules the time between state changes.
45 * If the second generator is set, it is used to set the duration of unavailability,
46 * while the first one set the duration of availability.
48 * \param id The name of the trace
49 * \param generator1 The #probabilist_event_generator_t which generates the time
50 * between two events, or which rules the duration of availability for state trace
51 * \param generator2 The #probabilist_event_generator_t which generates the value
52 * of each events, or the duration of unavailability for state trace.
53 * \param is_state_trace Is the trace will be used as a state trace
54 * \return The new #tmgr_trace_t
56 tmgr_trace_t tmgr_trace_new_from_generator(const char *id,
57 probabilist_event_generator_t generator1,
58 probabilist_event_generator_t generator2,
61 tmgr_trace_t trace = NULL;
63 trace = xbt_new0(s_tmgr_trace_t, 1);
64 trace->type = e_trace_probabilist;
66 trace->s_probabilist.event_generator[0] = generator1;
68 //FIXME : may also be a parameter
69 trace->s_probabilist.next_event = 0;
70 trace->s_probabilist.is_state_trace = is_state_trace;
72 if(generator2 != NULL) {
73 trace->s_probabilist.event_generator[1] = generator2;
74 } else if(is_state_trace) {
75 trace->s_probabilist.event_generator[1] = generator1;
77 THROW_IMPOSSIBLE; //That case should have been checked before, anyway...
85 * \brief Create a new #probabilist_event_generator_t following the uniform distribution
87 * This generator will generate uniformly distributed random values between min and max
88 * The id is important : it controls the seed of the generator. So, generators with the
89 * same id and the same parameters will generate the same values.
91 * \param id The name of the generator
92 * \param min The minimal generated value
93 * \param max The maximal generated value
94 * \return a new #probabilist_event_generator_t
96 probabilist_event_generator_t tmgr_event_generator_new_uniform(const char* id,
100 probabilist_event_generator_t event_generator = NULL;
101 RngStream rng_stream = NULL;
103 rng_stream = sg_platf_rng_stream_get(id);
105 event_generator = xbt_new0(s_probabilist_event_generator_t, 1);
106 event_generator->type = e_generator_uniform;
107 event_generator->s_uniform_parameters.min = min;
108 event_generator->s_uniform_parameters.max = max;
109 event_generator->rng_stream = rng_stream;
111 tmgr_event_generator_next_value(event_generator);
113 return event_generator;
118 * \brief Create a new #probabilist_event_generator_t following the exponential distribution
120 * This generator will generate random values following the exponential distribution.
121 * The mean value is 1/rate .
122 * The id is important : it controls the seed of the generator. So, generators with the
123 * same id and the same parameters will generate the same values.
125 * \param id The name of the generator
126 * \param rate The rate parameter
127 * \return a new #probabilist_event_generator_t
129 probabilist_event_generator_t tmgr_event_generator_new_exponential(const char* id,
132 probabilist_event_generator_t event_generator = NULL;
133 RngStream rng_stream = NULL;
135 rng_stream = sg_platf_rng_stream_get(id);
137 event_generator = xbt_new0(s_probabilist_event_generator_t, 1);
138 event_generator->type = e_generator_exponential;
139 event_generator->s_exponential_parameters.rate = rate;
140 event_generator->rng_stream = rng_stream;
142 tmgr_event_generator_next_value(event_generator);
144 return event_generator;
148 * \brief Create a new #probabilist_event_generator_t following the weibull distribution
150 * This generator will generate random values following the weibull distribution.
151 * The id is important : it controls the seed of the generator. So, generators with the
152 * same id and the same parameters will generate the same values.
154 * \param id The name of the generator
155 * \param scale The scale parameter
156 * \param shape The shape parameter
157 * \return a new #probabilist_event_generator_t
159 probabilist_event_generator_t tmgr_event_generator_new_weibull(const char* id,
163 probabilist_event_generator_t event_generator = NULL;
164 RngStream rng_stream = NULL;
166 rng_stream = sg_platf_rng_stream_get(id);
168 event_generator = xbt_new0(s_probabilist_event_generator_t, 1);
169 event_generator->type = e_generator_weibull;
170 event_generator->s_weibull_parameters.scale = scale;
171 event_generator->s_weibull_parameters.shape = shape;
172 event_generator->rng_stream = rng_stream;
174 tmgr_event_generator_next_value(event_generator);
176 return event_generator;
179 * \brief Get the next random value of a #probabilist_event_generator_t
180 * \param generator The #probabilist_event_generator_t
181 * \return the next random value
183 double tmgr_event_generator_next_value(probabilist_event_generator_t generator)
186 switch(generator->type) {
187 case e_generator_uniform:
188 generator->next_value = (RngStream_RandU01(generator->rng_stream)
189 * (generator->s_uniform_parameters.max - generator->s_uniform_parameters.min))
190 + generator->s_uniform_parameters.min;
192 case e_generator_exponential:
193 generator->next_value = -log(RngStream_RandU01(generator->rng_stream))
194 / generator->s_exponential_parameters.rate;
196 case e_generator_weibull:
197 generator->next_value = generator->s_weibull_parameters.scale
198 * pow( -log(RngStream_RandU01(generator->rng_stream)),
199 1.0 / generator->s_weibull_parameters.shape );
202 return generator->next_value;
205 tmgr_trace_t tmgr_trace_new_from_string(const char *id, const char *input,
208 tmgr_trace_t trace = NULL;
210 s_tmgr_event_t event;
211 tmgr_event_t last_event = NULL;
217 trace = xbt_dict_get_or_null(trace_list, id);
219 XBT_WARN("Ignoring redefinition of trace %s", id);
224 xbt_assert(periodicity >= 0,
225 "Invalid periodicity %lg (must be positive)", periodicity);
227 trace = xbt_new0(s_tmgr_trace_t, 1);
228 trace->type = e_trace_list;
229 trace->s_list.event_list = xbt_dynar_new(sizeof(s_tmgr_event_t), NULL);
231 list = xbt_str_split(input, "\n\r");
233 xbt_dynar_foreach(list, cpt, val) {
235 xbt_str_trim(val, " \t\n\r\x0B");
236 if (val[0] == '#' || val[0] == '\0' || val[0] == '%')
239 if (sscanf(val, "PERIODICITY " "%lg" "\n", &periodicity) == 1)
242 if (sscanf(val, "%lg" " " "%lg" "\n", &event.delta, &event.value) != 2)
243 xbt_die("%s:%d: Syntax error in trace\n%s", id, linecount, input);
246 if (last_event->delta > event.delta) {
247 xbt_die("%s:%d: Invalid trace: Events must be sorted, "
248 "but time %lg > time %lg.\n%s",
249 id, linecount, last_event->delta, event.delta, input);
251 last_event->delta = event.delta - last_event->delta;
253 xbt_dynar_push(trace->s_list.event_list, &event);
255 xbt_dynar_get_ptr(trace->s_list.event_list,
256 xbt_dynar_length(trace->s_list.event_list) - 1);
259 last_event->delta = periodicity;
262 trace_list = xbt_dict_new_homogeneous((void (*)(void *)) tmgr_trace_free);
264 xbt_dict_set(trace_list, id, (void *) trace, NULL);
266 xbt_dynar_free(&list);
270 tmgr_trace_t tmgr_trace_new_from_file(const char *filename)
274 tmgr_trace_t trace = NULL;
276 if ((!filename) || (strcmp(filename, "") == 0))
280 trace = xbt_dict_get_or_null(trace_list, filename);
282 XBT_WARN("Ignoring redefinition of trace %s", filename);
287 f = surf_fopen(filename, "r");
288 xbt_assert(f != NULL, "Cannot open file '%s' (path=%s)", filename,
289 xbt_str_join(surf_path, ":"));
291 tstr = xbt_str_from_file(f);
293 trace = tmgr_trace_new_from_string(filename, tstr, 0.);
299 tmgr_trace_t tmgr_empty_trace_new(void)
301 tmgr_trace_t trace = NULL;
302 s_tmgr_event_t event;
304 trace = xbt_new0(s_tmgr_trace_t, 1);
305 trace->type = e_trace_list;
306 trace->s_list.event_list = xbt_dynar_new(sizeof(s_tmgr_event_t), NULL);
310 xbt_dynar_push(trace->s_list.event_list, &event);
315 XBT_INLINE void tmgr_trace_free(tmgr_trace_t trace)
320 switch(trace->type) {
322 xbt_dynar_free(&(trace->s_list.event_list));
324 case e_trace_probabilist:
331 tmgr_trace_event_t tmgr_history_add_trace(tmgr_history_t h,
334 unsigned int offset, void *model)
336 tmgr_trace_event_t trace_event = NULL;
338 trace_event = xbt_new0(s_tmgr_trace_event_t, 1);
339 trace_event->trace = trace;
340 trace_event->idx = offset;
341 trace_event->model = model;
343 if(trace->type == e_trace_list) {
344 xbt_assert((trace_event->idx < xbt_dynar_length(trace->s_list.event_list)),
345 "You're referring to an event that does not exist!");
348 xbt_heap_push(h->heap, trace_event, start_time);
353 XBT_INLINE double tmgr_history_next_date(tmgr_history_t h)
355 if (xbt_heap_size(h->heap))
356 return (xbt_heap_maxkey(h->heap));
361 tmgr_trace_event_t tmgr_history_get_next_event_leq(tmgr_history_t h,
366 double event_date = tmgr_history_next_date(h);
367 tmgr_trace_event_t trace_event = NULL;
368 tmgr_event_t event = NULL;
369 tmgr_trace_t trace = NULL;
372 if (event_date > date)
375 if (!(trace_event = xbt_heap_pop(h->heap)))
378 trace = trace_event->trace;
379 *model = trace_event->model;
381 switch(trace->type) {
384 event = xbt_dynar_get_ptr(trace->s_list.event_list, trace_event->idx);
386 *value = event->value;
388 if (trace_event->idx < xbt_dynar_length(trace->s_list.event_list) - 1) {
389 xbt_heap_push(h->heap, trace_event, event_date + event->delta);
391 } else if (event->delta > 0) { /* Last element, checking for periodicity */
392 xbt_heap_push(h->heap, trace_event, event_date + event->delta);
393 trace_event->idx = 0;
394 } else { /* We don't need this trace_event anymore */
395 trace_event->free_me = 1;
399 case e_trace_probabilist:
401 //FIXME : not tested yet
402 if(trace->s_probabilist.is_state_trace) {
403 *value = (double) trace->s_probabilist.next_event;
404 if(trace->s_probabilist.next_event == 0) {
405 event_delta = tmgr_event_generator_next_value(trace->s_probabilist.event_generator[0]);
406 trace->s_probabilist.next_event = 1;
408 event_delta = tmgr_event_generator_next_value(trace->s_probabilist.event_generator[1]);
409 trace->s_probabilist.next_event = 0;
412 event_delta = tmgr_event_generator_next_value(trace->s_probabilist.event_generator[0]);
413 *value = tmgr_event_generator_next_value(trace->s_probabilist.event_generator[1]);
415 xbt_heap_push(h->heap, trace_event, event_date + event_delta);
416 XBT_DEBUG("Generating a new event at date %f, with value %f", event_date + event_delta, *value);
424 XBT_INLINE void tmgr_finalize(void)
426 xbt_dict_free(&trace_list);
429 int tmgr_trace_event_free(tmgr_trace_event_t trace_event)
431 if (trace_event->free_me) {
432 xbt_free(trace_event);