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