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