use -Wl on -no-undefined as it is a linker option:
[oweals/gnunet.git] / src / ats-tests / ats-testing-experiment.c
1 /*
2  This file is part of GNUnet.
3  (C) 2010-2013 Christian Grothoff (and other contributing authors)
4
5  GNUnet is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published
7  by the Free Software Foundation; either version 3, or (at your
8  option) any later version.
9
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  General Public License for more details.
14
15  You should have received a copy of the GNU General Public License
16  along with GNUnet; see the file COPYING.  If not, write to the
17  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  Boston, MA 02111-1307, USA.
19  */
20 /**
21  * @file ats-tests/ats-testing-experiment.c
22  * @brief ats benchmark: controlled experiment execution
23  * @author Christian Grothoff
24  * @author Matthias Wachs
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "ats-testing.h"
29
30 const char *
31 print_op (enum OperationType op)
32 {
33   switch (op) {
34     case START_SEND:
35       return "START_SEND";
36     case STOP_SEND:
37       return "STOP_SEND";
38     case SET_RATE:
39       return "SET_RATE";
40     case SET_PREFERENCE:
41       return "SET_PREFERENCE";
42     default:
43       break;
44   }
45   return "";
46 }
47
48
49 static struct Experiment *
50 create_experiment ()
51 {
52   struct Experiment *e;
53   e = GNUNET_new (struct Experiment);
54   e->name = NULL;
55   e->num_masters = 0;
56   e->num_slaves = 0;
57   e->start = NULL;
58   e->total_duration = GNUNET_TIME_UNIT_ZERO;
59   return e;
60 }
61
62 static void
63 free_experiment (struct Experiment *e)
64 {
65   struct Episode *cur;
66   struct Episode *next;
67   struct Operation *cur_o;
68   struct Operation *next_o;
69
70   next = e->start;
71   for (cur = next; NULL != cur; cur = next)
72   {
73     next = cur->next;
74
75     next_o = cur->head;
76     for (cur_o = next_o; NULL != cur_o; cur_o = next_o)
77     {
78       next_o = cur_o->next;
79       GNUNET_free (cur_o);
80     }
81     GNUNET_free (cur);
82   }
83
84   GNUNET_free_non_null (e->name);
85   GNUNET_free_non_null (e->cfg_file);
86   GNUNET_free (e);
87 }
88
89 static int
90 load_episode (struct Experiment *e, struct Episode *cur,
91     struct GNUNET_CONFIGURATION_Handle *cfg)
92 {
93   struct Operation *o;
94   char *sec_name;
95   char *op_name;
96   char *op;
97   int ep_counter = 0;
98   fprintf (stderr, "Parsing episode %u\n",cur->id);
99   GNUNET_asprintf(&sec_name, "episode-%u", cur->id);
100
101   while (1)
102   {
103
104     GNUNET_asprintf(&op_name, "op-%u-operation", ep_counter);
105     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg,
106         sec_name, op_name, &op))
107     {
108       break;
109     }
110     o = GNUNET_new (struct Operation);
111     /* operations = set_rate, start_send, stop_send, set_preference */
112     if (0 == strcmp (op, "start_send"))
113     {
114       o->type = START_SEND;
115     }
116     else if (0 == strcmp (op, "stop_send"))
117     {
118       o->type = STOP_SEND;
119     }
120     else if (0 == strcmp (op, "set_rate"))
121     {
122       o->type = SET_RATE;
123     }
124     else if (0 == strcmp (op, "set_preference"))
125     {
126       o->type = SET_PREFERENCE;
127     }
128     else
129     {
130       fprintf (stderr, "Invalid operation %u `%s' in episode %u\n",
131           ep_counter, op, cur->id);
132       GNUNET_free (op);
133       return GNUNET_SYSERR;
134     }
135
136     GNUNET_free (op_name);
137     GNUNET_asprintf(&op_name, "op-%u-src", ep_counter);
138     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
139         sec_name, op_name, &o->src_id))
140     {
141       fprintf (stderr, "Missing src in operation %u `%s' in episode %u\n",
142           ep_counter, op, cur->id);
143       GNUNET_free (op);
144       return GNUNET_SYSERR;
145     }
146     if (o->src_id > e->num_masters)
147     {
148       fprintf (stderr, "Invalid src %llu in operation %u `%s' in episode %u\n",
149           o->src_id, ep_counter, op, cur->id);
150       GNUNET_free (op);
151       return GNUNET_SYSERR;
152     }
153
154     GNUNET_free (op_name);
155     GNUNET_asprintf(&op_name, "op-%u-dest", ep_counter);
156     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
157         sec_name, op_name, &o->dest_id))
158     {
159       fprintf (stderr, "Missing src in operation %u `%s' in episode %u\n",
160           ep_counter, op, cur->id);
161       GNUNET_free (op);
162       return GNUNET_SYSERR;
163     }
164     if (o->dest_id > e->num_slaves)
165     {
166       fprintf (stderr, "Invalid destination %llu in operation %u `%s' in episode %u\n",
167           o->dest_id, ep_counter, op, cur->id);
168       GNUNET_free (op);
169       return GNUNET_SYSERR;
170     }
171
172
173     GNUNET_free (op_name);
174     GNUNET_asprintf(&op_name, "op-%u-value", ep_counter);
175     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
176         sec_name, op_name, &o->value))
177     {
178       fprintf (stderr, "Missing value in operation %u `%s' in episode %u\n",
179           ep_counter, op, cur->id);
180       GNUNET_free (op);
181       return GNUNET_SYSERR;
182     }
183     if (o->dest_id > e->num_slaves)
184     {
185       fprintf (stderr, "Invalid destination %llu in operation %u `%s' in episode %u\n",
186           o->dest_id, ep_counter, op, cur->id);
187       GNUNET_free (op);
188       return GNUNET_SYSERR;
189     }
190
191     fprintf (stderr, "Found operation %u in episode %u: %s [%llu]->[%llu] == %llu\n",
192         ep_counter, cur->id, print_op (o->type), o->src_id, o->dest_id, o->value);
193
194     GNUNET_CONTAINER_DLL_insert (cur->head,cur->tail, o);
195     GNUNET_free (op_name);
196     ep_counter++;
197   }
198   GNUNET_free (sec_name);
199
200   return GNUNET_OK;
201 }
202
203 static int
204 load_episodes (struct Experiment *e, struct GNUNET_CONFIGURATION_Handle *cfg)
205 {
206   int e_counter = 0;
207   char *sec_name;
208   struct GNUNET_TIME_Relative e_duration;
209   struct Episode *cur;
210   struct Episode *last;
211
212   e_counter = 0;
213   last = NULL;
214   while (1)
215   {
216     GNUNET_asprintf(&sec_name, "episode-%u", e_counter);
217     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time(cfg,
218         sec_name, "duration", &e_duration))
219     {
220       GNUNET_free (sec_name);
221       break;
222     }
223
224     cur = GNUNET_new (struct Episode);
225     cur->duration = e_duration;
226     cur->id = e_counter;
227
228     if (GNUNET_OK != load_episode (e, cur, cfg))
229     {
230       GNUNET_free (sec_name);
231       GNUNET_free (cur);
232       return GNUNET_SYSERR;
233     }
234
235     fprintf (stderr, "Found episode %u with duration %s \n",
236         e_counter,
237         GNUNET_STRINGS_relative_time_to_string(cur->duration, GNUNET_YES));
238
239     /* Update experiment */
240     e->num_episodes ++;
241     e->total_duration = GNUNET_TIME_relative_add(e->total_duration, cur->duration);
242     /* Put in linked list */
243     if (NULL == last)
244       e->start = cur;
245     else
246     last->next = cur;
247
248     GNUNET_free (sec_name);
249     e_counter ++;
250     last = cur;
251   }
252   return e_counter;
253 }
254
255 static void
256 timeout_experiment (void *cls, const struct GNUNET_SCHEDULER_TaskContext* tc)
257 {
258   struct Experiment *e = cls;
259   e->experiment_timeout_task = GNUNET_SCHEDULER_NO_TASK;
260   fprintf (stderr, "Experiment timeout!\n");
261
262   e->e_done_cb (e, GNUNET_TIME_absolute_get_duration(e->start_time),
263       GNUNET_SYSERR);
264 }
265
266 static void
267 enforce_start_send (struct Operation *op)
268 {
269   GNUNET_break (0);
270 }
271
272 static void
273 enforce_stop_send (struct Operation *op)
274 {
275   GNUNET_break (0);
276 }
277
278 static void
279 enforce_set_rate (struct Operation *op)
280 {
281   GNUNET_break (0);
282 }
283
284 static void
285 enforce_set_preference (struct Operation *op)
286 {
287   GNUNET_break (0);
288 }
289
290 static void enforce_episode (struct Episode *ep)
291 {
292   struct Operation *cur;
293   for (cur = ep->head; NULL != cur; cur = cur->next)
294   {
295
296     fprintf (stderr, "Enforcing operation: %s [%llu]->[%llu] == %llu\n",
297         print_op (cur->type), cur->src_id, cur->dest_id, cur->value);
298     switch (cur->type) {
299       case START_SEND:
300         enforce_start_send (cur);
301         break;
302       case STOP_SEND:
303         enforce_stop_send (cur);
304         break;
305       case SET_RATE:
306         enforce_set_rate (cur);
307         break;
308       case SET_PREFERENCE:
309         enforce_set_preference (cur);
310         break;
311       default:
312         break;
313     }
314   }
315 }
316
317 static void
318 timeout_episode (void *cls, const struct GNUNET_SCHEDULER_TaskContext* tc)
319 {
320   struct Experiment *e = cls;
321   e->episode_timeout_task = GNUNET_SCHEDULER_NO_TASK;
322   e->ep_done_cb (e->cur);
323
324   /* Scheduling next */
325   e->cur = e->cur->next;
326   if (NULL == e->cur)
327   {
328     /* done */
329     fprintf (stderr, "Last episode done!\n");
330     if (GNUNET_SCHEDULER_NO_TASK != e->experiment_timeout_task)
331     {
332       GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
333       e->experiment_timeout_task = GNUNET_SCHEDULER_NO_TASK;
334     }
335     e->e_done_cb (e, GNUNET_TIME_absolute_get_duration(e->start_time), GNUNET_OK);
336     return;
337   }
338
339   fprintf (stderr, "Running episode %u with timeout %s\n",
340       e->cur->id,
341       GNUNET_STRINGS_relative_time_to_string(e->cur->duration, GNUNET_YES));
342   enforce_episode(e->cur);
343
344   e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
345       &timeout_episode, e);
346 }
347
348
349 void
350 GNUNET_ATS_TEST_experimentation_run (struct Experiment *e,
351     GNUNET_ATS_TESTING_EpisodeDoneCallback ep_done_cb,
352     GNUNET_ATS_TESTING_ExperimentDoneCallback e_done_cb)
353 {
354   fprintf (stderr, "Running experiment `%s'  with timeout %s\n", e->name,
355       GNUNET_STRINGS_relative_time_to_string(e->max_duration, GNUNET_YES));
356   e->e_done_cb = e_done_cb;
357   e->ep_done_cb = ep_done_cb;
358   e->start_time = GNUNET_TIME_absolute_get();
359
360   /* Start total time out */
361   e->experiment_timeout_task = GNUNET_SCHEDULER_add_delayed (e->max_duration,
362       &timeout_experiment, e);
363
364   /* Start */
365   e->cur = e->start;
366   fprintf (stderr, "Running episode %u with timeout %s\n",
367       e->cur->id,
368       GNUNET_STRINGS_relative_time_to_string(e->cur->duration, GNUNET_YES));
369   enforce_episode(e->cur);
370   e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
371       &timeout_episode, e);
372
373
374 }
375
376
377 struct Experiment *
378 GNUNET_ATS_TEST_experimentation_load (char *filename)
379 {
380   struct Experiment *e;
381   struct GNUNET_CONFIGURATION_Handle *cfg;
382   e = NULL;
383
384   cfg = GNUNET_CONFIGURATION_create();
385   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, filename))
386   {
387     fprintf (stderr, "Failed to load `%s'\n", filename);
388     GNUNET_CONFIGURATION_destroy (cfg);
389     return NULL;
390   }
391
392   e = create_experiment ();
393
394   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "experiment",
395       "name", &e->name))
396   {
397     fprintf (stderr, "Invalid %s", "name");
398     free_experiment (e);
399     return NULL;
400   }
401   else
402     fprintf (stderr, "Experiment name: `%s'\n", e->name);
403
404   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_filename (cfg, "experiment",
405       "cfg_file", &e->cfg_file))
406   {
407     fprintf (stderr, "Invalid %s", "cfg_file");
408     free_experiment (e);
409     return NULL;
410   }
411   else
412     fprintf (stderr, "Experiment name: `%s'\n", e->cfg_file);
413
414   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number(cfg, "experiment",
415       "masters", &e->num_masters))
416   {
417     fprintf (stderr, "Invalid %s", "masters");
418     free_experiment (e);
419     return NULL;
420   }
421   else
422     fprintf (stderr, "Experiment masters: `%llu'\n",
423         e->num_masters);
424
425   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number(cfg, "experiment",
426       "slaves", &e->num_slaves))
427   {
428     fprintf (stderr, "Invalid %s", "slaves");
429     free_experiment (e);
430     return NULL;
431   }
432   else
433     fprintf (stderr, "Experiment slaves: `%llu'\n",
434         e->num_slaves);
435
436   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time(cfg, "experiment",
437       "max_duration", &e->max_duration))
438   {
439     fprintf (stderr, "Invalid %s", "max_duration");
440     free_experiment (e);
441     return NULL;
442   }
443   else
444     fprintf (stderr, "Experiment duration: `%s'\n",
445         GNUNET_STRINGS_relative_time_to_string (e->max_duration, GNUNET_YES));
446
447   load_episodes (e, cfg);
448   fprintf (stderr, "Loaded %u episodes with total duration %s\n",
449       e->num_episodes,
450       GNUNET_STRINGS_relative_time_to_string (e->total_duration, GNUNET_YES));
451
452   GNUNET_CONFIGURATION_destroy (cfg);
453   return e;
454 }
455
456 void
457 GNUNET_ATS_TEST_experimentation_stop (struct Experiment *e)
458 {
459   if (GNUNET_SCHEDULER_NO_TASK != e->experiment_timeout_task)
460   {
461     GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
462     e->experiment_timeout_task = GNUNET_SCHEDULER_NO_TASK;
463   }
464   free_experiment (e);
465 }
466
467 /* end of file ats-testing-experiment.c*/
468