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