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