always remember: GNUNET_i2s is not reentrant!!!!
[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_YES
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         if (results[MEASUREMENTS-1].peers == (10))
170                 {
171                         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Send data to gauger: %f \n", average);
172                         GAUGER ("TRANSPORT", "ATS execution time 10 peers", average , "ms");
173                 }
174         shutdown_peers();
175 }
176
177 int stats_cb (void *cls,
178                            const char *subsystem,
179                            const char *name,
180                            uint64_t value,
181                            int is_persistent)
182 {
183         if (0 == strcmp (name,"ATS solution"))
184         {
185                 s_solution = NULL;
186         }
187
188         if (0 == strcmp (name,"ATS peers"))
189         {
190                 s_peers = NULL;
191         }
192
193         if (0 == strcmp (name,"ATS mechanisms"))
194         {
195                 s_mechs = NULL;
196         }
197
198         if (0 == strcmp (name,"ATS duration"))
199         {
200                 s_duration = NULL;
201         }
202         if (0 == strcmp (name,"ATS timestamp"))
203         {
204                 s_time = NULL;
205         }
206
207     if ((measurement_started == GNUNET_NO) && (0 == strcmp (name, "ATS peers")) && (value == peers-1))
208     {
209                 measurement_started = GNUNET_YES;
210                 r_index = 0;
211                 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All %llu peers connected\n", value);
212     }
213     if (measurement_started == GNUNET_YES)
214     {
215                 // GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s == %llu\n", name ,value);
216                 if (0 == strcmp (name,"ATS timestamp"))
217                 {
218                         if (results[r_index].timestamp == 0)
219                                 results[r_index].timestamp = value;
220                         if (results[r_index].timestamp != value)
221                         {
222                                 r_index++;
223                                 fprintf(stderr, "(%i/%i)", r_index, MEASUREMENTS);
224                                 if (r_index >= MEASUREMENTS)
225                                 {
226                                         fprintf(stderr, "\n");
227                                         if (stats_task != GNUNET_SCHEDULER_NO_TASK)
228                                         {
229                                                 GNUNET_SCHEDULER_cancel(stats_task);
230                                                 stats_task = GNUNET_SCHEDULER_NO_TASK;
231                                         }
232                                         evaluate_measurements();
233                                         return GNUNET_NO;
234                                 }
235                                 fprintf(stderr, "..");
236
237                                 results[r_index].timestamp = value;
238                         }
239                         //GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "[%i] ATS solution: %s %llu \n", r_index, name, value);
240                 }
241
242                 if (0 == strcmp (name,"ATS solution"))
243                 {
244                         results[r_index].solution = value;
245                         //GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "[%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, "[%i] ATS peers: %s %llu \n", r_index, name, value);
252                 }
253
254                 if (0 == strcmp (name,"ATS mechanisms"))
255                 {
256                         results[r_index].mechs = value;
257                         //GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "[%i] ATS mechanisms: %s %llu \n", r_index, name, value);
258                 }
259
260                 if (0 == strcmp (name,"ATS duration"))
261                 {
262                         results[r_index].duration = value;
263                         // GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "[%i] ATS duration: %s %llu \n", r_index, name, value);
264                 }
265     }
266     return GNUNET_OK;
267 }
268
269
270 void
271 stats_get_task (void *cls,
272                           const struct GNUNET_SCHEDULER_TaskContext *tc)
273 {
274         stats_task = GNUNET_SCHEDULER_NO_TASK;
275         if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
276             return;
277
278         s_time = GNUNET_STATISTICS_get (stats, "transport", "ATS timestamp", TIMEOUT, NULL, &stats_cb, NULL);
279         s_solution = GNUNET_STATISTICS_get (stats, "transport", "ATS solution", TIMEOUT, NULL, &stats_cb, NULL);
280         s_duration = GNUNET_STATISTICS_get (stats, "transport","ATS duration", TIMEOUT, NULL, &stats_cb, NULL);
281         s_peers = GNUNET_STATISTICS_get (stats, "transport", "ATS peers", TIMEOUT, NULL, &stats_cb, NULL);
282         s_mechs = GNUNET_STATISTICS_get (stats, "transport", "ATS mechanisms", TIMEOUT, NULL, &stats_cb, NULL);
283
284         stats_task = GNUNET_SCHEDULER_add_delayed(GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250), &stats_get_task, NULL);
285 }
286
287 void
288 delay (void *cls,
289                           const struct GNUNET_SCHEDULER_TaskContext *tc)
290 {
291         shutdown_task = GNUNET_SCHEDULER_NO_TASK;
292         if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
293             return;
294
295 #if VERBOSE
296         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Delay over\n");
297 #endif
298         shutdown_peers ();
299 }
300
301 static void connect_peers()
302 {
303     shutdown_task = GNUNET_SCHEDULER_add_delayed(DELAY, &delay, NULL);
304
305 }
306
307 void daemon_connect_cb(void *cls,
308                                                 const struct GNUNET_PeerIdentity *first,
309                                                 const struct GNUNET_PeerIdentity *second,
310                                                 uint32_t distance,
311                                                 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
312                                                 const struct GNUNET_CONFIGURATION_Handle *second_cfg,
313                                                 struct GNUNET_TESTING_Daemon *first_daemon,
314                                                 struct GNUNET_TESTING_Daemon *second_daemon,
315                                                 const char *emsg)
316 {
317         char * firstc =  strdup(GNUNET_i2s(first));
318         char * secondc =  strdup(GNUNET_i2s(second));
319         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected peers `%s'<->`%s'\n", firstc, secondc);
320         GNUNET_free(firstc);
321         GNUNET_free(secondc);
322 }
323
324 void cont_cb (void *cls, int success)
325 {
326     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
327                 "STATS cont_cb: %i\n", success);
328 }
329
330 static void
331 daemon_start_cb (void *cls,
332        const struct GNUNET_PeerIdentity *id,
333        const struct GNUNET_CONFIGURATION_Handle *cfg,
334        struct GNUNET_TESTING_Daemon *d, const char *emsg)
335 {
336   if (id == NULL)
337     {
338       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
339                   "Start callback called with error (too long starting peers), aborting test!\n");
340       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n");
341       failed_peers++;
342       if (failed_peers == peers_left)
343         {
344           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
345                       "Too many peers failed, ending test!\n");
346           ok = 1;
347         shutdown_peers ();
348         }
349       return;
350     }
351   peers_left--;
352
353   if (master_deamon == NULL)
354   {
355           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Master peer `%s' '%s'\n", GNUNET_i2s(id), d->cfgfile);
356
357           master_deamon = d;
358           stats = GNUNET_STATISTICS_create("transport", master_deamon->cfg);
359           GNUNET_assert (stats != NULL);
360           stats_task = GNUNET_SCHEDULER_add_now(&stats_get_task, NULL);
361   }
362   else
363   {
364           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer `%s'\n", GNUNET_i2s(id), GNUNET_i2s(&master_deamon->id));
365           GNUNET_TESTING_daemons_connect(d, master_deamon, TIMEOUT, 0, GNUNET_YES,&daemon_connect_cb, NULL);
366   }
367
368   if (peers_left == 0)
369     {
370       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
371                   "All peers started successfully!\n");
372       connect_peers();
373       ok = 0;
374     }
375   else if (failed_peers == peers_left)
376     {
377       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
378                   "Too many peers failed, ending test!\n");
379       GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
380       ok = 1;
381     }
382 }
383
384
385 static void
386 run (void *cls,
387      char *const *args,
388      const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
389 {
390   ok = 1;
391   measurement_started = GNUNET_NO;
392 #if VERBOSE
393   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting %i peers.\n", peers);
394 #endif
395   peers_left = peers;
396   pg = GNUNET_TESTING_daemons_start (cfg,
397                                      peers_left, /* Total number of peers */
398                                      peers_left, /* Number of outstanding connections */
399                                      peers_left, /* Number of parallel ssh connections, or peers being started at once */
400                                      TIMEOUT,
401                                      NULL, NULL,
402                                      &daemon_start_cb, NULL, NULL, NULL, NULL);
403   GNUNET_assert (pg != NULL);
404 }
405
406 static int
407 check ()
408 {
409   char *const argv[] = { "test-testing",
410     "-c",
411     "test_transport_ats.conf",
412 #if VERBOSE
413     "-L", "DEBUG",
414 #endif
415     NULL
416   };
417   struct GNUNET_GETOPT_CommandLineOption options[] = {
418     GNUNET_GETOPT_OPTION_END
419   };
420   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
421                       argv, "test-transport-ats", "nohelp",
422                       options, &run, &ok);
423   return ok;
424 }
425
426 int
427 main (int argc, char *argv[])
428 {
429   int ret;
430
431   GNUNET_log_setup ("test-transport-ats",
432 #if VERBOSE
433                     "DEBUG",
434 #else
435                     "WARNING",
436 #endif
437                     NULL);
438
439   peers = NUM_PEERS;
440   if (argc >= 2)
441   {
442           peers = atoi(argv[1]);
443           peers++;
444           if(peers <1)
445                   peers = NUM_PEERS;
446   }
447   ret = check ();
448   /**
449    * Still need to remove the base testing directory here,
450    * because group starts will create subdirectories under this
451    * main dir.  However, we no longer need to sleep, as the
452    * shutdown sequence won't return until everything is cleaned
453    * up.
454    */
455   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing");
456   return ret;
457 }
458
459 /* end of test_transport_ats.c*/