-Merge branch 'master' of ssh://gnunet.org/gnunet into gsoc2018/rest_api
[oweals/gnunet.git] / src / ats-tests / ats-testing-traffic.c
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2010-2013, 2016 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-traffic.c
20  * @brief ats benchmark: traffic 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 TrafficGenerator *tg_head;
29 static struct TrafficGenerator *tg_tail;
30
31 extern struct GNUNET_ATS_TEST_Topology *top;
32
33 static struct GNUNET_TIME_Relative
34 get_delay (struct TrafficGenerator *tg)
35 {
36   struct GNUNET_TIME_Relative delay;
37   struct GNUNET_TIME_Relative time_delta;
38   long long int cur_rate;
39   long long int delta_rate;
40
41   delay.rel_value_us = 0;
42
43   /* Calculate the current transmission rate based on the type of traffic */
44   switch (tg->type) {
45     case GNUNET_ATS_TEST_TG_CONSTANT:
46       if (UINT32_MAX == tg->base_rate)
47         return GNUNET_TIME_UNIT_ZERO;
48       cur_rate = tg->base_rate;
49       break;
50     case GNUNET_ATS_TEST_TG_LINEAR:
51       time_delta = GNUNET_TIME_absolute_get_duration(tg->time_start);
52       /* Calculate point of time in the current period */
53       time_delta.rel_value_us = time_delta.rel_value_us % tg->duration_period.rel_value_us;
54       delta_rate = ((double) time_delta.rel_value_us  / tg->duration_period.rel_value_us) *
55           (tg->max_rate - tg->base_rate);
56       if ((tg->max_rate < tg->base_rate) && ((tg->max_rate - tg->base_rate) > tg->base_rate))
57       {
58         /* This will cause an underflow */
59         GNUNET_break (0);
60       }
61       cur_rate = tg->base_rate + delta_rate;
62       break;
63     case GNUNET_ATS_TEST_TG_RANDOM:
64       cur_rate = tg->base_rate + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
65           tg->max_rate - tg->base_rate);
66       break;
67     case GNUNET_ATS_TEST_TG_SINUS:
68       time_delta = GNUNET_TIME_absolute_get_duration(tg->time_start);
69       /* Calculate point of time in the current period */
70       time_delta.rel_value_us = time_delta.rel_value_us % tg->duration_period.rel_value_us;
71       if ((tg->max_rate - tg->base_rate) > tg->base_rate)
72       {
73         /* This will cause an underflow for second half of sinus period,
74          * will be detected in general when experiments are loaded */
75         GNUNET_break (0);
76       }
77       delta_rate = (tg->max_rate - tg->base_rate) *
78           sin ( (2 * M_PI) / ((double) tg->duration_period.rel_value_us) * time_delta.rel_value_us);
79       cur_rate = tg->base_rate + delta_rate;
80       break;
81     default:
82       return delay;
83       break;
84   }
85
86   if (cur_rate < 0)
87   {
88     cur_rate = 1;
89   }
90   /* Calculate the delay for the next message based on the current delay  */
91   delay.rel_value_us =  GNUNET_TIME_UNIT_SECONDS.rel_value_us * TEST_MESSAGE_SIZE / cur_rate;
92
93   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
94               "Current rate is %lld, calculated delay is %llu\n",
95               cur_rate,
96               (unsigned long long) delay.rel_value_us);
97   return delay;
98 }
99
100
101 static void
102 update_ping_data (void *cls)
103 {
104   struct BenchmarkPartner *p = cls;
105   struct GNUNET_TIME_Relative delay;
106
107   p->messages_sent++;
108   p->bytes_sent += TEST_MESSAGE_SIZE;
109   p->me->total_messages_sent++;
110   p->me->total_bytes_sent += TEST_MESSAGE_SIZE;
111
112   if (NULL == p->tg)
113   {
114     GNUNET_break (0);
115     return;
116   }
117   delay = get_delay (p->tg);
118   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
119               "Delay for next transmission %s\n",
120               GNUNET_STRINGS_relative_time_to_string (delay,
121                                                       GNUNET_YES));
122   p->tg->next_ping_transmission
123     = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get(),
124                                 delay);
125 }
126
127
128 static void
129 comm_schedule_send (void *cls)
130 {
131   struct BenchmarkPartner *p = cls;
132   struct TestMessage *msg;
133   struct GNUNET_MQ_Envelope *env;
134
135   p->tg->send_task = NULL;
136   p->last_message_sent = GNUNET_TIME_absolute_get();
137   env = GNUNET_MQ_msg (msg,
138                        TEST_MESSAGE_TYPE_PING);
139   memset (msg->padding,
140           'a',
141           sizeof (msg->padding));
142   GNUNET_MQ_notify_sent (env,
143                          &update_ping_data,
144                          p);
145   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
146               "Master [%u]: Sending PING to [%u]\n",
147               p->me->no,
148               p->dest->no);
149   GNUNET_MQ_send (p->mq,
150                   env);
151 }
152
153
154 static void
155 update_pong_data (void *cls)
156 {
157   struct BenchmarkPartner *p = cls;
158
159   p->messages_sent++;
160   p->bytes_sent += TEST_MESSAGE_SIZE;
161   p->me->total_messages_sent++;
162   p->me->total_bytes_sent += TEST_MESSAGE_SIZE;
163 }
164
165
166 void
167 GNUNET_ATS_TEST_traffic_handle_ping (struct BenchmarkPartner *p)
168 {
169   struct TestMessage *msg;
170   struct GNUNET_MQ_Envelope *env;
171
172   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
173               "Slave [%u]: Received PING from [%u], sending PONG\n",
174               p->me->no,
175               p->dest->no);
176   p->messages_received++;
177   p->bytes_received += TEST_MESSAGE_SIZE;
178   p->me->total_messages_received++;
179   p->me->total_bytes_received += TEST_MESSAGE_SIZE;
180
181   
182   env = GNUNET_MQ_msg (msg,
183                        TEST_MESSAGE_TYPE_PING);
184   memset (msg->padding,
185           'a',
186           sizeof (msg->padding));
187   GNUNET_MQ_notify_sent (env,
188                          &update_pong_data,
189                          p);
190   GNUNET_MQ_send (p->mq,
191                   env);
192 }
193
194
195 void
196 GNUNET_ATS_TEST_traffic_handle_pong (struct BenchmarkPartner *p)
197 {
198   struct GNUNET_TIME_Relative left;
199   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
200               "Master [%u]: Received PONG from [%u], next message\n",
201               p->me->no,
202               p->dest->no);
203
204   p->messages_received++;
205   p->bytes_received += TEST_MESSAGE_SIZE;
206   p->me->total_messages_received++;
207   p->me->total_bytes_received += TEST_MESSAGE_SIZE;
208   p->total_app_rtt += GNUNET_TIME_absolute_get_difference(p->last_message_sent,
209       GNUNET_TIME_absolute_get()).rel_value_us;
210
211   /* Schedule next send event */
212   if (NULL == p->tg)
213     return;
214
215   left = GNUNET_TIME_absolute_get_remaining(p->tg->next_ping_transmission);
216   if (UINT32_MAX == p->tg->base_rate)
217   {
218     p->tg->send_task = GNUNET_SCHEDULER_add_now (&comm_schedule_send, p);
219   }
220   else if (0 == left.rel_value_us)
221   {
222     p->tg->send_task = GNUNET_SCHEDULER_add_now (&comm_schedule_send, p);
223   }
224   else
225   {
226     /* Enforce minimum transmission rate 1 msg / sec */
227     if (GNUNET_TIME_UNIT_SECONDS.rel_value_us == (left = GNUNET_TIME_relative_min (left, GNUNET_TIME_UNIT_SECONDS)).rel_value_us)
228       GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
229           "Enforcing minimum send rate between master [%u] and slave [%u]\n",
230           p->me->no, p->dest->no);
231     p->tg->send_task = GNUNET_SCHEDULER_add_delayed (left,
232         &comm_schedule_send, p);
233   }
234 }
235
236
237 /**
238  * Generate between the source master and the partner and send traffic with a
239  * maximum rate.
240  *
241  * @param src traffic source
242  * @param dest traffic partner
243  * @param type type of traffic to generate
244  * @param base_rate traffic base rate to send data with
245  * @param max_rate  traffic maximum rate to send data with
246  * @param period duration of a period of traffic generation (~ 1/frequency)
247  * @param duration how long to generate traffic
248  * @return the traffic generator
249  */
250 struct TrafficGenerator *
251 GNUNET_ATS_TEST_generate_traffic_start (struct BenchmarkPeer *src,
252                                         struct BenchmarkPartner *dest,
253                                         enum GeneratorType type,
254                                         unsigned int base_rate,
255                                         unsigned int max_rate,
256                                         struct GNUNET_TIME_Relative period,
257                                         struct GNUNET_TIME_Relative duration)
258 {
259   struct TrafficGenerator *tg;
260
261   if (NULL != dest->tg)
262   {
263     GNUNET_break (0);
264     return NULL;
265   }
266
267   tg = GNUNET_new (struct TrafficGenerator);
268   GNUNET_CONTAINER_DLL_insert (tg_head,
269                                tg_tail,
270                                tg);
271   tg->type = type;
272   tg->src = src;
273   tg->dest = dest;
274   tg->base_rate = base_rate;
275   tg->max_rate = max_rate;
276   tg->duration_period = period;
277   tg->time_start = GNUNET_TIME_absolute_get();
278   tg->next_ping_transmission = GNUNET_TIME_UNIT_FOREVER_ABS;
279
280   switch (type) {
281   case GNUNET_ATS_TEST_TG_CONSTANT:
282     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
283                 "Setting up constant traffic generator master[%u] `%s' and slave [%u] `%s' max %u Bips\n",
284                 dest->me->no,
285                 GNUNET_i2s (&dest->me->id),
286                 dest->dest->no,
287                 GNUNET_i2s (&dest->dest->id),
288                 base_rate);
289     break;
290   case GNUNET_ATS_TEST_TG_LINEAR:
291     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
292                 "Setting up linear traffic generator master[%u] `%s' and slave [%u] `%s' min %u Bips max %u Bips\n",
293                 dest->me->no,
294                 GNUNET_i2s (&dest->me->id),
295                 dest->dest->no,
296                 GNUNET_i2s (&dest->dest->id),
297                 base_rate,
298                 max_rate);
299     break;
300   case GNUNET_ATS_TEST_TG_SINUS:
301     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
302                 "Setting up sinus traffic generator master[%u] `%s' and slave [%u] `%s' baserate %u Bips, amplitude %u Bps\n",
303                 dest->me->no,
304                 GNUNET_i2s (&dest->me->id),
305                 dest->dest->no,
306                 GNUNET_i2s (&dest->dest->id),
307                 base_rate,
308                 max_rate);
309     break;
310   case GNUNET_ATS_TEST_TG_RANDOM:
311     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
312                 "Setting up random traffic generator master[%u] `%s' and slave [%u] `%s' min %u Bips max %u Bps\n",
313                 dest->me->no,
314                 GNUNET_i2s (&dest->me->id),
315                 dest->dest->no,
316                 GNUNET_i2s (&dest->dest->id),
317                 base_rate,
318                 max_rate);
319       break;
320     default:
321       break;
322   }
323
324   dest->tg = tg;
325   tg->send_task
326     = GNUNET_SCHEDULER_add_now (&comm_schedule_send,
327                                 dest);
328   return tg;
329 }
330
331
332 void
333 GNUNET_ATS_TEST_generate_traffic_stop (struct TrafficGenerator *tg)
334 {
335   GNUNET_CONTAINER_DLL_remove (tg_head,
336                                tg_tail,
337                                tg);
338   tg->dest->tg = NULL;
339   if (NULL != tg->send_task)
340   {
341     GNUNET_SCHEDULER_cancel (tg->send_task);
342     tg->send_task = NULL;
343   }
344   GNUNET_free (tg);
345 }
346
347
348 /**
349  * Stop all traffic generators
350  */
351 void
352 GNUNET_ATS_TEST_generate_traffic_stop_all ()
353 {
354   struct TrafficGenerator *cur;
355   struct TrafficGenerator *next;
356
357   next = tg_head;
358   for (cur = next; NULL != cur; cur = next)
359   {
360     next = cur->next;
361     GNUNET_ATS_TEST_generate_traffic_stop(cur);
362   }
363 }
364
365 /* end of file ats-testing-traffic.c */