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