GNUnet  0.20.0
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 calculate 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;
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 
320  {
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);
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++;
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 {
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 
535  if (NULL == ats)
536  {
537  fprintf (stderr, "Failed to connect to ATS service\n");
538  ret = 1;
539  return;
540  }
541 
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 
561 }
562 
563 
564 int
565 main (int argc, char *const *argv)
566 {
567  int res;
568 
573 
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 
607  if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
608  return 2;
609 
610  res =
611  GNUNET_PROGRAM_run (argc,
612  argv,
613  "gnunet-transport",
614  gettext_noop ("Direct access to transport service."),
615  options,
616  &run,
617  NULL);
618  GNUNET_free_nz ((void *) argv);
619  if (GNUNET_OK == res)
620  return ret;
621  return 1;
622 }
623 
624 
625 /* end of gnunet-transport-profiler.c */
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_OPTION_END
Definition: 002.c:13
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
#define gettext_noop(String)
Definition: gettext.h:70
static struct GNUNET_ARM_MonitorHandle * m
Monitor connection with ARM.
Definition: gnunet-arm.c:104
static int res
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 struct GNUNET_CADET_MessageHandler handlers[]
Handlers, for diverse services.
static struct in_addr dummy
Target "dummy" address of the packet we pretend to respond to.
static struct GNUNET_TIME_Relative duration
How long do we run the test?
static int benchmark_send
Option -s.
static void iteration_start()
static unsigned int benchmark_size
Option -m.
static struct Iteration * ihead
static struct GNUNET_ATS_ConnectivityHandle * ats
Handle to ATS service.
static unsigned int verbosity
Selected level of verbosity.
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.
static struct Iteration * itail
static void iteration_done()
#define DEFAULT_ITERATION_COUNT
Benchmarking iteration count.
static struct GNUNET_MQ_Handle * mq
Handle for transmissions.
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
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.
static int blacklist_cb(void *cls, const struct GNUNET_PeerIdentity *peer)
static struct GNUNET_TRANSPORT_CoreHandle * handle
Handle to transport service.
static void shutdown_task(void *cls)
Task run in monitor mode when the user presses CTRL-C to abort.
static int ret
Global return value (0 success).
static struct GNUNET_CONFIGURATION_Handle * cfg
Configuration handle.
static struct GNUNET_TRANSPORT_Blacklist * bl_handle
#define DEFAULT_MESSAGE_SIZE
Benchmarking block size in bye.
static unsigned int benchmark_iterations
Option -i.
static unsigned int benchmark_count
Option -n.
static void handle_dummy(void *cls, const struct GNUNET_MessageHeader *message)
Function called by the transport for each received message.
#define DEFAULT_MESSAGE_COUNT
Benchmarking message count.
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.
static int check_dummy(void *cls, const struct GNUNET_MessageHeader *message)
Function called by the transport for each received message.
int main(int argc, char *const *argv)
static char * cpid
Which peer should we connect to?
static unsigned int benchmark_running
Benchmark running.
static int benchmark_receive
Option -b.
static struct GNUNET_ATS_ConnectivitySuggestHandle * ats_sh
Try_connect handle.
static void send_msg(void *cls)
Function called to notify a client about the socket begin ready to queue more data.
static unsigned long long traffic_received
Number of bytes of traffic we received so far.
Automatic transport selection and outbound bandwidth determination.
Constants for network protocols.
#define GNUNET_MAX_MESSAGE_SIZE
Largest supported message (to be precise, one byte more than the largest possible message,...
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.
void GNUNET_TRANSPORT_core_disconnect(struct GNUNET_TRANSPORT_CoreHandle *handle)
Disconnect from the transport service.
struct GNUNET_ATS_ConnectivityHandle * GNUNET_ATS_connectivity_init(const struct GNUNET_CONFIGURATION_Handle *cfg)
Initialize the ATS connectivity suggestion client handle.
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.
void GNUNET_ATS_connectivity_done(struct GNUNET_ATS_ConnectivityHandle *ch)
Client is done with ATS connectivity management, release resources.
void GNUNET_ATS_connectivity_suggest_cancel(struct GNUNET_ATS_ConnectivitySuggestHandle *sh)
We no longer care about being connected to a peer.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert_tail(head, tail, element)
Insert an element at the tail of a DLL.
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.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_verbose(unsigned int *level)
Define the '-V' verbosity option.
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.
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.
enum GNUNET_GenericReturnValue 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:358
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
const char * GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_free_nz(ptr)
Wrapper around free.
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:304
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#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:63
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
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:638
enum GNUNET_GenericReturnValue 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,...
Definition: program.c:400
#define GNUNET_MESSAGE_TYPE_DUMMY
Dummy messages for testing / benchmarking.
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:562
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,...
Definition: scheduler.c:1334
enum GNUNET_GenericReturnValue GNUNET_STRINGS_get_utf8_args(int argc, char *const *argv, int *u8argc, char *const **u8argv)
Returns utf-8 encoded arguments.
Definition: strings.c:1222
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:436
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:111
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:569
struct GNUNET_TRANSPORT_Blacklist * GNUNET_TRANSPORT_blacklist(const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_TRANSPORT_BlacklistCallback cb, void *cb_cls)
Install a blacklist callback.
void GNUNET_TRANSPORT_blacklist_cancel(struct GNUNET_TRANSPORT_Blacklist *br)
Abort the blacklist.
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
Handle to the ATS subsystem for connectivity management.
Handle for ATS address suggestion requests.
Definition of a command line option.
Handle to a message queue.
Definition: mq.c:87
Message handler for a specific message type.
Header for all communications.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
The identity of the host (wraps the signing key of the peer).
struct GNUNET_CRYPTO_EddsaPublicKey public_key
Time for absolute times used by GNUnet, in microseconds.
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.
Handle for blacklisting requests.
Handle for the transport service (includes all of the state for the transport service).
struct GNUNET_TIME_Absolute end
struct GNUNET_TIME_Absolute start
unsigned int msgs_sent
struct Iteration * prev
struct GNUNET_TIME_Relative dur
struct Iteration * next
struct GNUNET_TESTBED_Peer * peer
The peer associated with this model.