GNUnet  0.10.x
gnunet-transport-profiler.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2011-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 
30 #include "platform.h"
31 #include "gnunet_util_lib.h"
32 #include "gnunet_protocols.h"
33 #include "gnunet_ats_service.h"
35 
36 
37 struct Iteration {
38  struct Iteration *next;
39  struct Iteration *prev;
42 
44 
45  /* Transmission rate for this iteration in KB/s */
46  float rate;
47 
48  unsigned int msgs_sent;
49 };
50 
51 
55 #define CONNECT_TIMEOUT \
56  GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
57 
61 #define DEFAULT_MESSAGE_SIZE 1024
62 
66 #define DEFAULT_MESSAGE_COUNT 1024
67 
71 #define DEFAULT_ITERATION_COUNT 1
72 
76 static int benchmark_send;
77 
81 static int benchmark_receive;
82 
86 static unsigned int benchmark_count;
87 
91 static unsigned int benchmark_iterations;
92 
96 static unsigned int benchmark_size;
97 
101 static unsigned int benchmark_running;
102 
106 static char *cpid;
107 
112 
117 
122 
127 
128 static struct Iteration *ihead;
129 
130 static struct Iteration *itail;
131 
135 static int ret;
136 
140 static struct GNUNET_MQ_Handle *mq;
141 
143 
148 static struct GNUNET_PeerIdentity pid;
149 
153 static unsigned int verbosity;
154 
155 
162 static void
163 shutdown_task(void *cls)
164 {
165  struct Iteration *icur;
166  struct Iteration *inext;
167 
168  unsigned int iterations;
169 
170  unsigned long long avg_duration;
171  float avg_rate;
172  float stddev_rate;
173  float stddev_duration;
174 
175  if (NULL != ats_sh)
176  {
178  ats_sh = NULL;
179  }
180  if (NULL != bl_handle)
181  {
183  bl_handle = NULL;
184  }
185  if (NULL != ats)
186  {
188  ats = NULL;
189  }
190  if (NULL != handle)
191  {
193  handle = NULL;
194  }
195 
196  if (verbosity > 0)
197  fprintf(stdout, "\n");
198 
199  /* Output format:
200  * All time values in ms
201  * Rate in KB/s
202  * #messages;#messagesize;#avg_dur;#avg_rate;#duration_i0;#duration_i0;... */
203 
204  if (benchmark_send)
205  {
206  /* First iteration to calculcate avg and stddev */
207  iterations = 0;
208  avg_duration = 0;
209  avg_rate = 0.0;
210 
211  inext = ihead;
212  while (NULL != (icur = inext))
213  {
214  inext = icur->next;
215  icur->rate = ((benchmark_count * benchmark_size) / 1024) /
216  ((float)icur->dur.rel_value_us / (1000 * 1000));
217  if (verbosity > 0)
218  fprintf(stdout,
219  _("%llu B in %llu ms == %.2f KB/s!\n"),
220  ((long long unsigned int)benchmark_count * benchmark_size),
221  ((long long unsigned int)icur->dur.rel_value_us / 1000),
222  (float)icur->rate);
223 
224  avg_duration += icur->dur.rel_value_us / (1000);
225  avg_rate += icur->rate;
226  iterations++;
227  }
228  if (0 == iterations)
229  iterations = 1; /* avoid division by zero */
230  /* Calculate average rate */
231  avg_rate /= iterations;
232  /* Calculate average duration */
233  avg_duration /= iterations;
234 
235  stddev_rate = 0;
236  stddev_duration = 0;
237  inext = ihead;
238  while (NULL != (icur = inext))
239  {
240  inext = icur->next;
241  stddev_rate += ((icur->rate - avg_rate) * (icur->rate - avg_rate));
242  stddev_duration += (((icur->dur.rel_value_us / 1000) - avg_duration) *
243  ((icur->dur.rel_value_us / 1000) - avg_duration));
244  }
245  /* Calculate standard deviation rate */
246  stddev_rate = stddev_rate / iterations;
247  stddev_rate = sqrtf(stddev_rate);
248 
249  /* Calculate standard deviation duration */
250  stddev_duration = stddev_duration / iterations;
251  stddev_duration = sqrtf(stddev_duration);
252 
253  /* Output */
254  fprintf(stdout,
255  "%u;%u;%llu;%llu;%.2f;%.2f",
258  avg_duration,
259  (unsigned long long)stddev_duration,
260  avg_rate,
261  stddev_rate);
262 
263  inext = ihead;
264  while (NULL != (icur = inext))
265  {
266  inext = icur->next;
267  GNUNET_CONTAINER_DLL_remove(ihead, itail, icur);
268 
269  fprintf(stdout,
270  ";%llu;%.2f",
271  (long long unsigned int)(icur->dur.rel_value_us / 1000),
272  icur->rate);
273 
274  GNUNET_free(icur);
275  }
276  }
277 #if 0
278  if (benchmark_receive)
279  {
281  fprintf(stdout,
282  "Received %llu bytes/s (%llu bytes in %s)\n",
283  1000LL * 1000LL * traffic_received / (1 + duration.rel_value_us),
286  }
287 #endif
288  fprintf(stdout, "\n");
289 }
290 
291 
292 static void
294 
295 
307 static void
308 send_msg(void *cls)
309 {
310  struct GNUNET_MQ_Envelope *env;
311  struct GNUNET_MessageHeader *m;
312 
313  if (NULL == mq)
314  return;
316  memset(&m[1], 52, benchmark_size - sizeof(struct GNUNET_MessageHeader));
317 
318  if (itail->msgs_sent < benchmark_count)
319  {
320  GNUNET_MQ_notify_sent(env, &send_msg, NULL);
321  }
322  else
323  {
324  iteration_done();
325  }
326  GNUNET_MQ_send(mq, env);
327  if ((verbosity > 0) && (0 == itail->msgs_sent % 10))
328  fprintf(stdout, ".");
329 }
330 
331 
332 static void
334 {
335  struct Iteration *icur;
336 
337  ret = 0;
338  if (!benchmark_send)
339  return;
341  icur = GNUNET_new(struct Iteration);
342  GNUNET_CONTAINER_DLL_insert_tail(ihead, itail, icur);
344  if (verbosity > 0)
345  fprintf(
346  stdout,
347  "\nStarting benchmark, starting to send %u messages in %u byte blocks\n",
350  send_msg(NULL);
351 }
352 
353 
354 static void
356 {
357  static int it_count = 0;
358 
359  it_count++;
361  if (it_count == benchmark_iterations)
362  {
365  return;
366  }
367  iteration_start();
368 }
369 
370 
380 static void *
381 notify_connect(void *cls,
382  const struct GNUNET_PeerIdentity *peer,
383  struct GNUNET_MQ_Handle *m)
384 {
385  if (0 != memcmp(&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
386  {
387  fprintf(stdout, "Connected to different peer `%s'\n", GNUNET_i2s(&pid));
388  return NULL;
389  }
390 
391  if (verbosity > 0)
392  fprintf(stdout, "Successfully connected to `%s'\n", GNUNET_i2s(&pid));
393  mq = m;
394  iteration_start();
395  return NULL;
396 }
397 
398 
407 static void
409  const struct GNUNET_PeerIdentity *peer,
410  void *internal_cls)
411 {
412  if (0 != memcmp(&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
413  return;
414  mq = NULL;
416  {
417  fprintf(stdout,
418  "Disconnected from peer `%s' while benchmarking\n",
419  GNUNET_i2s(&pid));
420  return;
421  }
422 }
423 
424 
432 static int
433 check_dummy(void *cls, const struct GNUNET_MessageHeader *message)
434 {
435  return GNUNET_OK; /* all messages are fine */
436 }
437 
438 
445 static void
446 handle_dummy(void *cls, const struct GNUNET_MessageHeader *message)
447 {
448  if (!benchmark_receive)
449  return;
450  if (verbosity > 0)
451  fprintf(stdout,
452  "Received %u bytes\n",
453  (unsigned int)ntohs(message->size));
454 }
455 
456 
457 static int
458 blacklist_cb(void *cls, const struct GNUNET_PeerIdentity *peer)
459 {
460  if (0 != memcmp(&pid, peer, sizeof(struct GNUNET_PeerIdentity)))
461  {
462  if (verbosity > 0)
463  fprintf(stdout, "Denying connection to `%s'\n", GNUNET_i2s(peer));
464  return GNUNET_SYSERR;
465  }
466  return GNUNET_OK;
467 }
468 
469 
478 static void
479 run(void *cls,
480  char *const *args,
481  const char *cfgfile,
482  const struct GNUNET_CONFIGURATION_Handle *mycfg)
483 {
484  struct GNUNET_MQ_MessageHandler handlers[] =
487  struct GNUNET_MessageHeader,
488  NULL),
490 
491  cfg = (struct GNUNET_CONFIGURATION_Handle *)mycfg;
492 
493  ret = 1;
495  {
496  fprintf(stderr, "Message size too big!\n");
497  return;
498  }
499 
500  if (NULL == cpid)
501  {
502  fprintf(stderr, "No peer identity given\n");
503  return;
504  }
506  strlen(cpid),
507  &pid.public_key))
508  {
509  fprintf(stderr, "Failed to parse peer identity `%s'\n", cpid);
510  return;
511  }
512  if (1 == benchmark_send)
513  {
514  if (verbosity > 0)
515  fprintf(stderr,
516  "Trying to send %u messages with size %u to peer `%s'\n",
519  GNUNET_i2s(&pid));
520  }
521  else if (1 == benchmark_receive)
522  {
523  fprintf(stderr,
524  "Trying to receive messages from peer `%s'\n",
525  GNUNET_i2s(&pid));
526  }
527  else
528  {
529  fprintf(stderr, "No operation given\n");
530  return;
531  }
532 
533  ats = GNUNET_ATS_connectivity_init(cfg);
534  if (NULL == ats)
535  {
536  fprintf(stderr, "Failed to connect to ATS service\n");
537  ret = 1;
538  return;
539  }
540 
541  handle = GNUNET_TRANSPORT_core_connect(cfg,
542  NULL,
543  handlers,
544  NULL,
547  NULL);
548  if (NULL == handle)
549  {
550  fprintf(stderr, "Failed to connect to transport service\n");
552  ats = NULL;
553  ret = 1;
554  return;
555  }
556 
557  bl_handle = GNUNET_TRANSPORT_blacklist(cfg, &blacklist_cb, NULL);
558  ats_sh = GNUNET_ATS_connectivity_suggest(ats, &pid, 1);
560 }
561 
562 
563 int
564 main(int argc, char *const *argv)
565 {
566  int res;
567 
572 
573  struct GNUNET_GETOPT_CommandLineOption options[] = {
575  "send",
576  gettext_noop("send data to peer"),
577  &benchmark_send),
579  "receive",
580  gettext_noop("receive data from peer"),
583  "iterations",
584  NULL,
585  gettext_noop("iterations"),
588  "number",
589  NULL,
590  gettext_noop("number of messages to send"),
591  &benchmark_count),
593  "messagesize",
594  NULL,
595  gettext_noop("message size to use"),
596  &benchmark_size),
598  "peer",
599  "PEER",
600  gettext_noop("peer identity"),
601  &cpid),
604  };
605 
606  if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args(argc, argv, &argc, &argv))
607  return 2;
608 
609  res =
610  GNUNET_PROGRAM_run(argc,
611  argv,
612  "gnunet-transport",
613  gettext_noop("Direct access to transport service."),
614  options,
615  &run,
616  NULL);
617  GNUNET_free((void *)argv);
618  if (GNUNET_OK == res)
619  return ret;
620  return 1;
621 }
622 
623 /* end of gnunet-transport-profiler.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
static void handle_dummy(void *cls, const struct GNUNET_MessageHeader *message)
Function called by the transport for each received message.
static char * cpid
Which peer should we connect to?
uint64_t rel_value_us
The actual value.
static unsigned int verbosity
Selected level of verbosity.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received, or when GNUNET_SCHEDULER_shutdown() is being invoked.
Definition: scheduler.c:1284
static struct GNUNET_MQ_Handle * mq
Handle for transmissions.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_verbose(unsigned int *level)
Define the &#39;-V&#39; verbosity option.
static unsigned int benchmark_size
Option -m.
int GNUNET_STRINGS_get_utf8_args(int argc, char *const *argv, int *u8argc, char *const **u8argv)
Returns utf-8 encoded arguments.
Definition: strings.c:1439
struct Iteration * next
static struct GNUNET_ATS_ConnectivityHandle * ats
Handle to ATS service.
static struct Iteration * itail
static struct Iteration * ihead
#define GNUNET_MESSAGE_TYPE_DUMMY
Dummy messages for testing / benchmarking.
static struct GNUNET_ATS_ConnectivitySuggestHandle * ats_sh
Try_connect handle.
#define GNUNET_NO
Definition: gnunet_common.h:78
int main(int argc, char *const *argv)
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#define GNUNET_new(type)
Allocate a struct or union of the given type.
Definition of a command line option.
void GNUNET_ATS_connectivity_suggest_cancel(struct GNUNET_ATS_ConnectivitySuggestHandle *sh)
We no longer care about being connected to a peer.
void GNUNET_TRANSPORT_blacklist_cancel(struct GNUNET_TRANSPORT_Blacklist *br)
Abort the blacklist.
struct GNUNET_TRANSPORT_CoreHandle * GNUNET_TRANSPORT_core_connect(const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_PeerIdentity *self, const struct GNUNET_MQ_MessageHandler *handlers, void *cls, GNUNET_TRANSPORT_NotifyConnect nc, GNUNET_TRANSPORT_NotifyDisconnect nd)
Connect to the transport service.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
static struct GNUNET_TRANSPORT_CoreHandle * handle
Handle to transport service.
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:517
static int check_dummy(void *cls, const struct GNUNET_MessageHeader *message)
Function called by the transport for each received message.
#define DEFAULT_MESSAGE_COUNT
Benchmarking message count.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_OPTION_END
Definition: 002.c:13
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_string(char shortName, const char *name, const char *argumentHelp, const char *description, char **str)
Allow user to specify a string.
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
struct GNUNET_ATS_ConnectivitySuggestHandle * GNUNET_ATS_connectivity_suggest(struct GNUNET_ATS_ConnectivityHandle *ch, const struct GNUNET_PeerIdentity *peer, uint32_t strength)
We would like to receive address suggestions for a peer.
struct GNUNET_TIME_Absolute end
static struct GNUNET_ARM_MonitorHandle * m
Monitor connection with ARM.
Definition: gnunet-arm.c:99
static void * notify_connect(void *cls, const struct GNUNET_PeerIdentity *peer, struct GNUNET_MQ_Handle *m)
Function called to notify transport users that another peer connected to us.
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct...
Definition: gnunet_mq_lib.h:52
static unsigned int benchmark_count
Option -n.
void GNUNET_MQ_notify_sent(struct GNUNET_MQ_Envelope *ev, GNUNET_SCHEDULER_TaskCallback cb, void *cb_cls)
Call a callback once the envelope has been sent, that is, sending it can not be canceled anymore...
Definition: mq.c:772
#define DEFAULT_MESSAGE_SIZE
Benchmarking block size in bye.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
struct GNUNET_TRANSPORT_Blacklist * GNUNET_TRANSPORT_blacklist(const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_TRANSPORT_BlacklistCallback cb, void *cb_cls)
Install a blacklist callback.
const char * GNUNET_STRINGS_relative_time_to_string(struct GNUNET_TIME_Relative delta, int do_round)
Give relative time in human-readable fancy format.
Definition: strings.c:686
struct Iteration * prev
Handle for ATS address suggestion requests.
static unsigned int benchmark_iterations
Option -i.
static void run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *mycfg)
Main function that will be run by the scheduler.
unsigned int msgs_sent
Message handler for a specific message type.
static int res
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:118
struct GNUNET_TIME_Absolute start
static struct GNUNET_TIME_Absolute start_time
Start time of the current round; used to determine how long one iteration takes (which influences how...
static unsigned long long traffic_received
Number of bytes of traffic we received so far.
Handle for blacklisting requests.
struct GNUNET_TESTBED_Peer * peer
The peer associated with this model.
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
static struct GNUNET_CONFIGURATION_Handle * cfg
Configuration handle.
static struct GNUNET_TRANSPORT_Blacklist * bl_handle
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
#define GNUNET_CONTAINER_DLL_insert_tail(head, tail, element)
Insert an element at the tail of a DLL.
static void send_msg(void *cls)
Function called to notify a client about the socket begin ready to queue more data.
static int benchmark_send
Option -s.
static void iteration_start()
#define GNUNET_MAX_MESSAGE_SIZE
Largest supported message (to be precise, one byte more than the largest possible message...
static struct in_addr dummy
Target "dummy" address of the packet we pretend to respond to.
static unsigned int benchmark_running
Benchmark running.
Handle to a message queue.
Definition: mq.c:84
struct GNUNET_ATS_ConnectivityHandle * GNUNET_ATS_connectivity_init(const struct GNUNET_CONFIGURATION_Handle *cfg)
Initialize the ATS connectivity suggestion client handle.
int GNUNET_CRYPTO_eddsa_public_key_from_string(const char *enc, size_t enclen, struct GNUNET_CRYPTO_EddsaPublicKey *pub)
Convert a string representing a public key to a public key.
Definition: crypto_ecc.c:501
The identity of the host (wraps the signing key of the peer).
static void iteration_done()
static int ret
Global return value (0 success).
configuration data
Definition: configuration.c:83
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_duration(struct GNUNET_TIME_Absolute whence)
Get the duration of an operation as the difference of the current time and the given start time "henc...
Definition: time.c:373
void GNUNET_TRANSPORT_core_disconnect(struct GNUNET_TRANSPORT_CoreHandle *handle)
Disconnect from the transport service.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_flag(char shortName, const char *name, const char *description, int *val)
Allow user to specify a flag (which internally means setting an integer to 1/GNUNET_YES/GNUNET_OK.
Automatic transport selection and outbound bandwidth determination.
static struct GNUNET_TIME_Relative duration
How long do we run the test?
int GNUNET_PROGRAM_run(int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls)
Run a standard GNUnet command startup sequence (initialize loggers and configuration, parse options).
Definition: program.c:367
#define DEFAULT_ITERATION_COUNT
Benchmarking iteration count.
Header for all communications.
Time for absolute times used by GNUnet, in microseconds.
#define GNUNET_YES
Definition: gnunet_common.h:77
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition: mq.c:351
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_uint(char shortName, const char *name, const char *argumentHelp, const char *description, unsigned int *val)
Allow user to specify an unsigned int.
static int blacklist_cb(void *cls, const struct GNUNET_PeerIdentity *peer)
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
Handle for the transport service (includes all of the state for the transport service).
static void notify_disconnect(void *cls, const struct GNUNET_PeerIdentity *peer, void *internal_cls)
Function called to notify transport users that another peer disconnected from us. ...
struct GNUNET_TIME_Relative dur
Handle to the ATS subsystem for connectivity management.
void GNUNET_ATS_connectivity_done(struct GNUNET_ATS_ConnectivityHandle *ch)
Client is done with ATS connectivity management, release resources.
const char * GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
static void shutdown_task(void *cls)
Task run in monitor mode when the user presses CTRL-C to abort.
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define GNUNET_free(ptr)
Wrapper around free.
Time for relative time used by GNUnet, in microseconds.
struct GNUNET_CRYPTO_EddsaPublicKey public_key
#define gettext_noop(String)
Definition: gettext.h:69
static int benchmark_receive
Option -b.