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