2 This file is part of GNUnet.
3 (C) 2010,2011 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_solver.c
22 * @brief generic performance test for ATS solvers
23 * @author Christian Grothoff
24 * @author Matthias Wachs
27 #include "gnunet_util_lib.h"
28 #include "gnunet_statistics_service.h"
29 #include "gnunet-service-ats_addresses.h"
30 #include "gnunet-service-ats_normalization.h"
31 #include "gnunet_ats_service.h"
32 #include "gnunet_ats_plugin.h"
33 #include "test_ats_api_common.h"
35 #define DEFAULT_PEERS_START 10
36 #define DEFAULT_PEERS_END 10
37 #define DEFAULT_ADDRESSES 10
38 #define DEFAULT_ATS_COUNT 2
41 * Handle for ATS address component
48 struct PerfPeer *peers;
58 struct GNUNET_STATISTICS_Handle *stat;
61 * A multihashmap to store all addresses
63 struct GNUNET_CONTAINER_MultiPeerMap *addresses;
68 struct GNUNET_ATS_PluginEnvironment env;
74 struct Result *current_result;
80 * Solver description as string
85 * Configured ATS solver
90 * #peers to start benchmarking with
95 * #peers to end benchmarking with
100 * #addresses to benchmarking with
105 * Percentage of peers to update
107 int opt_update_percent;
110 * Number of peers to update
112 int opt_update_quantity;
115 * Is a bulk operation running?
120 * Is a bulk operation running?
122 int expecting_solution;
133 struct GNUNET_TIME_Relative d_setup;
134 struct GNUNET_TIME_Relative d_lp;
135 struct GNUNET_TIME_Relative d_mlp;
136 struct GNUNET_TIME_Relative d_total;
138 struct GNUNET_TIME_Absolute s_setup;
139 struct GNUNET_TIME_Absolute s_lp;
140 struct GNUNET_TIME_Absolute s_mlp;
141 struct GNUNET_TIME_Absolute s_total;
143 struct GNUNET_TIME_Absolute e_setup;
144 struct GNUNET_TIME_Absolute e_lp;
145 struct GNUNET_TIME_Absolute e_mlp;
146 struct GNUNET_TIME_Absolute e_total;
151 struct GNUNET_PeerIdentity id;
153 struct ATS_Address *head;
154 struct ATS_Address *tail;
157 static struct PerfHandle ph;
168 //static struct GNUNET_ATS_Information ats[2];
176 GNUNET_STATISTICS_destroy (ph.stat, GNUNET_NO);
180 if (NULL != addresses)
182 GNUNET_CONTAINER_multihashmap_iterate (addresses, &addr_it, NULL);
183 GNUNET_CONTAINER_multihashmap_destroy (addresses);
186 if (NULL != ph.peers)
188 GNUNET_free(ph.peers);
191 GAS_normalization_stop ();
197 perf_create_peer (int cp)
200 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
201 &ph.peers[cp].id, sizeof (struct GNUNET_PeerIdentity));
202 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Creating peer #%u: %s \n", cp,
203 GNUNET_i2s (&ph.peers[cp].id));
209 perf_update_address (struct ATS_Address *cur)
214 r_type = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2);
218 r_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100);
219 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
220 "Updating peer `%s' address %p type %s val %u\n",
221 GNUNET_i2s (&cur->peer), cur, "GNUNET_ATS_QUALITY_NET_DELAY", r_val);
222 ph.env.sf.s_address_update_property (ph.solver, cur,
223 GNUNET_ATS_QUALITY_NET_DELAY,
224 r_val, (double) (100 + r_val / 100));
227 r_val = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 10);
229 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
230 "Updating peer `%s' address %p type %s val %u\n",
231 GNUNET_i2s (&cur->peer), cur, "GNUNET_ATS_QUALITY_NET_DISTANCE", r_val);
232 ph.env.sf.s_address_update_property (ph.solver, cur,
233 GNUNET_ATS_QUALITY_NET_DISTANCE,
234 r_val, (double) (100 + r_val) / 100);
239 ph.env.sf.s_address_update_inuse (ph.solver, cur, GNUNET_YES);
245 bandwidth_changed_cb (void *cls, struct ATS_Address *address)
247 if (0 == ntohl(address->assigned_bw_out.value__) &&
248 0 == ntohl(address->assigned_bw_in.value__))
251 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
252 "Bandwidth changed addresses %s %p to %llu Bps out / %llu Bps in\n",
253 GNUNET_i2s (&address->peer),
255 ntohl(address->assigned_bw_out.value__),
256 ntohl(address->assigned_bw_in.value__));
257 if (GNUNET_YES == ph.bulk_running)
263 get_preferences_cb (void *cls, const struct GNUNET_PeerIdentity *id)
265 return GAS_normalization_get_preferences (id);
270 get_property_cb (void *cls, const struct ATS_Address *address)
272 return GAS_normalization_get_properties ((struct ATS_Address *) address);
276 normalized_property_changed_cb (void *cls, struct ATS_Address *peer,
277 uint32_t type, double prop_rel)
283 perf_address_initial_update (void *solver,
284 struct GNUNET_CONTAINER_MultiPeerMap * addresses,
285 struct ATS_Address *address)
287 ph.env.sf.s_address_update_property (solver, address, GNUNET_ATS_QUALITY_NET_DELAY,
289 (double) (100 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100))
292 ph.env.sf.s_address_update_property (solver, address,
293 GNUNET_ATS_QUALITY_NET_DISTANCE, 10,
294 (double) (100 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 100))
299 perf_update_all_addresses (unsigned int cp, unsigned int ca, unsigned int up_q)
301 struct ATS_Address *cur;
307 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
308 "Updating addresses %u addresses per peer \n", up_q);
311 for (c_peer = 0; c_peer < cp; c_peer++)
313 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Updating peer `%s'\n",
314 GNUNET_i2s (&ph.peers[c_peer].id));
315 for (c_select = 0; c_select < ca; c_select++)
318 while (c_select < ph.opt_update_quantity)
320 r = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, ca);
329 for (cur = ph.peers[c_peer].head; NULL != cur; cur = cur->next)
332 perf_update_address (cur);
339 static struct ATS_Address *
340 perf_create_address (int cp, int ca)
342 struct ATS_Address *a;
343 a = create_address (&ph.peers[cp].id,
344 "Test 1", "test 1", strlen ("test 1") + 1, 0);
345 GNUNET_CONTAINER_DLL_insert (ph.peers[cp].head, ph.peers[cp].tail, a);
346 GNUNET_CONTAINER_multipeermap_put (ph.addresses, &ph.peers[cp].id, a,
347 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
352 solver_info_cb (void *cls, enum GAS_Solver_Operation op,
353 enum GAS_Solver_Status stat)
360 case GAS_OP_SOLVE_START:
361 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
362 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_START",
363 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
364 if (GNUNET_NO == ph.expecting_solution)
369 if ((GAS_STAT_SUCCESS == stat) && (NULL == ph.current_result))
371 /* Create new result */
372 tmp = GNUNET_malloc (sizeof (struct Result));
373 ph.current_result = tmp;
374 GNUNET_CONTAINER_DLL_insert_tail(ph.head, ph.tail, tmp);
375 ph.current_result->addresses = ph.current_a;
376 ph.current_result->peers = ph.current_p;
377 ph.current_result->s_total = GNUNET_TIME_absolute_get ();
378 ph.current_result->d_total = GNUNET_TIME_relative_get_forever_ ();
379 ph.current_result->d_setup = GNUNET_TIME_relative_get_forever_ ();
380 ph.current_result->d_lp = GNUNET_TIME_relative_get_forever_ ();
381 ph.current_result->d_mlp = GNUNET_TIME_relative_get_forever_ ();
386 case GAS_OP_SOLVE_STOP:
387 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
388 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_STOP",
389 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
391 if (NULL != ph.current_result)
393 /* Finalize result */
394 ph.current_result->e_total = GNUNET_TIME_absolute_get ();
395 ph.current_result->d_total = GNUNET_TIME_absolute_get_difference (
396 ph.current_result->s_total, ph.current_result->e_total);
398 ph.current_result = NULL;
401 case GAS_OP_SOLVE_SETUP_START:
402 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
403 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_START",
404 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
405 if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
410 ph.current_result->s_setup = GNUNET_TIME_absolute_get ();
413 case GAS_OP_SOLVE_SETUP_STOP:
414 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
415 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_STOP",
416 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
418 if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
423 ph.current_result->e_setup = GNUNET_TIME_absolute_get ();
424 ph.current_result->d_setup = GNUNET_TIME_absolute_get_difference (
425 ph.current_result->s_setup, ph.current_result->e_setup);
428 case GAS_OP_SOLVE_LP_START:
429 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
430 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_START",
431 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
433 if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
438 ph.current_result->s_lp = GNUNET_TIME_absolute_get ();
441 case GAS_OP_SOLVE_LP_STOP:
442 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
443 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_STOP",
444 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
445 if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
450 ph.current_result->e_lp = GNUNET_TIME_absolute_get ();
451 ph.current_result->d_lp = GNUNET_TIME_absolute_get_difference (
452 ph.current_result->s_lp, ph.current_result->e_lp);
457 case GAS_OP_SOLVE_MLP_START:
458 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
459 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_START",
460 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
461 if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
466 ph.current_result->s_mlp = GNUNET_TIME_absolute_get ();
469 case GAS_OP_SOLVE_MLP_STOP:
470 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
471 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_STOP",
472 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
473 if ((GNUNET_NO == ph.expecting_solution) || (NULL == ph.current_result))
478 ph.current_result->e_mlp = GNUNET_TIME_absolute_get ();
479 ph.current_result->d_mlp = GNUNET_TIME_absolute_get_difference (
480 ph.current_result->s_mlp, ph.current_result->e_mlp);
494 while (NULL != (cur = next))
498 if (GNUNET_TIME_relative_get_forever_().rel_value_us != cur->d_total.rel_value_us)
500 fprintf (stderr, "Total time to solve for %u peers %u addresses: %llu us\n",
501 cur->peers, cur->addresses, (unsigned long long )cur->d_total.rel_value_us);
503 if (GNUNET_TIME_relative_get_forever_().rel_value_us != cur->d_setup.rel_value_us)
505 fprintf (stderr, "Total time to setup %u peers %u addresses: %llu us\n",
506 cur->peers, cur->addresses, (unsigned long long )cur->d_setup.rel_value_us);
508 if (GNUNET_TIME_relative_get_forever_().rel_value_us != cur->d_lp.rel_value_us)
510 fprintf (stderr, "Total time to solve LP for %u peers %u addresses: %llu us\n",
511 cur->peers, cur->addresses, (unsigned long long )cur->d_mlp.rel_value_us);
513 if (GNUNET_TIME_relative_get_forever_().rel_value_us != cur->d_mlp.rel_value_us)
515 fprintf (stderr, "Total time to solve MLP for %u peers %u addresses: %llu us\n",
516 cur->peers, cur->addresses, (unsigned long long )cur->d_lp.rel_value_us);
519 GNUNET_CONTAINER_DLL_remove (ph.head, ph.tail, cur);
527 struct ATS_Address *cur;
528 struct ATS_Address *next;
531 int count_p = ph.N_peers_end;
532 int count_a = ph.N_address;
533 struct ATS_Address * cur_addr;
536 ph.peers = GNUNET_malloc ((count_p) * sizeof (struct PerfPeer));
538 for (cp = 0; cp < count_p; cp++)
539 perf_create_peer (cp);
540 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
541 "Added %u peers\n", cp);
543 /* Set initial bulk start to not solve */
544 ph.env.sf.s_bulk_start (ph.solver);
545 ph.bulk_running = GNUNET_YES;
547 for (cp = 0; cp < count_p; cp++)
549 for (ca = 0; ca < count_a; ca++)
551 cur_addr = perf_create_address (cp, ca);
553 ph.env.sf.s_add (ph.solver, cur_addr, GNUNET_ATS_NET_LAN);
554 perf_address_initial_update (ph.solver, ph.addresses, cur_addr);
555 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
556 "Adding address for peer %u address %u\n", cp, ca);
558 /* Notify solver about request */
559 ph.env.sf.s_get (ph.solver, &ph.peers[cp].id);
561 if (cp + 1 >= ph.N_peers_start)
563 /* Disable bulk to solve the problem */
564 if (GNUNET_YES == ph.bulk_running)
566 ph.bulk_running = GNUNET_NO;
567 ph.expecting_solution = GNUNET_YES;
568 ph.current_p = cp + 1;
570 ph.env.sf.s_bulk_stop (ph.solver);
577 /* Problem is solved by the solver here due to unlocking */
579 ph.expecting_solution = GNUNET_NO;
580 /* Disable bulk to solve the problem */
581 if (GNUNET_NO == ph.bulk_running)
583 ph.env.sf.s_bulk_start (ph.solver);
584 ph.bulk_running = GNUNET_YES;
587 if ((0 < ph.opt_update_quantity) || (0 < ph.opt_update_percent))
590 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
591 "Updating problem with %u peers and %u addresses\n", cp + 1, ca);
592 //ph.env.sf.s_bulk_start (ph.solver);
593 //update_addresses (cp + 1, ca, ph.opt_update_quantity);
594 //ph.env.sf.s_bulk_stop (ph.solver);
599 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
600 "Done, cleaning up addresses\n");
601 if (GNUNET_NO == ph.bulk_running)
603 ph.env.sf.s_bulk_start (ph.solver);
604 ph.bulk_running = GNUNET_YES;
607 for (cp = 0; cp < count_p; cp++)
609 for (cur = ph.peers[cp].head; cur != NULL ; cur = next)
611 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
612 "Deleting addresses for peer %u\n", cp);
613 GNUNET_CONTAINER_multipeermap_remove (ph.addresses, &ph.peers[cp].id, cur);
614 ph.env.sf.s_del (ph.solver, cur, GNUNET_NO);
616 GNUNET_CONTAINER_DLL_remove(ph.peers[cp].head, ph.peers[cp].tail, cur);
621 GNUNET_free(ph.peers);
628 run (void *cls, char * const *args, const char *cfgfile,
629 const struct GNUNET_CONFIGURATION_Handle *cfg)
631 GNUNET_log_setup ("perf-ats-solver", "WARNING", NULL);
633 char *src_filename = GNUNET_strdup (__FILE__);
634 char *test_filename = cls;
637 unsigned long long quotas_in[GNUNET_ATS_NetworkTypeCount];
638 unsigned long long quotas_out[GNUNET_ATS_NetworkTypeCount];
641 /* Extract test name */
642 if (NULL == (sep = (strstr (src_filename,".c"))))
650 if (NULL != (sep = strstr (test_filename, ".exe")))
653 if (NULL == (solver = strstr (test_filename, src_filename)))
659 solver += strlen (src_filename) +1;
661 if (0 == strcmp(solver, "proportional"))
663 ph.ats_mode = MODE_PROPORTIONAL;
664 ph.ats_string = "proportional";
666 else if (0 == strcmp(solver, "mlp"))
668 ph.ats_mode = MODE_MLP;
669 ph.ats_string = "mlp";
671 else if ((0 == strcmp(solver, "ril")))
673 ph.ats_mode = MODE_RIL;
674 ph.ats_string = "ril";
678 GNUNET_free (src_filename);
683 GNUNET_free (src_filename);
685 /* Calculcate peers */
686 if ((0 == ph.N_peers_start) && (0 == ph.N_peers_end))
688 ph.N_peers_start = DEFAULT_PEERS_START;
689 ph.N_peers_end = DEFAULT_PEERS_END;
691 if (0 == ph.N_address)
692 ph.N_address = DEFAULT_ADDRESSES;
694 if (ph.opt_update_quantity > ph.N_address)
697 _("Trying to update more addresses than we have per peer! (%u vs %u)"),
698 ph.opt_update_quantity, ph.N_address);
702 if (ph.N_peers_start != ph.N_peers_end)
703 fprintf (stderr, "Benchmarking solver `%s' with %u to %u peers and %u addresses\n",
704 ph.ats_string, ph.N_peers_start, ph.N_peers_end, ph.N_address);
706 fprintf (stderr, "Benchmarking solver `%s' with %u peers and %u addresses\n",
707 ph.ats_string, ph.N_peers_end, ph.N_address);
710 if (GNUNET_ATS_NetworkTypeCount != load_quotas (cfg,
711 quotas_out, quotas_in, GNUNET_ATS_NetworkTypeCount))
720 ph.stat = GNUNET_STATISTICS_create ("ats", cfg);
721 ph.env.stats = ph.stat;
722 ph.addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
723 ph.env.addresses = ph.addresses;
724 ph.env.bandwidth_changed_cb = bandwidth_changed_cb;
725 ph.env.get_preferences = &get_preferences_cb;
726 ph.env.get_property = &get_property_cb;
727 ph.env.network_count = GNUNET_ATS_NetworkTypeCount;
728 ph.env.info_cb = &solver_info_cb;
729 ph.env.info_cb_cls = NULL;
731 int networks[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkType;
732 for (c = 0; c < GNUNET_ATS_NetworkTypeCount; c++)
734 ph.env.networks[c] = networks[c];
735 ph.env.out_quota[c] = quotas_out[c];
736 ph.env.in_quota[c] = quotas_in[c];
737 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Loading network quotas: `%s' %llu %llu \n",
738 GNUNET_ATS_print_network_type(ph.env.networks[c]),
742 GAS_normalization_start (NULL, NULL, &normalized_property_changed_cb, NULL );
744 GNUNET_asprintf (&plugin, "libgnunet_plugin_ats_%s", ph.ats_string);
745 GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Initializing solver `%s'\n"), ph.ats_string);
746 if (NULL == (ph.solver = GNUNET_PLUGIN_load (plugin, &ph.env)))
748 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, _("Failed to initialize solver `%s'!\n"), plugin);
757 GNUNET_log(GNUNET_ERROR_TYPE_INFO, _("Unloading solver `%s'\n"), ph.ats_string);
758 GNUNET_PLUGIN_unload (plugin, ph.solver);
759 GNUNET_free (plugin);
764 main (int argc, char *argv[])
766 /* extract command line arguments */
767 ph.opt_update_quantity = 0;
768 ph.opt_update_percent = 0;
769 ph.N_peers_start = 0;
772 ph.ats_string = NULL;
774 static struct GNUNET_GETOPT_CommandLineOption options[] = {
775 { 'a', "addresses", NULL,
776 gettext_noop ("addresses to use"),
777 1, &GNUNET_GETOPT_set_uint, &ph.N_address },
778 { 's', "start", NULL,
779 gettext_noop ("start with peer"),
780 1, &GNUNET_GETOPT_set_uint, &ph.N_peers_start },
782 gettext_noop ("end with peer"),
783 1, &GNUNET_GETOPT_set_uint, &ph.N_peers_end },
784 { 'p', "percentage", NULL,
785 gettext_noop ("update a fix percentage of addresses"),
786 1, &GNUNET_GETOPT_set_uint, &ph.opt_update_percent },
787 { 'q', "quantity", NULL,
788 gettext_noop ("update a fix quantity of addresses"),
789 1, &GNUNET_GETOPT_set_uint, &ph.opt_update_quantity },
790 GNUNET_GETOPT_OPTION_END
793 GNUNET_PROGRAM_run (argc, argv, argv[0], NULL, options, &run, argv[0]);
798 /* end of file perf_ats_solver.c */