implement GNUNET_NETWORK_test_port_free() for testcases to conveniently check if...
[oweals/gnunet.git] / src / ats-tests / gnunet-solver-eval.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 "gnunet_ats_plugin.h"
29 #include "gnunet_ats_service.h"
30 #include "ats-testing.h"
31
32
33 /**
34  * Experiments
35  */
36 const char *
37 print_op (enum OperationType op)
38 {
39   switch (op) {
40     case START_SEND:
41       return "START_SEND";
42     case STOP_SEND:
43       return "STOP_SEND";
44     case START_PREFERENCE:
45       return "START_PREFERENCE";
46     case STOP_PREFERENCE:
47       return "STOP_PREFERENCE";
48     default:
49       break;
50   }
51   return "";
52 }
53
54
55 static struct Experiment *
56 create_experiment ()
57 {
58   struct Experiment *e;
59   e = GNUNET_new (struct Experiment);
60   e->name = NULL;
61   e->num_masters = 0;
62   e->num_slaves = 0;
63   e->start = NULL;
64   e->total_duration = GNUNET_TIME_UNIT_ZERO;
65   return e;
66 }
67
68
69 static void
70 free_experiment (struct Experiment *e)
71 {
72   struct Episode *cur;
73   struct Episode *next;
74   struct GNUNET_ATS_TEST_Operation *cur_o;
75   struct GNUNET_ATS_TEST_Operation *next_o;
76
77   next = e->start;
78   for (cur = next; NULL != cur; cur = next)
79   {
80     next = cur->next;
81
82     next_o = cur->head;
83     for (cur_o = next_o; NULL != cur_o; cur_o = next_o)
84     {
85       next_o = cur_o->next;
86       GNUNET_free (cur_o);
87     }
88     GNUNET_free (cur);
89   }
90
91   GNUNET_free_non_null (e->name);
92   GNUNET_free_non_null (e->cfg_file);
93   GNUNET_free (e);
94 }
95
96
97 static int
98 load_episode (struct Experiment *e,
99               struct Episode *cur,
100               struct GNUNET_CONFIGURATION_Handle *cfg)
101 {
102   struct GNUNET_ATS_TEST_Operation *o;
103   char *sec_name;
104   char *op_name;
105   char *op;
106   char *type;
107   char *pref;
108   int op_counter = 0;
109   fprintf (stderr, "Parsing episode %u\n",cur->id);
110   GNUNET_asprintf(&sec_name, "episode-%u", cur->id);
111
112   while (1)
113   {
114     /* Load operation */
115     GNUNET_asprintf(&op_name, "op-%u-operation", op_counter);
116     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg,
117         sec_name, op_name, &op))
118     {
119       GNUNET_free (op_name);
120       break;
121     }
122     o = GNUNET_new (struct GNUNET_ATS_TEST_Operation);
123     /* operations = set_rate, start_send, stop_send, set_preference */
124     if (0 == strcmp (op, "start_send"))
125     {
126       o->type = START_SEND;
127     }
128     else if (0 == strcmp (op, "stop_send"))
129     {
130       o->type = STOP_SEND;
131     }
132     else if (0 == strcmp (op, "start_preference"))
133     {
134       o->type = START_PREFERENCE;
135     }
136     else if (0 == strcmp (op, "stop_preference"))
137     {
138       o->type = STOP_PREFERENCE;
139     }
140     else
141     {
142       fprintf (stderr, "Invalid operation %u `%s' in episode %u\n",
143           op_counter, op, cur->id);
144       GNUNET_free (op);
145       GNUNET_free (op_name);
146       GNUNET_free (sec_name);
147       GNUNET_free (o);
148       return GNUNET_SYSERR;
149     }
150     GNUNET_free (op_name);
151
152     /* Get source */
153     GNUNET_asprintf(&op_name, "op-%u-src", op_counter);
154     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
155         sec_name, op_name, &o->src_id))
156     {
157       fprintf (stderr, "Missing src in operation %u `%s' in episode %u\n",
158           op_counter, op, cur->id);
159       GNUNET_free (op);
160       GNUNET_free (op_name);
161       GNUNET_free (sec_name);
162       GNUNET_free (o);
163       return GNUNET_SYSERR;
164     }
165     if (o->src_id > (e->num_masters - 1))
166     {
167       fprintf (stderr, "Invalid src %llu in operation %u `%s' in episode %u\n",
168           o->src_id, op_counter, op, cur->id);
169       GNUNET_free (op);
170       GNUNET_free (op_name);
171       GNUNET_free (sec_name);
172       GNUNET_free (o);
173       return GNUNET_SYSERR;
174     }
175     GNUNET_free (op_name);
176
177     /* Get destination */
178     GNUNET_asprintf(&op_name, "op-%u-dest", op_counter);
179     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
180         sec_name, op_name, &o->dest_id))
181     {
182       fprintf (stderr, "Missing src in operation %u `%s' in episode %u\n",
183           op_counter, op, cur->id);
184       GNUNET_free (op);
185       GNUNET_free (op_name);
186       GNUNET_free (sec_name);
187       GNUNET_free (o);
188       return GNUNET_SYSERR;
189     }
190     if (o->dest_id > (e->num_slaves - 1))
191     {
192       fprintf (stderr,
193                "Invalid destination %llu in operation %u `%s' in episode %u\n",
194                o->dest_id,
195                op_counter,
196                op,
197                cur->id);
198       GNUNET_free (op);
199       GNUNET_free (op_name);
200       GNUNET_free (sec_name);
201       GNUNET_free (o);
202       return GNUNET_SYSERR;
203     }
204     GNUNET_free (op_name);
205
206     GNUNET_asprintf(&op_name, "op-%u-type", op_counter);
207     if ( (GNUNET_SYSERR !=
208           GNUNET_CONFIGURATION_get_value_string(cfg,
209                                                 sec_name,
210                                                 op_name,
211                                                 &type)) &&
212          (STOP_SEND != o->type) &&
213          (STOP_PREFERENCE != o->type) )
214     {
215       /* Load arguments for set_rate, start_send, set_preference */
216       if (0 == strcmp (type, "constant"))
217       {
218         o->gen_type = GNUNET_ATS_TEST_TG_CONSTANT;
219       }
220       else if (0 == strcmp (type, "linear"))
221       {
222         o->gen_type = GNUNET_ATS_TEST_TG_LINEAR;
223       }
224       else if (0 == strcmp (type, "sinus"))
225       {
226         o->gen_type = GNUNET_ATS_TEST_TG_SINUS;
227       }
228       else if (0 == strcmp (type, "random"))
229       {
230         o->gen_type = GNUNET_ATS_TEST_TG_RANDOM;
231       }
232       else
233       {
234         fprintf (stderr, "Invalid type %u `%s' in episode %u\n",
235             op_counter, op, cur->id);
236         GNUNET_free (type);
237         GNUNET_free (op);
238         GNUNET_free (op_name);
239         GNUNET_free (sec_name);
240         GNUNET_free (o);
241         return GNUNET_SYSERR;
242       }
243       GNUNET_free (op_name);
244
245       /* Get base rate */
246       GNUNET_asprintf(&op_name, "op-%u-base-rate", op_counter);
247       if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
248           sec_name, op_name, &o->base_rate))
249       {
250         fprintf (stderr, "Missing base rate in operation %u `%s' in episode %u\n",
251             op_counter, op, cur->id);
252         GNUNET_free (type);
253         GNUNET_free (op);
254         GNUNET_free (op_name);
255         GNUNET_free (sec_name);
256         GNUNET_free (o);
257         return GNUNET_SYSERR;
258       }
259       GNUNET_free (op_name);
260
261       /* Get max rate */
262       GNUNET_asprintf(&op_name, "op-%u-max-rate", op_counter);
263       if (GNUNET_SYSERR ==
264           GNUNET_CONFIGURATION_get_value_number (cfg,
265                                                  sec_name,
266                                                  op_name,
267                                                  &o->max_rate))
268       {
269         if ((GNUNET_ATS_TEST_TG_LINEAR == o->gen_type) ||
270             (GNUNET_ATS_TEST_TG_RANDOM == o->gen_type) ||
271             (GNUNET_ATS_TEST_TG_SINUS == o->gen_type))
272         {
273           fprintf (stderr, "Missing max rate in operation %u `%s' in episode %u\n",
274               op_counter, op, cur->id);
275           GNUNET_free (type);
276           GNUNET_free (op_name);
277           GNUNET_free (op);
278           GNUNET_free (sec_name);
279           GNUNET_free (o);
280           return GNUNET_SYSERR;
281         }
282       }
283       GNUNET_free (op_name);
284
285       /* Get period */
286       GNUNET_asprintf(&op_name, "op-%u-period", op_counter);
287       if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
288           sec_name, op_name, &o->period))
289       {
290         o->period = cur->duration;
291       }
292       GNUNET_free (op_name);
293
294       if (START_PREFERENCE == o->type)
295       {
296           /* Get frequency */
297           GNUNET_asprintf(&op_name, "op-%u-frequency", op_counter);
298           if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
299               sec_name, op_name, &o->frequency))
300           {
301               fprintf (stderr, "Missing frequency in operation %u `%s' in episode %u\n",
302                   op_counter, op, cur->id);
303               GNUNET_free (type);
304               GNUNET_free (op_name);
305               GNUNET_free (op);
306               GNUNET_free (sec_name);
307               GNUNET_free (o);
308               return GNUNET_SYSERR;
309           }
310           GNUNET_free (op_name);
311
312           /* Get preference */
313           GNUNET_asprintf(&op_name, "op-%u-pref", op_counter);
314           if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
315               sec_name, op_name, &pref))
316           {
317               fprintf (stderr, "Missing 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 (sec_name);
323               GNUNET_free_non_null (pref);
324               GNUNET_free (o);
325               return GNUNET_SYSERR;
326           }
327
328           if (0 == strcmp(pref, "bandwidth"))
329             o->pref_type = GNUNET_ATS_PREFERENCE_BANDWIDTH;
330           else if (0 == strcmp(pref, "latency"))
331             o->pref_type = GNUNET_ATS_PREFERENCE_LATENCY;
332           else
333           {
334               fprintf (stderr,
335                        "Invalid preference in operation %u `%s' in episode %u\n",
336                        op_counter,
337                        op,
338                        cur->id);
339               GNUNET_free (type);
340               GNUNET_free (op_name);
341               GNUNET_free (op);
342               GNUNET_free (sec_name);
343               GNUNET_free_non_null (pref);
344               GNUNET_free (o);
345               return GNUNET_SYSERR;
346           }
347           GNUNET_free (pref);
348           GNUNET_free (op_name);
349       }
350     }
351
352     /* Safety checks */
353     if ((GNUNET_ATS_TEST_TG_LINEAR == o->gen_type) ||
354         (GNUNET_ATS_TEST_TG_SINUS == o->gen_type))
355     {
356       if ((o->max_rate - o->base_rate) > o->base_rate)
357       {
358         /* This will cause an underflow */
359         GNUNET_break (0);
360       }
361       fprintf (stderr, "Selected max rate and base rate cannot be used for desired traffic form!\n");
362     }
363
364     if ((START_SEND == o->type) || (START_PREFERENCE == o->type))
365       fprintf (stderr, "Found operation %u in episode %u: %s [%llu]->[%llu] == %s, %llu -> %llu in %s\n",
366         op_counter, cur->id, print_op (o->type), o->src_id,
367         o->dest_id, (NULL != type) ? type : "",
368         o->base_rate, o->max_rate,
369         GNUNET_STRINGS_relative_time_to_string (o->period, GNUNET_YES));
370     else
371       fprintf (stderr, "Found operation %u in episode %u: %s [%llu]->[%llu]\n",
372         op_counter, cur->id, print_op (o->type), o->src_id, o->dest_id);
373
374     GNUNET_free_non_null (type);
375     GNUNET_free (op);
376
377     GNUNET_CONTAINER_DLL_insert (cur->head,cur->tail, o);
378     op_counter++;
379   }
380   GNUNET_free (sec_name);
381
382   return GNUNET_OK;
383 }
384
385 static int
386 load_episodes (struct Experiment *e, struct GNUNET_CONFIGURATION_Handle *cfg)
387 {
388   int e_counter = 0;
389   char *sec_name;
390   struct GNUNET_TIME_Relative e_duration;
391   struct Episode *cur;
392   struct Episode *last;
393
394   e_counter = 0;
395   last = NULL;
396   while (1)
397   {
398     GNUNET_asprintf(&sec_name, "episode-%u", e_counter);
399     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time(cfg,
400         sec_name, "duration", &e_duration))
401     {
402       GNUNET_free (sec_name);
403       break;
404     }
405
406     cur = GNUNET_new (struct Episode);
407     cur->duration = e_duration;
408     cur->id = e_counter;
409
410     if (GNUNET_OK != load_episode (e, cur, cfg))
411     {
412       GNUNET_free (sec_name);
413       GNUNET_free (cur);
414       return GNUNET_SYSERR;
415     }
416
417     fprintf (stderr, "Found episode %u with duration %s \n",
418         e_counter,
419         GNUNET_STRINGS_relative_time_to_string(cur->duration, GNUNET_YES));
420
421     /* Update experiment */
422     e->num_episodes ++;
423     e->total_duration = GNUNET_TIME_relative_add(e->total_duration, cur->duration);
424     /* Put in linked list */
425     if (NULL == last)
426       e->start = cur;
427     else
428     last->next = cur;
429
430     GNUNET_free (sec_name);
431     e_counter ++;
432     last = cur;
433   }
434   return e_counter;
435 }
436
437
438 static void
439 timeout_experiment (void *cls)
440 {
441   struct Experiment *e = cls;
442   e->experiment_timeout_task = NULL;
443   fprintf (stderr, "Experiment timeout!\n");
444
445   if (NULL != e->episode_timeout_task)
446   {
447     GNUNET_SCHEDULER_cancel (e->episode_timeout_task);
448     e->episode_timeout_task = NULL;
449   }
450
451   e->e_done_cb (e, GNUNET_TIME_absolute_get_duration(e->start_time),
452       GNUNET_SYSERR);
453 }
454
455
456 static void
457 enforce_start_send (struct GNUNET_ATS_TEST_Operation *op)
458 {
459   /*
460   struct BenchmarkPeer *peer;
461   struct BenchmarkPartner *partner;
462
463   peer = GNUNET_ATS_TEST_get_peer (op->src_id);
464   if (NULL == peer)
465   {
466     GNUNET_break (0);
467     return;
468   }
469
470   partner = GNUNET_ATS_TEST_get_partner (op->src_id, op->dest_id);
471   if (NULL == partner)
472   {
473     GNUNET_break (0);
474     return;
475   }
476
477   fprintf (stderr, "Found master %llu slave %llu\n",op->src_id, op->dest_id);
478
479   if (NULL != partner->tg)
480   {
481     fprintf (stderr, "Stopping traffic between master %llu slave %llu\n",op->src_id, op->dest_id);
482     GNUNET_ATS_TEST_generate_traffic_stop(partner->tg);
483     partner->tg = NULL;
484   }
485
486   partner->tg = GNUNET_ATS_TEST_generate_traffic_start(peer, partner,
487       op->tg_type, op->base_rate, op->max_rate, op->period,
488       GNUNET_TIME_UNIT_FOREVER_REL);
489    */
490 }
491
492 static void
493 enforce_stop_send (struct GNUNET_ATS_TEST_Operation *op)
494 {
495   /*
496   struct BenchmarkPartner *p;
497   p = GNUNET_ATS_TEST_get_partner (op->src_id, op->dest_id);
498   if (NULL == p)
499   {
500     GNUNET_break (0);
501     return;
502   }
503
504   fprintf (stderr, "Found master %llu slave %llu\n",op->src_id, op->dest_id);
505
506   if (NULL != p->tg)
507   {
508     fprintf (stderr, "Stopping traffic between master %llu slave %llu\n",
509         op->src_id, op->dest_id);
510     GNUNET_ATS_TEST_generate_traffic_stop(p->tg);
511     p->tg = NULL;
512   }
513   */
514 }
515
516
517 static void
518 enforce_start_preference (struct GNUNET_ATS_TEST_Operation *op)
519 {
520   /*
521   struct BenchmarkPeer *peer;
522   struct BenchmarkPartner *partner;
523
524   peer = GNUNET_ATS_TEST_get_peer (op->src_id);
525   if (NULL == peer)
526   {
527     GNUNET_break (0);
528     return;
529   }
530
531   partner = GNUNET_ATS_TEST_get_partner (op->src_id, op->dest_id);
532   if (NULL == partner)
533   {
534     GNUNET_break (0);
535     return;
536   }
537
538   fprintf (stderr, "Found master %llu slave %llu\n",op->src_id, op->dest_id);
539
540   if (NULL != partner->pg)
541   {
542     fprintf (stderr, "Stopping traffic between master %llu slave %llu\n",
543         op->src_id, op->dest_id);
544     GNUNET_ATS_TEST_generate_preferences_stop(partner->pg);
545     partner->pg = NULL;
546   }
547
548   partner->pg = GNUNET_ATS_TEST_generate_preferences_start(peer, partner,
549       op->tg_type, op->base_rate, op->max_rate, op->period, op->frequency,
550       op->pref_type);
551       */
552 }
553
554 static void
555 enforce_stop_preference (struct GNUNET_ATS_TEST_Operation *op)
556 {
557   /*
558   struct BenchmarkPartner *p;
559   p = GNUNET_ATS_TEST_get_partner (op->src_id, op->dest_id);
560   if (NULL == p)
561   {
562     GNUNET_break (0);
563     return;
564   }
565
566   fprintf (stderr, "Found master %llu slave %llu\n",op->src_id, op->dest_id);
567
568   if (NULL != p->pg)
569   {
570     fprintf (stderr, "Stopping preference between master %llu slave %llu\n",
571         op->src_id, op->dest_id);
572     GNUNET_ATS_TEST_generate_preferences_stop (p->pg);
573     p->pg = NULL;
574   }
575   */
576 }
577
578 static void enforce_episode (struct Episode *ep)
579 {
580   struct GNUNET_ATS_TEST_Operation *cur;
581   for (cur = ep->head; NULL != cur; cur = cur->next)
582   {
583
584     fprintf (stderr, "Enforcing operation: %s [%llu]->[%llu] == %llu\n",
585         print_op (cur->type), cur->src_id, cur->dest_id, cur->base_rate);
586     switch (cur->type) {
587       case START_SEND:
588         enforce_start_send (cur);
589         break;
590       case STOP_SEND:
591         enforce_stop_send (cur);
592         break;
593       case START_PREFERENCE:
594         enforce_start_preference (cur);
595         break;
596       case STOP_PREFERENCE:
597         enforce_stop_preference (cur);
598         break;
599       default:
600         break;
601     }
602   }
603 }
604
605
606 static void
607 timeout_episode (void *cls)
608 {
609   struct Experiment *e = cls;
610   e->episode_timeout_task = NULL;
611   if (NULL != e->ep_done_cb)
612     e->ep_done_cb (e->cur);
613
614   /* Scheduling next */
615   e->cur = e->cur->next;
616   if (NULL == e->cur)
617   {
618     /* done */
619     fprintf (stderr, "Last episode done!\n");
620     if (NULL != e->experiment_timeout_task)
621     {
622       GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
623       e->experiment_timeout_task = NULL;
624     }
625     e->e_done_cb (e, GNUNET_TIME_absolute_get_duration(e->start_time), GNUNET_OK);
626     return;
627   }
628
629   fprintf (stderr, "Running episode %u with timeout %s\n",
630       e->cur->id,
631       GNUNET_STRINGS_relative_time_to_string(e->cur->duration, GNUNET_YES));
632   enforce_episode(e->cur);
633
634   e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
635       &timeout_episode, e);
636 }
637
638
639 void
640 GNUNET_ATS_solvers_experimentation_run (struct Experiment *e,
641     GNUNET_ATS_TESTING_EpisodeDoneCallback ep_done_cb,
642     GNUNET_ATS_TESTING_ExperimentDoneCallback e_done_cb)
643 {
644   fprintf (stderr, "Running experiment `%s'  with timeout %s\n", e->name,
645       GNUNET_STRINGS_relative_time_to_string(e->max_duration, GNUNET_YES));
646   e->e_done_cb = e_done_cb;
647   e->ep_done_cb = ep_done_cb;
648   e->start_time = GNUNET_TIME_absolute_get();
649
650   /* Start total time out */
651   e->experiment_timeout_task = GNUNET_SCHEDULER_add_delayed (e->max_duration,
652       &timeout_experiment, e);
653
654   /* Start */
655   e->cur = e->start;
656   fprintf (stderr, "Running episode %u with timeout %s\n",
657       e->cur->id,
658       GNUNET_STRINGS_relative_time_to_string(e->cur->duration, GNUNET_YES));
659   enforce_episode(e->cur);
660   e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
661       &timeout_episode, e);
662
663
664 }
665
666
667 struct Experiment *
668 GNUNET_ATS_solvers_experimentation_load (char *filename)
669 {
670   struct Experiment *e;
671   struct GNUNET_CONFIGURATION_Handle *cfg;
672   e = NULL;
673
674   cfg = GNUNET_CONFIGURATION_create();
675   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, filename))
676   {
677     fprintf (stderr, "Failed to load `%s'\n", filename);
678     GNUNET_CONFIGURATION_destroy (cfg);
679     return NULL;
680   }
681
682   e = create_experiment ();
683
684   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "experiment",
685       "name", &e->name))
686   {
687     fprintf (stderr, "Invalid %s", "name");
688     free_experiment (e);
689     return NULL;
690   }
691   else
692     fprintf (stderr, "Experiment name: `%s'\n", e->name);
693
694   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_filename (cfg, "experiment",
695       "cfg_file", &e->cfg_file))
696   {
697     fprintf (stderr, "Invalid %s", "cfg_file");
698     free_experiment (e);
699     return NULL;
700   }
701   else
702     fprintf (stderr, "Experiment name: `%s'\n", e->cfg_file);
703
704   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number(cfg, "experiment",
705       "masters", &e->num_masters))
706   {
707     fprintf (stderr, "Invalid %s", "masters");
708     free_experiment (e);
709     return NULL;
710   }
711   else
712     fprintf (stderr, "Experiment masters: `%llu'\n",
713         e->num_masters);
714
715   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number(cfg, "experiment",
716       "slaves", &e->num_slaves))
717   {
718     fprintf (stderr, "Invalid %s", "slaves");
719     free_experiment (e);
720     return NULL;
721   }
722   else
723     fprintf (stderr, "Experiment slaves: `%llu'\n",
724         e->num_slaves);
725
726   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time(cfg, "experiment",
727       "log_freq", &e->log_freq))
728   {
729     fprintf (stderr, "Invalid %s", "log_freq");
730     free_experiment (e);
731     return NULL;
732   }
733   else
734     fprintf (stderr, "Experiment logging frequency: `%s'\n",
735         GNUNET_STRINGS_relative_time_to_string (e->log_freq, GNUNET_YES));
736
737   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time(cfg, "experiment",
738       "max_duration", &e->max_duration))
739   {
740     fprintf (stderr, "Invalid %s", "max_duration");
741     free_experiment (e);
742     return NULL;
743   }
744   else
745     fprintf (stderr, "Experiment duration: `%s'\n",
746         GNUNET_STRINGS_relative_time_to_string (e->max_duration, GNUNET_YES));
747
748   load_episodes (e, cfg);
749   fprintf (stderr, "Loaded %u episodes with total duration %s\n",
750       e->num_episodes,
751       GNUNET_STRINGS_relative_time_to_string (e->total_duration, GNUNET_YES));
752
753   GNUNET_CONFIGURATION_destroy (cfg);
754   return e;
755 }
756
757 void
758 GNUNET_ATS_solvers_experimentation_stop (struct Experiment *e)
759 {
760   if (NULL != e->experiment_timeout_task)
761   {
762     GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
763     e->experiment_timeout_task = NULL;
764   }
765   if (NULL != e->episode_timeout_task)
766   {
767     GNUNET_SCHEDULER_cancel (e->episode_timeout_task);
768     e->episode_timeout_task = NULL;
769   }
770   free_experiment (e);
771 }
772
773 /**
774  * Solver
775  */
776
777 struct GNUNET_ATS_TESTING_SolverHandle
778 {
779   char * plugin;
780   struct GNUNET_ATS_PluginEnvironment env;
781   void *solver;
782 };
783
784 enum GNUNET_ATS_Solvers
785 {
786   GNUNET_ATS_SOLVER_PROPORTIONAL,
787   GNUNET_ATS_SOLVER_MLP,
788   GNUNET_ATS_SOLVER_RIL,
789 };
790
791 void
792 GNUNET_ATS_solvers_solver_stop (struct GNUNET_ATS_TESTING_SolverHandle *sh)
793 {
794  GNUNET_PLUGIN_unload (sh->plugin, sh->solver);
795  GNUNET_free (sh->plugin);
796  GNUNET_free (sh);
797 }
798
799 struct GNUNET_ATS_TESTING_SolverHandle *
800 GNUNET_ATS_solvers_solver_start (enum GNUNET_ATS_Solvers type)
801 {
802   struct GNUNET_ATS_TESTING_SolverHandle *sh;
803   char * solver_str;
804
805   switch (type) {
806     case GNUNET_ATS_SOLVER_PROPORTIONAL:
807       solver_str = "proportional";
808       break;
809     case GNUNET_ATS_SOLVER_MLP:
810       solver_str = "mlp";
811       break;
812     case GNUNET_ATS_SOLVER_RIL:
813       solver_str = "ril";
814       break;
815     default:
816       GNUNET_break (0);
817       return NULL;
818       break;
819   }
820
821   sh = GNUNET_new (struct GNUNET_ATS_TESTING_SolverHandle);
822   GNUNET_asprintf (&sh->plugin, "libgnunet_plugin_ats_%s", solver_str);
823   //sh->solver = GNUNET_PLUGIN_load (sh->plugin, &sh->env);
824   if (NULL == sh->solver)
825   {
826     fprintf (stderr, "Failed to load solver `%s'\n", sh->plugin);
827     exit (1);
828   }
829
830   return sh;
831 }
832
833 static struct Experiment *e;
834
835 static struct GNUNET_ATS_TESTING_SolverHandle *sh;
836
837 /**
838  * cmd option -e: experiment file
839  */
840 static char *opt_exp_file;
841
842 static char *opt_solver;
843
844 /**
845  * cmd option -l: enable logging
846  */
847 static int opt_log;
848
849 /**
850  * cmd option -p: enable plots
851  */
852 static int opt_plot;
853
854 /**
855  * cmd option -v: verbose logs
856  */
857 static int opt_verbose;
858
859 static void
860 run (void *cls, char * const *args, const char *cfgfile,
861     const struct GNUNET_CONFIGURATION_Handle *cfg)
862 {
863   enum GNUNET_ATS_Solvers solver;
864
865   if (NULL == opt_exp_file)
866   {
867     fprintf (stderr, "No experiment given ...\n");
868     exit (1);
869   }
870
871   if (NULL == opt_solver)
872   {
873     fprintf (stderr, "No solver given ...\n");
874     exit (1);
875   }
876
877   if (0 == strcmp(opt_solver, "mlp"))
878   {
879     solver = GNUNET_ATS_SOLVER_MLP;
880   }
881   else if (0 == strcmp(opt_solver, "proportional"))
882   {
883     solver = GNUNET_ATS_SOLVER_PROPORTIONAL;
884   }
885   else if (0 == strcmp(opt_solver, "ril"))
886   {
887     solver = GNUNET_ATS_SOLVER_RIL;
888   }
889   else
890   {
891     fprintf (stderr, "No solver given ...");
892     return;
893   }
894
895   /* load experiment */
896   e = GNUNET_ATS_solvers_experimentation_load (opt_exp_file);
897   if (NULL == e)
898   {
899     fprintf (stderr, "Failed to load experiment ...\n");
900     return;
901   }
902
903   /* load solver */
904   sh = GNUNET_ATS_solvers_solver_start (solver);
905   if (NULL == sh)
906   {
907     fprintf (stderr, "Failed to start solver ...\n");
908     return;
909   }
910
911   /* start logging */
912
913   /* run experiment */
914
915   /* WAIT */
916 }
917
918
919 /**
920  * Main function of the benchmark
921  *
922  * @param argc argument count
923  * @param argv argument values
924  */
925 int
926 main (int argc, char *argv[])
927 {
928
929   opt_exp_file = NULL;
930   opt_solver = NULL;
931   opt_log = GNUNET_NO;
932   opt_plot = GNUNET_NO;
933
934   struct GNUNET_GETOPT_CommandLineOption options[] =
935   {
936     GNUNET_GETOPT_OPTION_STRING ('s',
937                                  "solver",
938                                  NULL,
939                                  gettext_noop ("solver to use"),
940                                  &opt_solver),
941
942     GNUNET_GETOPT_OPTION_STRING ('e',
943                                  "experiment",
944                                  NULL,
945                                  gettext_noop ("experiment to use"),
946                                  &opt_exp_file),
947  
948     GNUNET_GETOPT_OPTION_SET_ONE ('e',
949                                   "experiment",
950                                   gettext_noop ("experiment to use"),
951                                   &opt_verbose),
952     GNUNET_GETOPT_OPTION_END
953   };
954
955   if (GNUNET_OK !=
956       GNUNET_PROGRAM_run (argc,
957                           argv, argv[0],
958                           NULL,
959                           options,
960                           &run, argv[0]))
961     return 1;
962
963   return 0;
964 }
965 /* end of file gnunet-solver-eval.c*/