(no commit message)
[oweals/gnunet.git] / src / transport / test_transport_ats.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 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 testing/test_transport_ats.c
22  * @brief testcase for ats functionality
23  */
24 #include "platform.h"
25 #include "gnunet_testing_lib.h"
26 #include "gnunet_scheduler_lib.h"
27 #include "gauger.h"
28
29 #define VERBOSE GNUNET_NO
30
31 #define NUM_PEERS 11
32 #define MEASUREMENTS 5
33
34 #define DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
35 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
36
37
38 static int ok;
39
40 static int peers_left;
41
42 static int failed_peers;
43
44 static int measurement_started;
45
46 static struct GNUNET_TESTING_PeerGroup *pg;
47
48 static  GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
49 static  GNUNET_SCHEDULER_TaskIdentifier stats_task;
50 struct GNUNET_TESTING_Daemon * master_deamon;
51
52 struct GNUNET_STATISTICS_Handle * stats;
53
54 struct TEST_result
55 {
56         uint64_t timestamp;
57         uint64_t duration;
58         uint64_t mechs;
59         uint64_t peers;
60         uint64_t solution;
61 };
62
63 static int r_index;
64 //static int measurements;
65 static int peers;
66 static struct TEST_result results[MEASUREMENTS];
67
68 struct GNUNET_STATISTICS_GetHandle * s_solution;
69 struct GNUNET_STATISTICS_GetHandle * s_time;
70 struct GNUNET_STATISTICS_GetHandle * s_peers;
71 struct GNUNET_STATISTICS_GetHandle * s_mechs;
72 struct GNUNET_STATISTICS_GetHandle * s_duration;
73
74 /**
75  * Check whether peers successfully shut down.
76  */
77 void
78 shutdown_callback (void *cls, const char *emsg)
79 {
80   if (emsg != NULL)
81     {
82 #if VERBOSE
83       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n");
84 #endif
85       if (ok == 0)
86         ok = 666;
87     }
88   else
89     {
90 #if VERBOSE
91       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
92                   "All peers successfully shut down!\n");
93         if (stats != NULL)
94                 GNUNET_STATISTICS_destroy(stats, GNUNET_NO);
95         stats = NULL;
96 #endif
97     }
98 }
99
100 static void shutdown_peers()
101 {
102         if (shutdown_task != GNUNET_SCHEDULER_NO_TASK)
103         {
104                 GNUNET_SCHEDULER_cancel(shutdown_task);
105                 shutdown_task = GNUNET_SCHEDULER_NO_TASK;
106         }
107         if (stats_task != GNUNET_SCHEDULER_NO_TASK)
108         {
109                 GNUNET_SCHEDULER_cancel(stats_task);
110                 stats_task = GNUNET_SCHEDULER_NO_TASK;
111         }
112
113         if (s_time != NULL)
114         {
115                 GNUNET_STATISTICS_get_cancel(s_time);
116                 s_time = NULL;
117         }
118         if (s_peers != NULL)
119         {
120                 GNUNET_STATISTICS_get_cancel(s_peers);
121                 s_peers = NULL;
122         }
123         if (s_mechs != NULL)
124         {
125                 GNUNET_STATISTICS_get_cancel(s_mechs);
126                 s_mechs = NULL;
127         }
128         if (s_solution != NULL)
129         {
130                 GNUNET_STATISTICS_get_cancel(s_solution);
131                 s_solution = NULL;
132         }
133         if (s_duration != NULL)
134         {
135                 GNUNET_STATISTICS_get_cancel(s_duration);
136                 s_duration = NULL;
137         }
138
139
140     GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
141 }
142
143 static void evaluate_measurements()
144 {
145         int c;
146         char * output = NULL;
147         char * temp;
148         double average;
149         double stddev;
150         double measure = MEASUREMENTS;
151         for (c=0; c<MEASUREMENTS;c++)
152         {
153                 average += (double) results[c].duration;
154                 GNUNET_asprintf(&temp, "%sm%i,%llu,%llu,%llu,%llu,", (output==NULL) ? "" : output, c, results[c].peers, results[c].mechs, results[c].duration, results[c].solution);
155                 GNUNET_free_non_null (output);
156                 output = temp;
157         }
158         average /= measure;
159
160         for (c=0; c<MEASUREMENTS;c++)
161         {
162                 stddev += (results[c].duration - average) * (results[c].duration - average);
163         }
164         stddev /= measure;
165         stddev = sqrt (stddev);
166
167         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"%savg,%f,stddev,%f\n",output,average,stddev);
168         /* only log benchmark time for 10 peers */
169
170         if (results[c].peers == (10))
171         {
172                 GAUGER ("TRANSPORT", "ATS execution time 10 peers", (int) average , "ms");
173         }
174
175         shutdown_peers();
176 }
177
178 int stats_cb (void *cls,
179                            const char *subsystem,
180                            const char *name,
181                            uint64_t value,
182                            int is_persistent)
183 {
184         if (0 == strcmp (name,"ATS solution"))
185         {
186                 s_solution = NULL;
187         }
188
189         if (0 == strcmp (name,"ATS peers"))
190         {
191                 s_peers = NULL;
192         }
193
194         if (0 == strcmp (name,"ATS mechanisms"))
195         {
196                 s_mechs = NULL;
197         }
198
199         if (0 == strcmp (name,"ATS duration"))
200         {
201                 s_duration = NULL;
202         }
203         if (0 == strcmp (name,"ATS timestamp"))
204         {
205                 s_time = NULL;
206         }
207
208     if ((measurement_started == GNUNET_NO) && (0 == strcmp (name, "ATS peers")) && (value == peers-1))
209     {
210                 measurement_started = GNUNET_YES;
211                 r_index = 0;
212                 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All %llu peers connected\n", value);
213     }
214     if (measurement_started == GNUNET_YES)
215     {
216                 // GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s == %llu\n", name ,value);
217                 if (0 == strcmp (name,"ATS timestamp"))
218                 {
219                         if (results[r_index].timestamp == 0)
220                                 results[r_index].timestamp = value;
221                         if (results[r_index].timestamp != value)
222                         {
223                                 r_index++;
224                                 if (r_index >= MEASUREMENTS)
225                                 {
226                                         if (stats_task != GNUNET_SCHEDULER_NO_TASK)
227                                         {
228                                                 GNUNET_SCHEDULER_cancel(stats_task);
229                                                 stats_task = GNUNET_SCHEDULER_NO_TASK;
230                                         }
231                                         evaluate_measurements();
232                                         return GNUNET_NO;
233                                 }
234                                 results[r_index].timestamp = value;
235                         }
236
237                         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
238                                                 "[%i] ATS solution: %s %llu \n", r_index, name, value);
239                 }
240
241                 if (0 == strcmp (name,"ATS solution"))
242                 {
243                         results[r_index].solution = value;
244                         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
245                                                 "[%i] ATS solution: %s %llu \n", r_index, name, value);
246                 }
247
248                 if (0 == strcmp (name,"ATS peers"))
249                 {
250                         results[r_index].peers = value;
251                         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
252                                                 "[%i] ATS peers: %s %llu \n", r_index, name, value);
253                 }
254
255                 if (0 == strcmp (name,"ATS mechanisms"))
256                 {
257                         results[r_index].mechs = value;
258                         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "[%i] ATS mechanisms: %s %llu \n", r_index, name, value);
259                 }
260
261                 if (0 == strcmp (name,"ATS duration"))
262                 {
263                         results[r_index].duration = value;
264                         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "[%i] ATS duration: %s %llu \n", r_index, name, value);
265                 }
266     }
267     return GNUNET_OK;
268 }
269
270
271 void
272 stats_get_task (void *cls,
273                           const struct GNUNET_SCHEDULER_TaskContext *tc)
274 {
275         stats_task = GNUNET_SCHEDULER_NO_TASK;
276         if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
277             return;
278
279         s_time = GNUNET_STATISTICS_get (stats, "transport", "ATS timestamp", TIMEOUT, NULL, &stats_cb, NULL);
280         s_solution = GNUNET_STATISTICS_get (stats, "transport", "ATS solution", TIMEOUT, NULL, &stats_cb, NULL);
281         s_duration = GNUNET_STATISTICS_get (stats, "transport","ATS duration", TIMEOUT, NULL, &stats_cb, NULL);
282         s_peers = GNUNET_STATISTICS_get (stats, "transport", "ATS peers", TIMEOUT, NULL, &stats_cb, NULL);
283         s_mechs = GNUNET_STATISTICS_get (stats, "transport", "ATS mechanisms", TIMEOUT, NULL, &stats_cb, NULL);
284
285         stats_task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250), &stats_get_task, NULL);
286 }
287
288 void
289 delay (void *cls,
290                           const struct GNUNET_SCHEDULER_TaskContext *tc)
291 {
292         shutdown_task = GNUNET_SCHEDULER_NO_TASK;
293         if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
294             return;
295
296 #if VERBOSE
297         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Delay over\n");
298 #endif
299         shutdown_peers ();
300 }
301
302 static void connect_peers()
303 {
304     shutdown_task = GNUNET_SCHEDULER_add_delayed(DELAY, &delay, NULL);
305
306 }
307
308 void daemon_connect_cb(void *cls,
309                                                 const struct GNUNET_PeerIdentity *first,
310                                                 const struct GNUNET_PeerIdentity *second,
311                                                 uint32_t distance,
312                                                 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
313                                                 const struct GNUNET_CONFIGURATION_Handle *second_cfg,
314                                                 struct GNUNET_TESTING_Daemon *first_daemon,
315                                                 struct GNUNET_TESTING_Daemon *second_daemon,
316                                                 const char *emsg)
317 {
318           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected peers `%s'<->`%s': `%s' \n", GNUNET_i2s(first), GNUNET_i2s(second), (emsg==NULL) ? "OK" : emsg);
319 }
320
321 void cont_cb (void *cls, int success)
322 {
323     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
324                 "STATS cont_cb: %i\n", success);
325 }
326
327 static void
328 daemon_start_cb (void *cls,
329        const struct GNUNET_PeerIdentity *id,
330        const struct GNUNET_CONFIGURATION_Handle *cfg,
331        struct GNUNET_TESTING_Daemon *d, const char *emsg)
332 {
333   if (id == NULL)
334     {
335       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
336                   "Start callback called with error (too long starting peers), aborting test!\n");
337       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n");
338       failed_peers++;
339       if (failed_peers == peers_left)
340         {
341           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
342                       "Too many peers failed, ending test!\n");
343           ok = 1;
344         shutdown_peers ();
345         }
346       return;
347     }
348   peers_left--;
349
350   if (master_deamon == NULL)
351   {
352           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Master peer `%s' '%s'\n", GNUNET_i2s(id), d->cfgfile);
353
354           master_deamon = d;
355           stats = GNUNET_STATISTICS_create("transport", master_deamon->cfg);
356           GNUNET_assert (stats != NULL);
357           stats_task = GNUNET_SCHEDULER_add_now(&stats_get_task, NULL);
358   }
359   else
360   {
361           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer `%s'\n", GNUNET_i2s(id), GNUNET_i2s(&master_deamon->id));
362           GNUNET_TESTING_daemons_connect(d, master_deamon, TIMEOUT, 0, GNUNET_YES,&daemon_connect_cb, NULL);
363   }
364
365   if (peers_left == 0)
366     {
367       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
368                   "All peers started successfully!\n");
369       connect_peers();
370       ok = 0;
371     }
372   else if (failed_peers == peers_left)
373     {
374       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
375                   "Too many peers failed, ending test!\n");
376       GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
377       ok = 1;
378     }
379 }
380
381
382 static void
383 run (void *cls,
384      char *const *args,
385      const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
386 {
387   ok = 1;
388   measurement_started = GNUNET_NO;
389 #if VERBOSE
390   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting %i peers.\n", NUM_PEERS);
391 #endif
392   peers_left = peers;
393   pg = GNUNET_TESTING_daemons_start (cfg,
394                                      peers_left, /* Total number of peers */
395                                      peers_left, /* Number of outstanding connections */
396                                      peers_left, /* Number of parallel ssh connections, or peers being started at once */
397                                      TIMEOUT,
398                                      NULL, NULL,
399                                      &daemon_start_cb, NULL, NULL, NULL, NULL);
400   GNUNET_assert (pg != NULL);
401 }
402
403 static int
404 check ()
405 {
406   char *const argv[] = { "test-testing",
407     "-c",
408     "test_transport_ats.conf",
409 #if VERBOSE
410     "-L", "DEBUG",
411 #endif
412     NULL
413   };
414   struct GNUNET_GETOPT_CommandLineOption options[] = {
415     GNUNET_GETOPT_OPTION_END
416   };
417   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
418                       argv, "test-testing-group", "nohelp",
419                       options, &run, &ok);
420   return ok;
421 }
422
423 int
424 main (int argc, char *argv[])
425 {
426   int ret;
427
428   GNUNET_log_setup ("test-transport-ats",
429 #if VERBOSE
430                     "DEBUG",
431 #else
432                     "WARNING",
433 #endif
434                     NULL);
435
436   peers = NUM_PEERS;
437   if (argc >= 2)
438   {
439           peers = atoi(argv[1]);
440           peers++;
441           if(peers <1)
442                   peers = NUM_PEERS;
443   }
444   ret = check ();
445   /**
446    * Still need to remove the base testing directory here,
447    * because group starts will create subdirectories under this
448    * main dir.  However, we no longer need to sleep, as the
449    * shutdown sequence won't return until everything is cleaned
450    * up.
451    */
452   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing");
453   return ret;
454 }
455
456 /* end of test_transport_ats.c*/