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