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 {
39  struct Iteration *next;
40  struct Iteration *prev;
43 
45 
46  /* Transmission rate for this iteration in KB/s */
47  float rate;
48 
49  unsigned int msgs_sent;
50 };
51 
52 
56 #define CONNECT_TIMEOUT \
57  GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
58 
62 #define DEFAULT_MESSAGE_SIZE 1024
63 
67 #define DEFAULT_MESSAGE_COUNT 1024
68 
72 #define DEFAULT_ITERATION_COUNT 1
73 
77 static int benchmark_send;
78 
82 static int benchmark_receive;
83 
87 static unsigned int benchmark_count;
88 
92 static unsigned int benchmark_iterations;
93 
97 static unsigned int benchmark_size;
98 
102 static unsigned int benchmark_running;
103 
107 static char *cpid;
108 
113 
118 
123 
128 
129 static struct Iteration *ihead;
130 
131 static struct Iteration *itail;
132 
136 static int ret;
137 
141 static struct GNUNET_MQ_Handle *mq;
142 
144 
149 static struct GNUNET_PeerIdentity pid;
150 
154 static unsigned int verbosity;
155 
156 
163 static void
164 shutdown_task (void *cls)
165 {
166  struct Iteration *icur;
167  struct Iteration *inext;
168 
169  unsigned int iterations;
170 
171  unsigned long long avg_duration;
172  float avg_rate;
173  float stddev_rate;
174  float stddev_duration;
175 
176  if (NULL != ats_sh)
177  {
179  ats_sh = NULL;
180  }
181  if (NULL != bl_handle)
182  {
184  bl_handle = NULL;
185  }
186  if (NULL != ats)
187  {
189  ats = NULL;
190  }
191  if (NULL != handle)
192  {
194  handle = NULL;
195  }
196 
197  if (verbosity > 0)
198  FPRINTF (stdout, "\n");
199 
200  /* Output format:
201  * All time values in ms
202  * Rate in KB/s
203  * #messages;#messagesize;#avg_dur;#avg_rate;#duration_i0;#duration_i0;... */
204 
205  if (benchmark_send)
206  {
207  /* First iteration to calculcate avg and stddev */
208  iterations = 0;
209  avg_duration = 0;
210  avg_rate = 0.0;
211 
212  inext = ihead;
213  while (NULL != (icur = inext))
214  {
215  inext = icur->next;
216  icur->rate = ((benchmark_count * benchmark_size) / 1024) /
217  ((float) icur->dur.rel_value_us / (1000 * 1000));
218  if (verbosity > 0)
219  FPRINTF (stdout,
220  _ ("%llu B in %llu ms == %.2f KB/s!\n"),
221  ((long long unsigned int) benchmark_count * benchmark_size),
222  ((long long unsigned int) icur->dur.rel_value_us / 1000),
223  (float) icur->rate);
224 
225  avg_duration += icur->dur.rel_value_us / (1000);
226  avg_rate += icur->rate;
227  iterations++;
228  }
229  if (0 == iterations)
230  iterations = 1; /* avoid division by zero */
231  /* Calculate average rate */
232  avg_rate /= iterations;
233  /* Calculate average duration */
234  avg_duration /= iterations;
235 
236  stddev_rate = 0;
237  stddev_duration = 0;
238  inext = ihead;
239  while (NULL != (icur = inext))
240  {
241  inext = icur->next;
242  stddev_rate += ((icur->rate - avg_rate) * (icur->rate - avg_rate));
243  stddev_duration += (((icur->dur.rel_value_us / 1000) - avg_duration) *
244  ((icur->dur.rel_value_us / 1000) - avg_duration));
245  }
246  /* Calculate standard deviation rate */
247  stddev_rate = stddev_rate / iterations;
248  stddev_rate = sqrtf (stddev_rate);
249 
250  /* Calculate standard deviation duration */
251  stddev_duration = stddev_duration / iterations;
252  stddev_duration = sqrtf (stddev_duration);
253 
254  /* Output */
255  FPRINTF (stdout,
256  "%u;%u;%llu;%llu;%.2f;%.2f",
259  avg_duration,
260  (unsigned long long) stddev_duration,
261  avg_rate,
262  stddev_rate);
263 
264  inext = ihead;
265  while (NULL != (icur = inext))
266  {
267  inext = icur->next;
268  GNUNET_CONTAINER_DLL_remove (ihead, itail, icur);
269 
270  FPRINTF (stdout,
271  ";%llu;%.2f",
272  (long long unsigned int) (icur->dur.rel_value_us / 1000),
273  icur->rate);
274 
275  GNUNET_free (icur);
276  }
277  }
278 #if 0
279  if (benchmark_receive)
280  {
282  FPRINTF (stdout,
283  "Received %llu bytes/s (%llu bytes in %s)\n",
284  1000LL * 1000LL * traffic_received / (1 + duration.rel_value_us),
287  }
288 #endif
289  FPRINTF (stdout, "\n");
290 }
291 
292 
293 static void
294 iteration_done ();
295 
296 
308 static void
309 send_msg (void *cls)
310 {
311  struct GNUNET_MQ_Envelope *env;
312  struct GNUNET_MessageHeader *m;
313 
314  if (NULL == mq)
315  return;
317  memset (&m[1], 52, benchmark_size - sizeof (struct GNUNET_MessageHeader));
318 
319  if (itail->msgs_sent < benchmark_count)
320  {
321  GNUNET_MQ_notify_sent (env, &send_msg, NULL);
322  }
323  else
324  {
325  iteration_done ();
326  }
327  GNUNET_MQ_send (mq, env);
328  if ((verbosity > 0) && (0 == itail->msgs_sent % 10))
329  FPRINTF (stdout, ".");
330 }
331 
332 
333 static void
335 {
336  struct Iteration *icur;
337 
338  ret = 0;
339  if (! benchmark_send)
340  return;
342  icur = GNUNET_new (struct Iteration);
343  GNUNET_CONTAINER_DLL_insert_tail (ihead, itail, icur);
344  icur->start = GNUNET_TIME_absolute_get ();
345  if (verbosity > 0)
346  FPRINTF (
347  stdout,
348  "\nStarting benchmark, starting to send %u messages in %u byte blocks\n",
351  send_msg (NULL);
352 }
353 
354 
355 static void
357 {
358  static int it_count = 0;
359 
360  it_count++;
361  itail->dur = GNUNET_TIME_absolute_get_duration (itail->start);
362  if (it_count == benchmark_iterations)
363  {
366  return;
367  }
368  iteration_start ();
369 }
370 
371 
381 static void *
382 notify_connect (void *cls,
383  const struct GNUNET_PeerIdentity *peer,
384  struct GNUNET_MQ_Handle *m)
385 {
386  if (0 != memcmp (&pid, peer, sizeof (struct GNUNET_PeerIdentity)))
387  {
388  FPRINTF (stdout, "Connected to different peer `%s'\n", GNUNET_i2s (&pid));
389  return NULL;
390  }
391 
392  if (verbosity > 0)
393  FPRINTF (stdout, "Successfully connected to `%s'\n", GNUNET_i2s (&pid));
394  mq = m;
395  iteration_start ();
396  return NULL;
397 }
398 
399 
408 static void
409 notify_disconnect (void *cls,
410  const struct GNUNET_PeerIdentity *peer,
411  void *internal_cls)
412 {
413  if (0 != memcmp (&pid, peer, sizeof (struct GNUNET_PeerIdentity)))
414  return;
415  mq = NULL;
417  {
418  FPRINTF (stdout,
419  "Disconnected from peer `%s' while benchmarking\n",
420  GNUNET_i2s (&pid));
421  return;
422  }
423 }
424 
425 
433 static int
434 check_dummy (void *cls, const struct GNUNET_MessageHeader *message)
435 {
436  return GNUNET_OK; /* all messages are fine */
437 }
438 
439 
446 static void
447 handle_dummy (void *cls, const struct GNUNET_MessageHeader *message)
448 {
449  if (! benchmark_receive)
450  return;
451  if (verbosity > 0)
452  FPRINTF (stdout,
453  "Received %u bytes\n",
454  (unsigned int) ntohs (message->size));
455 }
456 
457 
458 static int
459 blacklist_cb (void *cls, const struct GNUNET_PeerIdentity *peer)
460 {
461  if (0 != memcmp (&pid, peer, sizeof (struct GNUNET_PeerIdentity)))
462  {
463  if (verbosity > 0)
464  FPRINTF (stdout, "Denying connection to `%s'\n", GNUNET_i2s (peer));
465  return GNUNET_SYSERR;
466  }
467  return GNUNET_OK;
468 }
469 
470 
479 static void
480 run (void *cls,
481  char *const *args,
482  const char *cfgfile,
483  const struct GNUNET_CONFIGURATION_Handle *mycfg)
484 {
485  struct GNUNET_MQ_MessageHandler handlers[] =
488  struct GNUNET_MessageHeader,
489  NULL),
491 
492  cfg = (struct GNUNET_CONFIGURATION_Handle *) mycfg;
493 
494  ret = 1;
496  {
497  FPRINTF (stderr, "Message size too big!\n");
498  return;
499  }
500 
501  if (NULL == cpid)
502  {
503  FPRINTF (stderr, "No peer identity given\n");
504  return;
505  }
507  strlen (cpid),
508  &pid.public_key))
509  {
510  FPRINTF (stderr, "Failed to parse peer identity `%s'\n", cpid);
511  return;
512  }
513  if (1 == benchmark_send)
514  {
515  if (verbosity > 0)
516  FPRINTF (stderr,
517  "Trying to send %u messages with size %u to peer `%s'\n",
520  GNUNET_i2s (&pid));
521  }
522  else if (1 == benchmark_receive)
523  {
524  FPRINTF (stderr,
525  "Trying to receive messages from peer `%s'\n",
526  GNUNET_i2s (&pid));
527  }
528  else
529  {
530  FPRINTF (stderr, "No operation given\n");
531  return;
532  }
533 
534  ats = GNUNET_ATS_connectivity_init (cfg);
535  if (NULL == ats)
536  {
537  FPRINTF (stderr, "Failed to connect to ATS service\n");
538  ret = 1;
539  return;
540  }
541 
542  handle = GNUNET_TRANSPORT_core_connect (cfg,
543  NULL,
544  handlers,
545  NULL,
548  NULL);
549  if (NULL == handle)
550  {
551  FPRINTF (stderr, "Failed to connect to transport service\n");
553  ats = NULL;
554  ret = 1;
555  return;
556  }
557 
558  bl_handle = GNUNET_TRANSPORT_blacklist (cfg, &blacklist_cb, NULL);
559  ats_sh = GNUNET_ATS_connectivity_suggest (ats, &pid, 1);
561 }
562 
563 
564 int
565 main (int argc, char *const *argv)
566 {
567  int res;
572 
573  struct GNUNET_GETOPT_CommandLineOption options[] = {
574 
576  "send",
577  gettext_noop ("send data to peer"),
578  &benchmark_send),
580  "receive",
581  gettext_noop ("receive data from peer"),
584  "iterations",
585  NULL,
586  gettext_noop ("iterations"),
589  "number",
590  NULL,
591  gettext_noop ("number of messages to send"),
592  &benchmark_count),
594  "messagesize",
595  NULL,
596  gettext_noop ("message size to use"),
597  &benchmark_size),
599  "peer",
600  "PEER",
601  gettext_noop ("peer identity"),
602  &cpid),
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 struct in_addr dummy
Target "dummy" address.
static unsigned int verbosity
Selected level of verbosity.
#define FPRINTF
Definition: plibc.h:683
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:1293
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:1521
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:81
int main(int argc, char *const *argv)
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
#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:524
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:208
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:774
#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:727
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:79
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 unsigned int benchmark_running
Benchmark running.
Handle to a message queue.
Definition: mq.c:85
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:85
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:361
#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:80
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:353
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.