GNUnet  0.20.0
gnunet-gns-benchmark.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2018 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  */
25 #include "platform.h"
26 #include <gnunet_util_lib.h>
27 #include <gnunet_gnsrecord_lib.h>
28 #include <gnunet_gns_service.h>
29 
30 
34 #define DEF_REQUEST_DELAY GNUNET_TIME_relative_multiply ( \
35  GNUNET_TIME_UNIT_MILLISECONDS, 1)
36 
40 #define DEF_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
41 
42 
50 {
51  RC_SHARED = 0,
56  RC_MAX = 2
57 };
58 
59 
65 struct Request
66 {
70  struct Request *next;
71 
75  struct Request *prev;
76 
81 
87  const char *hostname;
88 
94 
99 
103  enum RequestCategory cat;
104 };
105 
106 
110 static struct GNUNET_GNS_Handle *gns;
111 
115 static unsigned int lookups[RC_MAX];
116 
120 static unsigned int replies[RC_MAX];
121 
125 static unsigned int failures[RC_MAX];
126 
132 
136 static struct Request *act_head;
137 
141 static struct Request *act_tail;
142 
146 static struct Request *succ_head;
147 
151 static struct Request *succ_tail;
152 
156 static struct Request *todo_head;
157 
161 static struct Request *todo_tail;
162 
166 static struct GNUNET_SCHEDULER_Task *t;
167 
171 static struct GNUNET_TIME_Relative request_delay;
172 
176 static struct GNUNET_TIME_Relative timeout;
177 
181 static unsigned int active_cnt;
182 
186 static int g2d;
187 
193 static void
194 free_request (struct Request *req)
195 {
196  if (NULL != req->lr)
198  GNUNET_free (req);
199 }
200 
201 
210 static void
211 process_result (void *cls,
212  int gns_tld,
213  uint32_t rd_count,
214  const struct GNUNET_GNSRECORD_Data *rd)
215 {
216  struct Request *req = cls;
217 
218  (void) gns_tld;
219  (void) rd_count;
220  (void) rd;
221  active_cnt--;
223  "Got response for request `%s'\n",
224  req->hostname);
225  req->lr = NULL;
228  act_tail,
229  req);
231  succ_tail,
232  req);
233  replies[req->cat]++;
234  latency_sum[req->cat]
236  req->latency);
237 }
238 
239 
245 static void
246 process_queue (void *cls)
247 {
248  struct Request *req;
250 
251  (void) cls;
252  t = NULL;
253  /* check for expired requests */
254  while (NULL != (req = act_head))
255  {
258  break;
260  act_tail,
261  req);
263  "Failing request `%s' due to timeout\n",
264  req->hostname);
265  failures[req->cat]++;
266  active_cnt--;
267  free_request (req);
268  }
269  if (NULL == (req = todo_head))
270  {
271  struct GNUNET_TIME_Absolute at;
272 
273  if (NULL == (req = act_head))
274  {
276  return;
277  }
279  timeout);
281  &process_queue,
282  NULL);
283  return;
284  }
286  todo_tail,
287  req);
289  act_tail,
290  req);
291  lookups[req->cat]++;
292  active_cnt++;
295  "Starting request `%s' (%u in parallel)\n",
296  req->hostname,
297  active_cnt);
299  req->hostname,
300  g2d
305  req);
307  &process_queue,
308  NULL);
309 }
310 
311 
319 static int
320 compare_req (const void *c1,
321  const void *c2)
322 {
323  const struct Request *r1 = *(void **) c1;
324  const struct Request *r2 = *(void **) c2;
325 
327  return -1;
329  return 1;
330  return 0;
331 }
332 
333 
339 static void
340 do_shutdown (void *cls)
341 {
342  struct Request *req;
343  struct Request **ra[RC_MAX];
344  unsigned int rp[RC_MAX];
345 
346  (void) cls;
347  for (enum RequestCategory rc = 0; rc < RC_MAX; rc++)
348  {
349  ra[rc] = GNUNET_new_array (replies[rc],
350  struct Request *);
351  rp[rc] = 0;
352  }
353  for (req = succ_head; NULL != req; req = req->next)
354  {
355  GNUNET_assert (rp[req->cat] < replies[req->cat]);
356  ra[req->cat][rp[req->cat]++] = req;
357  }
358  for (enum RequestCategory rc = 0; rc < RC_MAX; rc++)
359  {
360  unsigned int off;
361 
362  fprintf (stdout,
363  "Category %u\n",
364  rc);
365  fprintf (stdout,
366  "\tlookups: %u replies: %u failures: %u\n",
367  lookups[rc],
368  replies[rc],
369  failures[rc]);
370  if (0 == rp[rc])
371  continue;
372  qsort (ra[rc],
373  rp[rc],
374  sizeof(struct Request *),
375  &compare_req);
377  replies[rc]);
378  fprintf (stdout,
379  "\taverage: %s\n",
381  GNUNET_YES));
382  off = rp[rc] * 50 / 100;
383  fprintf (stdout,
384  "\tmedian(50): %s\n",
386  GNUNET_YES));
387  off = rp[rc] * 75 / 100;
388  fprintf (stdout,
389  "\tquantile(75): %s\n",
391  GNUNET_YES));
392  off = rp[rc] * 90 / 100;
393  fprintf (stdout,
394  "\tquantile(90): %s\n",
396  GNUNET_YES));
397  off = rp[rc] * 99 / 100;
398  fprintf (stdout,
399  "\tquantile(99): %s\n",
401  GNUNET_YES));
402  GNUNET_free (ra[rc]);
403  }
404  if (NULL != t)
405  {
407  t = NULL;
408  }
409  while (NULL != (req = act_head))
410  {
412  act_tail,
413  req);
414  free_request (req);
415  }
416  while (NULL != (req = succ_head))
417  {
419  succ_tail,
420  req);
421  free_request (req);
422  }
423  while (NULL != (req = todo_head))
424  {
426  todo_tail,
427  req);
428  free_request (req);
429  }
430  if (NULL != gns)
431  {
433  gns = NULL;
434  }
435 }
436 
437 
444 static void
445 queue (const char *hostname,
446  enum RequestCategory cat)
447 {
448  struct Request *req;
449  const char *dot;
450  size_t hlen;
451 
452  dot = strchr (hostname,
453  (unsigned char) '.');
454  if (NULL == dot)
455  {
457  "Refusing invalid hostname `%s' (lacks '.')\n",
458  hostname);
459  return;
460  }
461  hlen = strlen (hostname) + 1;
462  req = GNUNET_malloc (sizeof(struct Request) + hlen);
463  req->cat = cat;
464  req->hostname = (char *) &req[1];
465  GNUNET_memcpy (&req[1],
466  hostname,
467  hlen);
469  todo_tail,
470  req);
471 }
472 
473 
479 static void
480 process_stdin (void *cls)
481 {
482  static struct GNUNET_TIME_Absolute last;
483  static uint64_t idot;
484  unsigned int cat;
485  char hn[256];
486  char in[270];
487 
488  (void) cls;
489  t = NULL;
490  while (NULL !=
491  fgets (in,
492  sizeof(in),
493  stdin))
494  {
495  if (strlen (in) > 0)
496  hn[strlen (in) - 1] = '\0'; /* eat newline */
497  if ((2 != sscanf (in,
498  "%u %255s",
499  &cat,
500  hn)) ||
501  (cat >= RC_MAX))
502  {
503  fprintf (stderr,
504  "Malformed input line `%s', skipping\n",
505  in);
506  continue;
507  }
508  if (0 == idot)
509  last = GNUNET_TIME_absolute_get ();
510  idot++;
511  if (0 == idot % 100000)
512  {
514 
516  last = GNUNET_TIME_absolute_get ();
517  fprintf (stderr,
518  "Read 100000 domain names in %s\n",
520  GNUNET_YES));
521  }
522  queue (hn,
523  (enum RequestCategory) cat);
524  }
525  fprintf (stderr,
526  "Done reading %llu domain names\n",
527  (unsigned long long) idot);
529  NULL);
530 }
531 
532 
542 static void
543 run (void *cls,
544  char *const *args,
545  const char *cfgfile,
546  const struct GNUNET_CONFIGURATION_Handle *cfg)
547 {
548  (void) cls;
549  (void) args;
550  (void) cfgfile;
552  NULL);
554  if (NULL == gns)
555  {
556  GNUNET_break (0);
558  return;
559  }
561  NULL);
562 }
563 
564 
572 int
573 main (int argc,
574  char *const*argv)
575 {
576  int ret = 0;
579  "delay",
580  "RELATIVETIME",
581  gettext_noop (
582  "how long to wait between queries"),
583  &request_delay),
585  "timeout",
586  "RELATIVETIME",
587  gettext_noop (
588  "how long to wait for an answer"),
589  &timeout),
591  "g2d",
592  gettext_noop (
593  "look for GNS2DNS records instead of ANY"),
594  &g2d),
596  };
597 
598  if (GNUNET_OK !=
599  GNUNET_STRINGS_get_utf8_args (argc, argv,
600  &argc, &argv))
601  return 2;
604  if (GNUNET_OK !=
605  GNUNET_PROGRAM_run (argc,
606  argv,
607  "gnunet-gns-benchmark",
608  "resolve GNS names and measure performance",
609  options,
610  &run,
611  NULL))
612  ret = 1;
613  GNUNET_free_nz ((void *) argv);
614  return ret;
615 }
616 
617 
618 /* end of gnunet-gns-benchmark.c */
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_OPTION_END
Definition: 002.c:13
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
#define GNUNET_GNSRECORD_TYPE_GNS2DNS
Delegation to DNS.
#define gettext_noop(String)
Definition: gettext.h:70
static const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration we are using.
Definition: gnunet-abd.c:36
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static struct Request * todo_head
Yet to be started requests are kept in a DLL.
static int g2d
Look for GNS2DNS records specifically?
static struct GNUNET_GNS_Handle * gns
GNS handle.
static struct Request * succ_tail
Completed successful requests are kept in a DLL.
static void queue(const char *hostname, enum RequestCategory cat)
Add hostname to the list of requests to be made.
static void free_request(struct Request *req)
Free req and data structures reachable from it.
static void process_queue(void *cls)
Process request from the queue.
RequestCategory
We distinguish between different categories of requests, for which we track statistics separately.
@ RC_MAX
Must be last and match number of categories.
@ RC_PRIVATE
@ RC_SHARED
static unsigned int active_cnt
Number of requests we have concurrently active.
#define DEF_TIMEOUT
How long do we wait until we consider a request failed by default?
static struct GNUNET_SCHEDULER_Task * t
Main task.
static struct GNUNET_TIME_Relative latency_sum[RC_MAX]
Sum of the observed latencies of successful queries, per category.
static struct Request * act_head
Active requests are kept in a DLL.
static void do_shutdown(void *cls)
Output statistics, then clean up and terminate the process.
static struct Request * todo_tail
Yet to be started requests are kept in a DLL.
static int compare_req(const void *c1, const void *c2)
Compare two requests by latency for qsort().
static unsigned int failures[RC_MAX]
Number of replies we got per category.
static struct GNUNET_TIME_Relative timeout
Timeout for requests.
static void run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
Process requests from the queue, then if the queue is not empty, try again.
static struct GNUNET_TIME_Relative request_delay
Delay between requests.
static void process_result(void *cls, int gns_tld, uint32_t rd_count, const struct GNUNET_GNSRECORD_Data *rd)
Function called with the result of a GNS resolution.
static unsigned int lookups[RC_MAX]
Number of lookups we performed overall per category.
static struct Request * act_tail
Active requests are kept in a DLL.
int main(int argc, char *const *argv)
Call with list of names with numeric category to query.
#define DEF_REQUEST_DELAY
How long do we wait at least between requests by default?
static unsigned int replies[RC_MAX]
Number of replies we got per category.
static void process_stdin(void *cls)
Begin processing hostnames from stdin.
static struct Request * succ_head
Completed successful requests are kept in a DLL.
static unsigned int rd_count
Number of records for currently parsed set.
static struct GNUNET_GNSRECORD_Data rd[50]
The record data under a single label.
static char * rp
Relying party.
static struct GNUNET_TIME_Relative duration
How long do we run the test?
static char * hostname
Our hostname; we give this to all the peers we start.
API to the GNS service.
API that can be used to manipulate GNS record data.
#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.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_relative_time(char shortName, const char *name, const char *argumentHelp, const char *description, struct GNUNET_TIME_Relative *val)
Allow user to specify a struct GNUNET_TIME_Relative (using human-readable "fancy" time).
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.
void GNUNET_GNS_disconnect(struct GNUNET_GNS_Handle *handle)
Shutdown connection with the GNS service.
Definition: gns_api.c:290
void * GNUNET_GNS_lookup_with_tld_cancel(struct GNUNET_GNS_LookupWithTldRequest *ltr)
Cancel pending lookup request.
Definition: gns_tld_api.c:332
struct GNUNET_GNS_LookupWithTldRequest * GNUNET_GNS_lookup_with_tld(struct GNUNET_GNS_Handle *handle, const char *name, uint32_t type, enum GNUNET_GNS_LocalOptions options, GNUNET_GNS_LookupResultProcessor2 proc, void *proc_cls)
Perform an asynchronous lookup operation on the GNS, determining the zone using the TLD of the given ...
Definition: gns_tld_api.c:241
struct GNUNET_GNS_Handle * GNUNET_GNS_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Initialize the connection with the GNS service.
Definition: gns_api.c:268
@ GNUNET_GNS_LO_DEFAULT
Defaults, look in cache, then in DHT.
#define GNUNET_GNSRECORD_TYPE_ANY
Record type indicating any record/'*'.
#define GNUNET_log(kind,...)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
@ GNUNET_OK
@ GNUNET_YES
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_free_nz(ptr)
Wrapper around free.
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
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:562
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1299
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
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_at(struct GNUNET_TIME_Absolute at, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run at the specified time.
Definition: scheduler.c:1249
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:975
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1272
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
struct GNUNET_TIME_Relative GNUNET_TIME_relative_add(struct GNUNET_TIME_Relative a1, struct GNUNET_TIME_Relative a2)
Add relative times together.
Definition: time.c:585
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_add(struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Relative duration)
Add a given relative duration to the given start time.
Definition: time.c:450
struct GNUNET_TIME_Relative GNUNET_TIME_relative_divide(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Divide relative time by a given factor.
Definition: time.c:550
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
static struct GNUNET_TIME_Relative delta
Definition: speedup.c:36
Definition of a command line option.
Connection to the GNS service.
Definition: gns_api.h:36
Handle to a lookup request.
Definition: gns_tld_api.c:45
Entry in list of pending tasks.
Definition: scheduler.c:136
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.
Request we should make.
char * hostname
Hostname we are resolving.
struct Request * next
Requests are kept in a DLL.
struct GNUNET_TIME_Relative latency
Observed latency, set once we got a reply.
enum RequestCategory cat
Category of the request.
struct GNUNET_TIME_Absolute op_start_time
While we are fetching the record, the value is set to the starting time of the GNS operation.
struct Request * prev
Requests are kept in a DLL.
struct GNUNET_GNS_LookupWithTldRequest * lr
Socket used to make the request, NULL if not active.