initialize partners during creation
[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 peer %u with peer %u\n"), cop->master->no,
530         cop->slave->no);
531   }
532   else
533   {
534     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
535         _("Failed to connect master peer%u with peer %u\n"), cop->master->no,
536         cop->slave->no);
537     GNUNET_break(0);
538     if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
539       GNUNET_SCHEDULER_cancel (shutdown_task);
540     shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL );
541   }
542   GNUNET_TESTBED_operation_done (op);
543   ops++;
544   for (c = 0; c < num_slaves; c++)
545   {
546     if (cop == &cop->master->core_connect_ops[c])
547       cop->master->core_connect_ops[c].connect_op = NULL;
548   }
549   if (ops == num_masters * num_slaves)
550   {
551     state.connected_PEERS = GNUNET_YES;
552     GNUNET_SCHEDULER_add_now (&do_benchmark, NULL );
553   }
554 }
555
556
557 static void
558 do_connect_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
559 {
560   int c_m;
561   int c_s;
562   struct BenchmarkPeer *p;
563
564   if ((state.connected_ATS_service == GNUNET_NO)
565       || (state.connected_CORE_service == GNUNET_NO))
566   {
567     return;
568   }
569
570   GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Connecting peers on CORE level\n"));
571
572   for (c_m = 0; c_m < num_masters; c_m++)
573   {
574     p = &mps[c_m];
575     p->core_connect_ops = GNUNET_malloc (num_slaves *
576         sizeof (struct TestbedConnectOperation));
577
578     for (c_s = 0; c_s < num_slaves; c_s++)
579     {
580       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
581           _("Connecting master peer %u with slave peer %u\n"), p->no,
582           sps[c_s].no);
583       p->core_connect_ops[c_s].master = p;
584       p->core_connect_ops[c_s].slave = &sps[c_s];
585       p->core_connect_ops[c_s].connect_op = GNUNET_TESTBED_overlay_connect (NULL,
586           &connect_completion_callback, &p->core_connect_ops[c_s],
587           sps[c_s].peer, p->peer);
588       if (NULL == p->core_connect_ops[c_s].connect_op)
589       {
590         GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
591             _("Could not connect master peer %u and slave peer %u\n"), p->no,
592             sps[c_s].no);
593         GNUNET_break(0);
594         if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
595           GNUNET_SCHEDULER_cancel (shutdown_task);
596         shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL );
597         return;
598       }
599     }
600   }
601 }
602
603
604 /**
605  * Method called whenever a given peer connects.
606  *
607  * @param cls closure
608  * @param peer peer identity this notification is about
609  */
610 static void
611 core_connect_cb (void *cls, const struct GNUNET_PeerIdentity * peer)
612 {
613   struct BenchmarkPeer *p = cls;
614   struct BenchmarkPeer *t;
615   char *id;
616   int c;
617   int completed;
618
619   t = find_peer (peer);
620   if (NULL == t)
621   {
622     GNUNET_break(0);
623     return;
624   }
625
626   id = GNUNET_strdup (GNUNET_i2s (&p->id));
627   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s %s connected to %s %s\n",
628       (p->master == GNUNET_YES) ? "Master": "Slave", id,
629       (t->master == GNUNET_YES) ? "Master": "Slave", GNUNET_i2s (peer));
630
631   p->core_connections++;
632   if ((GNUNET_YES == p->master) && (GNUNET_NO == t->master)
633       && (GNUNET_NO == state.connected_CORE))
634   {
635     p->mi.core_slave_connections++;
636
637     if (p->mi.core_slave_connections == num_slaves)
638     {
639       GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Master %u connected all slaves\n",
640           p->no);
641     }
642     completed = GNUNET_YES;
643     for (c = 0; c < num_masters; c++)
644     {
645       if (mps[c].mi.core_slave_connections != num_slaves)
646         completed = GNUNET_NO;
647     }
648     if (GNUNET_YES == completed)
649     {
650       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
651           "All master peers connected all slave peers\n", id,
652           GNUNET_i2s (peer));
653       state.connected_CORE = GNUNET_YES;
654       GNUNET_SCHEDULER_add_now (&do_benchmark, NULL );
655     }
656   }
657   GNUNET_free(id);
658 }
659
660
661 static void
662 core_disconnect_cb (void *cls, const struct GNUNET_PeerIdentity * peer)
663 {
664   struct BenchmarkPeer *p = cls;
665   struct BenchmarkPeer *t;
666   char *id;
667
668   t = find_peer (peer);
669   if (NULL == t)
670   {
671     GNUNET_break(0);
672     return;
673   }
674
675   id = GNUNET_strdup (GNUNET_i2s (&p->id));
676   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "%s disconnected from %s \n", id,
677       GNUNET_i2s (peer));
678   GNUNET_assert(p->core_connections > 0);
679   p->core_connections--;
680
681   if ((GNUNET_YES == state.benchmarking)
682       && ((GNUNET_YES == p->master) || (GNUNET_YES == t->master)))
683   {
684     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
685         "%s disconnected from %s while benchmarking \n", id, GNUNET_i2s (peer));
686   }
687   GNUNET_free(id);
688 }
689
690 static size_t
691 core_send_echo_ready (void *cls, size_t size, void *buf)
692 {
693   static char msgbuf[TEST_MESSAGE_SIZE];
694   struct BenchmarkPartner *p = cls;
695   struct GNUNET_MessageHeader *msg;
696
697   p->cth = NULL;
698
699   p->messages_sent ++;
700   p->bytes_sent += TEST_MESSAGE_SIZE;
701   p->me->total_messages_sent ++;
702   p->me->total_bytes_sent += TEST_MESSAGE_SIZE;
703
704   msg = (struct GNUNET_MessageHeader *) &msgbuf;
705   memset (&msgbuf, 'a', TEST_MESSAGE_SIZE);
706   msg->type = htons (TEST_MESSAGE_TYPE_PONG);
707   msg->size = htons (TEST_MESSAGE_SIZE);
708   memcpy (buf, msg, TEST_MESSAGE_SIZE);
709
710   return TEST_MESSAGE_SIZE;
711 }
712
713
714 static int
715 core_handle_ping (void *cls, const struct GNUNET_PeerIdentity *other,
716     const struct GNUNET_MessageHeader *message)
717 {
718   int c_m;
719   struct BenchmarkPeer *me = cls;
720   struct BenchmarkPartner *p = NULL;
721   for (c_m = 0; c_m < num_masters; c_m++)
722   {
723     if (0 == memcmp (other, &me->partners[c_m].dest->id, sizeof (struct GNUNET_PeerIdentity)))
724     {
725       p = &me->partners[c_m];
726       break;
727     }
728   }
729   if (NULL == p)
730   {
731     GNUNET_break (0);
732     return GNUNET_SYSERR;
733   }
734   GNUNET_assert (NULL == p->cth);
735
736   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
737       "Slave [%u]: Received PING from [%u], sending PONG\n",
738       me->no, p->dest->no);
739
740   p->messages_received ++;
741   p->bytes_received += TEST_MESSAGE_SIZE;
742   p->me->total_messages_received ++;
743   p->me->total_bytes_received += TEST_MESSAGE_SIZE;
744
745   p->cth = GNUNET_CORE_notify_transmit_ready (me->ch, GNUNET_NO, 0,
746       GNUNET_TIME_UNIT_MINUTES, &p->dest->id, TEST_MESSAGE_SIZE,
747       &core_send_echo_ready, p);
748   return GNUNET_OK;
749 }
750
751 static int
752 core_handle_pong (void *cls, const struct GNUNET_PeerIdentity *other,
753     const struct GNUNET_MessageHeader *message)
754 {
755   int c_s;
756   struct BenchmarkPeer *me = cls;
757   struct BenchmarkPartner *p = NULL;
758
759   for (c_s = 0; c_s < num_slaves; c_s++)
760   {
761     if (0 == memcmp (other, &me->partners[c_s].dest->id, sizeof (struct GNUNET_PeerIdentity)))
762     {
763       p = &me->partners[c_s];
764       break;
765     }
766   }
767   if (NULL == p)
768   {
769     GNUNET_break (0);
770     return GNUNET_SYSERR;
771   }
772   GNUNET_assert (NULL == p->cth);
773
774   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
775       "Master [%u]: Received PONG from [%u], next message\n",
776       me->no, p->dest->no);
777
778   p->messages_received ++;
779   p->bytes_received += TEST_MESSAGE_SIZE;
780   p->me->total_messages_received ++;
781   p->me->total_bytes_received += TEST_MESSAGE_SIZE;
782
783   p->cth = GNUNET_CORE_notify_transmit_ready (me->ch,
784             GNUNET_NO, 0, GNUNET_TIME_UNIT_MINUTES, &p->dest->id,
785             TEST_MESSAGE_SIZE, &core_send_ready, p);
786
787   return GNUNET_OK;
788 }
789
790 static void *
791 core_connect_adapter (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
792 {
793   struct BenchmarkPeer *peer = cls;
794
795   static const struct GNUNET_CORE_MessageHandler handlers[] = {
796       {&core_handle_ping, TEST_MESSAGE_TYPE_PING, 0 },
797       {&core_handle_pong, TEST_MESSAGE_TYPE_PONG, 0 },
798       { NULL, 0, 0 } };
799
800   peer->ch = GNUNET_CORE_connect (cfg, peer, NULL, core_connect_cb,
801       core_disconnect_cb, NULL, GNUNET_NO, NULL, GNUNET_NO, handlers);
802   if (NULL == peer->ch)
803     GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to create core connection \n");
804   return peer->ch;
805 }
806
807
808 static void
809 core_disconnect_adapter (void *cls, void *op_result)
810 {
811   struct BenchmarkPeer *peer = cls;
812
813   GNUNET_CORE_disconnect (peer->ch);
814   peer->ch = NULL;
815 }
816
817
818 static void
819 core_connect_completion_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
820     void *ca_result, const char *emsg)
821 {
822   static int core_done = 0;
823   if ((NULL != emsg) || (NULL == ca_result))
824   {
825     GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Initialization failed, shutdown\n"));
826     GNUNET_break(0);
827     if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
828       GNUNET_SCHEDULER_cancel (shutdown_task);
829     shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL );
830     return;
831   }
832   core_done++;
833
834   if (core_done == num_slaves + num_masters)
835   {
836     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Connected to all CORE services\n");
837     state.connected_CORE_service = GNUNET_YES;
838     GNUNET_SCHEDULER_add_now (&do_connect_peers, NULL );
839   }
840 }
841
842
843 static void
844 do_connect_core (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
845 {
846   int c_s;
847   int c_m;
848   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Connecting to all CORE services\n");
849   for (c_m = 0; c_m < num_masters; c_m++)
850   {
851     mps[c_m].core_op = GNUNET_TESTBED_service_connect (NULL,
852         mps[c_m].peer, "core", core_connect_completion_cb, NULL,
853         &core_connect_adapter, &core_disconnect_adapter, &mps[c_m]);
854   }
855
856   for (c_s = 0; c_s < num_slaves; c_s++)
857   {
858     sps[c_s].core_op = GNUNET_TESTBED_service_connect (NULL,
859         sps[c_s].peer, "core", core_connect_completion_cb, NULL,
860         &core_connect_adapter, &core_disconnect_adapter, &sps[c_s]);
861   }
862 }
863
864 static void
865 ats_performance_info_cb (void *cls, const struct GNUNET_HELLO_Address *address,
866     int address_active, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
867     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
868     const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
869 {
870   struct BenchmarkPeer *p = cls;
871   int c_a;
872   char *peer_id;
873
874   peer_id = GNUNET_strdup (GNUNET_i2s (&p->id));
875   for (c_a = 0; c_a < ats_count; c_a++)
876   {
877     /*GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("%c %03u: %s %s %u\n"),
878      (GNUNET_YES == p->master) ? 'M' : 'S',
879      p->no,
880      GNUNET_i2s (&address->peer),
881      GNUNET_ATS_print_property_type(ntohl(ats[c_a].type)),
882      ntohl(ats[c_a].value));*/
883   }
884 #if 0
885   if ((GNUNET_YES == p->master)
886       && (0 == memcmp (&address->peer, &p->destination->id,
887                        sizeof(struct GNUNET_PeerIdentity))))
888   {
889     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Bandwidth for master %u: %lu %lu\n",
890         p->no, (long unsigned int ) ntohl (bandwidth_in.value__),
891         (long unsigned int ) ntohl (bandwidth_in.value__));
892   }
893
894   store_information (&bp->id, address, address_active, bandwidth_in,
895       bandwidth_out, ats, ats_count);
896 #endif
897   GNUNET_free(peer_id);
898 }
899
900
901 static void *
902 ats_perf_connect_adapter (void *cls,
903     const struct GNUNET_CONFIGURATION_Handle *cfg)
904 {
905   struct BenchmarkPeer *peer = cls;
906
907   peer->ats_perf_handle = GNUNET_ATS_performance_init (cfg, &ats_performance_info_cb,
908       peer);
909   if (NULL == peer->ats_perf_handle)
910     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
911         "Failed to create ATS performance handle \n");
912   return peer->ats_perf_handle;
913 }
914
915
916 static void
917 ats_perf_disconnect_adapter (void *cls, void *op_result)
918 {
919   struct BenchmarkPeer *peer = cls;
920
921   GNUNET_ATS_performance_done (peer->ats_perf_handle);
922   peer->ats_perf_handle = NULL;
923 }
924
925 static void
926 ats_connect_completion_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
927     void *ca_result, const char *emsg)
928 {
929   static int op_done = 0;
930
931   if ((NULL != emsg) || (NULL == ca_result))
932   {
933     GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Initialization failed, shutdown\n"));
934     GNUNET_break(0);
935     if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
936       GNUNET_SCHEDULER_cancel (shutdown_task);
937     shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL );
938     return;
939   }
940   op_done++;
941   if (op_done == (num_masters+ num_slaves))
942   {
943     GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Connected to all ATS services\n");
944     state.connected_ATS_service = GNUNET_YES;
945     GNUNET_SCHEDULER_add_now (&do_connect_core, NULL );
946   }
947 }
948
949
950 static void
951 do_connect_ats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
952 {
953   int c_m;
954   int c_s;
955
956   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "Connecting to all ATS services\n");
957   for (c_m = 0; c_m < num_masters; c_m++)
958   {
959     mps[c_m].ats_perf_op = GNUNET_TESTBED_service_connect (NULL,
960         mps[c_m].peer, "ats", ats_connect_completion_cb, NULL,
961         &ats_perf_connect_adapter, &ats_perf_disconnect_adapter,
962         &mps[c_m]);
963
964   }
965
966   for (c_s = 0; c_s < num_slaves; c_s++)
967   {
968     sps[c_s].ats_perf_op = GNUNET_TESTBED_service_connect (NULL,
969         sps[c_s].peer, "ats", ats_connect_completion_cb, NULL,
970         &ats_perf_connect_adapter, &ats_perf_disconnect_adapter,
971         &sps[c_s]);
972   }
973
974 }
975
976 static void
977 peerinformation_cb (void *cb_cls, struct GNUNET_TESTBED_Operation *op,
978     const struct GNUNET_TESTBED_PeerInformation*pinfo, const char *emsg)
979 {
980   struct BenchmarkPeer *p = cb_cls;
981   static int done = 0;
982
983   GNUNET_assert (pinfo->pit == GNUNET_TESTBED_PIT_IDENTITY);
984
985   p->id = *pinfo->result.id;
986   GNUNET_log(GNUNET_ERROR_TYPE_INFO, "[%c %03u] Peers %s\n",
987       (p->master == GNUNET_YES) ? 'M' : 'S', p->no, GNUNET_i2s (&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
1172   mps = GNUNET_malloc (num_masters * sizeof (struct BenchmarkPeer));
1173   sps = GNUNET_malloc (num_slaves * sizeof (struct BenchmarkPeer));
1174
1175   /* Start topology */
1176   uint64_t event_mask;
1177   event_mask = 0;
1178   event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
1179   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
1180   (void) GNUNET_TESTBED_test_run ("perf_ats",
1181                                   conf_name, num_slaves + num_masters,
1182                                   event_mask, &controller_event_cb, NULL,
1183                                   &main_run, NULL);
1184
1185   GNUNET_free (solver);
1186   GNUNET_free (pref_str);
1187   GNUNET_free (conf_name);
1188   GNUNET_free (test_name);
1189   GNUNET_free (mps);
1190   GNUNET_free (sps);
1191
1192   return result;
1193 }
1194
1195 /* end of file perf_ats.c */