This file is part of GNUnet
Copyright (C) 2018 GNUnet e.V.
- GNUnet is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3, or (at your
- option) any later version.
+ GNUnet is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
GNUnet is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
- You should have received a copy of the GNU General Public License
- along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
+ SPDX-License-Identifier: AGPL3.0-or-later
*/
/**
* @file src/gns/gnunet-gns-benchmark.c
* this struct (optimizing memory consumption by reducing
* total number of allocations).
*/
- char *hostname;
+ const char *hostname;
/**
* While we are fetching the record, the value is set to the
* Observed latency, set once we got a reply.
*/
struct GNUNET_TIME_Relative latency;
-
+
/**
* Category of the request.
*/
enum RequestCategory cat;
-
+
};
*/
static struct GNUNET_TIME_Relative timeout;
+/**
+ * Number of requests we have concurrently active.
+ */
+static unsigned int active_cnt;
+
+/**
+ * Look for GNS2DNS records specifically?
+ */
+static int g2d;
/**
* Free @a req and data structures reachable from it.
(void) gns_tld;
(void) rd_count;
(void) rd;
+ active_cnt--;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got response for request `%s'\n",
+ req->hostname);
req->lr = NULL;
req->latency = GNUNET_TIME_absolute_get_duration (req->op_start_time);
GNUNET_CONTAINER_DLL_remove (act_head,
struct GNUNET_TIME_Relative duration;
(void) cls;
+ t = NULL;
/* check for expired requests */
while (NULL != (req = act_head))
{
GNUNET_CONTAINER_DLL_remove (act_head,
act_tail,
req);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Failing request `%s' due to timeout\n",
+ req->hostname);
failures[req->cat]++;
+ active_cnt--;
free_request (req);
}
if (NULL == (req = todo_head))
{
struct GNUNET_TIME_Absolute at;
-
+
if (NULL == (req = act_head))
{
GNUNET_SCHEDULER_shutdown ();
act_tail,
req);
lookups[req->cat]++;
+ active_cnt++;
req->op_start_time = GNUNET_TIME_absolute_get ();
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Starting request `%s' (%u in parallel)\n",
+ req->hostname,
+ active_cnt);
req->lr = GNUNET_GNS_lookup_with_tld (gns,
req->hostname,
- GNUNET_GNSRECORD_TYPE_ANY,
+ g2d
+ ? GNUNET_GNSRECORD_TYPE_GNS2DNS
+ : GNUNET_GNSRECORD_TYPE_ANY,
GNUNET_GNS_LO_DEFAULT,
&process_result,
req);
/**
- * Clean up and terminate the process.
+ * Compare two requests by latency for qsort().
+ *
+ * @param c1 pointer to `struct Request *`
+ * @param c2 pointer to `struct Request *`
+ * @return -1 if c1<c2, 1 if c1>c2, 0 if c1==c2.
+ */
+static int
+compare_req (const void *c1,
+ const void *c2)
+{
+ const struct Request *r1 = *(void **) c1;
+ const struct Request *r2 = *(void **) c2;
+
+ if (r1->latency.rel_value_us < r2->latency.rel_value_us)
+ return -1;
+ if (r1->latency.rel_value_us > r2->latency.rel_value_us)
+ return 1;
+ return 0;
+}
+
+
+/**
+ * Output statistics, then clean up and terminate the process.
*
* @param cls NULL
*/
do_shutdown (void *cls)
{
struct Request *req;
+ struct Request **ra[RC_MAX];
+ unsigned int rp[RC_MAX];
(void) cls;
- /* FIXME: calculate statistics */
- if (NULL != gns)
+ for (enum RequestCategory rc = 0;rc < RC_MAX;rc++)
{
- GNUNET_GNS_disconnect (gns);
- gns = NULL;
+ ra[rc] = GNUNET_new_array (replies[rc],
+ struct Request *);
+ rp[rc] = 0;
+ }
+ for (req = succ_head;NULL != req; req = req->next)
+ {
+ GNUNET_assert (rp[req->cat] < replies[req->cat]);
+ ra[req->cat][rp[req->cat]++] = req;
+ }
+ for (enum RequestCategory rc = 0;rc < RC_MAX;rc++)
+ {
+ unsigned int off;
+
+ fprintf (stdout,
+ "Category %u\n",
+ rc);
+ fprintf (stdout,
+ "\tlookups: %u replies: %u failures: %u\n",
+ lookups[rc],
+ replies[rc],
+ failures[rc]);
+ if (0 == rp[rc])
+ continue;
+ qsort (ra[rc],
+ rp[rc],
+ sizeof (struct Request *),
+ &compare_req);
+ latency_sum[rc] = GNUNET_TIME_relative_divide (latency_sum[rc],
+ replies[rc]);
+ fprintf (stdout,
+ "\taverage: %s\n",
+ GNUNET_STRINGS_relative_time_to_string (latency_sum[rc],
+ GNUNET_YES));
+ off = rp[rc] * 50 / 100;
+ fprintf (stdout,
+ "\tmedian(50): %s\n",
+ GNUNET_STRINGS_relative_time_to_string (ra[rc][off]->latency,
+ GNUNET_YES));
+ off = rp[rc] * 75 / 100;
+ fprintf (stdout,
+ "\tquantile(75): %s\n",
+ GNUNET_STRINGS_relative_time_to_string (ra[rc][off]->latency,
+ GNUNET_YES));
+ off = rp[rc] * 90 / 100;
+ fprintf (stdout,
+ "\tquantile(90): %s\n",
+ GNUNET_STRINGS_relative_time_to_string (ra[rc][off]->latency,
+ GNUNET_YES));
+ off = rp[rc] * 99 / 100;
+ fprintf (stdout,
+ "\tquantile(99): %s\n",
+ GNUNET_STRINGS_relative_time_to_string (ra[rc][off]->latency,
+ GNUNET_YES));
+ GNUNET_free (ra[rc]);
}
if (NULL != t)
{
req);
free_request (req);
}
+ if (NULL != gns)
+ {
+ GNUNET_GNS_disconnect (gns);
+ gns = NULL;
+ }
}
req = GNUNET_malloc (sizeof (struct Request) + hlen);
req->cat = cat;
req->hostname = (char *) &req[1];
- memcpy (req->hostname,
- hostname,
- hlen);
+ GNUNET_memcpy (&req[1],
+ hostname,
+ hlen);
GNUNET_CONTAINER_DLL_insert (todo_head,
todo_tail,
req);
{
static struct GNUNET_TIME_Absolute last;
static uint64_t idot;
- char hn[270];
+ unsigned int cat;
+ char hn[256];
+ char in[270];
(void) cls;
t = NULL;
while (NULL !=
- fgets (hn,
- sizeof (hn),
+ fgets (in,
+ sizeof (in),
stdin))
{
- if (strlen(hn) > 0)
- hn[strlen(hn)-1] = '\0'; /* eat newline */
+ if (strlen(in) > 0)
+ hn[strlen(in)-1] = '\0'; /* eat newline */
+ if ( (2 != sscanf (in,
+ "%u %255s",
+ &cat,
+ hn)) ||
+ (cat >= RC_MAX) )
+ {
+ fprintf (stderr,
+ "Malformed input line `%s', skipping\n",
+ in);
+ continue;
+ }
if (0 == idot)
last = GNUNET_TIME_absolute_get ();
idot++;
- if (0 == idot % 10000)
+ if (0 == idot % 100000)
{
struct GNUNET_TIME_Relative delta;
delta = GNUNET_TIME_absolute_get_duration (last);
last = GNUNET_TIME_absolute_get ();
fprintf (stderr,
- "Imported 10000 records in %s\n",
+ "Read 100000 domain names in %s\n",
GNUNET_STRINGS_relative_time_to_string (delta,
GNUNET_YES));
}
queue (hn,
- RC_SHARED); // FIXME: parse input line!
+ (enum RequestCategory) cat);
}
fprintf (stderr,
"Done reading %llu domain names\n",
"RELATIVETIME",
gettext_noop ("how long to wait for an answer"),
&timeout),
+ GNUNET_GETOPT_option_flag ('2',
+ "g2d",
+ gettext_noop ("look for GNS2DNS records instead of ANY"),
+ &g2d),
GNUNET_GETOPT_OPTION_END
};
NULL))
ret = 1;
GNUNET_free ((void*) argv);
- fprintf (stderr,
- "Statistics here\n");
return ret;
}