improved ats performance tests to support parallel transmissions
[oweals/gnunet.git] / src / ats-tests / perf_ats.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/perf_ats.c
22  * @brief ats benchmark: start peers and modify preferences, monitor change over time
23  * @author Christian Grothoff
24  * @author Matthias Wachs
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_testbed_service.h"
29 #include "gnunet_ats_service.h"
30 #include "gnunet_core_service.h"
31
32 #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
33 #define BENCHMARK_DURATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
34 #define TESTNAME_PREFIX "perf_ats_"
35 #define DEFAULT_SLAVES_NUM 3
36 #define DEFAULT_MASTERS_NUM 1
37
38 #define TEST_MESSAGE_TYPE_PING 12345
39 #define TEST_MESSAGE_TYPE_PONG 12346
40 #define TEST_MESSAGE_SIZE 1000
41 #define TEST_MESSAGE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
42
43 /**
44  * Information we track for a peer in the testbed.
45  */
46 struct BenchmarkPartner
47 {
48   struct BenchmarkPeer *src;
49
50   struct BenchmarkPeer *dest;
51   /**
52    * Core transmit handles
53    */
54   void *cth;
55
56   unsigned int messages_sent;
57
58   unsigned int bytes_sent;
59
60   unsigned int messages_received;
61
62   unsigned int bytes_received;
63 };
64
65
66 struct MasterInformation
67 {
68   int core_slave_connections;
69
70   /**
71    * Testbed connect operation
72    */
73   struct TestbedConnectOperation *core_connect_ops;
74 };
75
76 /**
77  * Connect peers with testbed
78  */
79 struct TestbedConnectOperation
80 {
81   struct BenchmarkPeer *master;
82
83   struct BenchmarkPeer *slave;
84
85   /**
86    * Testbed operation to connect peers
87    */
88   struct GNUNET_TESTBED_Operation *connect_op;
89 };
90
91
92
93 /**
94  * Information we track for a peer in the testbed.
95  */
96 struct BenchmarkPeer
97 {
98   /**
99    * Handle with testbed.
100    */
101   struct GNUNET_TESTBED_Peer *peer;
102
103   /**
104    * Unique identifier
105    */
106   int no;
107
108   int master;
109
110   /**
111    *  Peer ID
112    */
113   struct GNUNET_PeerIdentity id;
114
115   /**
116    * Testbed operation to get peer information
117    */
118   struct GNUNET_TESTBED_Operation *peer_id_op;
119
120   /**
121    * Testbed operation to connect to ATS performance service
122    */
123   struct GNUNET_TESTBED_Operation *ats_perf_op;
124
125   /**
126    * Testbed operation to connect to core
127    */
128   struct GNUNET_TESTBED_Operation *core_op;
129
130   /**
131    * ATS performance handle
132    */
133   struct GNUNET_ATS_PerformanceHandle *ats_perf_handle;
134
135   /**
136    *  Core handle
137    */
138   struct GNUNET_CORE_Handle *ch;
139
140   struct BenchmarkPartner *partners;
141
142   int core_connections;
143
144   struct MasterInformation mi;
145
146   unsigned int total_messages_sent;
147   unsigned int total_bytes_sent;
148   unsigned int total_messages_received;
149   unsigned int total_bytes_received;
150 };
151
152 struct BenchmarkState
153 {
154   /* Are we connected to ATS service of all peers: GNUNET_YES/NO */
155   int connected_ATS_service;
156
157   /* Are we connected to CORE service of all peers: GNUNET_YES/NO */
158   int connected_CORE_service;
159
160   /* Are we connected to all peers: GNUNET_YES/NO */
161   int connected_PEERS;
162
163   /* Are we connected to all slave peers on CORE level: GNUNET_YES/NO */
164   int connected_CORE;
165
166   /* Are we connected to CORE service of all peers: GNUNET_YES/NO */
167   int benchmarking;
168 };
169
170
171 /**
172  * Shutdown task
173  */
174 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
175
176 /**
177  * Test result
178  */
179 static int result;
180
181 /**
182  * Solver string
183  */
184 static char *solver;
185
186 /**
187  * Preference string
188  */
189 static char *pref_str;
190
191 /**
192  * ATS preference value
193  */
194 static int pref_val;
195
196 /**
197  * Number master peers
198  */
199 static int num_masters;
200
201 /**
202  * Array of master peers
203  */
204 struct BenchmarkPeer *mps;
205
206 /**
207  * Number slave peers
208  */
209 static int num_slaves;
210 /**
211  * Array of slave peers
212  */
213 struct BenchmarkPeer *sps;
214
215 /**
216  * Benchmark state
217  */
218 static struct BenchmarkState state;
219
220
221 static void
222 evaluate ()
223 {
224   int c_m;
225   int c_s;
226   unsigned int duration;
227   struct BenchmarkPeer *mp;
228
229   duration = (BENCHMARK_DURATION.rel_value_us / (1000 * 1000));
230   for (c_m = 0; c_m < num_masters; c_m++)
231   {
232     mp = &mps[c_m];
233     fprintf (stderr, _("Master [%u]: sent: %u KiB in %u sec. = %u KiB/s, received: %u KiB in %u sec. = %u KiB/s\n"),
234         mp->no,
235         mp->total_bytes_sent / 1024,
236         duration,
237         (mp->total_bytes_sent / 1024) / duration ,
238         mp->total_bytes_received / 1024,
239         duration,
240         (mp->total_bytes_received / 1024) / duration);
241
242     for (c_s = 0; c_s < num_slaves; c_s ++)
243     {
244       fprintf (stderr, "Master [%u] -> Slave [%u]: sent %u KiB/s, received %u KiB/s \n",
245           mp->no,
246           mp->partners[c_s].dest->no,
247           (mp->partners[c_s].bytes_sent / 1024) / duration,
248           (mp->partners[c_s].bytes_received / 1024) / duration);
249     }
250   }
251 }
252
253
254 /**
255  * Shutdown nicely
256  *
257  * @param cls NULL
258  * @param tc the task context
259  */
260 static void
261 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
262 {
263   int c_m;
264   int c_s;
265   int c_op;
266
267   shutdown_task = GNUNET_SCHEDULER_NO_TASK;
268   evaluate();
269   state.benchmarking = GNUNET_NO;
270   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Benchmarking done\n"));
271
272   for (c_m = 0; c_m < num_masters; c_m++)
273   {
274     if (NULL != mps[c_m].peer_id_op)
275     {
276       GNUNET_TESTBED_operation_done (mps[c_m].peer_id_op);
277       mps[c_m].peer_id_op = NULL;
278     }
279
280     for (c_op = 0; c_op < num_slaves; c_op++)
281     {
282
283       if (NULL != mps[c_m].partners[c_op].cth)
284       {
285         GNUNET_CORE_notify_transmit_ready_cancel (mps[c_m].partners[c_op].cth);
286         mps[c_m].partners[c_op].cth = NULL;
287       }
288
289       if (NULL != mps[c_m].mi.core_connect_ops[c_op].connect_op)
290       {
291         GNUNET_log(GNUNET_ERROR_TYPE_INFO,
292             _("Failed to connect peer 0 and %u\n"), c_op);
293         GNUNET_TESTBED_operation_done (
294             mps[c_m].mi.core_connect_ops[c_op].connect_op);
295         mps[c_m].mi.core_connect_ops[c_op].connect_op = NULL;
296         result = 1;
297       }
298     }
299
300     if (NULL != mps[c_m].ats_perf_op)
301     {
302       GNUNET_TESTBED_operation_done (mps[c_m].ats_perf_op);
303       mps[c_m].ats_perf_op = NULL;
304     }
305
306     if (NULL != mps[c_m].core_op)
307     {
308       GNUNET_TESTBED_operation_done (mps[c_m].core_op);
309       mps[c_m].core_op = NULL;
310     }
311   }
312
313
314   for (c_s = 0; c_s < num_slaves; c_s++)
315   {
316     if (NULL != sps[c_s].peer_id_op)
317     {
318       GNUNET_TESTBED_operation_done (sps[c_s].peer_id_op);
319       sps[c_s].peer_id_op = NULL;
320     }
321
322     for (c_op = 0; c_op < num_slaves; c_op++)
323     {
324       if (NULL != sps[c_s].partners[c_op].cth)
325       {
326         GNUNET_CORE_notify_transmit_ready_cancel (sps[c_s].partners[c_op].cth);
327         sps[c_s].partners[c_op].cth = NULL;
328       }
329     }
330
331
332     if (NULL != sps[c_s].ats_perf_op)
333     {
334       GNUNET_TESTBED_operation_done (sps[c_s].ats_perf_op);
335       sps[c_s].ats_perf_op = NULL;
336     }
337     if (NULL != sps[c_s].core_op)
338     {
339       GNUNET_TESTBED_operation_done (sps[c_s].core_op);
340       sps[c_s].core_op = NULL;
341     }
342   }
343
344   GNUNET_SCHEDULER_shutdown ();
345 }
346
347
348 static struct BenchmarkPeer *
349 find_peer (const struct GNUNET_PeerIdentity * peer)
350 {
351   int c_p;
352
353   for (c_p = 0; c_p < num_masters; c_p++)
354   {
355     if (0
356         == memcmp (&mps[c_p].id, peer,
357             sizeof(struct GNUNET_PeerIdentity)))
358       return &mps[c_p];
359   }
360
361   for (c_p = 0; c_p < num_slaves; c_p++)
362   {
363     if (0 == memcmp (&sps[c_p].id, peer,
364             sizeof(struct GNUNET_PeerIdentity)))
365       return &sps[c_p];
366   }
367   return NULL;
368 }
369
370
371 /**
372  * Controller event callback
373  *
374  * @param cls NULL
375  * @param event the controller event
376  */
377 static void
378 controller_event_cb (void *cls,
379     const struct GNUNET_TESTBED_EventInformation *event)
380 {
381   //struct BenchmarkPeer *p = cls;
382   switch (event->type)
383   {
384   case GNUNET_TESTBED_ET_CONNECT:
385     break;
386   case GNUNET_TESTBED_ET_OPERATION_FINISHED:
387     break;
388   default:
389     GNUNET_break(0);
390     result = 2;
391     GNUNET_SCHEDULER_cancel (shutdown_task);
392     shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL );
393   }
394 }
395
396
397 static size_t
398 core_send_ready (void *cls, size_t size, void *buf)
399 {
400   static char msgbuf[TEST_MESSAGE_SIZE];
401   struct BenchmarkPartner *partner = cls;
402   struct GNUNET_MessageHeader *msg;
403
404   partner->cth = NULL;
405   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Master [%u]: Sending PING to [%u]\n",
406         partner->src->no, partner->dest->no);
407
408   partner->messages_sent ++;
409   partner->bytes_sent += TEST_MESSAGE_SIZE;
410   partner->src->total_messages_sent ++;
411   partner->src->total_bytes_sent += TEST_MESSAGE_SIZE;
412
413   msg = (struct GNUNET_MessageHeader *) &msgbuf;
414   memset (&msgbuf, 'a', TEST_MESSAGE_SIZE);
415   msg->type = htons (TEST_MESSAGE_TYPE_PING);
416   msg->size = htons (TEST_MESSAGE_SIZE);
417   memcpy (buf, msg, TEST_MESSAGE_SIZE);
418   return TEST_MESSAGE_SIZE;
419 }
420
421
422 static void
423 do_benchmark ()
424 {
425   int c_m;
426   int c_s;
427
428   if ((state.connected_ATS_service == GNUNET_NO)
429       || (state.connected_CORE_service == GNUNET_NO)
430       || (state.connected_PEERS == GNUNET_NO)
431       || (state.connected_CORE == GNUNET_NO))
432     return;
433
434   state.benchmarking = GNUNET_YES;
435   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Benchmarking start\n"));
436
437   if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
438     GNUNET_SCHEDULER_cancel (shutdown_task);
439   shutdown_task = GNUNET_SCHEDULER_add_delayed (BENCHMARK_DURATION,
440       &do_shutdown, NULL );
441
442   /* Start sending test messages */
443   for (c_s = 0; c_s < num_slaves; c_s++)
444   {
445     for (c_m = 0; c_m < num_masters; c_m++)
446     {
447
448       sps[c_s].partners[c_m].src = &sps[c_s];
449       sps[c_s].partners[c_m].dest = &mps[c_m];
450     }
451   }
452
453   for (c_m = 0; c_m < num_masters; c_m++)
454   {
455     for (c_s = 0; c_s < num_slaves; c_s++)
456     {
457       mps[c_m].partners[c_s].src = &mps[c_m];
458       mps[c_m].partners[c_s].dest = &sps[c_s];
459       mps[c_m].partners[c_s].cth = GNUNET_CORE_notify_transmit_ready (mps[c_m].ch,
460           GNUNET_NO, 0, GNUNET_TIME_UNIT_MINUTES, &sps[c_s].id,
461           TEST_MESSAGE_SIZE, &core_send_ready, &mps[c_m].partners[c_s]);
462     }
463   }
464 }
465
466
467 static void
468 connect_completion_callback (void *cls, struct GNUNET_TESTBED_Operation *op,
469     const char *emsg)
470 {
471   struct TestbedConnectOperation *cop = cls;
472   static int ops = 0;
473   int c;
474   if (NULL == emsg)
475   {
476     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
477         _("Connected master peer %u with peer %u\n"), cop->master->no,
478         cop->slave->no);
479   }
480   else
481   {
482     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
483         _("Failed to connect master peer%u with peer %u\n"), cop->master->no,
484         cop->slave->no);
485     GNUNET_break(0);
486     if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
487       GNUNET_SCHEDULER_cancel (shutdown_task);
488     shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL );
489   }
490   GNUNET_TESTBED_operation_done (op);
491   ops++;
492   for (c = 0; c < num_slaves; c++)
493   {
494     if (cop == &cop->master->mi.core_connect_ops[c])
495       cop->master->mi.core_connect_ops[c].connect_op = NULL;
496   }
497   if (ops == num_masters * num_slaves)
498   {
499     state.connected_PEERS = GNUNET_YES;
500     GNUNET_SCHEDULER_add_now (&do_benchmark, NULL );
501   }
502 }
503
504
505 static void
506 do_connect_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
507 {
508   int c_m;
509   int c_s;
510   struct BenchmarkPeer *p;
511
512   if ((state.connected_ATS_service == GNUNET_NO)
513       || (state.connected_CORE_service == GNUNET_NO))
514   {
515     return;
516   }
517
518   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Connecting peers on CORE level\n"));
519
520   for (c_m = 0; c_m < num_masters; c_m++)
521   {
522     p = &mps[c_m];
523     p->mi.core_connect_ops = GNUNET_malloc (num_slaves *
524         sizeof (struct TestbedConnectOperation));
525
526     for (c_s = 0; c_s < num_slaves; c_s++)
527     {
528       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
529           _("Connecting master peer %u with slave peer %u\n"), p->no,
530           sps[c_s].no);
531       p->mi.core_connect_ops[c_s].master = p;
532       p->mi.core_connect_ops[c_s].slave = &sps[c_s];
533       p->mi.core_connect_ops[c_s].connect_op = GNUNET_TESTBED_overlay_connect (NULL,
534           &connect_completion_callback, &p->mi.core_connect_ops[c_s],
535           sps[c_s].peer, p->peer);
536       if (NULL == p->mi.core_connect_ops[c_s].connect_op)
537       {
538         GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
539             _("Could not connect master peer %u and slave peer %u\n"), p->no,
540             sps[c_s].no);
541         GNUNET_break(0);
542         if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
543           GNUNET_SCHEDULER_cancel (shutdown_task);
544         shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL );
545         return;
546       }
547     }
548   }
549 }
550
551
552 /**
553  * Method called whenever a given peer connects.
554  *
555  * @param cls closure
556  * @param peer peer identity this notification is about
557  */
558 static void
559 core_connect_cb (void *cls, const struct GNUNET_PeerIdentity * peer)
560 {
561   struct BenchmarkPeer *p = cls;
562   struct BenchmarkPeer *t;
563   char *id;
564   int c;
565   int completed;
566
567   t = find_peer (peer);
568   if (NULL == t)
569   {
570     GNUNET_break(0);
571     return;
572   }
573
574   id = GNUNET_strdup (GNUNET_i2s (&p->id));
575   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s %s connected to %s %s\n",
576       (p->master == GNUNET_YES) ? "Master": "Slave", id,
577       (t->master == GNUNET_YES) ? "Master": "Slave", GNUNET_i2s (peer));
578
579   p->core_connections++;
580   if ((GNUNET_YES == p->master) && (GNUNET_NO == t->master)
581       && (GNUNET_NO == state.connected_CORE))
582   {
583     p->mi.core_slave_connections++;
584
585     if (p->mi.core_slave_connections == num_slaves)
586     {
587       GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Master %u connected all slaves\n",
588           p->no);
589     }
590     completed = GNUNET_YES;
591     for (c = 0; c < num_masters; c++)
592     {
593       if (mps[c].mi.core_slave_connections != num_slaves)
594         completed = GNUNET_NO;
595     }
596     if (GNUNET_YES == completed)
597     {
598       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
599           "All master peers connected all slave peers\n", id,
600           GNUNET_i2s (peer));
601       state.connected_CORE = GNUNET_YES;
602       GNUNET_SCHEDULER_add_now (&do_benchmark, NULL );
603     }
604   }
605   GNUNET_free(id);
606 }
607
608
609 static void
610 core_disconnect_cb (void *cls, const struct GNUNET_PeerIdentity * peer)
611 {
612   struct BenchmarkPeer *p = cls;
613   struct BenchmarkPeer *t;
614   char *id;
615
616   t = find_peer (peer);
617   if (NULL == t)
618   {
619     GNUNET_break(0);
620     return;
621   }
622
623   id = GNUNET_strdup (GNUNET_i2s (&p->id));
624   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s disconnected from %s \n", id,
625       GNUNET_i2s (peer));
626   GNUNET_assert(p->core_connections > 0);
627   p->core_connections--;
628
629   if ((GNUNET_YES == state.benchmarking)
630       && ((GNUNET_YES == p->master) || (GNUNET_YES == t->master)))
631   {
632     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
633         "%s disconnected from %s while benchmarking \n", id, GNUNET_i2s (peer));
634   }
635   GNUNET_free(id);
636 }
637
638 static size_t
639 core_send_echo_ready (void *cls, size_t size, void *buf)
640 {
641   static char msgbuf[TEST_MESSAGE_SIZE];
642   struct BenchmarkPartner *p = cls;
643   struct GNUNET_MessageHeader *msg;
644
645   p->cth = NULL;
646
647   p->messages_sent ++;
648   p->bytes_sent += TEST_MESSAGE_SIZE;
649   p->src->total_messages_sent ++;
650   p->src->total_bytes_sent += TEST_MESSAGE_SIZE;
651
652   msg = (struct GNUNET_MessageHeader *) &msgbuf;
653   memset (&msgbuf, 'a', TEST_MESSAGE_SIZE);
654   msg->type = htons (TEST_MESSAGE_TYPE_PONG);
655   msg->size = htons (TEST_MESSAGE_SIZE);
656   memcpy (buf, msg, TEST_MESSAGE_SIZE);
657
658   return TEST_MESSAGE_SIZE;
659 }
660
661
662 static int
663 core_handle_ping (void *cls, const struct GNUNET_PeerIdentity *other,
664     const struct GNUNET_MessageHeader *message)
665 {
666   int c_m;
667   struct BenchmarkPeer *me = cls;
668   struct BenchmarkPartner *p = NULL;
669   for (c_m = 0; c_m < num_masters; c_m++)
670   {
671     if (0 == memcmp (other, &me->partners[c_m].dest->id, sizeof (struct GNUNET_PeerIdentity)))
672     {
673       p = &me->partners[c_m];
674       break;
675     }
676   }
677   if (NULL == p)
678   {
679     GNUNET_break (0);
680     return GNUNET_SYSERR;
681   }
682   GNUNET_assert (NULL == p->cth);
683
684   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
685       "Slave [%u]: Received PING from [%u], sending PONG\n",
686       me->no, p->dest->no);
687
688   p->messages_received ++;
689   p->bytes_received += TEST_MESSAGE_SIZE;
690   p->src->total_messages_received ++;
691   p->src->total_bytes_received += TEST_MESSAGE_SIZE;
692
693   p->cth = GNUNET_CORE_notify_transmit_ready (me->ch, GNUNET_NO, 0,
694       GNUNET_TIME_UNIT_MINUTES, &p->dest->id, TEST_MESSAGE_SIZE,
695       &core_send_echo_ready, p);
696   return GNUNET_OK;
697 }
698
699 static int
700 core_handle_pong (void *cls, const struct GNUNET_PeerIdentity *other,
701     const struct GNUNET_MessageHeader *message)
702 {
703   int c_s;
704   struct BenchmarkPeer *me = cls;
705   struct BenchmarkPartner *p = NULL;
706
707   for (c_s = 0; c_s < num_slaves; c_s++)
708   {
709     if (0 == memcmp (other, &me->partners[c_s].dest->id, sizeof (struct GNUNET_PeerIdentity)))
710     {
711       p = &me->partners[c_s];
712       break;
713     }
714   }
715   if (NULL == p)
716   {
717     GNUNET_break (0);
718     return GNUNET_SYSERR;
719   }
720   GNUNET_assert (NULL == p->cth);
721
722   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
723       "Master [%u]: Received PONG from [%u], next message\n",
724       me->no, p->dest->no);
725
726   p->messages_received ++;
727   p->bytes_received += TEST_MESSAGE_SIZE;
728   p->src->total_messages_received ++;
729   p->src->total_bytes_received += TEST_MESSAGE_SIZE;
730
731   p->cth = GNUNET_CORE_notify_transmit_ready (me->ch,
732             GNUNET_NO, 0, GNUNET_TIME_UNIT_MINUTES, &p->dest->id,
733             TEST_MESSAGE_SIZE, &core_send_ready, p);
734
735   return GNUNET_OK;
736 }
737
738 static void *
739 core_connect_adapter (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
740 {
741   struct BenchmarkPeer *peer = cls;
742
743   static const struct GNUNET_CORE_MessageHandler handlers[] = {
744       {&core_handle_ping, TEST_MESSAGE_TYPE_PING, 0 },
745       {&core_handle_pong, TEST_MESSAGE_TYPE_PONG, 0 },
746       { NULL, 0, 0 } };
747
748   peer->ch = GNUNET_CORE_connect (cfg, peer, NULL, core_connect_cb,
749       core_disconnect_cb, NULL, GNUNET_NO, NULL, GNUNET_NO, handlers);
750   if (NULL == peer->ch)
751     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to create core connection \n");
752   return peer->ch;
753 }
754
755
756 static void
757 core_disconnect_adapter (void *cls, void *op_result)
758 {
759   struct BenchmarkPeer *peer = cls;
760
761   GNUNET_CORE_disconnect (peer->ch);
762   peer->ch = NULL;
763 }
764
765
766 static void
767 core_connect_completion_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
768     void *ca_result, const char *emsg)
769 {
770   static int core_done = 0;
771   if ((NULL != emsg) || (NULL == ca_result))
772   {
773     GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Initialization failed, shutdown\n"));
774     GNUNET_break(0);
775     if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
776       GNUNET_SCHEDULER_cancel (shutdown_task);
777     shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL );
778     return;
779   }
780   core_done++;
781
782   if (core_done == num_slaves + num_masters)
783   {
784     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Connected to all CORE services\n");
785     state.connected_CORE_service = GNUNET_YES;
786     GNUNET_SCHEDULER_add_now (&do_connect_peers, NULL );
787   }
788 }
789
790
791 static void
792 do_connect_core (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
793 {
794   int c_s;
795   int c_m;
796   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Connecting to all CORE services\n");
797   for (c_m = 0; c_m < num_masters; c_m++)
798   {
799     mps[c_m].core_op = GNUNET_TESTBED_service_connect (NULL,
800         mps[c_m].peer, "core", core_connect_completion_cb, NULL,
801         &core_connect_adapter, &core_disconnect_adapter, &mps[c_m]);
802   }
803
804   for (c_s = 0; c_s < num_slaves; c_s++)
805   {
806     sps[c_s].core_op = GNUNET_TESTBED_service_connect (NULL,
807         sps[c_s].peer, "core", core_connect_completion_cb, NULL,
808         &core_connect_adapter, &core_disconnect_adapter, &sps[c_s]);
809   }
810 }
811
812 static void
813 ats_performance_info_cb (void *cls, const struct GNUNET_HELLO_Address *address,
814     int address_active, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
815     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
816     const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
817 {
818   struct BenchmarkPeer *p = cls;
819   int c_a;
820   char *peer_id;
821
822   peer_id = GNUNET_strdup (GNUNET_i2s (&p->id));
823   for (c_a = 0; c_a < ats_count; c_a++)
824   {
825     /*GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("%c %03u: %s %s %u\n"),
826      (GNUNET_YES == p->master) ? 'M' : 'S',
827      p->no,
828      GNUNET_i2s (&address->peer),
829      GNUNET_ATS_print_property_type(ntohl(ats[c_a].type)),
830      ntohl(ats[c_a].value));*/
831   }
832 #if 0
833   if ((GNUNET_YES == p->master)
834       && (0 == memcmp (&address->peer, &p->destination->id,
835                        sizeof(struct GNUNET_PeerIdentity))))
836   {
837     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Bandwidth for master %u: %lu %lu\n",
838         p->no, (long unsigned int ) ntohl (bandwidth_in.value__),
839         (long unsigned int ) ntohl (bandwidth_in.value__));
840   }
841
842   store_information (&bp->id, address, address_active, bandwidth_in,
843       bandwidth_out, ats, ats_count);
844 #endif
845   GNUNET_free(peer_id);
846 }
847
848
849 static void *
850 ats_perf_connect_adapter (void *cls,
851     const struct GNUNET_CONFIGURATION_Handle *cfg)
852 {
853   struct BenchmarkPeer *peer = cls;
854
855   peer->ats_perf_handle = GNUNET_ATS_performance_init (cfg, &ats_performance_info_cb,
856       peer);
857   if (NULL == peer->ats_perf_handle)
858     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
859         "Failed to create ATS performance handle \n");
860   return peer->ats_perf_handle;
861 }
862
863
864 static void
865 ats_perf_disconnect_adapter (void *cls, void *op_result)
866 {
867   struct BenchmarkPeer *peer = cls;
868
869   GNUNET_ATS_performance_done (peer->ats_perf_handle);
870   peer->ats_perf_handle = NULL;
871 }
872
873 static void
874 ats_connect_completion_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
875     void *ca_result, const char *emsg)
876 {
877   static int op_done = 0;
878
879   if ((NULL != emsg) || (NULL == ca_result))
880   {
881     GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Initialization failed, shutdown\n"));
882     GNUNET_break(0);
883     if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
884       GNUNET_SCHEDULER_cancel (shutdown_task);
885     shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL );
886     return;
887   }
888   op_done++;
889   if (op_done == (num_masters+ num_slaves))
890   {
891     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Connected to all ATS services\n");
892     state.connected_ATS_service = GNUNET_YES;
893     GNUNET_SCHEDULER_add_now (&do_connect_core, NULL );
894   }
895 }
896
897
898 static void
899 do_connect_ats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
900 {
901   int c_m;
902   int c_s;
903
904   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Connecting to all ATS services\n");
905   for (c_m = 0; c_m < num_masters; c_m++)
906   {
907     mps[c_m].ats_perf_op = GNUNET_TESTBED_service_connect (NULL,
908         mps[c_m].peer, "ats", ats_connect_completion_cb, NULL,
909         &ats_perf_connect_adapter, &ats_perf_disconnect_adapter,
910         &mps[c_m]);
911
912   }
913
914   for (c_s = 0; c_s < num_slaves; c_s++)
915   {
916     sps[c_s].ats_perf_op = GNUNET_TESTBED_service_connect (NULL,
917         sps[c_s].peer, "ats", ats_connect_completion_cb, NULL,
918         &ats_perf_connect_adapter, &ats_perf_disconnect_adapter,
919         &sps[c_s]);
920   }
921
922 }
923
924 static void
925 peerinformation_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op,
926     const struct GNUNET_TESTBED_PeerInformation*pinfo, const char *emsg)
927 {
928   struct BenchmarkPeer *p = cb_cls;
929   static int done = 0;
930
931   GNUNET_assert (pinfo->pit == GNUNET_TESTBED_PIT_IDENTITY);
932
933   p->id = *pinfo->result.id;
934   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "[%c %03u] Peers %s\n",
935       (p->master == GNUNET_YES) ? 'M' : 'S', p->no, GNUNET_i2s (&p->id));
936
937   GNUNET_TESTBED_operation_done (op);
938   p->peer_id_op = NULL;
939   done++;
940
941   if (done == num_slaves + num_masters)
942   {
943     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
944         "Retrieved all peer ID, connect to ATS\n");
945     GNUNET_SCHEDULER_add_now (&do_connect_ats, NULL );
946   }
947 }
948
949 /**
950  * Signature of a main function for a testcase.
951  *
952  * @param cls closure
953  * @param num_peers number of peers in 'peers'
954  * @param peers_ handle to peers run in the testbed
955  * @param links_succeeded the number of overlay link connection attempts that
956  *          succeeded
957  * @param links_failed the number of overlay link connection attempts that
958  *          failed
959  */
960 static void
961 main_run (void *cls, struct GNUNET_TESTBED_RunHandle *h,
962     unsigned int num_peers, struct GNUNET_TESTBED_Peer **peers_,
963     unsigned int links_succeeded, unsigned int links_failed)
964 {
965   int c_m;
966   int c_s;
967   GNUNET_assert(NULL == cls);
968   GNUNET_assert(num_masters + num_slaves == num_peers);
969   GNUNET_assert(NULL != peers_);
970
971   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
972       _("Benchmarking solver `%s' on preference `%s' with %u master and %u slave peers\n"),
973       solver, pref_str, num_masters, num_slaves);
974
975   shutdown_task = GNUNET_SCHEDULER_add_delayed (
976       GNUNET_TIME_relative_multiply (TEST_TIMEOUT,
977           num_masters + num_slaves), &do_shutdown, NULL );
978
979   /* Setup master peers */
980   for (c_m = 0; c_m < num_masters; c_m++)
981   {
982     GNUNET_assert(NULL != peers_[c_m]);
983     mps[c_m].peer = peers_[c_m];
984     mps[c_m].no = c_m;
985     mps[c_m].master = GNUNET_YES;
986     mps[c_m].partners = GNUNET_malloc (num_slaves * sizeof (struct BenchmarkPeer));
987     mps[c_m].peer_id_op = GNUNET_TESTBED_peer_get_information (
988             mps[c_m].peer, GNUNET_TESTBED_PIT_IDENTITY,
989             &peerinformation_cb,
990             &mps[c_m]);
991   }
992
993   /* Setup slave peers */
994   for (c_s = 0; c_s < num_slaves; c_s++)
995   {
996     GNUNET_assert(NULL != peers_[c_s + num_masters]);
997     sps[c_s].peer = peers_[c_s + num_masters];
998     sps[c_s].no = c_s + num_masters;
999     sps[c_s].master = GNUNET_NO;
1000     sps[c_s].partners = GNUNET_malloc (num_masters * sizeof (struct BenchmarkPeer));
1001     sps[c_s].peer_id_op = GNUNET_TESTBED_peer_get_information (
1002             sps[c_s].peer, GNUNET_TESTBED_PIT_IDENTITY,
1003             &peerinformation_cb,
1004             &sps[c_s]);
1005   }
1006 }
1007
1008 int
1009 main (int argc, char *argv[])
1010 {
1011   char *tmp;
1012   char *tmp_sep;
1013   char *test_name;
1014   char *conf_name;
1015   char *dotexe;
1016   char *prefs[GNUNET_ATS_PreferenceCount] = GNUNET_ATS_PreferenceTypeString;
1017   int c;
1018
1019   result = 0;
1020
1021   /* figure out testname */
1022   tmp = strstr (argv[0], TESTNAME_PREFIX);
1023   if (NULL == tmp)
1024   {
1025         fprintf (stderr, "Unable to parse test name `%s'\n", argv[0]);
1026         return GNUNET_SYSERR;
1027   }
1028   tmp += strlen(TESTNAME_PREFIX);
1029   solver = GNUNET_strdup (tmp);
1030   if (NULL != (dotexe = strstr (solver, ".exe")) &&
1031       dotexe[4] == '\0')
1032     dotexe[0] = '\0';
1033   tmp_sep = strchr (solver, '_');
1034   if (NULL == tmp_sep)
1035   {
1036         fprintf (stderr, "Unable to parse test name `%s'\n", argv[0]);
1037         GNUNET_free (solver);
1038         return GNUNET_SYSERR;
1039   }
1040   tmp_sep[0] = '\0';
1041   pref_str = GNUNET_strdup(tmp_sep + 1);
1042
1043   GNUNET_asprintf(&conf_name, "%s%s_%s.conf", TESTNAME_PREFIX, solver, pref_str);
1044   GNUNET_asprintf(&test_name, "%s%s_%s", TESTNAME_PREFIX, solver, pref_str);
1045
1046   for (c = 0; c <= strlen (pref_str); c++)
1047   {
1048         pref_str[c] = toupper(pref_str[c]);
1049   }
1050   pref_val = -1;
1051         for (c = 1; c < GNUNET_ATS_PreferenceCount; c++)
1052         {
1053                 if (0 == strcmp (pref_str, prefs[c]))
1054                 {
1055                         pref_val = c;
1056                         break;
1057                 }
1058         }
1059         if (-1 == pref_val)
1060         {
1061                 fprintf (stderr, "Unknown preference: `%s'\n", pref_str);
1062           GNUNET_free (solver);
1063           GNUNET_free (pref_str);
1064           return -1;
1065         }
1066
1067   for (c = 0; c < (argc -1); c++)
1068   {
1069         if (0 == strcmp(argv[c], "-s"))
1070                 break;
1071   }
1072   if (c < argc-1)
1073   {
1074     if ((0L != (num_slaves = strtol (argv[c + 1], NULL, 10))) && (num_slaves >= 1))
1075       fprintf (stderr, "Starting %u slave peers\n", num_slaves);
1076     else
1077         num_slaves = DEFAULT_SLAVES_NUM;
1078   }
1079   else
1080         num_slaves = DEFAULT_SLAVES_NUM;
1081
1082   for (c = 0; c < (argc -1); c++)
1083   {
1084         if (0 == strcmp(argv[c], "-m"))
1085                 break;
1086   }
1087   if (c < argc-1)
1088   {
1089     if ((0L != (num_masters = strtol (argv[c + 1], NULL, 10))) && (num_masters >= 2))
1090       fprintf (stderr, "Starting %u master peers\n", num_masters);
1091     else
1092         num_masters = DEFAULT_MASTERS_NUM;
1093   }
1094   else
1095         num_masters = DEFAULT_MASTERS_NUM;
1096
1097   state.connected_ATS_service = GNUNET_NO;
1098   state.connected_CORE_service = GNUNET_NO;
1099   state.connected_PEERS = GNUNET_NO;
1100
1101   mps = GNUNET_malloc (num_masters * sizeof (struct BenchmarkPeer));
1102   sps = GNUNET_malloc (num_slaves * sizeof (struct BenchmarkPeer));
1103
1104   /* Start topology */
1105   uint64_t event_mask;
1106   event_mask = 0;
1107   event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
1108   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
1109   (void) GNUNET_TESTBED_test_run ("perf_ats",
1110                                   conf_name, num_slaves + num_masters,
1111                                   event_mask, &controller_event_cb, NULL,
1112                                   &main_run, NULL);
1113
1114   GNUNET_free (solver);
1115   GNUNET_free (pref_str);
1116   GNUNET_free (conf_name);
1117   GNUNET_free (test_name);
1118   GNUNET_free (mps);
1119   GNUNET_free (sps);
1120
1121   return result;
1122 }
1123
1124 /* end of file perf_ats.c */