supporting multi master/slave approach
[oweals/gnunet.git] / src / ats / 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 TESTNAME_PREFIX "perf_ats_"
34 #define DEFAULT_SLAVES_NUM 3
35 #define DEFAULT_MASTERS_NUM 1
36
37
38
39 /**
40  * Information we track for a peer in the testbed.
41  */
42 struct BenchmarkPeer
43 {
44   /**
45    * Handle with testbed.
46    */
47   struct GNUNET_TESTBED_Peer *peer;
48
49   int no;
50
51   int master; /* master: GNUNET_YES/NO */
52
53   struct GNUNET_PeerIdentity id;
54
55   struct GNUNET_CORE_Handle *ch;
56
57   /**
58    * Testbed operation to connect to ATS performance service
59    */
60   struct GNUNET_TESTBED_Operation *ats_perf_op;
61
62   /**
63    * Testbed operation to get peer information
64    */
65   struct GNUNET_TESTBED_Operation *info_op;
66
67   /**
68    * Testbed operation to connect peers
69    */
70   struct GNUNET_TESTBED_Operation *connect_op;
71
72   /**
73    * Testbed operation to connect to core
74    */
75   struct GNUNET_TESTBED_Operation *core_op;
76
77   /**
78    * ATS performance handle
79    */
80   struct GNUNET_ATS_PerformanceHandle *p_handle;
81
82   int core_connections;
83 };
84
85
86 static int c_master_peers;
87
88 /**
89  * Array of master peers
90  * Preferences to be set for
91  */
92 static struct BenchmarkPeer *bp_master;
93
94 static int c_slave_peers;
95
96 /**
97  * Array of slave peers
98  * Peer used for measurements
99  */
100 static struct BenchmarkPeer *bp_slaves;
101
102
103 struct BenchmarkState
104 {
105         /* Are we connected to ATS service of all peers: GNUNET_YES/NO */
106         int connected_ATS_service;
107
108         /* Are we connected to CORE service of all peers: GNUNET_YES/NO */
109         int connected_CORE_service;
110
111         /* Are we connected to CORE service of all peers: GNUNET_YES/NO */
112         int connected_PEERS;
113         int connected_CORE;
114
115         int *core_connections;
116 };
117
118 static struct BenchmarkState state;
119
120 /**
121  * Shutdown task
122  */
123 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
124
125 static int result;
126 static char *solver;
127 static char *preference;
128
129
130
131 static void
132 core_connect_completion_cb (void *cls,
133                             struct GNUNET_TESTBED_Operation *op,
134                             void *ca_result,
135                             const char *emsg );
136
137 /**
138  * Shutdown nicely
139  *
140  * @param cls NULL
141  * @param tc the task context
142  */
143 static void
144 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
145 {
146   int c_p;
147   shutdown_task = GNUNET_SCHEDULER_NO_TASK;
148
149   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Benchmarking done\n"));
150
151   for (c_p = 0; c_p < c_master_peers; c_p++)
152   {
153         if (NULL != bp_master[c_p].ats_perf_op)
154         {
155                 GNUNET_TESTBED_operation_done (bp_master[c_p].ats_perf_op);
156                 bp_master[c_p].ats_perf_op = NULL;
157         }
158
159         if (NULL != bp_master[c_p].core_op)
160         {
161                 GNUNET_TESTBED_operation_done (bp_master[c_p].core_op);
162                 bp_master[c_p].core_op = NULL;
163         }
164
165         if (NULL != bp_master[c_p].info_op)
166         {
167                 GNUNET_break (0);
168                 GNUNET_TESTBED_operation_done (bp_master[c_p].info_op);
169                 bp_master[c_p].info_op = NULL;
170         }
171         if (NULL != bp_master[c_p].connect_op)
172         {
173                 GNUNET_break (0);
174                 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Failed to connect peer 0 and %u\n"), c_p);
175                 GNUNET_TESTBED_operation_done (bp_master[c_p].connect_op);
176                 bp_master[c_p].connect_op = NULL;
177         result = 1;
178         }
179   }
180
181   for (c_p = 0; c_p < c_slave_peers; c_p++)
182   {
183         if (NULL != bp_slaves[c_p].ats_perf_op)
184         {
185                 GNUNET_TESTBED_operation_done (bp_slaves[c_p].ats_perf_op);
186                 bp_slaves[c_p].ats_perf_op = NULL;
187         }
188
189         if (NULL != bp_slaves[c_p].core_op)
190         {
191                 GNUNET_TESTBED_operation_done (bp_slaves[c_p].core_op);
192                 bp_slaves[c_p].core_op = NULL;
193         }
194
195         if (NULL != bp_slaves[c_p].info_op)
196         {
197                 GNUNET_break (0);
198                 GNUNET_TESTBED_operation_done (bp_slaves[c_p].info_op);
199                 bp_slaves[c_p].info_op = NULL;
200         }
201         if (NULL != bp_slaves[c_p].connect_op)
202         {
203                 GNUNET_break (0);
204                 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Failed to connect peer 0 and %u\n"), c_p);
205                 GNUNET_TESTBED_operation_done (bp_slaves[c_p].connect_op);
206         bp_slaves[c_p].connect_op = NULL;
207         result = 1;
208         }
209   }
210
211         GNUNET_SCHEDULER_shutdown();
212 }
213
214
215 static void
216 ats_performance_info_cb (void *cls,
217                          const struct GNUNET_HELLO_Address *address,
218                          int address_active,
219                          struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
220                          struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
221                          const struct GNUNET_ATS_Information *ats,
222                          uint32_t ats_count)
223 {
224         struct BenchmarkPeer *p = cls;
225         int c_a;
226         char *peer_id;
227         if (p != &bp_slaves[0])
228                 return; /* print only master peer */
229         peer_id = GNUNET_strdup (GNUNET_i2s (&p->id));
230         for (c_a = 0; c_a < ats_count; c_a++)
231         {
232                 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("%s: %s %s %u\n"), 
233                             peer_id, 
234                             GNUNET_i2s (&address->peer),
235                             GNUNET_ATS_print_property_type(ntohl(ats[c_a].type)),
236                             ntohl(ats[c_a].value));
237         }
238         GNUNET_free (peer_id);
239 }
240
241
242 static void 
243 do_benchmark ()
244 {
245         if ((state.connected_ATS_service == GNUNET_NO) ||
246                         (state.connected_CORE_service == GNUNET_NO) ||
247                         (state.connected_PEERS == GNUNET_NO) ||
248                         (state.connected_CORE == GNUNET_NO))
249                 return;
250
251         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
252                         _("BENCHMARKING\n"));
253 }
254
255
256 static void 
257 connect_completion_callback (void *cls,
258                              struct GNUNET_TESTBED_Operation *op,
259                              const char *emsg)
260 {
261         static int connections = 0;
262         struct BenchmarkPeer *p = cls;
263
264         if (NULL == emsg)
265         {
266                 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
267                                 _("Connected peer 0 with peer %p\n"), p->peer);
268         }
269         else
270         {
271                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
272                                 _("Failed to connect peer 0 with peer %p\n"), p->peer);
273                 GNUNET_break (0);
274                 if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
275                         GNUNET_SCHEDULER_cancel(shutdown_task);
276                 shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL);
277         }
278         GNUNET_TESTBED_operation_done(op);
279         p->connect_op = NULL;
280         connections++;
281         if (connections == c_slave_peers -1)
282         {
283                 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
284                                 "All peers connected, start benchmarking \n");
285                  GNUNET_SCHEDULER_add_now (&do_benchmark, NULL);
286                  state.connected_PEERS = GNUNET_YES;
287         }
288 }
289
290
291 static void
292 do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
293 {
294         int c_p;
295
296         if ((state.connected_ATS_service == GNUNET_NO) ||
297                         (state.connected_CORE_service == GNUNET_NO))
298                 return;
299
300         for (c_p = 1; c_p < c_slave_peers; c_p ++)
301         {
302                 bp_slaves[c_p].connect_op = GNUNET_TESTBED_overlay_connect( NULL,
303                                 &connect_completion_callback, &bp_slaves[c_p], bp_slaves[0].peer, bp_slaves[c_p].peer);
304                 if (NULL == bp_slaves[c_p].connect_op)
305                 {
306                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
307                                         _("Could not connect peer 0 and peer %u\n"), c_p);
308                         GNUNET_break (0);
309                         if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
310                                 GNUNET_SCHEDULER_cancel(shutdown_task);
311                         shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL);
312                         return;
313                 }
314         }
315 }
316
317
318 /**
319  * Controller event callback
320  *
321  * @param cls NULL
322  * @param event the controller event
323  */
324 static void
325 controller_event_cb (void *cls,
326                      const struct GNUNET_TESTBED_EventInformation *event)
327 {
328         //struct BenchmarkPeer *p = cls;
329   switch (event->type)
330   {
331   case GNUNET_TESTBED_ET_CONNECT:
332     break;
333   case GNUNET_TESTBED_ET_OPERATION_FINISHED:
334     break;
335   default:
336     GNUNET_break (0);
337     result = 2;
338     GNUNET_SCHEDULER_cancel (shutdown_task);
339     shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
340   }
341 }
342
343
344 /**
345  * Called to open a connection to the peer's ATS performance
346  *
347  * @param cls peer context
348  * @param cfg configuration of the peer to connect to; will be available until
349  *          GNUNET_TESTBED_operation_done() is called on the operation returned
350  *          from GNUNET_TESTBED_service_connect()
351  * @return service handle to return in 'op_result', NULL on error
352  */
353 static void *
354 ats_perf_connect_adapter (void *cls,
355                       const struct GNUNET_CONFIGURATION_Handle *cfg)
356 {
357   struct BenchmarkPeer *peer = cls;
358
359   peer->p_handle = GNUNET_ATS_performance_init (cfg, &ats_performance_info_cb, peer);
360   if (NULL == peer->p_handle)
361     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to create ATS performance handle \n");
362   return peer->p_handle;
363 }
364
365
366 /**
367  * Called to disconnect from peer's statistics service
368  *
369  * @param cls peer context
370  * @param op_result service handle returned from the connect adapter
371  */
372 static void
373 ats_perf_disconnect_adapter (void *cls, void *op_result)
374 {
375   struct BenchmarkPeer *peer = cls;
376
377   GNUNET_ATS_performance_done(peer->p_handle);
378   peer->p_handle = NULL;
379 }
380
381
382 /**
383  * Callback to be called when a service connect operation is completed
384  *
385  * @param cls the callback closure from functions generating an operation
386  * @param op the operation that has been finished
387  * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
388  * @param emsg error message in case the operation has failed; will be NULL if
389  *          operation has executed successfully.
390  */
391 static void 
392 ats_connect_completion_cb (void *cls,
393                            struct GNUNET_TESTBED_Operation *op,
394                            void *ca_result,
395                            const char *emsg )
396 {
397         static int op_done = 0;
398         if ((NULL != emsg) || (NULL == ca_result))
399         {
400                 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
401                                 _("Initialization failed, shutdown\n"));
402                 GNUNET_break (0);
403                 if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
404                         GNUNET_SCHEDULER_cancel(shutdown_task);
405                 shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL);
406                 return;
407         }
408
409         op_done ++;
410         if (op_done ==  c_slave_peers)
411         {
412                 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
413                                 _("Initialization done, connecting peers\n"));
414                 state.connected_ATS_service = GNUNET_YES;
415                 GNUNET_SCHEDULER_add_now (&do_connect, NULL);
416         }
417 }
418
419
420 /**
421  * Method called whenever a given peer connects.
422  *
423  * @param cls closure
424  * @param peer peer identity this notification is about
425  */
426 static void
427 core_connect_cb (void *cls, const struct GNUNET_PeerIdentity * peer)
428 {
429   struct BenchmarkPeer *p = cls;
430   char *id;
431
432   p->core_connections ++;
433   id = GNUNET_strdup (GNUNET_i2s (&p->id));
434   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
435               "%s connected to %s \n",
436               id, GNUNET_i2s (peer));
437   if (p->core_connections == c_slave_peers)
438   {
439     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
440                 "%s connected all peers\n", 
441                 id);
442   }
443   if ((p->core_connections == c_slave_peers) && (p == &bp_slaves[0]))
444   {
445     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
446                 "Master peer %s connected all peers on CORE level\n", id, GNUNET_i2s (peer));
447     state.connected_CORE = GNUNET_YES;
448     GNUNET_SCHEDULER_add_now (&do_benchmark, NULL);
449   }
450   GNUNET_free (id);
451 }
452
453
454 /**
455  * Method called whenever a peer disconnects.
456  *
457  * @param cls closure
458  * @param peer peer identity this notification is about
459  */
460 static void
461 core_disconnect_cb (void *cls, const struct GNUNET_PeerIdentity * peer)
462 {
463   struct BenchmarkPeer *p = cls;
464   char *id;
465
466   id = GNUNET_strdup (GNUNET_i2s (&p->id));
467   GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
468               "%s disconnected from %s \n", id, GNUNET_i2s (peer));
469   GNUNET_free (id);
470 }
471
472
473 /**
474  * Called to open a connection to the peer's ATS performance
475  *
476  * @param cls peer context
477  * @param cfg configuration of the peer to connect to; will be available until
478  *          GNUNET_TESTBED_operation_done() is called on the operation returned
479  *          from GNUNET_TESTBED_service_connect()
480  * @return service handle to return in 'op_result', NULL on error
481  */
482 static void *
483 core_connect_adapter (void *cls,
484                       const struct GNUNET_CONFIGURATION_Handle *cfg)
485 {
486   struct BenchmarkPeer *peer = cls;
487
488   peer->ch = GNUNET_CORE_connect(cfg, peer, NULL,
489                                  core_connect_cb,
490                                  core_disconnect_cb,
491                                  NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
492   if (NULL == peer->ch)
493     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
494                 "Failed to create core connection \n");
495   return peer->ch;
496 }
497
498
499 /**
500  * Callback to be called when a service connect operation is completed
501  *
502  * @param cls the callback closure from functions generating an operation
503  * @param op the operation that has been finished
504  * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
505  * @param emsg error message in case the operation has failed; will be NULL if
506  *          operation has executed successfully.
507  */
508 static void
509 core_connect_completion_cb (void *cls,
510                             struct GNUNET_TESTBED_Operation *op,
511                             void *ca_result,
512                             const char *emsg )
513 {
514         static int core_done = 0;
515         if ((NULL != emsg) || (NULL == ca_result))
516         {
517                 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
518                                 _("Initialization failed, shutdown\n"));
519                 GNUNET_break (0);
520                 if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
521                         GNUNET_SCHEDULER_cancel(shutdown_task);
522                 shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL);
523                 return;
524         }
525         core_done ++;
526         if (core_done == c_slave_peers)
527         {
528                 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
529                                 "Connected to all CORE services\n");
530                 state.connected_CORE_service = GNUNET_YES;
531                 GNUNET_SCHEDULER_add_now (&do_connect, NULL);
532         }
533 }
534
535
536 /**
537  * Called to disconnect from peer's statistics service
538  *
539  * @param cls peer context
540  * @param op_result service handle returned from the connect adapter
541  */
542 static void
543 core_disconnect_adapter (void *cls, void *op_result)
544 {
545   struct BenchmarkPeer *peer = cls;
546
547   GNUNET_CORE_disconnect (peer->ch);
548   peer->ch = NULL;
549 }
550
551
552 /**
553  * Callback to be called when the requested peer information is available
554  *
555  * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
556  * @param op the operation this callback corresponds to
557  * @param pinfo the result; will be NULL if the operation has failed
558  * @param emsg error message if the operation has failed; will be NULL if the
559  *          operation is successfull
560  */
561 static void
562 peerinformation_cb (void *cb_cls,
563                     struct GNUNET_TESTBED_Operation *op,
564                     const struct GNUNET_TESTBED_PeerInformation*pinfo,
565                     const char *emsg)
566 {
567   struct BenchmarkPeer *p = cb_cls;
568
569   if (pinfo->pit == GNUNET_TESTBED_PIT_IDENTITY)
570   {
571     p->id = *pinfo->result.id;
572     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
573                 "[%c %03u] Peers %s\n",
574                 (p->master == GNUNET_YES) ? 'M' : 'S', p->no, GNUNET_i2s (&p->id));
575   }
576   else
577   {
578     GNUNET_assert (0);
579   }
580   GNUNET_TESTBED_operation_done (op);
581   p->info_op = NULL;
582 }
583
584
585 /**
586  * Signature of a main function for a testcase.
587  *
588  * @param cls closure
589  * @param num_peers number of peers in 'peers'
590  * @param peers_ handle to peers run in the testbed
591  * @param links_succeeded the number of overlay link connection attempts that
592  *          succeeded
593  * @param links_failed the number of overlay link connection attempts that
594  *          failed
595  */
596 static void
597 test_main (void *cls, unsigned int num_peers,
598            struct GNUNET_TESTBED_Peer **peers_,
599            unsigned int links_succeeded,
600            unsigned int links_failed)
601 {
602   int c_p;
603
604   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
605               _("Benchmarking solver `%s' on preference `%s' with %u master and %u slave peers\n"),
606               solver, preference, c_master_peers, c_slave_peers);
607
608   shutdown_task = GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &do_shutdown, NULL);
609
610   GNUNET_assert (NULL == cls);
611   GNUNET_assert (c_slave_peers + c_master_peers == num_peers);
612   GNUNET_assert (NULL != peers_);
613
614   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
615               _("Initializing... \n"));
616
617   for (c_p = 0; c_p < c_master_peers; c_p++)
618   {
619     GNUNET_assert (NULL != peers_[c_p]);
620     bp_master[c_p].no = c_p;
621     bp_master[c_p].master = GNUNET_YES;
622     /* Connect to ATS performance service */
623     bp_master[c_p].peer = peers_[c_p];
624     bp_master[c_p].info_op = GNUNET_TESTBED_peer_get_information (bp_master[c_p].peer,
625                                                            GNUNET_TESTBED_PIT_IDENTITY,
626                                                            &peerinformation_cb, &bp_master[c_p]);
627 /*
628     bp_master[c_p].core_op = GNUNET_TESTBED_service_connect (NULL,
629                                                       peers_[c_p], "ats",
630                                                       core_connect_completion_cb, NULL,
631                                                       &core_connect_adapter,
632                                                       &core_disconnect_adapter,
633                                                       &bp_master[c_p]);
634
635     bp_master[c_p].ats_perf_op = GNUNET_TESTBED_service_connect (NULL,
636                                                           peers_[c_p], "ats",
637                                                           ats_connect_completion_cb, NULL,
638                                                           &ats_perf_connect_adapter,
639                                                           &ats_perf_disconnect_adapter,
640                                                           &bp_master[c_p]);
641 */
642   }
643
644   for (c_p = 0; c_p < c_slave_peers; c_p++)
645   {
646     GNUNET_assert (NULL != peers_[c_p + c_master_peers]);
647     bp_slaves[c_p].no = c_p + c_master_peers;
648     bp_slaves[c_p].master = GNUNET_NO;
649     /* Connect to ATS performance service */
650     bp_slaves[c_p].peer = peers_[c_p + c_master_peers];
651     bp_slaves[c_p].info_op = GNUNET_TESTBED_peer_get_information (bp_slaves[c_p].peer,
652                                                            GNUNET_TESTBED_PIT_IDENTITY, 
653                                                            &peerinformation_cb, &bp_slaves[c_p]);
654 /*
655     bp_slaves[c_p].core_op = GNUNET_TESTBED_service_connect (NULL,
656                                                       peers_[c_p], "ats",
657                                                       core_connect_completion_cb, NULL,
658                                                       &core_connect_adapter,
659                                                       &core_disconnect_adapter,
660                                                       &bp_slaves[c_p]);
661
662     bp_slaves[c_p].ats_perf_op = GNUNET_TESTBED_service_connect (NULL,
663                                                           peers_[c_p], "ats",
664                                                           ats_connect_completion_cb, NULL,
665                                                           &ats_perf_connect_adapter,
666                                                           &ats_perf_disconnect_adapter,
667                                                           &bp_slaves[c_p]);
668 */
669   }
670
671 }
672
673
674 int
675 main (int argc, char *argv[])
676 {
677   char *tmp;
678   char *tmp_sep;
679   char *test_name;
680   char *conf_name;
681   char *dotexe;
682   int c;
683
684   result = 0;
685
686   /* figure out testname */
687   tmp = strstr (argv[0], TESTNAME_PREFIX);
688   if (NULL == tmp)
689   {
690         fprintf (stderr, "Unable to parse test name `%s'\n", argv[0]);
691         return GNUNET_SYSERR;
692   }
693   tmp += strlen(TESTNAME_PREFIX);
694   solver = GNUNET_strdup (tmp);
695   if (NULL != (dotexe = strstr (solver, ".exe")) &&
696       dotexe[4] == '\0')
697     dotexe[0] = '\0';
698   tmp_sep = strchr (solver, '_');
699   if (NULL == tmp_sep)
700   {
701         fprintf (stderr, "Unable to parse test name `%s'\n", argv[0]);
702         GNUNET_free (solver);
703         return GNUNET_SYSERR;
704   }
705   tmp_sep[0] = '\0';
706   preference = GNUNET_strdup(tmp_sep + 1);
707
708   GNUNET_asprintf(&conf_name, "%s%s_%s.conf", TESTNAME_PREFIX, solver, preference);
709   GNUNET_asprintf(&test_name, "%s%s_%s", TESTNAME_PREFIX, solver, preference);
710
711   for (c = 0; c < (argc -1); c++)
712   {
713         if (0 == strcmp(argv[c], "-s"))
714                 break;
715   }
716   if (c < argc-1)
717   {
718     if ((0L != (c_slave_peers = strtol (argv[c + 1], NULL, 10))) && (c_slave_peers >= 2))
719       fprintf (stderr, "Starting %u slave peers\n", c_slave_peers);
720     else
721         c_slave_peers = DEFAULT_SLAVES_NUM;
722   }
723   else
724         c_slave_peers = DEFAULT_SLAVES_NUM;
725
726   for (c = 0; c < (argc -1); c++)
727   {
728         if (0 == strcmp(argv[c], "-m"))
729                 break;
730   }
731   if (c < argc-1)
732   {
733     if ((0L != (c_slave_peers = strtol (argv[c + 1], NULL, 10))) && (c_slave_peers >= 2))
734       fprintf (stderr, "Starting %u master peers\n", c_slave_peers);
735     else
736         c_master_peers = DEFAULT_MASTERS_NUM;
737   }
738   else
739         c_master_peers = DEFAULT_MASTERS_NUM;
740
741   bp_slaves = GNUNET_malloc (c_slave_peers * sizeof (struct BenchmarkPeer));
742   bp_master = GNUNET_malloc (c_master_peers * sizeof (struct BenchmarkPeer));
743
744   state.connected_ATS_service = GNUNET_NO;
745   state.connected_CORE_service = GNUNET_NO;
746   state.connected_PEERS = GNUNET_NO;
747
748   /* Start topology */
749   uint64_t event_mask;
750   event_mask = 0;
751   event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
752   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
753   (void) GNUNET_TESTBED_test_run (test_name,
754                                   conf_name, c_slave_peers + c_master_peers,
755                                   event_mask, &controller_event_cb, NULL,
756                                   &test_main, NULL);
757
758   GNUNET_free (solver);
759   GNUNET_free (preference);
760   GNUNET_free (conf_name);
761   GNUNET_free (test_name);
762   GNUNET_free (bp_slaves);
763
764   return result;
765 }
766
767 /* end of file perf_ats.c */