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