fca3743248ee254be6cfd27f6129d43e07e0dcc6
[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 static struct Experiment *
31 create_experiment ()
32 {
33   struct Experiment *e;
34   e = GNUNET_new (struct Experiment);
35   e->name = NULL;
36   e->num_masters = 0;
37   e->num_slaves = 0;
38   e->start = NULL;
39   e->total_duration = GNUNET_TIME_UNIT_ZERO;
40   return e;
41 }
42
43 static void
44 free_experiment (struct Experiment *e)
45 {
46   struct Episode *cur;
47   struct Episode *next;
48
49   next = e->start;
50   for (cur = next; NULL != cur; cur = next)
51   {
52     next = cur->next;
53     GNUNET_free (cur);
54   }
55
56   GNUNET_free_non_null (e->name);
57   GNUNET_free_non_null (e->cfg_file);
58   GNUNET_free (e);
59 }
60
61 static int
62 load_episodes (struct Experiment *e, struct GNUNET_CONFIGURATION_Handle *cfg)
63 {
64   int e_counter = 0;
65   char *sec_name;
66   struct GNUNET_TIME_Relative e_duration;
67   struct Episode *cur;
68   struct Episode *last;
69
70   e_counter = 0;
71   last = NULL;
72   while (1)
73   {
74     GNUNET_asprintf(&sec_name, "episode-%u", e_counter);
75     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time(cfg,
76         sec_name, "duration", &e_duration))
77     {
78       GNUNET_free (sec_name);
79       break;
80     }
81
82     cur = GNUNET_new (struct Episode);
83     cur->duration = e_duration;
84     cur->id = e_counter;
85
86     fprintf (stderr, "Found episode %u with duration %s \n",
87         e_counter,
88         GNUNET_STRINGS_relative_time_to_string(cur->duration, GNUNET_YES));
89
90     /* Update experiment */
91     e->num_episodes ++;
92     e->total_duration = GNUNET_TIME_relative_add(e->total_duration, cur->duration);
93     /* Put in linked list */
94     if (NULL == last)
95       e->start = cur;
96     else
97     last->next = cur;
98
99     GNUNET_free (sec_name);
100     e_counter ++;
101     last = cur;
102   }
103   return e_counter;
104 }
105
106 static void
107 timeout_experiment (void *cls, const struct GNUNET_SCHEDULER_TaskContext* tc)
108 {
109   struct Experiment *e = cls;
110   e->experiment_timeout_task = GNUNET_SCHEDULER_NO_TASK;
111   fprintf (stderr, "Experiment timeout!\n");
112
113   e->e_done_cb (e, GNUNET_SYSERR);
114 }
115
116 static void
117 timeout_episode (void *cls, const struct GNUNET_SCHEDULER_TaskContext* tc)
118 {
119   struct Experiment *e = cls;
120   e->episode_timeout_task = GNUNET_SCHEDULER_NO_TASK;
121   e->ep_done_cb (e->cur);
122
123   /* Scheduling next */
124   e->cur = e->cur->next;
125   if (NULL == e->cur)
126   {
127     /* done */
128     fprintf (stderr, "Last episode done!\n");
129     if (GNUNET_SCHEDULER_NO_TASK != e->experiment_timeout_task)
130     {
131       GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
132       e->experiment_timeout_task = GNUNET_SCHEDULER_NO_TASK;
133     }
134     e->e_done_cb (e, GNUNET_OK);
135     return;
136   }
137
138   fprintf (stderr, "Running episode %u with timeout %s\n",
139       e->cur->id,
140       GNUNET_STRINGS_relative_time_to_string(e->cur->duration, GNUNET_YES));
141   e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
142       &timeout_episode, e);
143 }
144
145
146 void
147 GNUNET_ATS_TEST_experimentation_run (struct Experiment *e,
148     GNUNET_ATS_TESTING_EpisodeDoneCallback ep_done_cb,
149     GNUNET_ATS_TESTING_ExperimentDoneCallback e_done_cb)
150 {
151   fprintf (stderr, "Running experiment `%s'  with timeout %s\n", e->name,
152       GNUNET_STRINGS_relative_time_to_string(e->max_duration, GNUNET_YES));
153   e->e_done_cb = e_done_cb;
154   e->ep_done_cb = ep_done_cb;
155
156   /* Start total time out */
157   e->experiment_timeout_task = GNUNET_SCHEDULER_add_delayed (e->max_duration,
158       &timeout_experiment, e);
159
160   /* Start */
161   e->cur = e->start;
162   fprintf (stderr, "Running episode %u with timeout %s\n",
163       e->cur->id,
164       GNUNET_STRINGS_relative_time_to_string(e->cur->duration, GNUNET_YES));
165   e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
166       &timeout_episode, e);
167
168
169 }
170
171 struct Experiment *
172 GNUNET_ATS_TEST_experimentation_load (char *filename)
173 {
174   struct Experiment *e;
175   struct GNUNET_CONFIGURATION_Handle *cfg;
176   e = NULL;
177
178   cfg = GNUNET_CONFIGURATION_create();
179   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, filename))
180   {
181     fprintf (stderr, "Failed to load `%s'\n", filename);
182     GNUNET_CONFIGURATION_destroy (cfg);
183     return NULL;
184   }
185
186   e = create_experiment ();
187
188   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "experiment",
189       "name", &e->name))
190   {
191     fprintf (stderr, "Invalid %s", "name");
192     free_experiment (e);
193     return NULL;
194   }
195   else
196     fprintf (stderr, "Experiment name: `%s'\n", e->name);
197
198   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_filename (cfg, "experiment",
199       "cfg_file", &e->cfg_file))
200   {
201     fprintf (stderr, "Invalid %s", "cfg_file");
202     free_experiment (e);
203     return NULL;
204   }
205   else
206     fprintf (stderr, "Experiment name: `%s'\n", e->cfg_file);
207
208   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number(cfg, "experiment",
209       "masters", &e->num_masters))
210   {
211     fprintf (stderr, "Invalid %s", "masters");
212     free_experiment (e);
213     return NULL;
214   }
215   else
216     fprintf (stderr, "Experiment masters: `%llu'\n",
217         e->num_masters);
218
219   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number(cfg, "experiment",
220       "slaves", &e->num_slaves))
221   {
222     fprintf (stderr, "Invalid %s", "slaves");
223     free_experiment (e);
224     return NULL;
225   }
226   else
227     fprintf (stderr, "Experiment slaves: `%llu'\n",
228         e->num_slaves);
229
230   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time(cfg, "experiment",
231       "max_duration", &e->max_duration))
232   {
233     fprintf (stderr, "Invalid %s", "max_duration");
234     free_experiment (e);
235     return NULL;
236   }
237   else
238     fprintf (stderr, "Experiment duration: `%s'\n",
239         GNUNET_STRINGS_relative_time_to_string (e->max_duration, GNUNET_YES));
240
241   load_episodes (e, cfg);
242   fprintf (stderr, "Loaded %u episodes with total duration %s\n",
243       e->num_episodes,
244       GNUNET_STRINGS_relative_time_to_string (e->total_duration, GNUNET_YES));
245
246   GNUNET_CONFIGURATION_destroy (cfg);
247   return e;
248 }
249
250 void
251 GNUNET_ATS_TEST_experimentation_stop (struct Experiment *e)
252 {
253   if (GNUNET_SCHEDULER_NO_TASK != e->experiment_timeout_task)
254   {
255     GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
256     e->experiment_timeout_task = GNUNET_SCHEDULER_NO_TASK;
257   }
258   free_experiment (e);
259 }
260
261 /* end of file ats-testing-experiment.c*/
262