constant traffic generator
[oweals/gnunet.git] / src / ats-tests / ats-testing-traffic.c
1 /*
2  This file is part of GNUnet.
3  (C) 2010-2013 Christian Grothoff (and other contributing authors)
4
5  GNUnet is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published
7  by the Free Software Foundation; either version 3, or (at your
8  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  General Public License for more details.
14
15  You should have received a copy of the GNU General Public License
16  along with GNUnet; see the file COPYING.  If not, write to the
17  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  Boston, MA 02111-1307, USA.
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   delay.rel_value_us = 0;
40
41   switch (tg->type) {
42     case GNUNET_ATS_TEST_TG_CONSTANT:
43       if (UINT32_MAX == tg->rate)
44         delay.rel_value_us = 0;
45       else if (tg->rate <= TEST_MESSAGE_SIZE)
46         delay.rel_value_us = (GNUNET_TIME_UNIT_SECONDS.rel_value_us);
47       else
48         delay.rel_value_us = (GNUNET_TIME_UNIT_SECONDS.rel_value_us / (tg->rate / TEST_MESSAGE_SIZE));
49       break;
50     default:
51       return delay;
52       break;
53   }
54   return delay;
55 }
56
57 static size_t
58 send_ping_ready_cb (void *cls, size_t size, void *buf)
59 {
60   struct BenchmarkPartner *p = cls;
61   static char msgbuf[TEST_MESSAGE_SIZE];
62   struct GNUNET_MessageHeader *msg;
63
64   if (NULL == buf)
65   {
66     GNUNET_break (0);
67     return 0;
68   }
69   if (size < TEST_MESSAGE_SIZE)
70   {
71     GNUNET_break (0);
72     return 0;
73   }
74
75   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Master [%u]: Sending PING to [%u]\n",
76       p->me->no, p->dest->no);
77
78   if (top->test_core)
79   {
80       if (NULL == p->cth)
81       {
82         GNUNET_break (0);
83       }
84       p->cth = NULL;
85   }
86   else
87   {
88       if (NULL == p->tth)
89       {
90         GNUNET_break (0);
91       }
92       p->tth = NULL;
93   }
94
95   msg = (struct GNUNET_MessageHeader *) &msgbuf;
96   memset (&msgbuf, 'a', TEST_MESSAGE_SIZE);
97   msg->type = htons (TEST_MESSAGE_TYPE_PING);
98   msg->size = htons (TEST_MESSAGE_SIZE);
99   memcpy (buf, msg, TEST_MESSAGE_SIZE);
100
101   p->messages_sent++;
102   p->bytes_sent += TEST_MESSAGE_SIZE;
103   p->me->total_messages_sent++;
104   p->me->total_bytes_sent += TEST_MESSAGE_SIZE;
105
106   if (NULL == p->tg)
107   {
108     GNUNET_break (0);
109     return TEST_MESSAGE_SIZE;
110   }
111   p->tg->next_ping_transmission = GNUNET_TIME_absolute_add(GNUNET_TIME_absolute_get(),
112       get_delay (p->tg));
113
114   return TEST_MESSAGE_SIZE;
115 }
116
117
118 static void
119 comm_schedule_send (void *cls,
120     const struct GNUNET_SCHEDULER_TaskContext* tc)
121 {
122   struct BenchmarkPartner *p = cls;
123
124   p->tg->send_task = GNUNET_SCHEDULER_NO_TASK;
125
126   p->last_message_sent = GNUNET_TIME_absolute_get();
127   if (GNUNET_YES == top->test_core)
128   {
129     p->cth = GNUNET_CORE_notify_transmit_ready (
130       p->me->ch, GNUNET_NO,
131       GNUNET_CORE_PRIO_BEST_EFFORT,
132       GNUNET_TIME_UNIT_MINUTES, &p->dest->id,
133       TEST_MESSAGE_SIZE, &send_ping_ready_cb, p);
134   }
135   else
136   {
137     p->tth = GNUNET_TRANSPORT_notify_transmit_ready (
138       p->me->th, &p->dest->id, TEST_MESSAGE_SIZE, 0,GNUNET_TIME_UNIT_MINUTES,
139       &send_ping_ready_cb, p);
140   }
141
142 }
143
144 static size_t
145 comm_send_pong_ready (void *cls, size_t size, void *buf)
146 {
147   static char msgbuf[TEST_MESSAGE_SIZE];
148   struct BenchmarkPartner *p = cls;
149   struct GNUNET_MessageHeader *msg;
150
151   if (GNUNET_YES == top->test_core)
152     p->cth = NULL;
153   else
154     p->tth = NULL;
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   msg = (struct GNUNET_MessageHeader *) &msgbuf;
162   memset (&msgbuf, 'a', TEST_MESSAGE_SIZE);
163   msg->type = htons (TEST_MESSAGE_TYPE_PONG);
164   msg->size = htons (TEST_MESSAGE_SIZE);
165   memcpy (buf, msg, TEST_MESSAGE_SIZE);
166
167   return TEST_MESSAGE_SIZE;
168 }
169
170
171 void
172 GNUNET_ATS_TEST_traffic_handle_ping (struct BenchmarkPartner *p)
173 {
174   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
175       "Slave [%u]: Received PING from [%u], sending PONG\n", p->me->no,
176       p->dest->no);
177
178   p->messages_received++;
179   p->bytes_received += TEST_MESSAGE_SIZE;
180   p->me->total_messages_received++;
181   p->me->total_bytes_received += TEST_MESSAGE_SIZE;
182
183   if (GNUNET_YES == top->test_core)
184   {
185     GNUNET_assert (NULL == p->cth);
186
187     p->cth
188       = GNUNET_CORE_notify_transmit_ready (p->me->ch, GNUNET_NO,
189                                            GNUNET_CORE_PRIO_BEST_EFFORT,
190                                            GNUNET_TIME_UNIT_MINUTES,
191                                            &p->dest->id, TEST_MESSAGE_SIZE,
192                                            &comm_send_pong_ready, p);
193   }
194   else
195   {
196     GNUNET_assert (NULL == p->tth);
197     p->tth = GNUNET_TRANSPORT_notify_transmit_ready (p->me->th, &p->dest->id,
198         TEST_MESSAGE_SIZE, 0, GNUNET_TIME_UNIT_MINUTES, &comm_send_pong_ready,
199         p);
200   }
201 }
202
203 void
204 GNUNET_ATS_TEST_traffic_handle_pong (struct BenchmarkPartner *p)
205 {
206   struct GNUNET_TIME_Relative left;
207   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
208       "Master [%u]: Received PONG from [%u], next message\n", p->me->no,
209       p->dest->no);
210
211   p->messages_received++;
212   p->bytes_received += TEST_MESSAGE_SIZE;
213   p->me->total_messages_received++;
214   p->me->total_bytes_received += TEST_MESSAGE_SIZE;
215   p->total_app_rtt += GNUNET_TIME_absolute_get_difference(p->last_message_sent,
216       GNUNET_TIME_absolute_get()).rel_value_us;
217
218   /* Schedule next send event */
219   left = GNUNET_TIME_absolute_get_remaining(p->tg->next_ping_transmission);
220   if (UINT32_MAX == p->tg->rate)
221   {
222     p->tg->send_task = GNUNET_SCHEDULER_add_now (&comm_schedule_send, p);
223   }
224   else if (0 == left.rel_value_us)
225   {
226     p->tg->send_task = GNUNET_SCHEDULER_add_now (&comm_schedule_send, p);
227   }
228   else
229   {
230     p->tg->send_task = GNUNET_SCHEDULER_add_delayed (left,
231         &comm_schedule_send, p);
232   }
233 }
234
235
236 /**
237  * Generate between the source master and the partner and send traffic with a
238  * maximum rate.
239  *
240  */
241 struct TrafficGenerator *
242 GNUNET_ATS_TEST_generate_traffic_start (struct BenchmarkPeer *src,
243     struct BenchmarkPartner *dest,
244     enum TrafficGeneratorType type,
245     unsigned int rate,
246     struct GNUNET_TIME_Relative duration)
247 {
248   struct TrafficGenerator * tg;
249   tg = NULL;
250
251   if (NULL != dest->tg)
252   {
253     GNUNET_break (0);
254     return NULL;
255   }
256
257   tg = GNUNET_new (struct TrafficGenerator);
258   GNUNET_CONTAINER_DLL_insert (tg_head, tg_tail, tg);
259   tg->type = type;
260   tg->src = src;
261   tg->dest = dest;
262   tg->rate = rate;
263   tg->next_ping_transmission = GNUNET_TIME_UNIT_FOREVER_ABS;
264
265   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
266       "Setting up traffic generator master[%u] `%s' and slave [%u] `%s' max %u Bips\n",
267       dest->me->no, GNUNET_i2s (&dest->me->id),
268       dest->dest->no, GNUNET_i2s (&dest->dest->id),
269       rate);
270
271   if ( ((GNUNET_YES == top->test_core) && (NULL != dest->cth)) ||
272        ((GNUNET_NO == top->test_core) && (NULL != dest->tth)) )
273   {
274         GNUNET_break (0);
275         GNUNET_CONTAINER_DLL_remove (tg_head, tg_tail, tg);
276         GNUNET_free (tg);
277         return NULL;
278   }
279
280   dest->tg = tg;
281   tg->send_task = GNUNET_SCHEDULER_add_now (&comm_schedule_send, dest);
282   return tg;
283 }
284
285 void
286 GNUNET_ATS_TEST_generate_traffic_stop (struct TrafficGenerator *tg)
287 {
288
289   GNUNET_CONTAINER_DLL_remove (tg_head, tg_tail, tg);
290   tg->dest->tg = NULL;
291
292   if (GNUNET_SCHEDULER_NO_TASK != tg->send_task)
293   {
294     GNUNET_SCHEDULER_cancel (tg->send_task);
295     tg->send_task = GNUNET_SCHEDULER_NO_TASK;
296   }
297   if (top->test_core)
298   {
299       if (NULL != tg->dest->cth)
300       {
301           GNUNET_CORE_notify_transmit_ready_cancel (tg->dest->cth);
302           tg->dest->cth = NULL;
303       }
304   }
305   else
306   {
307       if (NULL != tg->dest->tth)
308       {
309           GNUNET_TRANSPORT_notify_transmit_ready_cancel (tg->dest->tth);
310           tg->dest->tth = NULL;
311       }
312   }
313   GNUNET_free (tg);
314 }
315
316 /**
317  * Stop all traffic generators
318  */
319 void
320 GNUNET_ATS_TEST_generate_traffic_stop_all ()
321 {
322   struct TrafficGenerator *cur;
323   struct TrafficGenerator *next;
324   next = tg_head;
325   for (cur = next; NULL != cur; cur = next)
326   {
327       next = cur->next;
328       GNUNET_ATS_TEST_generate_traffic_stop(cur);
329   }
330 }
331
332 /* end of file ats-testing-traffic.c */
333