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