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