Merge branch 'master' of gnunet.org:gnunet
[oweals/gnunet.git] / src / ats-tests / ats-testing-preferences.c
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2010-2013 GNUnet e.V.
4
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your 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  Affero General Public License for more details.
14
15  You should have received a copy of the GNU Affero General Public License
16  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 /**
19  * @file ats-tests/ats-testing-preferences.c
20  * @brief ats benchmark: preference generator
21  * @author Christian Grothoff
22  * @author Matthias Wachs
23  */
24 #include "platform.h"
25 #include "gnunet_util_lib.h"
26 #include "ats-testing.h"
27
28 static struct PreferenceGenerator *pg_head;
29 static struct PreferenceGenerator *pg_tail;
30
31 extern struct GNUNET_ATS_TEST_Topology *top;
32
33 static double
34 get_preference (struct PreferenceGenerator *pg)
35 {
36   struct GNUNET_TIME_Relative time_delta;
37   double delta_value;
38   double pref_value;
39
40   /* Calculate the current preference value */
41   switch (pg->type) {
42     case GNUNET_ATS_TEST_TG_CONSTANT:
43       pref_value = pg->base_value;
44       break;
45     case GNUNET_ATS_TEST_TG_LINEAR:
46       time_delta = GNUNET_TIME_absolute_get_duration(pg->time_start);
47       /* Calculate point of time in the current period */
48       time_delta.rel_value_us = time_delta.rel_value_us %
49           pg->duration_period.rel_value_us;
50       delta_value = ((double) time_delta.rel_value_us  /
51           pg->duration_period.rel_value_us) * (pg->max_value - pg->base_value);
52       if ((pg->max_value < pg->base_value) &&
53           ((pg->max_value - pg->base_value) > pg->base_value))
54       {
55         /* This will cause an underflow */
56         GNUNET_break (0);
57       }
58       pref_value = pg->base_value + delta_value;
59       break;
60     case GNUNET_ATS_TEST_TG_RANDOM:
61       delta_value =  (double) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
62           10000 * (pg->max_value - pg->base_value)) / 10000;
63       pref_value = pg->base_value + delta_value;
64       break;
65     case GNUNET_ATS_TEST_TG_SINUS:
66       time_delta = GNUNET_TIME_absolute_get_duration(pg->time_start);
67       /* Calculate point of time in the current period */
68       time_delta.rel_value_us = time_delta.rel_value_us %
69           pg->duration_period.rel_value_us;
70       if ((pg->max_value - pg->base_value) > pg->base_value)
71       {
72         /* This will cause an underflow for second half of sinus period,
73          * will be detected in general when experiments are loaded */
74         GNUNET_break (0);
75       }
76       delta_value = (pg->max_value - pg->base_value) *
77           sin ( (2 * M_PI) / ((double) pg->duration_period.rel_value_us) *
78               time_delta.rel_value_us);
79       pref_value = pg->base_value + delta_value;
80       break;
81     default:
82       pref_value = 0.0;
83       break;
84   }
85   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Current preference value is %f\n",
86       pref_value);
87   return pref_value;
88 }
89
90
91 static void
92 set_pref_task (void *cls)
93 {
94   struct BenchmarkPartner *p = cls;
95   double pref_value;
96   p->pg->set_task = NULL;
97
98   pref_value = get_preference (p->pg);
99
100   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
101       "Setting preference for master [%u] and slave [%u] for %s to %f\n",
102       p->me->no, p->dest->no,
103       GNUNET_ATS_print_preference_type (p->pg->kind), pref_value);
104
105   GNUNET_ATS_performance_change_preference(p->me->ats_perf_handle,
106                                            &p->dest->id,
107                                            p->pg->kind,
108                                            pref_value,
109                                            GNUNET_ATS_PREFERENCE_END);
110
111   switch (p->pg->kind) {
112     case GNUNET_ATS_PREFERENCE_BANDWIDTH:
113       p->pref_bandwidth = pref_value;
114       break;
115     case GNUNET_ATS_PREFERENCE_LATENCY:
116       p->pref_delay = pref_value;
117       break;
118     default:
119       break;
120   }
121
122   p->pg->set_task = GNUNET_SCHEDULER_add_delayed (p->pg->frequency,
123       set_pref_task, p);
124
125 }
126
127
128 /**
129  * Generate between the source master and the partner and set preferences with a
130  * value depending on the generator.
131  *
132  * @param src source
133  * @param dest partner
134  * @param type type of preferences to generate
135  * @param base_value traffic base rate to send data with
136  * @param value_rate  traffic maximum rate to send data with
137  * @param period duration of a period of preferences generation (~ 1/frequency)
138  * @param frequency how long to generate preferences
139  * @param kind ATS preference to generate
140  * @return the preference generator
141  */
142 struct PreferenceGenerator *
143 GNUNET_ATS_TEST_generate_preferences_start (struct BenchmarkPeer *src,
144                                             struct BenchmarkPartner *dest,
145                                             enum GeneratorType type,
146                                             unsigned int base_value,
147                                             unsigned int value_rate,
148                                             struct GNUNET_TIME_Relative period,
149                                             struct GNUNET_TIME_Relative frequency,
150                                             enum GNUNET_ATS_PreferenceKind kind)
151 {
152   struct PreferenceGenerator *pg;
153
154   if (NULL != dest->pg)
155   {
156     GNUNET_break (0);
157     return NULL;
158   }
159
160   pg = GNUNET_new (struct PreferenceGenerator);
161   GNUNET_CONTAINER_DLL_insert (pg_head, pg_tail, pg);
162   pg->type = type;
163   pg->src = src;
164   pg->dest = dest;
165   pg->kind = kind;
166   pg->base_value = base_value;
167   pg->max_value = value_rate;
168   pg->duration_period = period;
169   pg->frequency = frequency;
170   pg->time_start = GNUNET_TIME_absolute_get();
171
172   switch (type) {
173     case GNUNET_ATS_TEST_TG_CONSTANT:
174       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
175                   "Setting up constant preference generator master[%u] `%s' and slave [%u] `%s' max %u Bips\n",
176                   dest->me->no, GNUNET_i2s (&dest->me->id),
177                   dest->dest->no, GNUNET_i2s (&dest->dest->id),
178                   base_value);
179       break;
180     case GNUNET_ATS_TEST_TG_LINEAR:
181       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
182                   "Setting up linear preference generator master[%u] `%s' and slave [%u] `%s' min %u Bips max %u Bips\n",
183                   dest->me->no, GNUNET_i2s (&dest->me->id),
184                   dest->dest->no, GNUNET_i2s (&dest->dest->id),
185                   base_value, value_rate);
186       break;
187     case GNUNET_ATS_TEST_TG_SINUS:
188       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
189                   "Setting up sinus preference generator master[%u] `%s' and slave [%u] `%s' baserate %u Bips, amplitude %u Bps\n",
190                   dest->me->no, GNUNET_i2s (&dest->me->id),
191                   dest->dest->no, GNUNET_i2s (&dest->dest->id),
192                   base_value, value_rate);
193       break;
194     case GNUNET_ATS_TEST_TG_RANDOM:
195       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
196                   "Setting up random preference generator master[%u] `%s' and slave [%u] `%s' min %u Bips max %u Bps\n",
197                   dest->me->no, GNUNET_i2s (&dest->me->id),
198                   dest->dest->no, GNUNET_i2s (&dest->dest->id),
199                   base_value, value_rate);
200       break;
201     default:
202       break;
203   }
204
205   dest->pg = pg;
206   pg->set_task = GNUNET_SCHEDULER_add_now (&set_pref_task, dest);
207   return pg;
208 }
209
210
211 void
212 GNUNET_ATS_TEST_generate_preferences_stop (struct PreferenceGenerator *pg)
213 {
214   GNUNET_CONTAINER_DLL_remove (pg_head, pg_tail, pg);
215   pg->dest->pg = NULL;
216
217   if (NULL != pg->set_task)
218   {
219     GNUNET_SCHEDULER_cancel (pg->set_task);
220     pg->set_task = NULL;
221   }
222
223   GNUNET_free (pg);
224 }
225
226
227 /**
228  * Stop all preferences generators
229  */
230 void
231 GNUNET_ATS_TEST_generate_preferences_stop_all ()
232 {
233   struct PreferenceGenerator *cur;
234   struct PreferenceGenerator *next;
235   next = pg_head;
236   for (cur = next; NULL != cur; cur = next)
237   {
238       next = cur->next;
239       GNUNET_ATS_TEST_generate_preferences_stop(cur);
240   }
241 }
242
243 /* end of file ats-testing-preferences.c */