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