2 This file is part of GNUnet.
3 Copyright (C) 2010-2013 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
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 Affero General Public License for more details.
16 * @file ats-tests/ats-testing-experiment.c
17 * @brief ats benchmark: controlled experiment execution
18 * @author Christian Grothoff
19 * @author Matthias Wachs
22 #include "gnunet_util_lib.h"
23 #include "gnunet_ats_plugin.h"
24 #include "gnunet_ats_service.h"
25 #include "ats-testing.h"
32 print_op (enum OperationType op)
39 case START_PREFERENCE:
40 return "START_PREFERENCE";
42 return "STOP_PREFERENCE";
50 static struct Experiment *
54 e = GNUNET_new (struct Experiment);
59 e->total_duration = GNUNET_TIME_UNIT_ZERO;
65 free_experiment (struct Experiment *e)
69 struct GNUNET_ATS_TEST_Operation *cur_o;
70 struct GNUNET_ATS_TEST_Operation *next_o;
73 for (cur = next; NULL != cur; cur = next)
78 for (cur_o = next_o; NULL != cur_o; cur_o = next_o)
86 GNUNET_free_non_null (e->name);
87 GNUNET_free_non_null (e->cfg_file);
93 load_episode (struct Experiment *e,
95 struct GNUNET_CONFIGURATION_Handle *cfg)
97 struct GNUNET_ATS_TEST_Operation *o;
104 fprintf (stderr, "Parsing episode %u\n",cur->id);
105 GNUNET_asprintf(&sec_name, "episode-%u", cur->id);
110 GNUNET_asprintf(&op_name, "op-%u-operation", op_counter);
111 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg,
112 sec_name, op_name, &op))
114 GNUNET_free (op_name);
117 o = GNUNET_new (struct GNUNET_ATS_TEST_Operation);
118 /* operations = set_rate, start_send, stop_send, set_preference */
119 if (0 == strcmp (op, "start_send"))
121 o->type = START_SEND;
123 else if (0 == strcmp (op, "stop_send"))
127 else if (0 == strcmp (op, "start_preference"))
129 o->type = START_PREFERENCE;
131 else if (0 == strcmp (op, "stop_preference"))
133 o->type = STOP_PREFERENCE;
137 fprintf (stderr, "Invalid operation %u `%s' in episode %u\n",
138 op_counter, op, cur->id);
140 GNUNET_free (op_name);
141 GNUNET_free (sec_name);
143 return GNUNET_SYSERR;
145 GNUNET_free (op_name);
148 GNUNET_asprintf(&op_name, "op-%u-src", op_counter);
149 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
150 sec_name, op_name, &o->src_id))
152 fprintf (stderr, "Missing src in operation %u `%s' in episode %u\n",
153 op_counter, op, cur->id);
155 GNUNET_free (op_name);
156 GNUNET_free (sec_name);
158 return GNUNET_SYSERR;
160 if (o->src_id > (e->num_masters - 1))
162 fprintf (stderr, "Invalid src %llu in operation %u `%s' in episode %u\n",
163 o->src_id, op_counter, op, cur->id);
165 GNUNET_free (op_name);
166 GNUNET_free (sec_name);
168 return GNUNET_SYSERR;
170 GNUNET_free (op_name);
172 /* Get destination */
173 GNUNET_asprintf(&op_name, "op-%u-dest", op_counter);
174 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
175 sec_name, op_name, &o->dest_id))
177 fprintf (stderr, "Missing src in operation %u `%s' in episode %u\n",
178 op_counter, op, cur->id);
180 GNUNET_free (op_name);
181 GNUNET_free (sec_name);
183 return GNUNET_SYSERR;
185 if (o->dest_id > (e->num_slaves - 1))
188 "Invalid destination %llu in operation %u `%s' in episode %u\n",
194 GNUNET_free (op_name);
195 GNUNET_free (sec_name);
197 return GNUNET_SYSERR;
199 GNUNET_free (op_name);
201 GNUNET_asprintf(&op_name, "op-%u-type", op_counter);
202 if ( (GNUNET_SYSERR !=
203 GNUNET_CONFIGURATION_get_value_string(cfg,
207 (STOP_SEND != o->type) &&
208 (STOP_PREFERENCE != o->type) )
210 /* Load arguments for set_rate, start_send, set_preference */
211 if (0 == strcmp (type, "constant"))
213 o->gen_type = GNUNET_ATS_TEST_TG_CONSTANT;
215 else if (0 == strcmp (type, "linear"))
217 o->gen_type = GNUNET_ATS_TEST_TG_LINEAR;
219 else if (0 == strcmp (type, "sinus"))
221 o->gen_type = GNUNET_ATS_TEST_TG_SINUS;
223 else if (0 == strcmp (type, "random"))
225 o->gen_type = GNUNET_ATS_TEST_TG_RANDOM;
229 fprintf (stderr, "Invalid type %u `%s' in episode %u\n",
230 op_counter, op, cur->id);
233 GNUNET_free (op_name);
234 GNUNET_free (sec_name);
236 return GNUNET_SYSERR;
238 GNUNET_free (op_name);
241 GNUNET_asprintf(&op_name, "op-%u-base-rate", op_counter);
242 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
243 sec_name, op_name, &o->base_rate))
245 fprintf (stderr, "Missing base rate in operation %u `%s' in episode %u\n",
246 op_counter, op, cur->id);
249 GNUNET_free (op_name);
250 GNUNET_free (sec_name);
252 return GNUNET_SYSERR;
254 GNUNET_free (op_name);
257 GNUNET_asprintf(&op_name, "op-%u-max-rate", op_counter);
259 GNUNET_CONFIGURATION_get_value_number (cfg,
264 if ((GNUNET_ATS_TEST_TG_LINEAR == o->gen_type) ||
265 (GNUNET_ATS_TEST_TG_RANDOM == o->gen_type) ||
266 (GNUNET_ATS_TEST_TG_SINUS == o->gen_type))
268 fprintf (stderr, "Missing max rate in operation %u `%s' in episode %u\n",
269 op_counter, op, cur->id);
271 GNUNET_free (op_name);
273 GNUNET_free (sec_name);
275 return GNUNET_SYSERR;
278 GNUNET_free (op_name);
281 GNUNET_asprintf(&op_name, "op-%u-period", op_counter);
282 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
283 sec_name, op_name, &o->period))
285 o->period = cur->duration;
287 GNUNET_free (op_name);
289 if (START_PREFERENCE == o->type)
292 GNUNET_asprintf(&op_name, "op-%u-frequency", op_counter);
293 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
294 sec_name, op_name, &o->frequency))
296 fprintf (stderr, "Missing frequency in operation %u `%s' in episode %u\n",
297 op_counter, op, cur->id);
299 GNUNET_free (op_name);
301 GNUNET_free (sec_name);
303 return GNUNET_SYSERR;
305 GNUNET_free (op_name);
308 GNUNET_asprintf(&op_name, "op-%u-pref", op_counter);
309 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
310 sec_name, op_name, &pref))
312 fprintf (stderr, "Missing preference in operation %u `%s' in episode %u\n",
313 op_counter, op, cur->id);
315 GNUNET_free (op_name);
317 GNUNET_free (sec_name);
318 GNUNET_free_non_null (pref);
320 return GNUNET_SYSERR;
323 if (0 == strcmp(pref, "bandwidth"))
324 o->pref_type = GNUNET_ATS_PREFERENCE_BANDWIDTH;
325 else if (0 == strcmp(pref, "latency"))
326 o->pref_type = GNUNET_ATS_PREFERENCE_LATENCY;
330 "Invalid preference in operation %u `%s' in episode %u\n",
335 GNUNET_free (op_name);
337 GNUNET_free (sec_name);
338 GNUNET_free_non_null (pref);
340 return GNUNET_SYSERR;
343 GNUNET_free (op_name);
348 if ((GNUNET_ATS_TEST_TG_LINEAR == o->gen_type) ||
349 (GNUNET_ATS_TEST_TG_SINUS == o->gen_type))
351 if ((o->max_rate - o->base_rate) > o->base_rate)
353 /* This will cause an underflow */
356 fprintf (stderr, "Selected max rate and base rate cannot be used for desired traffic form!\n");
359 if ((START_SEND == o->type) || (START_PREFERENCE == o->type))
360 fprintf (stderr, "Found operation %u in episode %u: %s [%llu]->[%llu] == %s, %llu -> %llu in %s\n",
361 op_counter, cur->id, print_op (o->type), o->src_id,
362 o->dest_id, (NULL != type) ? type : "",
363 o->base_rate, o->max_rate,
364 GNUNET_STRINGS_relative_time_to_string (o->period, GNUNET_YES));
366 fprintf (stderr, "Found operation %u in episode %u: %s [%llu]->[%llu]\n",
367 op_counter, cur->id, print_op (o->type), o->src_id, o->dest_id);
369 GNUNET_free_non_null (type);
372 GNUNET_CONTAINER_DLL_insert (cur->head,cur->tail, o);
375 GNUNET_free (sec_name);
381 load_episodes (struct Experiment *e, struct GNUNET_CONFIGURATION_Handle *cfg)
385 struct GNUNET_TIME_Relative e_duration;
387 struct Episode *last;
393 GNUNET_asprintf(&sec_name, "episode-%u", e_counter);
394 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time(cfg,
395 sec_name, "duration", &e_duration))
397 GNUNET_free (sec_name);
401 cur = GNUNET_new (struct Episode);
402 cur->duration = e_duration;
405 if (GNUNET_OK != load_episode (e, cur, cfg))
407 GNUNET_free (sec_name);
409 return GNUNET_SYSERR;
412 fprintf (stderr, "Found episode %u with duration %s \n",
414 GNUNET_STRINGS_relative_time_to_string(cur->duration, GNUNET_YES));
416 /* Update experiment */
418 e->total_duration = GNUNET_TIME_relative_add(e->total_duration, cur->duration);
419 /* Put in linked list */
425 GNUNET_free (sec_name);
434 timeout_experiment (void *cls)
436 struct Experiment *e = cls;
437 e->experiment_timeout_task = NULL;
438 fprintf (stderr, "Experiment timeout!\n");
440 if (NULL != e->episode_timeout_task)
442 GNUNET_SCHEDULER_cancel (e->episode_timeout_task);
443 e->episode_timeout_task = NULL;
446 e->e_done_cb (e, GNUNET_TIME_absolute_get_duration(e->start_time),
452 enforce_start_send (struct GNUNET_ATS_TEST_Operation *op)
455 struct BenchmarkPeer *peer;
456 struct BenchmarkPartner *partner;
458 peer = GNUNET_ATS_TEST_get_peer (op->src_id);
465 partner = GNUNET_ATS_TEST_get_partner (op->src_id, op->dest_id);
472 fprintf (stderr, "Found master %llu slave %llu\n",op->src_id, op->dest_id);
474 if (NULL != partner->tg)
476 fprintf (stderr, "Stopping traffic between master %llu slave %llu\n",op->src_id, op->dest_id);
477 GNUNET_ATS_TEST_generate_traffic_stop(partner->tg);
481 partner->tg = GNUNET_ATS_TEST_generate_traffic_start(peer, partner,
482 op->tg_type, op->base_rate, op->max_rate, op->period,
483 GNUNET_TIME_UNIT_FOREVER_REL);
488 enforce_stop_send (struct GNUNET_ATS_TEST_Operation *op)
491 struct BenchmarkPartner *p;
492 p = GNUNET_ATS_TEST_get_partner (op->src_id, op->dest_id);
499 fprintf (stderr, "Found master %llu slave %llu\n",op->src_id, op->dest_id);
503 fprintf (stderr, "Stopping traffic between master %llu slave %llu\n",
504 op->src_id, op->dest_id);
505 GNUNET_ATS_TEST_generate_traffic_stop(p->tg);
513 enforce_start_preference (struct GNUNET_ATS_TEST_Operation *op)
516 struct BenchmarkPeer *peer;
517 struct BenchmarkPartner *partner;
519 peer = GNUNET_ATS_TEST_get_peer (op->src_id);
526 partner = GNUNET_ATS_TEST_get_partner (op->src_id, op->dest_id);
533 fprintf (stderr, "Found master %llu slave %llu\n",op->src_id, op->dest_id);
535 if (NULL != partner->pg)
537 fprintf (stderr, "Stopping traffic between master %llu slave %llu\n",
538 op->src_id, op->dest_id);
539 GNUNET_ATS_TEST_generate_preferences_stop(partner->pg);
543 partner->pg = GNUNET_ATS_TEST_generate_preferences_start(peer, partner,
544 op->tg_type, op->base_rate, op->max_rate, op->period, op->frequency,
550 enforce_stop_preference (struct GNUNET_ATS_TEST_Operation *op)
553 struct BenchmarkPartner *p;
554 p = GNUNET_ATS_TEST_get_partner (op->src_id, op->dest_id);
561 fprintf (stderr, "Found master %llu slave %llu\n",op->src_id, op->dest_id);
565 fprintf (stderr, "Stopping preference between master %llu slave %llu\n",
566 op->src_id, op->dest_id);
567 GNUNET_ATS_TEST_generate_preferences_stop (p->pg);
573 static void enforce_episode (struct Episode *ep)
575 struct GNUNET_ATS_TEST_Operation *cur;
576 for (cur = ep->head; NULL != cur; cur = cur->next)
579 fprintf (stderr, "Enforcing operation: %s [%llu]->[%llu] == %llu\n",
580 print_op (cur->type), cur->src_id, cur->dest_id, cur->base_rate);
583 enforce_start_send (cur);
586 enforce_stop_send (cur);
588 case START_PREFERENCE:
589 enforce_start_preference (cur);
591 case STOP_PREFERENCE:
592 enforce_stop_preference (cur);
602 timeout_episode (void *cls)
604 struct Experiment *e = cls;
605 e->episode_timeout_task = NULL;
606 if (NULL != e->ep_done_cb)
607 e->ep_done_cb (e->cur);
609 /* Scheduling next */
610 e->cur = e->cur->next;
614 fprintf (stderr, "Last episode done!\n");
615 if (NULL != e->experiment_timeout_task)
617 GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
618 e->experiment_timeout_task = NULL;
620 e->e_done_cb (e, GNUNET_TIME_absolute_get_duration(e->start_time), GNUNET_OK);
624 fprintf (stderr, "Running episode %u with timeout %s\n",
626 GNUNET_STRINGS_relative_time_to_string(e->cur->duration, GNUNET_YES));
627 enforce_episode(e->cur);
629 e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
630 &timeout_episode, e);
635 GNUNET_ATS_solvers_experimentation_run (struct Experiment *e,
636 GNUNET_ATS_TESTING_EpisodeDoneCallback ep_done_cb,
637 GNUNET_ATS_TESTING_ExperimentDoneCallback e_done_cb)
639 fprintf (stderr, "Running experiment `%s' with timeout %s\n", e->name,
640 GNUNET_STRINGS_relative_time_to_string(e->max_duration, GNUNET_YES));
641 e->e_done_cb = e_done_cb;
642 e->ep_done_cb = ep_done_cb;
643 e->start_time = GNUNET_TIME_absolute_get();
645 /* Start total time out */
646 e->experiment_timeout_task = GNUNET_SCHEDULER_add_delayed (e->max_duration,
647 &timeout_experiment, e);
651 fprintf (stderr, "Running episode %u with timeout %s\n",
653 GNUNET_STRINGS_relative_time_to_string(e->cur->duration, GNUNET_YES));
654 enforce_episode(e->cur);
655 e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
656 &timeout_episode, e);
663 GNUNET_ATS_solvers_experimentation_load (char *filename)
665 struct Experiment *e;
666 struct GNUNET_CONFIGURATION_Handle *cfg;
669 cfg = GNUNET_CONFIGURATION_create();
670 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, filename))
672 fprintf (stderr, "Failed to load `%s'\n", filename);
673 GNUNET_CONFIGURATION_destroy (cfg);
677 e = create_experiment ();
679 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "experiment",
682 fprintf (stderr, "Invalid %s", "name");
687 fprintf (stderr, "Experiment name: `%s'\n", e->name);
689 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_filename (cfg, "experiment",
690 "cfg_file", &e->cfg_file))
692 fprintf (stderr, "Invalid %s", "cfg_file");
697 fprintf (stderr, "Experiment name: `%s'\n", e->cfg_file);
699 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number(cfg, "experiment",
700 "masters", &e->num_masters))
702 fprintf (stderr, "Invalid %s", "masters");
707 fprintf (stderr, "Experiment masters: `%llu'\n",
710 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number(cfg, "experiment",
711 "slaves", &e->num_slaves))
713 fprintf (stderr, "Invalid %s", "slaves");
718 fprintf (stderr, "Experiment slaves: `%llu'\n",
721 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time(cfg, "experiment",
722 "log_freq", &e->log_freq))
724 fprintf (stderr, "Invalid %s", "log_freq");
729 fprintf (stderr, "Experiment logging frequency: `%s'\n",
730 GNUNET_STRINGS_relative_time_to_string (e->log_freq, GNUNET_YES));
732 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time(cfg, "experiment",
733 "max_duration", &e->max_duration))
735 fprintf (stderr, "Invalid %s", "max_duration");
740 fprintf (stderr, "Experiment duration: `%s'\n",
741 GNUNET_STRINGS_relative_time_to_string (e->max_duration, GNUNET_YES));
743 load_episodes (e, cfg);
744 fprintf (stderr, "Loaded %u episodes with total duration %s\n",
746 GNUNET_STRINGS_relative_time_to_string (e->total_duration, GNUNET_YES));
748 GNUNET_CONFIGURATION_destroy (cfg);
753 GNUNET_ATS_solvers_experimentation_stop (struct Experiment *e)
755 if (NULL != e->experiment_timeout_task)
757 GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
758 e->experiment_timeout_task = NULL;
760 if (NULL != e->episode_timeout_task)
762 GNUNET_SCHEDULER_cancel (e->episode_timeout_task);
763 e->episode_timeout_task = NULL;
772 struct GNUNET_ATS_TESTING_SolverHandle
775 struct GNUNET_ATS_PluginEnvironment env;
779 enum GNUNET_ATS_Solvers
781 GNUNET_ATS_SOLVER_PROPORTIONAL,
782 GNUNET_ATS_SOLVER_MLP,
783 GNUNET_ATS_SOLVER_RIL,
787 GNUNET_ATS_solvers_solver_stop (struct GNUNET_ATS_TESTING_SolverHandle *sh)
789 GNUNET_PLUGIN_unload (sh->plugin, sh->solver);
790 GNUNET_free (sh->plugin);
794 struct GNUNET_ATS_TESTING_SolverHandle *
795 GNUNET_ATS_solvers_solver_start (enum GNUNET_ATS_Solvers type)
797 struct GNUNET_ATS_TESTING_SolverHandle *sh;
801 case GNUNET_ATS_SOLVER_PROPORTIONAL:
802 solver_str = "proportional";
804 case GNUNET_ATS_SOLVER_MLP:
807 case GNUNET_ATS_SOLVER_RIL:
816 sh = GNUNET_new (struct GNUNET_ATS_TESTING_SolverHandle);
817 GNUNET_asprintf (&sh->plugin, "libgnunet_plugin_ats_%s", solver_str);
818 //sh->solver = GNUNET_PLUGIN_load (sh->plugin, &sh->env);
819 if (NULL == sh->solver)
821 fprintf (stderr, "Failed to load solver `%s'\n", sh->plugin);
828 static struct Experiment *e;
830 static struct GNUNET_ATS_TESTING_SolverHandle *sh;
833 * cmd option -e: experiment file
835 static char *opt_exp_file;
837 static char *opt_solver;
840 * cmd option -l: enable logging
845 * cmd option -p: enable plots
850 * cmd option -v: verbose logs
852 static int opt_verbose;
855 run (void *cls, char * const *args, const char *cfgfile,
856 const struct GNUNET_CONFIGURATION_Handle *cfg)
858 enum GNUNET_ATS_Solvers solver;
860 if (NULL == opt_exp_file)
862 fprintf (stderr, "No experiment given ...\n");
866 if (NULL == opt_solver)
868 fprintf (stderr, "No solver given ...\n");
872 if (0 == strcmp(opt_solver, "mlp"))
874 solver = GNUNET_ATS_SOLVER_MLP;
876 else if (0 == strcmp(opt_solver, "proportional"))
878 solver = GNUNET_ATS_SOLVER_PROPORTIONAL;
880 else if (0 == strcmp(opt_solver, "ril"))
882 solver = GNUNET_ATS_SOLVER_RIL;
886 fprintf (stderr, "No solver given ...");
890 /* load experiment */
891 e = GNUNET_ATS_solvers_experimentation_load (opt_exp_file);
894 fprintf (stderr, "Failed to load experiment ...\n");
899 sh = GNUNET_ATS_solvers_solver_start (solver);
902 fprintf (stderr, "Failed to start solver ...\n");
915 * Main function of the benchmark
917 * @param argc argument count
918 * @param argv argument values
921 main (int argc, char *argv[])
927 opt_plot = GNUNET_NO;
929 struct GNUNET_GETOPT_CommandLineOption options[] =
931 GNUNET_GETOPT_option_string ('s',
934 gettext_noop ("solver to use"),
937 GNUNET_GETOPT_option_string ('e',
940 gettext_noop ("experiment to use"),
943 GNUNET_GETOPT_option_flag ('e',
945 gettext_noop ("experiment to use"),
947 GNUNET_GETOPT_OPTION_END
951 GNUNET_PROGRAM_run (argc,
960 /* end of file gnunet-solver-eval.c*/