GNUnet 0.21.1
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>
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{
56 RC_MAX = 2
57};
58
59
65struct Request
66{
70 struct Request *next;
71
75 struct Request *prev;
76
81
87 const char *hostname;
88
94
99
104};
105
106
110static struct GNUNET_GNS_Handle *gns;
111
115static unsigned int lookups[RC_MAX];
116
120static unsigned int replies[RC_MAX];
121
125static unsigned int failures[RC_MAX];
126
132
136static struct Request *act_head;
137
141static struct Request *act_tail;
142
146static struct Request *succ_head;
147
151static struct Request *succ_tail;
152
156static struct Request *todo_head;
157
161static struct Request *todo_tail;
162
167
172
177
181static unsigned int active_cnt;
182
186static int g2d;
187
193static void
195{
196 if (NULL != req->lr)
198 GNUNET_free (req);
199}
200
201
210static void
211process_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
245static void
246process_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);
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);
308 NULL);
309}
310
311
319static int
320compare_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
339static void
340do_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
444static void
445queue (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
479static void
480process_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
542static void
543run (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
572int
573main (int argc,
574 char *const*argv)
575{
576 int ret = 0;
579 "delay",
580 "RELATIVETIME",
582 "how long to wait between queries"),
585 "timeout",
586 "RELATIVETIME",
588 "how long to wait for an answer"),
589 &timeout),
591 "g2d",
593 "look for GNS2DNS records instead of ANY"),
594 &g2d),
596 };
597
598 if (GNUNET_OK !=
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 gettext_noop(String)
Definition: gettext.h:70
static int ret
Final status code.
Definition: gnunet-arm.c:94
static struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition: gnunet-arm.c:109
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
Option '-d': duration of the mapping.
Definition: gnunet-vpn.c:90
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:289
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:240
void * GNUNET_GNS_lookup_with_tld_cancel(struct GNUNET_GNS_LookupWithTldRequest *ltr)
Cancel pending lookup request.
Definition: gns_tld_api.c:331
struct GNUNET_GNS_Handle * GNUNET_GNS_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Initialize the connection with the GNS service.
Definition: gns_api.c:267
@ 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:567
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:1255
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:1340
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:981
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:1305
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:1278
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:1230
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
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:570
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
static struct GNUNET_TIME_Relative delta
Definition: speedup.c:36
#define GNUNET_GNSRECORD_TYPE_GNS2DNS
Delegation to DNS.
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:44
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, allocated at the end of this struct (optimizing memory consumption by redu...
struct Request * next
Active requests are kept in a DLL.
struct GNUNET_TIME_Relative latency
Observed latency, set once we got a reply.
const char * hostname
Hostname we are resolving, allocated at the end of this struct (optimizing memory consumption by redu...
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 DNS operation.
struct Request * prev
Active requests are kept in a DLL.
struct GNUNET_GNS_LookupWithTldRequest * lr
Socket used to make the request, NULL if not active.