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