diff options
author | Nathan S. Evans <evans@in.tum.de> | 2011-02-05 16:17:53 +0000 |
---|---|---|
committer | Nathan S. Evans <evans@in.tum.de> | 2011-02-05 16:17:53 +0000 |
commit | 30eaa74c6e9a89373f255f4183d21a4599598035 (patch) | |
tree | 5fc5313837ba3c0a20949c615e7e6949e9ec86ee /src/testing/testing_group.c | |
parent | 0d53baa57a6d03f4e09082b0b835681dec6d71bd (diff) | |
download | gnunet-30eaa74c6e9a89373f255f4183d21a4599598035.tar.gz gnunet-30eaa74c6e9a89373f255f4183d21a4599598035.zip |
vastly reduce cpu overhead when connecting peers
Diffstat (limited to 'src/testing/testing_group.c')
-rw-r--r-- | src/testing/testing_group.c | 101 |
1 files changed, 85 insertions, 16 deletions
diff --git a/src/testing/testing_group.c b/src/testing/testing_group.c index 929cc9128..88408e871 100644 --- a/src/testing/testing_group.c +++ b/src/testing/testing_group.c | |||
@@ -662,6 +662,11 @@ struct GNUNET_TESTING_PeerGroup | |||
662 | unsigned int outstanding_connects; | 662 | unsigned int outstanding_connects; |
663 | 663 | ||
664 | /** | 664 | /** |
665 | * How many connects have already been scheduled? | ||
666 | */ | ||
667 | unsigned int total_connects_scheduled; | ||
668 | |||
669 | /** | ||
665 | * Hostkeys loaded from a file. | 670 | * Hostkeys loaded from a file. |
666 | */ | 671 | */ |
667 | char *hostkey_data; | 672 | char *hostkey_data; |
@@ -685,10 +690,24 @@ struct ConnectTopologyContext | |||
685 | unsigned int remaining_connections; | 690 | unsigned int remaining_connections; |
686 | 691 | ||
687 | /** | 692 | /** |
693 | * How many more connections do we need to schedule? | ||
694 | */ | ||
695 | unsigned int remaining_connects_to_schedule; | ||
696 | |||
697 | /** | ||
688 | * Handle to group of peers. | 698 | * Handle to group of peers. |
689 | */ | 699 | */ |
690 | struct GNUNET_TESTING_PeerGroup *pg; | 700 | struct GNUNET_TESTING_PeerGroup *pg; |
691 | 701 | ||
702 | /** | ||
703 | * How long to try this connection before timing out. | ||
704 | */ | ||
705 | struct GNUNET_TIME_Relative connect_timeout; | ||
706 | |||
707 | /** | ||
708 | * How many times to retry connecting the two peers. | ||
709 | */ | ||
710 | unsigned int connect_attempts; | ||
692 | 711 | ||
693 | /** | 712 | /** |
694 | * Temp value set for each iteration. | 713 | * Temp value set for each iteration. |
@@ -724,16 +743,6 @@ struct ConnectContext | |||
724 | struct ConnectTopologyContext *ct_ctx; | 743 | struct ConnectTopologyContext *ct_ctx; |
725 | 744 | ||
726 | /** | 745 | /** |
727 | * How long to try this connection before timing out. | ||
728 | */ | ||
729 | struct GNUNET_TIME_Relative connect_timeout; | ||
730 | |||
731 | /** | ||
732 | * How many times to retry connecting the two peers. | ||
733 | */ | ||
734 | unsigned int connect_attempts; | ||
735 | |||
736 | /** | ||
737 | * Whether this connection has been accounted for in the schedule_connect call. | 746 | * Whether this connection has been accounted for in the schedule_connect call. |
738 | */ | 747 | */ |
739 | int counted; | 748 | int counted; |
@@ -2815,6 +2824,41 @@ create_and_copy_blacklist_files (struct GNUNET_TESTING_PeerGroup *pg, | |||
2815 | return ret; | 2824 | return ret; |
2816 | } | 2825 | } |
2817 | 2826 | ||
2827 | /* Forward Declaration */ | ||
2828 | static void | ||
2829 | schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
2830 | |||
2831 | /** | ||
2832 | * Choose a random peer's next connection to create, and | ||
2833 | * call schedule_connect to set up the connect task. | ||
2834 | * | ||
2835 | * @param ct_ctx the overall connection context | ||
2836 | */ | ||
2837 | static void preschedule_connect(struct ConnectTopologyContext *ct_ctx) | ||
2838 | { | ||
2839 | struct GNUNET_TESTING_PeerGroup *pg = ct_ctx->pg; | ||
2840 | struct PeerConnection *connection_iter; | ||
2841 | struct ConnectContext *connect_context; | ||
2842 | uint32_t random_peer; | ||
2843 | |||
2844 | if (ct_ctx->remaining_connects_to_schedule == 0) | ||
2845 | return; | ||
2846 | random_peer = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, pg->total); | ||
2847 | while (pg->peers[random_peer].connect_peers_head == NULL) | ||
2848 | random_peer = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, pg->total); | ||
2849 | |||
2850 | connection_iter = pg->peers[random_peer].connect_peers_head; | ||
2851 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Scheduling connection between %d and %d\n", random_peer, connection_iter->index); | ||
2852 | |||
2853 | connect_context = GNUNET_malloc (sizeof (struct ConnectContext)); | ||
2854 | connect_context->first = pg->peers[random_peer].daemon; | ||
2855 | connect_context->second = pg->peers[connection_iter->index].daemon; | ||
2856 | connect_context->ct_ctx = ct_ctx; | ||
2857 | GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context); | ||
2858 | GNUNET_CONTAINER_DLL_remove(pg->peers[random_peer].connect_peers_head, pg->peers[random_peer].connect_peers_tail, connection_iter); | ||
2859 | ct_ctx->remaining_connects_to_schedule--; | ||
2860 | } | ||
2861 | |||
2818 | 2862 | ||
2819 | /** | 2863 | /** |
2820 | * Internal notification of a connection, kept so that we can ensure some connections | 2864 | * Internal notification of a connection, kept so that we can ensure some connections |
@@ -2841,6 +2885,8 @@ internal_connect_notify (void *cls, | |||
2841 | ct_ctx->notify_connections_done (ct_ctx->notify_cls, NULL); | 2885 | ct_ctx->notify_connections_done (ct_ctx->notify_cls, NULL); |
2842 | GNUNET_free (ct_ctx); | 2886 | GNUNET_free (ct_ctx); |
2843 | } | 2887 | } |
2888 | else | ||
2889 | preschedule_connect(ct_ctx); | ||
2844 | 2890 | ||
2845 | if (pg->notify_connection != NULL) | 2891 | if (pg->notify_connection != NULL) |
2846 | pg->notify_connection (pg->notify_connection_cls, first, second, distance, | 2892 | pg->notify_connection (pg->notify_connection_cls, first, second, distance, |
@@ -2884,10 +2930,11 @@ schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
2884 | outstanding_connects); | 2930 | outstanding_connects); |
2885 | #endif | 2931 | #endif |
2886 | pg->outstanding_connects++; | 2932 | pg->outstanding_connects++; |
2933 | pg->total_connects_scheduled++; | ||
2887 | GNUNET_TESTING_daemons_connect (connect_context->first, | 2934 | GNUNET_TESTING_daemons_connect (connect_context->first, |
2888 | connect_context->second, | 2935 | connect_context->second, |
2889 | connect_context->connect_timeout, | 2936 | connect_context->ct_ctx->connect_timeout, |
2890 | connect_context->connect_attempts, | 2937 | connect_context->ct_ctx->connect_attempts, |
2891 | &internal_connect_notify, | 2938 | &internal_connect_notify, |
2892 | connect_context->ct_ctx); | 2939 | connect_context->ct_ctx); |
2893 | GNUNET_free (connect_context); | 2940 | GNUNET_free (connect_context); |
@@ -3017,8 +3064,8 @@ connect_topology (struct GNUNET_TESTING_PeerGroup *pg, | |||
3017 | struct ConnectTopologyContext *ct_ctx; | 3064 | struct ConnectTopologyContext *ct_ctx; |
3018 | #if OLD | 3065 | #if OLD |
3019 | struct PeerConnection *connection_iter; | 3066 | struct PeerConnection *connection_iter; |
3020 | struct ConnectContext *connect_context; | ||
3021 | #else | 3067 | #else |
3068 | struct ConnectContext *connect_context; | ||
3022 | int ret; | 3069 | int ret; |
3023 | #endif | 3070 | #endif |
3024 | 3071 | ||
@@ -3048,9 +3095,32 @@ connect_topology (struct GNUNET_TESTING_PeerGroup *pg, | |||
3048 | GNUNET_free (ct_ctx); | 3095 | GNUNET_free (ct_ctx); |
3049 | return total; | 3096 | return total; |
3050 | } | 3097 | } |
3098 | ct_ctx->connect_timeout = connect_timeout; | ||
3099 | ct_ctx->connect_attempts = connect_attempts; | ||
3051 | ct_ctx->remaining_connections = total; | 3100 | ct_ctx->remaining_connections = total; |
3052 | total = 0; | 3101 | ct_ctx->remaining_connects_to_schedule = total; |
3102 | |||
3053 | 3103 | ||
3104 | /** | ||
3105 | * FIXME: iterating over peer lists in this way means that a single peer will have | ||
3106 | * all of its connections scheduled basically at once. This means a single peer | ||
3107 | * will have a lot of work to do, and may slow down the connection process. If | ||
3108 | * we could choose a connection *randomly* that would work much better. | ||
3109 | * | ||
3110 | * Even using the hashmap method we still choose all of a single peers connections. | ||
3111 | * | ||
3112 | * Will we incur a serious performance penalty iterating over the lists a bunch of | ||
3113 | * times? Probably not compared to the delays in connecting peers. Can't hurt | ||
3114 | * to try anyhow... | ||
3115 | */ | ||
3116 | for (pg_iter = 0; pg_iter < pg->max_outstanding_connections; pg_iter++) | ||
3117 | { | ||
3118 | preschedule_connect(ct_ctx); | ||
3119 | } | ||
3120 | return total; | ||
3121 | |||
3122 | #if SLOW | ||
3123 | total = 0; | ||
3054 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) | 3124 | for (pg_iter = 0; pg_iter < pg->total; pg_iter++) |
3055 | { | 3125 | { |
3056 | #if OLD | 3126 | #if OLD |
@@ -3062,8 +3132,6 @@ connect_topology (struct GNUNET_TESTING_PeerGroup *pg, | |||
3062 | connect_context->first = pg->peers[pg_iter].daemon; | 3132 | connect_context->first = pg->peers[pg_iter].daemon; |
3063 | connect_context->second = pg->peers[connection_iter->index].daemon; | 3133 | connect_context->second = pg->peers[connection_iter->index].daemon; |
3064 | connect_context->ct_ctx = ct_ctx; | 3134 | connect_context->ct_ctx = ct_ctx; |
3065 | connect_context->connect_timeout = connect_timeout; | ||
3066 | connect_context->connect_attempts = connect_attempts; | ||
3067 | GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context); | 3135 | GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context); |
3068 | connection_iter = connection_iter->next; | 3136 | connection_iter = connection_iter->next; |
3069 | total++; | 3137 | total++; |
@@ -3078,6 +3146,7 @@ connect_topology (struct GNUNET_TESTING_PeerGroup *pg, | |||
3078 | #endif | 3146 | #endif |
3079 | } | 3147 | } |
3080 | return total; | 3148 | return total; |
3149 | #endif | ||
3081 | } | 3150 | } |
3082 | 3151 | ||
3083 | 3152 | ||