small API change: do no longer pass rarely needed GNUNET_SCHEDULER_TaskContext to...
[oweals/gnunet.git] / src / ats-tests / ats-testing-experiment.c
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2010-2013 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, 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 START_PREFERENCE:
39       return "START_PREFERENCE";
40     case STOP_PREFERENCE:
41       return "STOP_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 GNUNET_ATS_TEST_Operation *cur_o;
68   struct GNUNET_ATS_TEST_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
90 static int
91 load_episode (struct Experiment *e,
92               struct Episode *cur,
93               struct GNUNET_CONFIGURATION_Handle *cfg)
94 {
95   struct GNUNET_ATS_TEST_Operation *o;
96   char *sec_name;
97   char *op_name;
98   char *op;
99   char *type;
100   char *pref;
101   int op_counter = 0;
102
103   fprintf (stderr, "Parsing episode %u\n",cur->id);
104   GNUNET_asprintf (&sec_name, "episode-%u", cur->id);
105
106   while (1)
107   {
108     /* Load operation */
109     GNUNET_asprintf (&op_name, "op-%u-operation", op_counter);
110     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg,
111         sec_name, op_name, &op))
112     {
113       GNUNET_free (op_name);
114       break;
115     }
116     o = GNUNET_new (struct GNUNET_ATS_TEST_Operation);
117     /* operations = set_rate, start_send, stop_send, set_preference */
118     if (0 == strcmp (op, "start_send"))
119     {
120       o->type = START_SEND;
121     }
122     else if (0 == strcmp (op, "stop_send"))
123     {
124       o->type = STOP_SEND;
125     }
126     else if (0 == strcmp (op, "start_preference"))
127     {
128       o->type = START_PREFERENCE;
129     }
130     else if (0 == strcmp (op, "stop_preference"))
131     {
132       o->type = STOP_PREFERENCE;
133     }
134     else
135     {
136       fprintf (stderr, "Invalid operation %u `%s' in episode %u\n",
137           op_counter, op, cur->id);
138       GNUNET_free (op);
139       GNUNET_free (op_name);
140       GNUNET_free (o);
141       GNUNET_free (sec_name);
142       return GNUNET_SYSERR;
143     }
144     GNUNET_free (op_name);
145
146     /* Get source */
147     GNUNET_asprintf(&op_name, "op-%u-src", op_counter);
148     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
149         sec_name, op_name, &o->src_id))
150     {
151       fprintf (stderr, "Missing src in operation %u `%s' in episode %u\n",
152           op_counter, op, cur->id);
153       GNUNET_free (op);
154       GNUNET_free (op_name);
155       GNUNET_free (o);
156       GNUNET_free (sec_name);
157       return GNUNET_SYSERR;
158     }
159     if (o->src_id > (e->num_masters - 1))
160     {
161       fprintf (stderr, "Invalid src %llu in operation %u `%s' in episode %u\n",
162           o->src_id, op_counter, op, cur->id);
163       GNUNET_free (op);
164       GNUNET_free (op_name);
165       GNUNET_free (o);
166       GNUNET_free (sec_name);
167       return GNUNET_SYSERR;
168     }
169     GNUNET_free (op_name);
170
171     /* Get destination */
172     GNUNET_asprintf(&op_name, "op-%u-dest", op_counter);
173     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
174         sec_name, op_name, &o->dest_id))
175     {
176       fprintf (stderr, "Missing src in operation %u `%s' in episode %u\n",
177           op_counter, op, cur->id);
178       GNUNET_free (op);
179       GNUNET_free (op_name);
180       GNUNET_free (o);
181       GNUNET_free (sec_name);
182       return GNUNET_SYSERR;
183     }
184     if (o->dest_id > (e->num_slaves - 1))
185     {
186       fprintf (stderr, "Invalid destination %llu in operation %u `%s' in episode %u\n",
187           o->dest_id, op_counter, op, cur->id);
188       GNUNET_free (op);
189       GNUNET_free (op_name);
190       GNUNET_free (o);
191       GNUNET_free (sec_name);
192       return GNUNET_SYSERR;
193     }
194     GNUNET_free (op_name);
195
196     GNUNET_asprintf(&op_name, "op-%u-type", op_counter);
197     if ( (GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_string(cfg,
198             sec_name, op_name, &type)) &&
199         ((STOP_SEND != o->type) || (STOP_PREFERENCE != o->type)))
200     {
201       /* Load arguments for set_rate, start_send, set_preference */
202       if (0 == strcmp (type, "constant"))
203       {
204         o->gen_type = GNUNET_ATS_TEST_TG_CONSTANT;
205       }
206       else if (0 == strcmp (type, "linear"))
207       {
208         o->gen_type = GNUNET_ATS_TEST_TG_LINEAR;
209       }
210       else if (0 == strcmp (type, "sinus"))
211       {
212         o->gen_type = GNUNET_ATS_TEST_TG_SINUS;
213       }
214       else if (0 == strcmp (type, "random"))
215       {
216         o->gen_type = GNUNET_ATS_TEST_TG_RANDOM;
217       }
218       else
219       {
220         fprintf (stderr, "Invalid type %u `%s' in episode %u\n",
221             op_counter, op, cur->id);
222         GNUNET_free (type);
223         GNUNET_free (op);
224         GNUNET_free (op_name);
225         GNUNET_free (sec_name);
226         GNUNET_free (o);
227         return GNUNET_SYSERR;
228       }
229       GNUNET_free (op_name);
230
231       /* Get base rate */
232       GNUNET_asprintf(&op_name, "op-%u-base-rate", op_counter);
233       if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
234           sec_name, op_name, &o->base_rate))
235       {
236         fprintf (stderr, "Missing base rate in operation %u `%s' in episode %u\n",
237             op_counter, op, cur->id);
238         GNUNET_free (type);
239         GNUNET_free (op);
240         GNUNET_free (op_name);
241         GNUNET_free (sec_name);
242         GNUNET_free (o);
243         return GNUNET_SYSERR;
244       }
245       GNUNET_free (op_name);
246
247       /* Get max rate */
248       GNUNET_asprintf(&op_name, "op-%u-max-rate", op_counter);
249       if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
250           sec_name, op_name, &o->max_rate))
251       {
252         if ((GNUNET_ATS_TEST_TG_LINEAR == o->gen_type) ||
253             (GNUNET_ATS_TEST_TG_RANDOM == o->gen_type) ||
254             (GNUNET_ATS_TEST_TG_SINUS == o->gen_type))
255         {
256           fprintf (stderr, "Missing max rate in operation %u `%s' in episode %u\n",
257               op_counter, op, cur->id);
258           GNUNET_free (type);
259           GNUNET_free (op_name);
260           GNUNET_free (op);
261           GNUNET_free (o);
262           GNUNET_free (sec_name);
263           return GNUNET_SYSERR;
264         }
265       }
266       GNUNET_free (op_name);
267
268       /* Get period */
269       GNUNET_asprintf(&op_name, "op-%u-period", op_counter);
270       if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
271           sec_name, op_name, &o->period))
272       {
273         o->period = cur->duration;
274       }
275       GNUNET_free (op_name);
276
277       if (START_PREFERENCE == o->type)
278       {
279           /* Get frequency */
280           GNUNET_asprintf(&op_name, "op-%u-frequency", op_counter);
281           if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
282               sec_name, op_name, &o->frequency))
283           {
284               fprintf (stderr, "Missing frequency in operation %u `%s' in episode %u\n",
285                   op_counter, op, cur->id);
286               GNUNET_free (type);
287               GNUNET_free (op_name);
288               GNUNET_free (op);
289               GNUNET_free (o);
290               GNUNET_free (sec_name);
291               return GNUNET_SYSERR;
292           }
293           GNUNET_free (op_name);
294
295           /* Get preference */
296           GNUNET_asprintf(&op_name, "op-%u-pref", op_counter);
297           if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
298               sec_name, op_name, &pref))
299           {
300               fprintf (stderr, "Missing preference in operation %u `%s' in episode %u\n",
301                   op_counter, op, cur->id);
302               GNUNET_free (type);
303               GNUNET_free (op_name);
304               GNUNET_free (op);
305               GNUNET_free_non_null (pref);
306               GNUNET_free (o);
307               GNUNET_free (sec_name);
308               return GNUNET_SYSERR;
309           }
310
311           if (0 == strcmp(pref, "bandwidth"))
312             o->pref_type = GNUNET_ATS_PREFERENCE_BANDWIDTH;
313           else if (0 == strcmp(pref, "latency"))
314             o->pref_type = GNUNET_ATS_PREFERENCE_LATENCY;
315           else
316           {
317               fprintf (stderr, "Invalid preference in operation %u `%s' in episode %u\n",
318                   op_counter, op, cur->id);
319               GNUNET_free (type);
320               GNUNET_free (op_name);
321               GNUNET_free (op);
322               GNUNET_free_non_null (pref);
323               GNUNET_free (o);
324               GNUNET_free (sec_name);
325               return GNUNET_SYSERR;
326           }
327           GNUNET_free (pref);
328           GNUNET_free (op_name);
329       }
330     }
331
332     /* Safety checks */
333     if ((GNUNET_ATS_TEST_TG_LINEAR == o->gen_type) ||
334         (GNUNET_ATS_TEST_TG_SINUS == o->gen_type))
335     {
336       if ((o->max_rate - o->base_rate) > o->base_rate)
337       {
338         /* This will cause an underflow */
339         GNUNET_break (0);
340       }
341       fprintf (stderr, "Selected max rate and base rate cannot be used for desired traffic form!\n");
342     }
343
344     if ((START_SEND == o->type) || (START_PREFERENCE == o->type))
345       fprintf (stderr, "Found operation %u in episode %u: %s [%llu]->[%llu] == %s, %llu -> %llu in %s\n",
346         op_counter, cur->id, print_op (o->type), o->src_id,
347         o->dest_id, (NULL != type) ? type : "",
348         o->base_rate, o->max_rate,
349         GNUNET_STRINGS_relative_time_to_string (o->period, GNUNET_YES));
350     else
351       fprintf (stderr, "Found operation %u in episode %u: %s [%llu]->[%llu]\n",
352         op_counter, cur->id, print_op (o->type), o->src_id, o->dest_id);
353
354     GNUNET_free_non_null (type);
355     GNUNET_free (op);
356
357     GNUNET_CONTAINER_DLL_insert (cur->head,cur->tail, o);
358     op_counter++;
359   }
360   GNUNET_free (sec_name);
361
362   return GNUNET_OK;
363 }
364
365
366 static int
367 load_episodes (struct Experiment *e, struct GNUNET_CONFIGURATION_Handle *cfg)
368 {
369   int e_counter = 0;
370   char *sec_name;
371   struct GNUNET_TIME_Relative e_duration;
372   struct Episode *cur;
373   struct Episode *last;
374
375   e_counter = 0;
376   last = NULL;
377   while (1)
378   {
379     GNUNET_asprintf(&sec_name, "episode-%u", e_counter);
380     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time(cfg,
381         sec_name, "duration", &e_duration))
382     {
383       GNUNET_free (sec_name);
384       break;
385     }
386
387     cur = GNUNET_new (struct Episode);
388     cur->duration = e_duration;
389     cur->id = e_counter;
390
391     if (GNUNET_OK != load_episode (e, cur, cfg))
392     {
393       GNUNET_free (sec_name);
394       GNUNET_free (cur);
395       return GNUNET_SYSERR;
396     }
397
398     fprintf (stderr, "Found episode %u with duration %s \n",
399         e_counter,
400         GNUNET_STRINGS_relative_time_to_string(cur->duration, GNUNET_YES));
401
402     /* Update experiment */
403     e->num_episodes ++;
404     e->total_duration = GNUNET_TIME_relative_add(e->total_duration, cur->duration);
405     /* Put in linked list */
406     if (NULL == last)
407       e->start = cur;
408     else
409     last->next = cur;
410
411     GNUNET_free (sec_name);
412     e_counter ++;
413     last = cur;
414   }
415   return e_counter;
416 }
417
418
419 static void
420 timeout_experiment (void *cls)
421 {
422   struct Experiment *e = cls;
423   e->experiment_timeout_task = NULL;
424   fprintf (stderr, "Experiment timeout!\n");
425
426   if (NULL != e->episode_timeout_task)
427   {
428     GNUNET_SCHEDULER_cancel (e->episode_timeout_task);
429     e->episode_timeout_task = NULL;
430   }
431
432   e->e_done_cb (e, GNUNET_TIME_absolute_get_duration(e->start_time),
433       GNUNET_SYSERR);
434 }
435
436
437 static void
438 enforce_start_send (struct GNUNET_ATS_TEST_Operation *op)
439 {
440   struct BenchmarkPeer *peer;
441   struct BenchmarkPartner *partner;
442
443   peer = GNUNET_ATS_TEST_get_peer (op->src_id);
444   if (NULL == peer)
445   {
446     GNUNET_break (0);
447     return;
448   }
449
450   partner = GNUNET_ATS_TEST_get_partner (op->src_id, op->dest_id);
451   if (NULL == partner)
452   {
453     GNUNET_break (0);
454     return;
455   }
456
457   fprintf (stderr, "Found master %llu slave %llu\n",op->src_id, op->dest_id);
458
459   if (NULL != partner->tg)
460   {
461     fprintf (stderr, "Stopping traffic between master %llu slave %llu\n",op->src_id, op->dest_id);
462     GNUNET_ATS_TEST_generate_traffic_stop(partner->tg);
463     partner->tg = NULL;
464   }
465
466   partner->tg = GNUNET_ATS_TEST_generate_traffic_start(peer, partner,
467       op->gen_type, op->base_rate, op->max_rate, op->period,
468       GNUNET_TIME_UNIT_FOREVER_REL);
469 }
470
471 static void
472 enforce_stop_send (struct GNUNET_ATS_TEST_Operation *op)
473 {
474   struct BenchmarkPartner *p;
475   p = GNUNET_ATS_TEST_get_partner (op->src_id, op->dest_id);
476   if (NULL == p)
477   {
478     GNUNET_break (0);
479     return;
480   }
481
482   fprintf (stderr, "Found master %llu slave %llu\n",op->src_id, op->dest_id);
483
484   if (NULL != p->tg)
485   {
486     fprintf (stderr, "Stopping traffic between master %llu slave %llu\n",
487         op->src_id, op->dest_id);
488     GNUNET_ATS_TEST_generate_traffic_stop(p->tg);
489     p->tg = NULL;
490   }
491 }
492
493
494 static void
495 enforce_start_preference (struct GNUNET_ATS_TEST_Operation *op)
496 {
497   struct BenchmarkPeer *peer;
498   struct BenchmarkPartner *partner;
499
500   peer = GNUNET_ATS_TEST_get_peer (op->src_id);
501   if (NULL == peer)
502   {
503     GNUNET_break (0);
504     return;
505   }
506
507   partner = GNUNET_ATS_TEST_get_partner (op->src_id, op->dest_id);
508   if (NULL == partner)
509   {
510     GNUNET_break (0);
511     return;
512   }
513
514   fprintf (stderr, "Found master %llu slave %llu\n",op->src_id, op->dest_id);
515
516   if (NULL != partner->pg)
517   {
518     fprintf (stderr, "Stopping traffic between master %llu slave %llu\n",
519         op->src_id, op->dest_id);
520     GNUNET_ATS_TEST_generate_preferences_stop(partner->pg);
521     partner->pg = NULL;
522   }
523
524   partner->pg = GNUNET_ATS_TEST_generate_preferences_start(peer, partner,
525       op->gen_type, op->base_rate, op->max_rate, op->period, op->frequency,
526       op->pref_type);
527 }
528
529 static void
530 enforce_stop_preference (struct GNUNET_ATS_TEST_Operation *op)
531 {
532   struct BenchmarkPartner *p;
533   p = GNUNET_ATS_TEST_get_partner (op->src_id, op->dest_id);
534   if (NULL == p)
535   {
536     GNUNET_break (0);
537     return;
538   }
539
540   fprintf (stderr, "Found master %llu slave %llu\n",op->src_id, op->dest_id);
541
542   if (NULL != p->pg)
543   {
544     fprintf (stderr, "Stopping preference between master %llu slave %llu\n",
545         op->src_id, op->dest_id);
546     GNUNET_ATS_TEST_generate_preferences_stop (p->pg);
547     p->pg = NULL;
548   }
549 }
550
551 static void enforce_episode (struct Episode *ep)
552 {
553   struct GNUNET_ATS_TEST_Operation *cur;
554   for (cur = ep->head; NULL != cur; cur = cur->next)
555   {
556
557     fprintf (stderr, "Enforcing operation: %s [%llu]->[%llu] == %llu\n",
558         print_op (cur->type), cur->src_id, cur->dest_id, cur->base_rate);
559     switch (cur->type) {
560       case START_SEND:
561         enforce_start_send (cur);
562         break;
563       case STOP_SEND:
564         enforce_stop_send (cur);
565         break;
566       case START_PREFERENCE:
567         enforce_start_preference (cur);
568         break;
569       case STOP_PREFERENCE:
570         enforce_stop_preference (cur);
571         break;
572       default:
573         break;
574     }
575   }
576 }
577
578
579 static void
580 timeout_episode (void *cls)
581 {
582   struct Experiment *e = cls;
583
584   e->episode_timeout_task = NULL;
585   if (NULL != e->ep_done_cb)
586     e->ep_done_cb (e->cur);
587
588   /* Scheduling next */
589   e->cur = e->cur->next;
590   if (NULL == e->cur)
591   {
592     /* done */
593     fprintf (stderr, "Last episode done!\n");
594     if (NULL != e->experiment_timeout_task)
595     {
596       GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
597       e->experiment_timeout_task = NULL;
598     }
599     e->e_done_cb (e, GNUNET_TIME_absolute_get_duration(e->start_time), GNUNET_OK);
600     return;
601   }
602
603   fprintf (stderr, "Running episode %u with timeout %s\n",
604       e->cur->id,
605       GNUNET_STRINGS_relative_time_to_string(e->cur->duration, GNUNET_YES));
606   enforce_episode(e->cur);
607
608   e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
609       &timeout_episode, e);
610 }
611
612
613 void
614 GNUNET_ATS_TEST_experimentation_run (struct Experiment *e,
615     GNUNET_ATS_TESTING_EpisodeDoneCallback ep_done_cb,
616     GNUNET_ATS_TESTING_ExperimentDoneCallback e_done_cb)
617 {
618   fprintf (stderr, "Running experiment `%s'  with timeout %s\n", e->name,
619       GNUNET_STRINGS_relative_time_to_string(e->max_duration, GNUNET_YES));
620   e->e_done_cb = e_done_cb;
621   e->ep_done_cb = ep_done_cb;
622   e->start_time = GNUNET_TIME_absolute_get();
623
624   /* Start total time out */
625   e->experiment_timeout_task = GNUNET_SCHEDULER_add_delayed (e->max_duration,
626       &timeout_experiment, e);
627
628   /* Start */
629   e->cur = e->start;
630   fprintf (stderr, "Running episode %u with timeout %s\n",
631       e->cur->id,
632       GNUNET_STRINGS_relative_time_to_string(e->cur->duration, GNUNET_YES));
633   enforce_episode(e->cur);
634   e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
635       &timeout_episode, e);
636
637
638 }
639
640
641 struct Experiment *
642 GNUNET_ATS_TEST_experimentation_load (char *filename)
643 {
644   struct Experiment *e;
645   struct GNUNET_CONFIGURATION_Handle *cfg;
646   e = NULL;
647
648   cfg = GNUNET_CONFIGURATION_create();
649   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, filename))
650   {
651     fprintf (stderr, "Failed to load `%s'\n", filename);
652     GNUNET_CONFIGURATION_destroy (cfg);
653     return NULL;
654   }
655
656   e = create_experiment ();
657
658   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "experiment",
659       "name", &e->name))
660   {
661     fprintf (stderr, "Invalid %s", "name");
662     free_experiment (e);
663     return NULL;
664   }
665   else
666     fprintf (stderr, "Experiment name: `%s'\n", e->name);
667
668   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_filename (cfg, "experiment",
669       "cfg_file", &e->cfg_file))
670   {
671     fprintf (stderr, "Invalid %s", "cfg_file");
672     free_experiment (e);
673     return NULL;
674   }
675   else
676     fprintf (stderr, "Experiment name: `%s'\n", e->cfg_file);
677
678   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number(cfg, "experiment",
679       "masters", &e->num_masters))
680   {
681     fprintf (stderr, "Invalid %s", "masters");
682     free_experiment (e);
683     return NULL;
684   }
685   else
686     fprintf (stderr, "Experiment masters: `%llu'\n",
687         e->num_masters);
688
689   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number(cfg, "experiment",
690       "slaves", &e->num_slaves))
691   {
692     fprintf (stderr, "Invalid %s", "slaves");
693     free_experiment (e);
694     return NULL;
695   }
696   else
697     fprintf (stderr, "Experiment slaves: `%llu'\n",
698         e->num_slaves);
699
700   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time(cfg, "experiment",
701       "log_freq", &e->log_freq))
702   {
703     fprintf (stderr, "Invalid %s", "log_freq");
704     free_experiment (e);
705     return NULL;
706   }
707   else
708     fprintf (stderr, "Experiment logging frequency: `%s'\n",
709         GNUNET_STRINGS_relative_time_to_string (e->log_freq, GNUNET_YES));
710
711   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time(cfg, "experiment",
712       "max_duration", &e->max_duration))
713   {
714     fprintf (stderr, "Invalid %s", "max_duration");
715     free_experiment (e);
716     return NULL;
717   }
718   else
719     fprintf (stderr, "Experiment duration: `%s'\n",
720         GNUNET_STRINGS_relative_time_to_string (e->max_duration, GNUNET_YES));
721
722   load_episodes (e, cfg);
723   fprintf (stderr, "Loaded %u episodes with total duration %s\n",
724       e->num_episodes,
725       GNUNET_STRINGS_relative_time_to_string (e->total_duration, GNUNET_YES));
726
727   GNUNET_CONFIGURATION_destroy (cfg);
728   return e;
729 }
730
731 void
732 GNUNET_ATS_TEST_experimentation_stop (struct Experiment *e)
733 {
734   if (NULL != e->experiment_timeout_task)
735   {
736     GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
737     e->experiment_timeout_task = NULL;
738   }
739   if (NULL != e->episode_timeout_task)
740   {
741     GNUNET_SCHEDULER_cancel (e->episode_timeout_task);
742     e->episode_timeout_task = NULL;
743   }
744   free_experiment (e);
745 }
746
747 /* end of file ats-testing-experiment.c*/