2 This file is part of GNUnet.
3 (C) 2010-2013 Christian Grothoff (and other contributing authors)
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.
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.
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.
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
27 #include "gnunet_util_lib.h"
28 #include "gnunet_testbed_service.h"
29 #include "gnunet_ats_service.h"
30 #include "gnunet_core_service.h"
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
40 * Information we track for a peer in the testbed.
45 * Handle with testbed.
47 struct GNUNET_TESTBED_Peer *peer;
51 int master; /* master: GNUNET_YES/NO */
53 struct GNUNET_PeerIdentity id;
55 struct GNUNET_CORE_Handle *ch;
58 * Testbed operation to connect to ATS performance service
60 struct GNUNET_TESTBED_Operation *ats_perf_op;
63 * Testbed operation to get peer information
65 struct GNUNET_TESTBED_Operation *info_op;
68 * Testbed operation to connect peers
70 struct GNUNET_TESTBED_Operation *connect_op;
73 * Testbed operation to connect to core
75 struct GNUNET_TESTBED_Operation *core_op;
78 * ATS performance handle
80 struct GNUNET_ATS_PerformanceHandle *p_handle;
86 static int c_master_peers;
89 * Array of master peers
90 * Preferences to be set for
92 static struct BenchmarkPeer *bp_master;
94 static int c_slave_peers;
97 * Array of slave peers
98 * Peer used for measurements
100 static struct BenchmarkPeer *bp_slaves;
103 struct BenchmarkState
105 /* Are we connected to ATS service of all peers: GNUNET_YES/NO */
106 int connected_ATS_service;
108 /* Are we connected to CORE service of all peers: GNUNET_YES/NO */
109 int connected_CORE_service;
111 /* Are we connected to CORE service of all peers: GNUNET_YES/NO */
115 int *core_connections;
118 static struct BenchmarkState state;
123 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
127 static char *preference;
132 core_connect_completion_cb (void *cls,
133 struct GNUNET_TESTBED_Operation *op,
141 * @param tc the task context
144 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
147 shutdown_task = GNUNET_SCHEDULER_NO_TASK;
149 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Benchmarking done\n"));
151 for (c_p = 0; c_p < c_master_peers; c_p++)
153 if (NULL != bp_master[c_p].ats_perf_op)
155 GNUNET_TESTBED_operation_done (bp_master[c_p].ats_perf_op);
156 bp_master[c_p].ats_perf_op = NULL;
159 if (NULL != bp_master[c_p].core_op)
161 GNUNET_TESTBED_operation_done (bp_master[c_p].core_op);
162 bp_master[c_p].core_op = NULL;
165 if (NULL != bp_master[c_p].info_op)
168 GNUNET_TESTBED_operation_done (bp_master[c_p].info_op);
169 bp_master[c_p].info_op = NULL;
171 if (NULL != bp_master[c_p].connect_op)
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;
181 for (c_p = 0; c_p < c_slave_peers; c_p++)
183 if (NULL != bp_slaves[c_p].ats_perf_op)
185 GNUNET_TESTBED_operation_done (bp_slaves[c_p].ats_perf_op);
186 bp_slaves[c_p].ats_perf_op = NULL;
189 if (NULL != bp_slaves[c_p].core_op)
191 GNUNET_TESTBED_operation_done (bp_slaves[c_p].core_op);
192 bp_slaves[c_p].core_op = NULL;
195 if (NULL != bp_slaves[c_p].info_op)
198 GNUNET_TESTBED_operation_done (bp_slaves[c_p].info_op);
199 bp_slaves[c_p].info_op = NULL;
201 if (NULL != bp_slaves[c_p].connect_op)
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;
211 GNUNET_SCHEDULER_shutdown();
216 ats_performance_info_cb (void *cls,
217 const struct GNUNET_HELLO_Address *address,
219 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
220 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
221 const struct GNUNET_ATS_Information *ats,
224 struct BenchmarkPeer *p = cls;
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++)
232 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("%s: %s %s %u\n"),
234 GNUNET_i2s (&address->peer),
235 GNUNET_ATS_print_property_type(ntohl(ats[c_a].type)),
236 ntohl(ats[c_a].value));
238 GNUNET_free (peer_id);
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))
251 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
252 _("BENCHMARKING\n"));
257 connect_completion_callback (void *cls,
258 struct GNUNET_TESTBED_Operation *op,
261 static int connections = 0;
262 struct BenchmarkPeer *p = cls;
266 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
267 _("Connected peer 0 with peer %p\n"), p->peer);
271 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
272 _("Failed to connect peer 0 with peer %p\n"), p->peer);
274 if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
275 GNUNET_SCHEDULER_cancel(shutdown_task);
276 shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL);
278 GNUNET_TESTBED_operation_done(op);
279 p->connect_op = NULL;
281 if (connections == c_slave_peers -1)
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;
292 do_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
296 if ((state.connected_ATS_service == GNUNET_NO) ||
297 (state.connected_CORE_service == GNUNET_NO))
300 for (c_p = 1; c_p < c_slave_peers; c_p ++)
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)
306 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
307 _("Could not connect peer 0 and peer %u\n"), c_p);
309 if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
310 GNUNET_SCHEDULER_cancel(shutdown_task);
311 shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL);
319 * Controller event callback
322 * @param event the controller event
325 controller_event_cb (void *cls,
326 const struct GNUNET_TESTBED_EventInformation *event)
328 //struct BenchmarkPeer *p = cls;
331 case GNUNET_TESTBED_ET_CONNECT:
333 case GNUNET_TESTBED_ET_OPERATION_FINISHED:
338 GNUNET_SCHEDULER_cancel (shutdown_task);
339 shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
345 * Called to open a connection to the peer's ATS performance
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
354 ats_perf_connect_adapter (void *cls,
355 const struct GNUNET_CONFIGURATION_Handle *cfg)
357 struct BenchmarkPeer *peer = cls;
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;
367 * Called to disconnect from peer's statistics service
369 * @param cls peer context
370 * @param op_result service handle returned from the connect adapter
373 ats_perf_disconnect_adapter (void *cls, void *op_result)
375 struct BenchmarkPeer *peer = cls;
377 GNUNET_ATS_performance_done(peer->p_handle);
378 peer->p_handle = NULL;
383 * Callback to be called when a service connect operation is completed
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.
392 ats_connect_completion_cb (void *cls,
393 struct GNUNET_TESTBED_Operation *op,
397 static int op_done = 0;
398 if ((NULL != emsg) || (NULL == ca_result))
400 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
401 _("Initialization failed, shutdown\n"));
403 if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
404 GNUNET_SCHEDULER_cancel(shutdown_task);
405 shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL);
410 if (op_done == c_slave_peers)
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);
421 * Method called whenever a given peer connects.
424 * @param peer peer identity this notification is about
427 core_connect_cb (void *cls, const struct GNUNET_PeerIdentity * peer)
429 struct BenchmarkPeer *p = cls;
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)
439 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
440 "%s connected all peers\n",
443 if ((p->core_connections == c_slave_peers) && (p == &bp_slaves[0]))
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);
455 * Method called whenever a peer disconnects.
458 * @param peer peer identity this notification is about
461 core_disconnect_cb (void *cls, const struct GNUNET_PeerIdentity * peer)
463 struct BenchmarkPeer *p = cls;
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));
474 * Called to open a connection to the peer's ATS performance
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
483 core_connect_adapter (void *cls,
484 const struct GNUNET_CONFIGURATION_Handle *cfg)
486 struct BenchmarkPeer *peer = cls;
488 peer->ch = GNUNET_CORE_connect(cfg, peer, NULL,
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");
500 * Callback to be called when a service connect operation is completed
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.
509 core_connect_completion_cb (void *cls,
510 struct GNUNET_TESTBED_Operation *op,
514 static int core_done = 0;
515 if ((NULL != emsg) || (NULL == ca_result))
517 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
518 _("Initialization failed, shutdown\n"));
520 if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
521 GNUNET_SCHEDULER_cancel(shutdown_task);
522 shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL);
526 if (core_done == c_slave_peers)
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);
537 * Called to disconnect from peer's statistics service
539 * @param cls peer context
540 * @param op_result service handle returned from the connect adapter
543 core_disconnect_adapter (void *cls, void *op_result)
545 struct BenchmarkPeer *peer = cls;
547 GNUNET_CORE_disconnect (peer->ch);
553 * Callback to be called when the requested peer information is available
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
562 peerinformation_cb (void *cb_cls,
563 struct GNUNET_TESTBED_Operation *op,
564 const struct GNUNET_TESTBED_PeerInformation*pinfo,
567 struct BenchmarkPeer *p = cb_cls;
569 if (pinfo->pit == GNUNET_TESTBED_PIT_IDENTITY)
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));
580 GNUNET_TESTBED_operation_done (op);
586 * Signature of a main function for a testcase.
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
593 * @param links_failed the number of overlay link connection attempts that
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)
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);
608 shutdown_task = GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, &do_shutdown, NULL);
610 GNUNET_assert (NULL == cls);
611 GNUNET_assert (c_slave_peers + c_master_peers == num_peers);
612 GNUNET_assert (NULL != peers_);
614 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
615 _("Initializing... \n"));
617 for (c_p = 0; c_p < c_master_peers; c_p++)
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]);
628 bp_master[c_p].core_op = GNUNET_TESTBED_service_connect (NULL,
630 core_connect_completion_cb, NULL,
631 &core_connect_adapter,
632 &core_disconnect_adapter,
635 bp_master[c_p].ats_perf_op = GNUNET_TESTBED_service_connect (NULL,
637 ats_connect_completion_cb, NULL,
638 &ats_perf_connect_adapter,
639 &ats_perf_disconnect_adapter,
644 for (c_p = 0; c_p < c_slave_peers; c_p++)
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]);
655 bp_slaves[c_p].core_op = GNUNET_TESTBED_service_connect (NULL,
657 core_connect_completion_cb, NULL,
658 &core_connect_adapter,
659 &core_disconnect_adapter,
662 bp_slaves[c_p].ats_perf_op = GNUNET_TESTBED_service_connect (NULL,
664 ats_connect_completion_cb, NULL,
665 &ats_perf_connect_adapter,
666 &ats_perf_disconnect_adapter,
675 main (int argc, char *argv[])
686 /* figure out testname */
687 tmp = strstr (argv[0], TESTNAME_PREFIX);
690 fprintf (stderr, "Unable to parse test name `%s'\n", argv[0]);
691 return GNUNET_SYSERR;
693 tmp += strlen(TESTNAME_PREFIX);
694 solver = GNUNET_strdup (tmp);
695 if (NULL != (dotexe = strstr (solver, ".exe")) &&
698 tmp_sep = strchr (solver, '_');
701 fprintf (stderr, "Unable to parse test name `%s'\n", argv[0]);
702 GNUNET_free (solver);
703 return GNUNET_SYSERR;
706 preference = GNUNET_strdup(tmp_sep + 1);
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);
711 for (c = 0; c < (argc -1); c++)
713 if (0 == strcmp(argv[c], "-s"))
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);
721 c_slave_peers = DEFAULT_SLAVES_NUM;
724 c_slave_peers = DEFAULT_SLAVES_NUM;
726 for (c = 0; c < (argc -1); c++)
728 if (0 == strcmp(argv[c], "-m"))
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);
736 c_master_peers = DEFAULT_MASTERS_NUM;
739 c_master_peers = DEFAULT_MASTERS_NUM;
741 bp_slaves = GNUNET_malloc (c_slave_peers * sizeof (struct BenchmarkPeer));
742 bp_master = GNUNET_malloc (c_master_peers * sizeof (struct BenchmarkPeer));
744 state.connected_ATS_service = GNUNET_NO;
745 state.connected_CORE_service = GNUNET_NO;
746 state.connected_PEERS = GNUNET_NO;
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,
758 GNUNET_free (solver);
759 GNUNET_free (preference);
760 GNUNET_free (conf_name);
761 GNUNET_free (test_name);
762 GNUNET_free (bp_slaves);
767 /* end of file perf_ats.c */