f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * Copyright (C) 2000, 2001 Nominum, Inc.
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * Permission to use, copy, modify, and distribute this software for any
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * purpose with or without fee is hereby granted, provided that the above
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * copyright notice and this permission notice appear in all copies.
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * Copyright (C) 2004 - 2015 Nominum, Inc.
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * Permission to use, copy, modify, and distribute this software and its
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * documentation for any purpose with or without fee is hereby granted,
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * provided that the above copyright notice and this permission notice
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * appear in all copies.
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt *** DNS Resolution Performance Testing Tool
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt *** Version $Id: resperf.c 263304 2015-12-15 01:14:10Z bwelling $
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * Global stuff
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * This link links the query into the list of outstanding
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * queries or the list of available query IDs.
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * The list this query is on.
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt/* The target traffic level at the end of the ramp-up */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt/* The time period over which we ramp up traffic */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt/* How long to send constant traffic after the initial ramp-up */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt/* How long to wait for responses after sending traffic */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt/* Total duration of the traffic-sending part of the test */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt/* Total duration of the test */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt/* Interval between plot data points, in microseconds */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt/* The number of plot data points */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt/* The plot data file */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt/* The largest acceptable query loss when reporting max throughput */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt/* The maximum number of outstanding queries */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * The last plot data point containing actual data; this can
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * be less than than (n_buckets - 1) if the traffic sending
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * phase is cut short
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * The statistics for queries sent during one bucket_interval
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * of the traffic sending phase.
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunttypedef struct {
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt/* Pointer to array of n_buckets ramp_bucket structures */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * The ramp-up phase: we are steadily increasing traffic.
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * The sustain phase: we are sending traffic at a constant
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * The wait phase: we have stopped sending queries and are
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * just waiting for any remaining responses.
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt/* The time when the sustain/wait phase began */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Huntstatic isc_uint64_t sustain_phase_began, wait_phase_began;
f3ad877eb05befbc862b0233d985758c0caef29aEvan Huntstatic char *
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt snprintf(buf, sizeof(buf), "%.*f", precision, value);
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt unsigned int i;
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt bucket_interval = DEFAULT_BUCKET_INTERVAL * MILLION;
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "address family of DNS transport, inet or inet6", "any",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "the server to query", DEFAULT_SERVER_NAME, &server_name);
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "the port on which to query the server",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "the local address from which to send queries", NULL,
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "the local port from which to send queries",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "the timeout for query completion in seconds",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "socket send/receive buffer size in kilobytes", NULL,
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "set the DNSSEC OK bit (implies EDNS)", NULL, &dnssec);
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt perf_opt_add('y', perf_opt_string, "[alg:]name:secret",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt perf_opt_add('i', perf_opt_timeval, "plot_interval",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "the time interval between plot data points, in seconds",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt stringify(DEFAULT_BUCKET_INTERVAL, 1), &bucket_interval);
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "the maximum number of queries per second",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "the name of the plot data file", plotfile, &plotfile);
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "the ramp-up time in seconds",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt perf_opt_add('c', perf_opt_timeval, "constant_traffic_time",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "how long to send constant traffic, in seconds",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt stringify(DEFAULT_SUSTAIN_TIME, 0), &sustain_time);
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt perf_opt_add('L', perf_opt_double, "max_query_loss",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "the maximum acceptable query loss, in percent",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt stringify(max_loss_percent, 0), &max_loss_percent);
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt perf_opt_add('q', perf_opt_uint, "num_outstanding",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "the maximum number of queries outstanding",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt stringify(DEFAULT_MAX_OUTSTANDING, 0), &max_outstanding);
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt if (max_outstanding > nsocks * DEFAULT_MAX_OUTSTANDING)
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt perf_log_fatal("number of outstanding packets (%u) must not "
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt perf_log_fatal("rampup_time and constant_traffic_time must not "
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "both be 0");
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt queries = isc_mem_get(mctx, max_outstanding * sizeof(query_info));
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt for (i = 0; i < max_outstanding; i++) {
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt ISC_LIST_APPEND(instanding_list, &queries[i], link);
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt perf_net_parseserver(sock_family, server_name, server_port,
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt perf_net_parselocal(isc_sockaddr_pf(&server_addr),
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt tsigkey = perf_dns_parsetsigkey(tsigkey_str, mctx);
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt for (i = 0; i < nsocks; i++)
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt socks[i] = perf_net_opensocket(&server_addr, &local_addr, i,
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt unsigned int i;
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt for (i = 0; i < nsocks; i++)
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt isc_mem_put(mctx, queries, max_outstanding * sizeof(query_info));
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt isc_mem_put(mctx, buckets, n_buckets * sizeof(ramp_bucket));
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt/* Find the ramp_bucket for queries sent at time "when" */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt isc_uint64_t sent_at = when - time_of_program_start;
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt int i = (int) ((n_buckets * sent_at) / traffic_time);
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * Guard against array bounds violations due to roundoff
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * errors or scheduling jitter
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * print_statistics:
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * Print out statistics based on the results of the test
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt isc_uint64_t run_time = time_of_end_of_run - time_of_program_start;
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt printf(" Queries sent: %" ISC_PRINT_QUADFORMAT "u\n",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt printf(" Queries completed: %" ISC_PRINT_QUADFORMAT "u\n",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt printf(" Queries lost: %" ISC_PRINT_QUADFORMAT "u\n",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt for (i = 0; i < 16; i++) {
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt (rcodecounts[i] * 100.0) / num_responses_received);
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt /* Find the maximum throughput, subject to the -L option */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt for (i = 0; i <= last_bucket_used; i++) {
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt b->responses / (bucket_interval / (double) MILLION);
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt (b->queries - b->responses) / (double) b->queries : 0.0;
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt printf(" Maximum throughput: %.6lf qps\n", max_throughput);
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt printf(" Lost at that point: %.2f%%\n", loss_at_max_throughput);
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt for (i = 0; i < n; i++) {
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt p[i].queries = p[i].responses = p[i].failures = 0;
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * Send a query based on a line of input.
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * Return ISC_R_NOMORE if we ran out of query IDs.
f3ad877eb05befbc862b0233d985758c0caef29aEvan Huntdo_one_line(isc_buffer_t *lines, isc_buffer_t *msg) {
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt result = perf_datafile_next(input, lines, ISC_FALSE);
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt result = perf_dns_buildrequest(NULL, (isc_textregion_t *) &used,
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt printf("[Status] Ramp-up done, sending constant traffic\n");
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * try_process_response:
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * Receive from the given socket & process an individual response packet.
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * Remove it from the list of open queries (status[]) and decrement the
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt * number of outstanding queries if it matches an open query.
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt n = recvfrom(socks[sockindex], packet_buffer, sizeof(packet_buffer),
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt if (n < 0) {
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt } else if (n < 4) {
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt latency = (time_now - q->sent_timestamp) / (double)MILLION;
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt if (!(rcode == dns_rcode_noerror || rcode == dns_rcode_nxdomain))
f3ad877eb05befbc862b0233d985758c0caef29aEvan Huntstatic inline int
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt } else { /* PHASE_SUSTAIN */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt return 0.5 * max_qps * (ramp_time / (double)MILLION) +
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt printf("DNS Resolution Performance Testing Tool\n"
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt isc_buffer_init(&lines, input_data, sizeof(input_data));
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt max_packet_size = edns ? MAX_EDNS_PACKET : MAX_UDP_PACKET;
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt isc_buffer_init(&msg, outpacket_buffer, max_packet_size);
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt n_buckets = (traffic_time + bucket_interval - 1) / bucket_interval;
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt printf("[Status] Command line: %s", isc_file_basename(argv[0]));
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "ending test at %.0f qps\n",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt printf("[Status] Reached %u outstanding queries\n",
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt /* Print column headers */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "responses_per_sec failures_per_sec "
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt "avg_latency\n");
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt /* Don't print unused buckets */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt last_bucket_used = find_bucket(wait_phase_began) - buckets;
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt /* Don't print a partial bucket at the end */
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt for (i = 0; i <= last_bucket_used; i++) {
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt t <= ramp_dtime ? (t / ramp_dtime) * max_qps : max_qps;
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt buckets[i].latency_sum / buckets[i].responses : 0;
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt double interval = bucket_interval / (double) MILLION;
f3ad877eb05befbc862b0233d985758c0caef29aEvan Hunt fprintf(plotf, "%7.3f %8.2f %8.2f %8.2f %8.2f %8.6f\n",