aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-05-12 10:31:38 +0200
committerChristian Grothoff <christian@grothoff.org>2018-05-12 10:31:38 +0200
commit620bdac536dff4b17317d9d20b8a6840836d6490 (patch)
treec26d468621ac29b1d6d3b4cd0682b413bffca3aa /src
parente7b6bcdfd095ba3dfc3f8721a2a1f8a7f69d792b (diff)
downloadgnunet-620bdac536dff4b17317d9d20b8a6840836d6490.tar.gz
gnunet-620bdac536dff4b17317d9d20b8a6840836d6490.zip
add first sketch of gns benchmarking tool
Diffstat (limited to 'src')
-rw-r--r--src/gns/.gitignore1
-rw-r--r--src/gns/Makefile.am11
-rw-r--r--src/gns/gnunet-gns-benchmark.c495
3 files changed, 507 insertions, 0 deletions
diff --git a/src/gns/.gitignore b/src/gns/.gitignore
index 5aecfd51d..2b9a18f21 100644
--- a/src/gns/.gitignore
+++ b/src/gns/.gitignore
@@ -3,3 +3,4 @@ gnunet-bcd
3gnunet-dns2gns 3gnunet-dns2gns
4gnunet-gns 4gnunet-gns
5gnunet-gns-proxy 5gnunet-gns-proxy
6gnunet-gns-benchmark
diff --git a/src/gns/Makefile.am b/src/gns/Makefile.am
index b2b81d73f..ac11c834e 100644
--- a/src/gns/Makefile.am
+++ b/src/gns/Makefile.am
@@ -76,6 +76,9 @@ bin_PROGRAMS = \
76 $(DO_NONPOSIX_GNSIMPORT) \ 76 $(DO_NONPOSIX_GNSIMPORT) \
77 gnunet-gns 77 gnunet-gns
78 78
79noinst_PROGRAMS = \
80 gnunet-gns-benchmark
81
79if HAVE_MHD 82if HAVE_MHD
80if LINUX 83if LINUX
81bin_PROGRAMS += gnunet-bcd 84bin_PROGRAMS += gnunet-bcd
@@ -114,6 +117,14 @@ gnunet_gns_LDADD = \
114 $(top_builddir)/src/util/libgnunetutil.la \ 117 $(top_builddir)/src/util/libgnunetutil.la \
115 $(GN_LIBINTL) 118 $(GN_LIBINTL)
116 119
120gnunet_gns_benchmark_SOURCES = \
121 gnunet-gns-benchmark.c
122gnunet_gns_benchmark_LDADD = \
123 libgnunetgns.la \
124 $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \
125 $(top_builddir)/src/util/libgnunetutil.la \
126 $(GN_LIBINTL)
127
117 128
118gnunet_bcd_SOURCES = \ 129gnunet_bcd_SOURCES = \
119 gnunet-bcd.c 130 gnunet-bcd.c
diff --git a/src/gns/gnunet-gns-benchmark.c b/src/gns/gnunet-gns-benchmark.c
new file mode 100644
index 000000000..f1efaac09
--- /dev/null
+++ b/src/gns/gnunet-gns-benchmark.c
@@ -0,0 +1,495 @@
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
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20/**
21 * @file src/gns/gnunet-gns-benchmark.c
22 * @brief issue many queries to GNS and compute performance statistics
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include <gnunet_util_lib.h>
27#include <gnunet_gnsrecord_lib.h>
28#include <gnunet_gns_service.h>
29
30
31/**
32 * How long do we wait at least between requests by default?
33 */
34#define DEF_REQUEST_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 1)
35
36/**
37 * How long do we wait until we consider a request failed by default?
38 */
39#define DEF_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
40
41
42/**
43 * We distinguish between different categories of
44 * requests, for which we track statistics separately.
45 * However, this process does not change how it acts
46 * based on the category.
47 */
48enum RequestCategory
49{
50 RC_SHARED = 0,
51 RC_PRIVATE = 1,
52 /**
53 * Must be last and match number of categories.
54 */
55 RC_MAX = 2
56};
57
58
59/**
60 * Request we should make. We keep this struct in memory per request,
61 * thus optimizing it is crucial for the overall memory consumption of
62 * the zone importer.
63 */
64struct Request
65{
66
67 /**
68 * Active requests are kept in a DLL.
69 */
70 struct Request *next;
71
72 /**
73 * Active requests are kept in a DLL.
74 */
75 struct Request *prev;
76
77 /**
78 * Socket used to make the request, NULL if not active.
79 */
80 struct GNUNET_GNS_LookupWithTldRequest *lr;
81
82 /**
83 * Hostname we are resolving, allocated at the end of
84 * this struct (optimizing memory consumption by reducing
85 * total number of allocations).
86 */
87 char *hostname;
88
89 /**
90 * While we are fetching the record, the value is set to the
91 * starting time of the GNS operation.
92 */
93 struct GNUNET_TIME_Absolute op_start_time;
94
95 /**
96 * Observed latency, set once we got a reply.
97 */
98 struct GNUNET_TIME_Relative latency;
99
100 /**
101 * Category of the request.
102 */
103 enum RequestCategory cat;
104
105};
106
107
108/**
109 * GNS handle.
110 */
111static struct GNUNET_GNS_Handle *gns;
112
113/**
114 * Number of lookups we performed overall per category.
115 */
116static unsigned int lookups[RC_MAX];
117
118/**
119 * Number of replies we got per category.
120 */
121static unsigned int replies[RC_MAX];
122
123/**
124 * Number of replies we got per category.
125 */
126static unsigned int failures[RC_MAX];
127
128/**
129 * Sum of the observed latencies of successful queries,
130 * per category.
131 */
132static struct GNUNET_TIME_Relative latency_sum[RC_MAX];
133
134/**
135 * Active requests are kept in a DLL.
136 */
137static struct Request *act_head;
138
139/**
140 * Active requests are kept in a DLL.
141 */
142static struct Request *act_tail;
143
144/**
145 * Completed successful requests are kept in a DLL.
146 */
147static struct Request *succ_head;
148
149/**
150 * Completed successful requests are kept in a DLL.
151 */
152static struct Request *succ_tail;
153
154/**
155 * Yet to be started requests are kept in a DLL.
156 */
157static struct Request *todo_head;
158
159/**
160 * Yet to be started requests are kept in a DLL.
161 */
162static struct Request *todo_tail;
163
164/**
165 * Main task.
166 */
167static struct GNUNET_SCHEDULER_Task *t;
168
169/**
170 * Delay between requests.
171 */
172static struct GNUNET_TIME_Relative request_delay;
173
174/**
175 * Timeout for requests.
176 */
177static struct GNUNET_TIME_Relative timeout;
178
179
180/**
181 * Free @a req and data structures reachable from it.
182 *
183 * @param req request to free
184 */
185static void
186free_request (struct Request *req)
187{
188 if (NULL != req->lr)
189 GNUNET_GNS_lookup_with_tld_cancel (req->lr);
190 GNUNET_free (req);
191}
192
193
194/**
195 * Function called with the result of a GNS resolution.
196 *
197 * @param cls closure with the `struct Request`
198 * @param gns_tld #GNUNET_YES if GNS lookup was attempted
199 * @param rd_count number of records in @a rd
200 * @param rd the records in reply
201 */
202static void
203process_result (void *cls,
204 int gns_tld,
205 uint32_t rd_count,
206 const struct GNUNET_GNSRECORD_Data *rd)
207{
208 struct Request *req = cls;
209
210 (void) gns_tld;
211 (void) rd_count;
212 (void) rd;
213 req->lr = NULL;
214 req->latency = GNUNET_TIME_absolute_get_duration (req->op_start_time);
215 GNUNET_CONTAINER_DLL_remove (act_head,
216 act_tail,
217 req);
218 GNUNET_CONTAINER_DLL_insert (succ_head,
219 succ_tail,
220 req);
221 replies[req->cat]++;
222 latency_sum[req->cat]
223 = GNUNET_TIME_relative_add (latency_sum[req->cat],
224 req->latency);
225}
226
227
228/**
229 * Process request from the queue.
230 *
231 * @param cls NULL
232 */
233static void
234process_queue (void *cls)
235{
236 struct Request *req;
237 struct GNUNET_TIME_Relative duration;
238
239 (void) cls;
240 /* check for expired requests */
241 while (NULL != (req = act_head))
242 {
243 duration = GNUNET_TIME_absolute_get_duration (req->op_start_time);
244 if (duration.rel_value_us < timeout.rel_value_us)
245 break;
246 GNUNET_CONTAINER_DLL_remove (act_head,
247 act_tail,
248 req);
249 failures[req->cat]++;
250 free_request (req);
251 }
252 if (NULL == (req = todo_head))
253 {
254 struct GNUNET_TIME_Absolute at;
255
256 if (NULL == (req = act_head))
257 {
258 GNUNET_SCHEDULER_shutdown ();
259 return;
260 }
261 at = GNUNET_TIME_absolute_add (req->op_start_time,
262 timeout);
263 t = GNUNET_SCHEDULER_add_at (at,
264 &process_queue,
265 NULL);
266 return;
267 }
268 GNUNET_CONTAINER_DLL_remove (todo_head,
269 todo_tail,
270 req);
271 GNUNET_CONTAINER_DLL_insert_tail (act_head,
272 act_tail,
273 req);
274 lookups[req->cat]++;
275 req->op_start_time = GNUNET_TIME_absolute_get ();
276 req->lr = GNUNET_GNS_lookup_with_tld (gns,
277 req->hostname,
278 GNUNET_GNSRECORD_TYPE_ANY,
279 GNUNET_GNS_LO_DEFAULT,
280 &process_result,
281 req);
282 t = GNUNET_SCHEDULER_add_delayed (request_delay,
283 &process_queue,
284 NULL);
285}
286
287
288/**
289 * Clean up and terminate the process.
290 *
291 * @param cls NULL
292 */
293static void
294do_shutdown (void *cls)
295{
296 struct Request *req;
297
298 (void) cls;
299 /* FIXME: calculate statistics */
300 if (NULL != gns)
301 {
302 GNUNET_GNS_disconnect (gns);
303 gns = NULL;
304 }
305 if (NULL != t)
306 {
307 GNUNET_SCHEDULER_cancel (t);
308 t = NULL;
309 }
310 while (NULL != (req = act_head))
311 {
312 GNUNET_CONTAINER_DLL_remove (act_head,
313 act_tail,
314 req);
315 free_request (req);
316 }
317 while (NULL != (req = succ_head))
318 {
319 GNUNET_CONTAINER_DLL_remove (succ_head,
320 succ_tail,
321 req);
322 free_request (req);
323 }
324 while (NULL != (req = todo_head))
325 {
326 GNUNET_CONTAINER_DLL_remove (todo_head,
327 todo_tail,
328 req);
329 free_request (req);
330 }
331}
332
333
334/**
335 * Add @a hostname to the list of requests to be made.
336 *
337 * @param hostname name to resolve
338 * @param cat category of the @a hostname
339 */
340static void
341queue (const char *hostname,
342 enum RequestCategory cat)
343{
344 struct Request *req;
345 const char *dot;
346 size_t hlen;
347
348 dot = strchr (hostname,
349 (unsigned char) '.');
350 if (NULL == dot)
351 {
352 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
353 "Refusing invalid hostname `%s' (lacks '.')\n",
354 hostname);
355 return;
356 }
357 hlen = strlen (hostname) + 1;
358 req = GNUNET_malloc (sizeof (struct Request) + hlen);
359 req->cat = cat;
360 req->hostname = (char *) &req[1];
361 memcpy (req->hostname,
362 hostname,
363 hlen);
364 GNUNET_CONTAINER_DLL_insert (todo_head,
365 todo_tail,
366 req);
367}
368
369
370/**
371 * Begin processing hostnames from stdin.
372 *
373 * @param cls NULL
374 */
375static void
376process_stdin (void *cls)
377{
378 static struct GNUNET_TIME_Absolute last;
379 static uint64_t idot;
380 char hn[270];
381
382 (void) cls;
383 t = NULL;
384 while (NULL !=
385 fgets (hn,
386 sizeof (hn),
387 stdin))
388 {
389 if (strlen(hn) > 0)
390 hn[strlen(hn)-1] = '\0'; /* eat newline */
391 if (0 == idot)
392 last = GNUNET_TIME_absolute_get ();
393 idot++;
394 if (0 == idot % 10000)
395 {
396 struct GNUNET_TIME_Relative delta;
397
398 delta = GNUNET_TIME_absolute_get_duration (last);
399 last = GNUNET_TIME_absolute_get ();
400 fprintf (stderr,
401 "Imported 10000 records in %s\n",
402 GNUNET_STRINGS_relative_time_to_string (delta,
403 GNUNET_YES));
404 }
405 queue (hn,
406 RC_SHARED); // FIXME: parse input line!
407 }
408 fprintf (stderr,
409 "Done reading %llu domain names\n",
410 (unsigned long long) idot);
411 t = GNUNET_SCHEDULER_add_now (&process_queue,
412 NULL);
413}
414
415
416/**
417 * Process requests from the queue, then if the queue is
418 * not empty, try again.
419 *
420 * @param cls NULL
421 * @param args remaining command-line arguments
422 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
423 * @param cfg configuration
424 */
425static void
426run (void *cls,
427 char *const *args,
428 const char *cfgfile,
429 const struct GNUNET_CONFIGURATION_Handle *cfg)
430{
431 (void) cls;
432 (void) args;
433 (void) cfgfile;
434 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
435 NULL);
436 gns = GNUNET_GNS_connect (cfg);
437 if (NULL == gns)
438 {
439 GNUNET_break (0);
440 GNUNET_SCHEDULER_shutdown ();
441 return;
442 }
443 t = GNUNET_SCHEDULER_add_now (&process_stdin,
444 NULL);
445}
446
447
448/**
449 * Call with list of names with numeric category to query.
450 *
451 * @param argc unused
452 * @param argv unused
453 * @return 0 on success
454 */
455int
456main (int argc,
457 char *const*argv)
458{
459 int ret = 0;
460 struct GNUNET_GETOPT_CommandLineOption options[] = {
461 GNUNET_GETOPT_option_relative_time ('d',
462 "delay",
463 "RELATIVETIME",
464 gettext_noop ("how long to wait between queries"),
465 &request_delay),
466 GNUNET_GETOPT_option_relative_time ('t',
467 "timeout",
468 "RELATIVETIME",
469 gettext_noop ("how long to wait for an answer"),
470 &timeout),
471 GNUNET_GETOPT_OPTION_END
472 };
473
474 if (GNUNET_OK !=
475 GNUNET_STRINGS_get_utf8_args (argc, argv,
476 &argc, &argv))
477 return 2;
478 timeout = DEF_TIMEOUT;
479 request_delay = DEF_REQUEST_DELAY;
480 if (GNUNET_OK !=
481 GNUNET_PROGRAM_run (argc,
482 argv,
483 "gnunet-gns-benchmark",
484 "resolve GNS names and measure performance",
485 options,
486 &run,
487 NULL))
488 ret = 1;
489 GNUNET_free ((void*) argv);
490 fprintf (stderr,
491 "Statistics here\n");
492 return ret;
493}
494
495/* end of gnunet-gns-benchmark.c */