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