Adding upstream version 2.11.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
6dd69c3878
commit
7ffd64128a
50 changed files with 895 additions and 132 deletions
48
CHANGES
48
CHANGES
|
@ -1,3 +1,51 @@
|
||||||
|
2023-02-08 Jerry Lundström
|
||||||
|
|
||||||
|
Release 2.11.0
|
||||||
|
|
||||||
|
A couple of new features this release courtesy of Petr Špaček
|
||||||
|
@pspacek (ISC) and a bunch of bugfixes.
|
||||||
|
|
||||||
|
First off `dnsperf` can now do verbose statistics during each interval
|
||||||
|
when using `-S`, see long option `verbose-interval-stats`.
|
||||||
|
|
||||||
|
Next is a new latency histogram output using data structures (hg64)
|
||||||
|
created by Tony Finch @fanf2 (ISC), see long option
|
||||||
|
`latency-histogram`. These will also be shown during `-S` when used
|
||||||
|
together with `verbose-interval-stats`.
|
||||||
|
|
||||||
|
Lastly a small change to boolean long options, they no longer require
|
||||||
|
a value (`=yes`) to be enabled.
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
- Make sure the number of outstanding queries don't go negative,
|
||||||
|
happens if queries are timed out before being sent
|
||||||
|
- Fixed #208:
|
||||||
|
- `recv_one()`: Fix handling errno, only store EAGAIN if no other
|
||||||
|
error has been received
|
||||||
|
- `do_recv()`: Don't break on error as it will count it as a received
|
||||||
|
message
|
||||||
|
- Treat `EBADF` as `EAGAIN` for stateful connections, receive thread
|
||||||
|
might read from a closed socket if send thread is reconnecting
|
||||||
|
- `dnsperf`: warn if -c, -T, -q, -Q values are auto-adjusted
|
||||||
|
- Fixed #222: don't process unexpected message if the message is
|
||||||
|
suppressed
|
||||||
|
|
||||||
|
14db835 Opt arg
|
||||||
|
fb81481 Suppress unexpected
|
||||||
|
64b8c6d stats_t initialization
|
||||||
|
8290775 Fix first call to diff_stats
|
||||||
|
4f8bd24 Compile support histograms
|
||||||
|
a9b4f04 External code, latency histograms
|
||||||
|
d1f4b65 add detailed latency histograms
|
||||||
|
044e3a2 data structures for detailed latency histograms
|
||||||
|
ad3fb03 Opt, verbose statistics
|
||||||
|
38bc936 Command usage warnings
|
||||||
|
9f31595 Bad file descriptor
|
||||||
|
d3650eb Receive socket error handling
|
||||||
|
84c8e72 Negative outstanding
|
||||||
|
e7df5e1 Clarify meaning of dnsperf -S output in the man page
|
||||||
|
830eb43 verbose interval stats for dnsperf
|
||||||
|
|
||||||
2022-11-11 Jerry Lundström
|
2022-11-11 Jerry Lundström
|
||||||
|
|
||||||
Release 2.10.0
|
Release 2.10.0
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright 2019-2022 OARC, Inc.
|
# Copyright 2019-2023 OARC, Inc.
|
||||||
# Copyright 2017-2018 Akamai Technologies
|
# Copyright 2017-2018 Akamai Technologies
|
||||||
# Copyright 2006-2016 Nominum, Inc.
|
# Copyright 2006-2016 Nominum, Inc.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
@SET_MAKE@
|
@SET_MAKE@
|
||||||
|
|
||||||
# Copyright 2019-2022 OARC, Inc.
|
# Copyright 2019-2023 OARC, Inc.
|
||||||
# Copyright 2017-2018 Akamai Technologies
|
# Copyright 2017-2018 Akamai Technologies
|
||||||
# Copyright 2006-2016 Nominum, Inc.
|
# Copyright 2006-2016 Nominum, Inc.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
|
|
|
@ -100,7 +100,7 @@ The contrib directory contains additional software related to `dnsperf` and
|
||||||
## License
|
## License
|
||||||
|
|
||||||
```
|
```
|
||||||
Copyright 2019-2022 OARC, Inc.
|
Copyright 2019-2023 OARC, Inc.
|
||||||
Copyright 2017-2018 Akamai Technologies
|
Copyright 2017-2018 Akamai Technologies
|
||||||
Copyright 2006-2016 Nominum, Inc.
|
Copyright 2006-2016 Nominum, Inc.
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
46
configure
vendored
46
configure
vendored
|
@ -1,6 +1,6 @@
|
||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# Guess values for system-dependent variables and create Makefiles.
|
# Guess values for system-dependent variables and create Makefiles.
|
||||||
# Generated by GNU Autoconf 2.69 for dnsperf 2.10.0.
|
# Generated by GNU Autoconf 2.69 for dnsperf 2.11.0.
|
||||||
#
|
#
|
||||||
# Report bugs to <admin@dns-oarc.net>.
|
# Report bugs to <admin@dns-oarc.net>.
|
||||||
#
|
#
|
||||||
|
@ -590,8 +590,8 @@ MAKEFLAGS=
|
||||||
# Identity of this package.
|
# Identity of this package.
|
||||||
PACKAGE_NAME='dnsperf'
|
PACKAGE_NAME='dnsperf'
|
||||||
PACKAGE_TARNAME='dnsperf'
|
PACKAGE_TARNAME='dnsperf'
|
||||||
PACKAGE_VERSION='2.10.0'
|
PACKAGE_VERSION='2.11.0'
|
||||||
PACKAGE_STRING='dnsperf 2.10.0'
|
PACKAGE_STRING='dnsperf 2.11.0'
|
||||||
PACKAGE_BUGREPORT='admin@dns-oarc.net'
|
PACKAGE_BUGREPORT='admin@dns-oarc.net'
|
||||||
PACKAGE_URL='https://github.com/DNS-OARC/dnsperf/issues'
|
PACKAGE_URL='https://github.com/DNS-OARC/dnsperf/issues'
|
||||||
|
|
||||||
|
@ -649,6 +649,8 @@ libssl_CFLAGS
|
||||||
PKG_CONFIG_LIBDIR
|
PKG_CONFIG_LIBDIR
|
||||||
PKG_CONFIG_PATH
|
PKG_CONFIG_PATH
|
||||||
PKG_CONFIG
|
PKG_CONFIG
|
||||||
|
HAVE_STDATOMIC_FALSE
|
||||||
|
HAVE_STDATOMIC_TRUE
|
||||||
PTHREAD_CFLAGS
|
PTHREAD_CFLAGS
|
||||||
PTHREAD_LIBS
|
PTHREAD_LIBS
|
||||||
PTHREAD_CC
|
PTHREAD_CC
|
||||||
|
@ -1360,7 +1362,7 @@ if test "$ac_init_help" = "long"; then
|
||||||
# Omit some internal or obsolete options to make the list less imposing.
|
# Omit some internal or obsolete options to make the list less imposing.
|
||||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||||
cat <<_ACEOF
|
cat <<_ACEOF
|
||||||
\`configure' configures dnsperf 2.10.0 to adapt to many kinds of systems.
|
\`configure' configures dnsperf 2.11.0 to adapt to many kinds of systems.
|
||||||
|
|
||||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||||
|
|
||||||
|
@ -1431,7 +1433,7 @@ fi
|
||||||
|
|
||||||
if test -n "$ac_init_help"; then
|
if test -n "$ac_init_help"; then
|
||||||
case $ac_init_help in
|
case $ac_init_help in
|
||||||
short | recursive ) echo "Configuration of dnsperf 2.10.0:";;
|
short | recursive ) echo "Configuration of dnsperf 2.11.0:";;
|
||||||
esac
|
esac
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
|
@ -1570,7 +1572,7 @@ fi
|
||||||
test -n "$ac_init_help" && exit $ac_status
|
test -n "$ac_init_help" && exit $ac_status
|
||||||
if $ac_init_version; then
|
if $ac_init_version; then
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
dnsperf configure 2.10.0
|
dnsperf configure 2.11.0
|
||||||
generated by GNU Autoconf 2.69
|
generated by GNU Autoconf 2.69
|
||||||
|
|
||||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||||
|
@ -1939,7 +1941,7 @@ cat >config.log <<_ACEOF
|
||||||
This file contains any messages produced by compilers while
|
This file contains any messages produced by compilers while
|
||||||
running configure, to aid debugging if configure makes a mistake.
|
running configure, to aid debugging if configure makes a mistake.
|
||||||
|
|
||||||
It was created by dnsperf $as_me 2.10.0, which was
|
It was created by dnsperf $as_me 2.11.0, which was
|
||||||
generated by GNU Autoconf 2.69. Invocation command line was
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
$ $0 $@
|
$ $0 $@
|
||||||
|
@ -2802,7 +2804,7 @@ fi
|
||||||
|
|
||||||
# Define the identity of the package.
|
# Define the identity of the package.
|
||||||
PACKAGE='dnsperf'
|
PACKAGE='dnsperf'
|
||||||
VERSION='2.10.0'
|
VERSION='2.11.0'
|
||||||
|
|
||||||
|
|
||||||
cat >>confdefs.h <<_ACEOF
|
cat >>confdefs.h <<_ACEOF
|
||||||
|
@ -12891,6 +12893,26 @@ _ACEOF
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
for ac_header in stdatomic.h
|
||||||
|
do :
|
||||||
|
ac_fn_c_check_header_mongrel "$LINENO" "stdatomic.h" "ac_cv_header_stdatomic_h" "$ac_includes_default"
|
||||||
|
if test "x$ac_cv_header_stdatomic_h" = xyes; then :
|
||||||
|
cat >>confdefs.h <<_ACEOF
|
||||||
|
#define HAVE_STDATOMIC_H 1
|
||||||
|
_ACEOF
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
if test "x$ac_cv_header_stdatomic_h" != "xno"; then
|
||||||
|
HAVE_STDATOMIC_TRUE=
|
||||||
|
HAVE_STDATOMIC_FALSE='#'
|
||||||
|
else
|
||||||
|
HAVE_STDATOMIC_TRUE='#'
|
||||||
|
HAVE_STDATOMIC_FALSE=
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Check for OpenSSL
|
# Check for OpenSSL
|
||||||
|
|
||||||
|
@ -14013,6 +14035,10 @@ if test -z "${ENABLE_GCOV_TRUE}" && test -z "${ENABLE_GCOV_FALSE}"; then
|
||||||
as_fn_error $? "conditional \"ENABLE_GCOV\" was never defined.
|
as_fn_error $? "conditional \"ENABLE_GCOV\" was never defined.
|
||||||
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||||
fi
|
fi
|
||||||
|
if test -z "${HAVE_STDATOMIC_TRUE}" && test -z "${HAVE_STDATOMIC_FALSE}"; then
|
||||||
|
as_fn_error $? "conditional \"HAVE_STDATOMIC\" was never defined.
|
||||||
|
Usually this means the macro was only invoked conditionally." "$LINENO" 5
|
||||||
|
fi
|
||||||
|
|
||||||
: "${CONFIG_STATUS=./config.status}"
|
: "${CONFIG_STATUS=./config.status}"
|
||||||
ac_write_fail=0
|
ac_write_fail=0
|
||||||
|
@ -14410,7 +14436,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
|
||||||
# report actual input values of CONFIG_FILES etc. instead of their
|
# report actual input values of CONFIG_FILES etc. instead of their
|
||||||
# values after options handling.
|
# values after options handling.
|
||||||
ac_log="
|
ac_log="
|
||||||
This file was extended by dnsperf $as_me 2.10.0, which was
|
This file was extended by dnsperf $as_me 2.11.0, which was
|
||||||
generated by GNU Autoconf 2.69. Invocation command line was
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
CONFIG_FILES = $CONFIG_FILES
|
CONFIG_FILES = $CONFIG_FILES
|
||||||
|
@ -14477,7 +14503,7 @@ _ACEOF
|
||||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||||
ac_cs_version="\\
|
ac_cs_version="\\
|
||||||
dnsperf config.status 2.10.0
|
dnsperf config.status 2.11.0
|
||||||
configured by $0, generated by GNU Autoconf 2.69,
|
configured by $0, generated by GNU Autoconf 2.69,
|
||||||
with options \\"\$ac_cs_config\\"
|
with options \\"\$ac_cs_config\\"
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright 2019-2022 OARC, Inc.
|
# Copyright 2019-2023 OARC, Inc.
|
||||||
# Copyright 2017-2018 Akamai Technologies
|
# Copyright 2017-2018 Akamai Technologies
|
||||||
# Copyright 2006-2016 Nominum, Inc.
|
# Copyright 2006-2016 Nominum, Inc.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
AC_PREREQ(2.64)
|
AC_PREREQ(2.64)
|
||||||
AC_INIT([dnsperf], [2.10.0], [admin@dns-oarc.net], [dnsperf], [https://github.com/DNS-OARC/dnsperf/issues])
|
AC_INIT([dnsperf], [2.11.0], [admin@dns-oarc.net], [dnsperf], [https://github.com/DNS-OARC/dnsperf/issues])
|
||||||
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
|
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
|
||||||
AC_CONFIG_SRCDIR([src/dnsperf.c])
|
AC_CONFIG_SRCDIR([src/dnsperf.c])
|
||||||
AC_CONFIG_HEADER([src/config.h])
|
AC_CONFIG_HEADER([src/config.h])
|
||||||
|
@ -56,6 +56,8 @@ AM_EXTRA_RECURSIVE_TARGETS([gcov])
|
||||||
# Checks for support.
|
# Checks for support.
|
||||||
AX_PTHREAD
|
AX_PTHREAD
|
||||||
AC_CHECK_LIB([m], [sqrt])
|
AC_CHECK_LIB([m], [sqrt])
|
||||||
|
AC_CHECK_HEADERS([stdatomic.h])
|
||||||
|
AM_CONDITIONAL([HAVE_STDATOMIC], [test "x$ac_cv_header_stdatomic_h" != "xno"])
|
||||||
|
|
||||||
# Check for OpenSSL
|
# Check for OpenSSL
|
||||||
PKG_CHECK_MODULES([libssl], [libssl])
|
PKG_CHECK_MODULES([libssl], [libssl])
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
#
|
#
|
||||||
# Copyright 2019-2022 OARC, Inc.
|
# Copyright 2019-2023 OARC, Inc.
|
||||||
# Copyright 2017-2018 Akamai Technologies
|
# Copyright 2017-2018 Akamai Technologies
|
||||||
# Copyright 2006-2016 Nominum, Inc.
|
# Copyright 2006-2016 Nominum, Inc.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
.\" Copyright 2019-2022 OARC, Inc.
|
.\" Copyright 2019-2023 OARC, Inc.
|
||||||
.\" Copyright 2017-2018 Akamai Technologies
|
.\" Copyright 2017-2018 Akamai Technologies
|
||||||
.\" Copyright 2006-2016 Nominum, Inc.
|
.\" Copyright 2006-2016 Nominum, Inc.
|
||||||
.\" All rights reserved.
|
.\" All rights reserved.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright 2019-2022 OARC, Inc.
|
# Copyright 2019-2023 OARC, Inc.
|
||||||
# Copyright 2017-2018 Akamai Technologies
|
# Copyright 2017-2018 Akamai Technologies
|
||||||
# Copyright 2006-2016 Nominum, Inc.
|
# Copyright 2006-2016 Nominum, Inc.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright 2019-2022 OARC, Inc.
|
# Copyright 2019-2023 OARC, Inc.
|
||||||
# Copyright 2017-2018 Akamai Technologies
|
# Copyright 2017-2018 Akamai Technologies
|
||||||
# Copyright 2006-2016 Nominum, Inc.
|
# Copyright 2006-2016 Nominum, Inc.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
|
@ -30,9 +30,15 @@ bin_PROGRAMS = dnsperf resperf
|
||||||
dist_bin_SCRIPTS = resperf-report
|
dist_bin_SCRIPTS = resperf-report
|
||||||
|
|
||||||
_libperf_sources = datafile.c dns.c log.c net.c opt.c os.c strerror.c qtype.c \
|
_libperf_sources = datafile.c dns.c log.c net.c opt.c os.c strerror.c qtype.c \
|
||||||
edns.c tsig.c net_udp.c net_tcp.c net_dot.c net_doh.c parse_uri.c
|
edns.c tsig.c net_udp.c net_tcp.c net_dot.c net_doh.c ext/parse_uri.c
|
||||||
|
|
||||||
_libperf_headers = datafile.h dns.h log.h net.h opt.h os.h util.h strerror.h \
|
_libperf_headers = datafile.h dns.h log.h net.h opt.h os.h util.h strerror.h \
|
||||||
list.h result.h buffer.h qtype.h edns.h tsig.h parse_uri.h
|
list.h result.h buffer.h qtype.h edns.h tsig.h ext/parse_uri.h
|
||||||
|
|
||||||
|
if HAVE_STDATOMIC
|
||||||
|
_libperf_sources += ext/hg64.c
|
||||||
|
_libperf_headers += ext/hg64.h
|
||||||
|
endif
|
||||||
|
|
||||||
dnsperf_SOURCES = $(_libperf_sources) dnsperf.c
|
dnsperf_SOURCES = $(_libperf_sources) dnsperf.c
|
||||||
dist_dnsperf_SOURCES = $(_libperf_headers)
|
dist_dnsperf_SOURCES = $(_libperf_headers)
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
@SET_MAKE@
|
@SET_MAKE@
|
||||||
|
|
||||||
# Copyright 2019-2022 OARC, Inc.
|
# Copyright 2019-2023 OARC, Inc.
|
||||||
# Copyright 2017-2018 Akamai Technologies
|
# Copyright 2017-2018 Akamai Technologies
|
||||||
# Copyright 2006-2016 Nominum, Inc.
|
# Copyright 2006-2016 Nominum, Inc.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
|
@ -107,6 +107,8 @@ POST_UNINSTALL = :
|
||||||
build_triplet = @build@
|
build_triplet = @build@
|
||||||
host_triplet = @host@
|
host_triplet = @host@
|
||||||
bin_PROGRAMS = dnsperf$(EXEEXT) resperf$(EXEEXT)
|
bin_PROGRAMS = dnsperf$(EXEEXT) resperf$(EXEEXT)
|
||||||
|
@HAVE_STDATOMIC_TRUE@am__append_1 = ext/hg64.c
|
||||||
|
@HAVE_STDATOMIC_TRUE@am__append_2 = ext/hg64.h
|
||||||
subdir = src
|
subdir = src
|
||||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||||
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_append_flag.m4 \
|
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_append_flag.m4 \
|
||||||
|
@ -127,14 +129,23 @@ CONFIG_CLEAN_VPATH_FILES =
|
||||||
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" \
|
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" \
|
||||||
"$(DESTDIR)$(man1dir)"
|
"$(DESTDIR)$(man1dir)"
|
||||||
PROGRAMS = $(bin_PROGRAMS)
|
PROGRAMS = $(bin_PROGRAMS)
|
||||||
am__objects_1 = datafile.$(OBJEXT) dns.$(OBJEXT) log.$(OBJEXT) \
|
am__dnsperf_SOURCES_DIST = datafile.c dns.c log.c net.c opt.c os.c \
|
||||||
|
strerror.c qtype.c edns.c tsig.c net_udp.c net_tcp.c net_dot.c \
|
||||||
|
net_doh.c ext/parse_uri.c ext/hg64.c dnsperf.c
|
||||||
|
am__dirstamp = $(am__leading_dot)dirstamp
|
||||||
|
@HAVE_STDATOMIC_TRUE@am__objects_1 = ext/hg64.$(OBJEXT)
|
||||||
|
am__objects_2 = datafile.$(OBJEXT) dns.$(OBJEXT) log.$(OBJEXT) \
|
||||||
net.$(OBJEXT) opt.$(OBJEXT) os.$(OBJEXT) strerror.$(OBJEXT) \
|
net.$(OBJEXT) opt.$(OBJEXT) os.$(OBJEXT) strerror.$(OBJEXT) \
|
||||||
qtype.$(OBJEXT) edns.$(OBJEXT) tsig.$(OBJEXT) \
|
qtype.$(OBJEXT) edns.$(OBJEXT) tsig.$(OBJEXT) \
|
||||||
net_udp.$(OBJEXT) net_tcp.$(OBJEXT) net_dot.$(OBJEXT) \
|
net_udp.$(OBJEXT) net_tcp.$(OBJEXT) net_dot.$(OBJEXT) \
|
||||||
net_doh.$(OBJEXT) parse_uri.$(OBJEXT)
|
net_doh.$(OBJEXT) ext/parse_uri.$(OBJEXT) $(am__objects_1)
|
||||||
am_dnsperf_OBJECTS = $(am__objects_1) dnsperf.$(OBJEXT)
|
am_dnsperf_OBJECTS = $(am__objects_2) dnsperf.$(OBJEXT)
|
||||||
am__objects_2 =
|
am__dist_dnsperf_SOURCES_DIST = datafile.h dns.h log.h net.h opt.h \
|
||||||
dist_dnsperf_OBJECTS = $(am__objects_2)
|
os.h util.h strerror.h list.h result.h buffer.h qtype.h edns.h \
|
||||||
|
tsig.h ext/parse_uri.h ext/hg64.h
|
||||||
|
am__objects_3 =
|
||||||
|
am__objects_4 = $(am__objects_3)
|
||||||
|
dist_dnsperf_OBJECTS = $(am__objects_4)
|
||||||
dnsperf_OBJECTS = $(am_dnsperf_OBJECTS) $(dist_dnsperf_OBJECTS)
|
dnsperf_OBJECTS = $(am_dnsperf_OBJECTS) $(dist_dnsperf_OBJECTS)
|
||||||
am__DEPENDENCIES_1 =
|
am__DEPENDENCIES_1 =
|
||||||
dnsperf_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
|
dnsperf_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
|
||||||
|
@ -144,8 +155,14 @@ AM_V_lt = $(am__v_lt_@AM_V@)
|
||||||
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
|
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
|
||||||
am__v_lt_0 = --silent
|
am__v_lt_0 = --silent
|
||||||
am__v_lt_1 =
|
am__v_lt_1 =
|
||||||
am_resperf_OBJECTS = $(am__objects_1) resperf.$(OBJEXT)
|
am__resperf_SOURCES_DIST = datafile.c dns.c log.c net.c opt.c os.c \
|
||||||
dist_resperf_OBJECTS = $(am__objects_2)
|
strerror.c qtype.c edns.c tsig.c net_udp.c net_tcp.c net_dot.c \
|
||||||
|
net_doh.c ext/parse_uri.c ext/hg64.c resperf.c
|
||||||
|
am_resperf_OBJECTS = $(am__objects_2) resperf.$(OBJEXT)
|
||||||
|
am__dist_resperf_SOURCES_DIST = datafile.h dns.h log.h net.h opt.h \
|
||||||
|
os.h util.h strerror.h list.h result.h buffer.h qtype.h edns.h \
|
||||||
|
tsig.h ext/parse_uri.h ext/hg64.h
|
||||||
|
dist_resperf_OBJECTS = $(am__objects_4)
|
||||||
resperf_OBJECTS = $(am_resperf_OBJECTS) $(dist_resperf_OBJECTS)
|
resperf_OBJECTS = $(am_resperf_OBJECTS) $(dist_resperf_OBJECTS)
|
||||||
resperf_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
|
resperf_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
|
||||||
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
|
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
|
||||||
|
@ -198,9 +215,9 @@ am__depfiles_remade = ./$(DEPDIR)/datafile.Po ./$(DEPDIR)/dns.Po \
|
||||||
./$(DEPDIR)/net.Po ./$(DEPDIR)/net_doh.Po \
|
./$(DEPDIR)/net.Po ./$(DEPDIR)/net_doh.Po \
|
||||||
./$(DEPDIR)/net_dot.Po ./$(DEPDIR)/net_tcp.Po \
|
./$(DEPDIR)/net_dot.Po ./$(DEPDIR)/net_tcp.Po \
|
||||||
./$(DEPDIR)/net_udp.Po ./$(DEPDIR)/opt.Po ./$(DEPDIR)/os.Po \
|
./$(DEPDIR)/net_udp.Po ./$(DEPDIR)/opt.Po ./$(DEPDIR)/os.Po \
|
||||||
./$(DEPDIR)/parse_uri.Po ./$(DEPDIR)/qtype.Po \
|
./$(DEPDIR)/qtype.Po ./$(DEPDIR)/resperf.Po \
|
||||||
./$(DEPDIR)/resperf.Po ./$(DEPDIR)/strerror.Po \
|
./$(DEPDIR)/strerror.Po ./$(DEPDIR)/tsig.Po \
|
||||||
./$(DEPDIR)/tsig.Po
|
ext/$(DEPDIR)/hg64.Po ext/$(DEPDIR)/parse_uri.Po
|
||||||
am__mv = mv -f
|
am__mv = mv -f
|
||||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||||
|
@ -222,8 +239,9 @@ am__v_CCLD_0 = @echo " CCLD " $@;
|
||||||
am__v_CCLD_1 =
|
am__v_CCLD_1 =
|
||||||
SOURCES = $(dnsperf_SOURCES) $(dist_dnsperf_SOURCES) \
|
SOURCES = $(dnsperf_SOURCES) $(dist_dnsperf_SOURCES) \
|
||||||
$(resperf_SOURCES) $(dist_resperf_SOURCES)
|
$(resperf_SOURCES) $(dist_resperf_SOURCES)
|
||||||
DIST_SOURCES = $(dnsperf_SOURCES) $(dist_dnsperf_SOURCES) \
|
DIST_SOURCES = $(am__dnsperf_SOURCES_DIST) \
|
||||||
$(resperf_SOURCES) $(dist_resperf_SOURCES)
|
$(am__dist_dnsperf_SOURCES_DIST) $(am__resperf_SOURCES_DIST) \
|
||||||
|
$(am__dist_resperf_SOURCES_DIST)
|
||||||
RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
|
RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
|
||||||
ctags-recursive dvi-recursive html-recursive info-recursive \
|
ctags-recursive dvi-recursive html-recursive info-recursive \
|
||||||
install-data-recursive install-dvi-recursive \
|
install-data-recursive install-dvi-recursive \
|
||||||
|
@ -440,12 +458,12 @@ AM_CFLAGS = -I$(srcdir) \
|
||||||
|
|
||||||
EXTRA_DIST = dnsperf.1.in resperf-report resperf.1.in
|
EXTRA_DIST = dnsperf.1.in resperf-report resperf.1.in
|
||||||
dist_bin_SCRIPTS = resperf-report
|
dist_bin_SCRIPTS = resperf-report
|
||||||
_libperf_sources = datafile.c dns.c log.c net.c opt.c os.c strerror.c qtype.c \
|
_libperf_sources = datafile.c dns.c log.c net.c opt.c os.c strerror.c \
|
||||||
edns.c tsig.c net_udp.c net_tcp.c net_dot.c net_doh.c parse_uri.c
|
qtype.c edns.c tsig.c net_udp.c net_tcp.c net_dot.c net_doh.c \
|
||||||
|
ext/parse_uri.c $(am__append_1)
|
||||||
_libperf_headers = datafile.h dns.h log.h net.h opt.h os.h util.h strerror.h \
|
_libperf_headers = datafile.h dns.h log.h net.h opt.h os.h util.h \
|
||||||
list.h result.h buffer.h qtype.h edns.h tsig.h parse_uri.h
|
strerror.h list.h result.h buffer.h qtype.h edns.h tsig.h \
|
||||||
|
ext/parse_uri.h $(am__append_2)
|
||||||
dnsperf_SOURCES = $(_libperf_sources) dnsperf.c
|
dnsperf_SOURCES = $(_libperf_sources) dnsperf.c
|
||||||
dist_dnsperf_SOURCES = $(_libperf_headers)
|
dist_dnsperf_SOURCES = $(_libperf_headers)
|
||||||
dnsperf_LDADD = $(PTHREAD_LIBS) $(libssl_LIBS) $(libcrypto_LIBS) \
|
dnsperf_LDADD = $(PTHREAD_LIBS) $(libssl_LIBS) $(libcrypto_LIBS) \
|
||||||
|
@ -555,6 +573,15 @@ clean-binPROGRAMS:
|
||||||
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
|
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
|
||||||
echo " rm -f" $$list; \
|
echo " rm -f" $$list; \
|
||||||
rm -f $$list
|
rm -f $$list
|
||||||
|
ext/$(am__dirstamp):
|
||||||
|
@$(MKDIR_P) ext
|
||||||
|
@: > ext/$(am__dirstamp)
|
||||||
|
ext/$(DEPDIR)/$(am__dirstamp):
|
||||||
|
@$(MKDIR_P) ext/$(DEPDIR)
|
||||||
|
@: > ext/$(DEPDIR)/$(am__dirstamp)
|
||||||
|
ext/parse_uri.$(OBJEXT): ext/$(am__dirstamp) \
|
||||||
|
ext/$(DEPDIR)/$(am__dirstamp)
|
||||||
|
ext/hg64.$(OBJEXT): ext/$(am__dirstamp) ext/$(DEPDIR)/$(am__dirstamp)
|
||||||
|
|
||||||
dnsperf$(EXEEXT): $(dnsperf_OBJECTS) $(dnsperf_DEPENDENCIES) $(EXTRA_dnsperf_DEPENDENCIES)
|
dnsperf$(EXEEXT): $(dnsperf_OBJECTS) $(dnsperf_DEPENDENCIES) $(EXTRA_dnsperf_DEPENDENCIES)
|
||||||
@rm -f dnsperf$(EXEEXT)
|
@rm -f dnsperf$(EXEEXT)
|
||||||
|
@ -601,6 +628,7 @@ uninstall-dist_binSCRIPTS:
|
||||||
|
|
||||||
mostlyclean-compile:
|
mostlyclean-compile:
|
||||||
-rm -f *.$(OBJEXT)
|
-rm -f *.$(OBJEXT)
|
||||||
|
-rm -f ext/*.$(OBJEXT)
|
||||||
|
|
||||||
distclean-compile:
|
distclean-compile:
|
||||||
-rm -f *.tab.c
|
-rm -f *.tab.c
|
||||||
|
@ -617,11 +645,12 @@ distclean-compile:
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net_udp.Po@am__quote@ # am--include-marker
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net_udp.Po@am__quote@ # am--include-marker
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opt.Po@am__quote@ # am--include-marker
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opt.Po@am__quote@ # am--include-marker
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os.Po@am__quote@ # am--include-marker
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os.Po@am__quote@ # am--include-marker
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse_uri.Po@am__quote@ # am--include-marker
|
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qtype.Po@am__quote@ # am--include-marker
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qtype.Po@am__quote@ # am--include-marker
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resperf.Po@am__quote@ # am--include-marker
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resperf.Po@am__quote@ # am--include-marker
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strerror.Po@am__quote@ # am--include-marker
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strerror.Po@am__quote@ # am--include-marker
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsig.Po@am__quote@ # am--include-marker
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsig.Po@am__quote@ # am--include-marker
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@ext/$(DEPDIR)/hg64.Po@am__quote@ # am--include-marker
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@ext/$(DEPDIR)/parse_uri.Po@am__quote@ # am--include-marker
|
||||||
|
|
||||||
$(am__depfiles_remade):
|
$(am__depfiles_remade):
|
||||||
@$(MKDIR_P) $(@D)
|
@$(MKDIR_P) $(@D)
|
||||||
|
@ -893,6 +922,8 @@ clean-generic:
|
||||||
distclean-generic:
|
distclean-generic:
|
||||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||||
|
-rm -f ext/$(DEPDIR)/$(am__dirstamp)
|
||||||
|
-rm -f ext/$(am__dirstamp)
|
||||||
|
|
||||||
maintainer-clean-generic:
|
maintainer-clean-generic:
|
||||||
@echo "This command is intended for maintainers to use"
|
@echo "This command is intended for maintainers to use"
|
||||||
|
@ -916,11 +947,12 @@ distclean: distclean-recursive
|
||||||
-rm -f ./$(DEPDIR)/net_udp.Po
|
-rm -f ./$(DEPDIR)/net_udp.Po
|
||||||
-rm -f ./$(DEPDIR)/opt.Po
|
-rm -f ./$(DEPDIR)/opt.Po
|
||||||
-rm -f ./$(DEPDIR)/os.Po
|
-rm -f ./$(DEPDIR)/os.Po
|
||||||
-rm -f ./$(DEPDIR)/parse_uri.Po
|
|
||||||
-rm -f ./$(DEPDIR)/qtype.Po
|
-rm -f ./$(DEPDIR)/qtype.Po
|
||||||
-rm -f ./$(DEPDIR)/resperf.Po
|
-rm -f ./$(DEPDIR)/resperf.Po
|
||||||
-rm -f ./$(DEPDIR)/strerror.Po
|
-rm -f ./$(DEPDIR)/strerror.Po
|
||||||
-rm -f ./$(DEPDIR)/tsig.Po
|
-rm -f ./$(DEPDIR)/tsig.Po
|
||||||
|
-rm -f ext/$(DEPDIR)/hg64.Po
|
||||||
|
-rm -f ext/$(DEPDIR)/parse_uri.Po
|
||||||
-rm -f Makefile
|
-rm -f Makefile
|
||||||
distclean-am: clean-am distclean-compile distclean-generic \
|
distclean-am: clean-am distclean-compile distclean-generic \
|
||||||
distclean-hdr distclean-tags
|
distclean-hdr distclean-tags
|
||||||
|
@ -982,11 +1014,12 @@ maintainer-clean: maintainer-clean-recursive
|
||||||
-rm -f ./$(DEPDIR)/net_udp.Po
|
-rm -f ./$(DEPDIR)/net_udp.Po
|
||||||
-rm -f ./$(DEPDIR)/opt.Po
|
-rm -f ./$(DEPDIR)/opt.Po
|
||||||
-rm -f ./$(DEPDIR)/os.Po
|
-rm -f ./$(DEPDIR)/os.Po
|
||||||
-rm -f ./$(DEPDIR)/parse_uri.Po
|
|
||||||
-rm -f ./$(DEPDIR)/qtype.Po
|
-rm -f ./$(DEPDIR)/qtype.Po
|
||||||
-rm -f ./$(DEPDIR)/resperf.Po
|
-rm -f ./$(DEPDIR)/resperf.Po
|
||||||
-rm -f ./$(DEPDIR)/strerror.Po
|
-rm -f ./$(DEPDIR)/strerror.Po
|
||||||
-rm -f ./$(DEPDIR)/tsig.Po
|
-rm -f ./$(DEPDIR)/tsig.Po
|
||||||
|
-rm -f ext/$(DEPDIR)/hg64.Po
|
||||||
|
-rm -f ext/$(DEPDIR)/parse_uri.Po
|
||||||
-rm -f Makefile
|
-rm -f Makefile
|
||||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -36,6 +36,9 @@
|
||||||
/* Have PTHREAD_PRIO_INHERIT. */
|
/* Have PTHREAD_PRIO_INHERIT. */
|
||||||
#undef HAVE_PTHREAD_PRIO_INHERIT
|
#undef HAVE_PTHREAD_PRIO_INHERIT
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <stdatomic.h> header file. */
|
||||||
|
#undef HAVE_STDATOMIC_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdint.h> header file. */
|
/* Define to 1 if you have the <stdint.h> header file. */
|
||||||
#undef HAVE_STDINT_H
|
#undef HAVE_STDINT_H
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
.\" Copyright 2019-2022 OARC, Inc.
|
.\" Copyright 2019-2023 OARC, Inc.
|
||||||
.\" Copyright 2017-2018 Akamai Technologies
|
.\" Copyright 2017-2018 Akamai Technologies
|
||||||
.\" Copyright 2006-2016 Nominum, Inc.
|
.\" Copyright 2006-2016 Nominum, Inc.
|
||||||
.\" All rights reserved.
|
.\" All rights reserved.
|
||||||
|
@ -341,8 +341,9 @@ The default is the loopback address, 127.0.0.1.
|
||||||
\fB-S \fIstats_interval\fR
|
\fB-S \fIstats_interval\fR
|
||||||
.br
|
.br
|
||||||
.RS
|
.RS
|
||||||
If this parameter is specified, a count of the number of queries per second
|
If this parameter is specified, a count of the number of answers received
|
||||||
during the interval will be printed out every stats_interval seconds.
|
per second during the interval will be printed out every \fIstats_interval\fR
|
||||||
|
seconds.
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
\fB-t \fItimeout\fR
|
\fB-t \fItimeout\fR
|
||||||
|
@ -458,7 +459,6 @@ Following type are available.
|
||||||
.br
|
.br
|
||||||
\fBunexpected\fR: Suppress messages about answers with an unexpected message ID
|
\fBunexpected\fR: Suppress messages about answers with an unexpected message ID
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
\fBnum-queries-per-conn=\fINUMBER\fR
|
\fBnum-queries-per-conn=\fINUMBER\fR
|
||||||
.br
|
.br
|
||||||
.RS
|
.RS
|
||||||
|
@ -474,6 +474,29 @@ Waiting for responses may timeout and the timeout used for this is the
|
||||||
same as specified by \fB-t\fR.
|
same as specified by \fB-t\fR.
|
||||||
Note that this option is only useful for connection oriented protocols.
|
Note that this option is only useful for connection oriented protocols.
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
|
\fBverbose-interval-stats\fR
|
||||||
|
.br
|
||||||
|
.RS
|
||||||
|
Change the statistics format of \fB-S\fR to that shown at end of run.
|
||||||
|
|
||||||
|
\fIPlease note\fR: Min/max values for latency and connections are not
|
||||||
|
available in interval statistics.
|
||||||
|
Number of answers received within \fIstats_interval\fR can legitimately
|
||||||
|
exceed number of queries sent, depending on answer latency, configured
|
||||||
|
\fItimeout\fR, and \fIstats_interval\fR.
|
||||||
|
.RE
|
||||||
|
|
||||||
|
\fBlatency-histogram\fR
|
||||||
|
.br
|
||||||
|
.RS
|
||||||
|
Print detailed latency histograms for DNS answers and connections.
|
||||||
|
Latency is quantized into bins with roughly 3 % resolution, and latency
|
||||||
|
range for individual bins increases logarithmically.
|
||||||
|
This is done to to limit amount of memory required for histograms
|
||||||
|
and also allows to visualize latency using logarithmic percentile histograms
|
||||||
|
with minimal postprocessing.
|
||||||
|
.RE
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
\fBresperf\fR(1)
|
\fBresperf\fR(1)
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
|
|
230
src/dnsperf.c
230
src/dnsperf.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
@ -32,6 +32,10 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
#if HAVE_STDATOMIC_H
|
||||||
|
#include "ext/hg64.h"
|
||||||
|
#define USE_HISTOGRAMS
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -49,6 +53,8 @@
|
||||||
#include <openssl/conf.h>
|
#include <openssl/conf.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
|
||||||
|
#define HISTOGRAM_SIGBITS 5 /* about 3 % latency precision */
|
||||||
|
|
||||||
#define DEFAULT_SERVER_NAME "127.0.0.1"
|
#define DEFAULT_SERVER_NAME "127.0.0.1"
|
||||||
#define DEFAULT_SERVER_PORT 53
|
#define DEFAULT_SERVER_PORT 53
|
||||||
#define DEFAULT_SERVER_DOT_PORT 853
|
#define DEFAULT_SERVER_DOT_PORT 853
|
||||||
|
@ -85,6 +91,7 @@ typedef struct {
|
||||||
uint32_t max_outstanding;
|
uint32_t max_outstanding;
|
||||||
uint32_t max_qps;
|
uint32_t max_qps;
|
||||||
uint64_t stats_interval;
|
uint64_t stats_interval;
|
||||||
|
bool verbose_interval_stats;
|
||||||
bool updates;
|
bool updates;
|
||||||
bool binary_input;
|
bool binary_input;
|
||||||
perf_input_format_t input_format;
|
perf_input_format_t input_format;
|
||||||
|
@ -92,6 +99,9 @@ typedef struct {
|
||||||
enum perf_net_mode mode;
|
enum perf_net_mode mode;
|
||||||
perf_suppress_t suppress;
|
perf_suppress_t suppress;
|
||||||
size_t num_queries_per_conn;
|
size_t num_queries_per_conn;
|
||||||
|
#ifdef USE_HISTOGRAMS
|
||||||
|
bool latency_histogram;
|
||||||
|
#endif
|
||||||
} config_t;
|
} config_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -101,8 +111,9 @@ typedef struct {
|
||||||
struct timespec stop_time_ns;
|
struct timespec stop_time_ns;
|
||||||
} times_t;
|
} times_t;
|
||||||
|
|
||||||
|
#define DNSPERF_STATS_RCODECOUNTS 16
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint64_t rcodecounts[16];
|
uint64_t rcodecounts[DNSPERF_STATS_RCODECOUNTS];
|
||||||
|
|
||||||
uint64_t num_sent;
|
uint64_t num_sent;
|
||||||
uint64_t num_interrupted;
|
uint64_t num_interrupted;
|
||||||
|
@ -124,6 +135,11 @@ typedef struct {
|
||||||
uint64_t conn_latency_sum_squares;
|
uint64_t conn_latency_sum_squares;
|
||||||
uint64_t conn_latency_min;
|
uint64_t conn_latency_min;
|
||||||
uint64_t conn_latency_max;
|
uint64_t conn_latency_max;
|
||||||
|
|
||||||
|
#ifdef USE_HISTOGRAMS
|
||||||
|
hg64* latency;
|
||||||
|
hg64* conn_latency;
|
||||||
|
#endif
|
||||||
} stats_t;
|
} stats_t;
|
||||||
|
|
||||||
typedef perf_list(struct query_info) query_list;
|
typedef perf_list(struct query_info) query_list;
|
||||||
|
@ -257,7 +273,86 @@ stddev(uint64_t sum_of_squares, uint64_t sum, uint64_t total)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print_statistics(const config_t* config, const times_t* times, stats_t* stats)
|
diff_stats(const config_t* config, stats_t* last, stats_t* now, stats_t* diff)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (; i < DNSPERF_STATS_RCODECOUNTS; i++) {
|
||||||
|
diff->rcodecounts[i] = now->rcodecounts[i] - last->rcodecounts[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
diff->num_sent = now->num_sent - last->num_sent;
|
||||||
|
diff->num_interrupted = now->num_interrupted - last->num_interrupted;
|
||||||
|
diff->num_timedout = now->num_timedout - last->num_timedout;
|
||||||
|
diff->num_completed = now->num_completed - last->num_completed;
|
||||||
|
|
||||||
|
diff->total_request_size = now->total_request_size - last->total_request_size;
|
||||||
|
diff->total_response_size = now->total_response_size - last->total_response_size;
|
||||||
|
|
||||||
|
diff->latency_sum = now->latency_sum - last->latency_sum;
|
||||||
|
diff->latency_sum_squares = now->latency_sum_squares - last->latency_sum_squares;
|
||||||
|
diff->latency_min = 0; /* not enough data */
|
||||||
|
diff->latency_max = 0;
|
||||||
|
|
||||||
|
diff->num_conn_reconnect = now->num_conn_reconnect - last->num_conn_reconnect;
|
||||||
|
diff->num_conn_completed = now->num_conn_completed - last->num_conn_completed;
|
||||||
|
|
||||||
|
diff->conn_latency_sum = now->conn_latency_sum - last->conn_latency_sum;
|
||||||
|
diff->conn_latency_sum_squares = now->conn_latency_sum_squares - last->conn_latency_sum_squares;
|
||||||
|
diff->conn_latency_min = 0;
|
||||||
|
diff->conn_latency_max = 0;
|
||||||
|
|
||||||
|
#ifdef USE_HISTOGRAMS
|
||||||
|
if (config->latency_histogram) {
|
||||||
|
free(diff->latency);
|
||||||
|
diff->latency = hg64_create(HISTOGRAM_SIGBITS);
|
||||||
|
if (last->latency) {
|
||||||
|
hg64_diff(now->latency, last->latency, diff->latency);
|
||||||
|
} else { /* first sample */
|
||||||
|
hg64_merge(diff->latency, now->latency);
|
||||||
|
}
|
||||||
|
hg64_get(diff->latency, hg64_min_key(diff->latency), &diff->latency_min, NULL, NULL);
|
||||||
|
hg64_get(diff->latency, hg64_max_key(diff->latency), NULL, &diff->latency_max, NULL);
|
||||||
|
|
||||||
|
free(diff->conn_latency);
|
||||||
|
diff->conn_latency = hg64_create(HISTOGRAM_SIGBITS);
|
||||||
|
if (last->conn_latency) {
|
||||||
|
hg64_diff(now->conn_latency, last->conn_latency, diff->conn_latency);
|
||||||
|
} else { /* first sample */
|
||||||
|
hg64_merge(diff->conn_latency, now->conn_latency);
|
||||||
|
}
|
||||||
|
hg64_get(diff->conn_latency, hg64_min_key(diff->conn_latency), &diff->conn_latency_min, NULL, NULL);
|
||||||
|
hg64_get(diff->conn_latency, hg64_max_key(diff->conn_latency), NULL, &diff->conn_latency_max, NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_HISTOGRAMS
|
||||||
|
static void
|
||||||
|
print_histogram(hg64* histogram, const char* const desc)
|
||||||
|
{
|
||||||
|
printf(" Latency bucket (s): %s\n", desc);
|
||||||
|
uint64_t pmin, pmax, pcount;
|
||||||
|
for (unsigned key = 0;
|
||||||
|
hg64_get(histogram, key, &pmin, &pmax, &pcount) == true;
|
||||||
|
key = hg64_next(histogram, key)) {
|
||||||
|
if (pcount == 0)
|
||||||
|
continue;
|
||||||
|
printf(" %" PRIu64 ".%06" PRIu64 " - %" PRIu64 ".%06" PRIu64 ": %" PRIu64 "\n",
|
||||||
|
pmin / MILLION,
|
||||||
|
pmin % MILLION,
|
||||||
|
pmax / MILLION,
|
||||||
|
pmax % MILLION,
|
||||||
|
pcount);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* now != 0 is call to print stats in the middle of test run.
|
||||||
|
* min-max values are not available on per-interval basis, so skip them.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
print_statistics(const config_t* config, const times_t* times, stats_t* stats, uint64_t now, uint64_t interval_time)
|
||||||
{
|
{
|
||||||
const char* units;
|
const char* units;
|
||||||
uint64_t run_time;
|
uint64_t run_time;
|
||||||
|
@ -267,9 +362,12 @@ print_statistics(const config_t* config, const times_t* times, stats_t* stats)
|
||||||
|
|
||||||
units = config->updates ? "Updates" : "Queries";
|
units = config->updates ? "Updates" : "Queries";
|
||||||
|
|
||||||
|
if (now)
|
||||||
|
run_time = now - times->start_time;
|
||||||
|
else
|
||||||
run_time = times->end_time - times->start_time;
|
run_time = times->end_time - times->start_time;
|
||||||
|
|
||||||
printf("Statistics:\n\n");
|
printf("%sStatistics:\n\n", now ? "Interval " : "");
|
||||||
|
|
||||||
printf(" %s sent: %" PRIu64 "\n",
|
printf(" %s sent: %" PRIu64 "\n",
|
||||||
units, stats->num_sent);
|
units, stats->num_sent);
|
||||||
|
@ -287,7 +385,7 @@ print_statistics(const config_t* config, const times_t* times, stats_t* stats)
|
||||||
|
|
||||||
printf(" Response codes: ");
|
printf(" Response codes: ");
|
||||||
first_rcode = true;
|
first_rcode = true;
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < DNSPERF_STATS_RCODECOUNTS; i++) {
|
||||||
if (stats->rcodecounts[i] == 0)
|
if (stats->rcodecounts[i] == 0)
|
||||||
continue;
|
continue;
|
||||||
if (first_rcode)
|
if (first_rcode)
|
||||||
|
@ -308,23 +406,33 @@ print_statistics(const config_t* config, const times_t* times, stats_t* stats)
|
||||||
(unsigned int)(run_time / MILLION),
|
(unsigned int)(run_time / MILLION),
|
||||||
(unsigned int)(run_time % MILLION));
|
(unsigned int)(run_time % MILLION));
|
||||||
printf(" %s per second: %.6lf\n", units,
|
printf(" %s per second: %.6lf\n", units,
|
||||||
PERF_SAFE_DIV(stats->num_completed, (((double)run_time) / MILLION)));
|
PERF_SAFE_DIV(stats->num_completed, (((double)(now ? interval_time : run_time) / MILLION))));
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
latency_avg = PERF_SAFE_DIV(stats->latency_sum, stats->num_completed);
|
latency_avg = PERF_SAFE_DIV(stats->latency_sum, stats->num_completed);
|
||||||
printf(" Average Latency (s): %u.%06u (min %u.%06u, max %u.%06u)\n",
|
printf(" Average Latency (s): %u.%06u",
|
||||||
(unsigned int)(latency_avg / MILLION),
|
(unsigned int)(latency_avg / MILLION),
|
||||||
(unsigned int)(latency_avg % MILLION),
|
(unsigned int)(latency_avg % MILLION));
|
||||||
|
if (!now) {
|
||||||
|
printf(" (min %u.%06u, max %u.%06u)\n",
|
||||||
(unsigned int)(stats->latency_min / MILLION),
|
(unsigned int)(stats->latency_min / MILLION),
|
||||||
(unsigned int)(stats->latency_min % MILLION),
|
(unsigned int)(stats->latency_min % MILLION),
|
||||||
(unsigned int)(stats->latency_max / MILLION),
|
(unsigned int)(stats->latency_max / MILLION),
|
||||||
(unsigned int)(stats->latency_max % MILLION));
|
(unsigned int)(stats->latency_max % MILLION));
|
||||||
|
} else {
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (stats->num_completed > 1) {
|
if (stats->num_completed > 1) {
|
||||||
printf(" Latency StdDev (s): %f\n",
|
printf(" Latency StdDev (s): %f\n",
|
||||||
stddev(stats->latency_sum_squares, stats->latency_sum,
|
stddev(stats->latency_sum_squares, stats->latency_sum,
|
||||||
stats->num_completed)
|
stats->num_completed)
|
||||||
/ MILLION);
|
/ MILLION);
|
||||||
|
#ifdef USE_HISTOGRAMS
|
||||||
|
if (config->latency_histogram)
|
||||||
|
print_histogram(stats->latency, "answer count");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
@ -336,32 +444,56 @@ print_statistics(const config_t* config, const times_t* times, stats_t* stats)
|
||||||
printf("Connection Statistics:\n\n");
|
printf("Connection Statistics:\n\n");
|
||||||
printf(" Reconnections: %" PRIu64 "\n\n", stats->num_conn_reconnect);
|
printf(" Reconnections: %" PRIu64 "\n\n", stats->num_conn_reconnect);
|
||||||
latency_avg = PERF_SAFE_DIV(stats->conn_latency_sum, stats->num_conn_completed);
|
latency_avg = PERF_SAFE_DIV(stats->conn_latency_sum, stats->num_conn_completed);
|
||||||
printf(" Average Latency (s): %u.%06u (min %u.%06u, max %u.%06u)\n",
|
printf(" Average Latency (s): %u.%06u",
|
||||||
(unsigned int)(latency_avg / MILLION),
|
(unsigned int)(latency_avg / MILLION),
|
||||||
(unsigned int)(latency_avg % MILLION),
|
(unsigned int)(latency_avg % MILLION));
|
||||||
|
if (!now) {
|
||||||
|
printf(" (min %u.%06u, max %u.%06u)\n",
|
||||||
(unsigned int)(stats->conn_latency_min / MILLION),
|
(unsigned int)(stats->conn_latency_min / MILLION),
|
||||||
(unsigned int)(stats->conn_latency_min % MILLION),
|
(unsigned int)(stats->conn_latency_min % MILLION),
|
||||||
(unsigned int)(stats->conn_latency_max / MILLION),
|
(unsigned int)(stats->conn_latency_max / MILLION),
|
||||||
(unsigned int)(stats->conn_latency_max % MILLION));
|
(unsigned int)(stats->conn_latency_max % MILLION));
|
||||||
|
} else {
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
if (stats->num_conn_completed > 1) {
|
if (stats->num_conn_completed > 1) {
|
||||||
printf(" Latency StdDev (s): %f\n",
|
printf(" Latency StdDev (s): %f\n",
|
||||||
stddev(stats->conn_latency_sum_squares, stats->conn_latency_sum, stats->num_conn_completed) / MILLION);
|
stddev(stats->conn_latency_sum_squares, stats->conn_latency_sum, stats->num_conn_completed) / MILLION);
|
||||||
|
#ifdef USE_HISTOGRAMS
|
||||||
|
if (config->latency_histogram)
|
||||||
|
print_histogram(stats->latency, "connection count");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Caller must free() stats->latency and stats->conn_latency.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
sum_stats(const config_t* config, stats_t* total)
|
sum_stats(const config_t* config, stats_t* total)
|
||||||
{
|
{
|
||||||
unsigned int i, j;
|
unsigned int i, j;
|
||||||
|
|
||||||
memset(total, 0, sizeof(*total));
|
memset(total, 0, sizeof(*total));
|
||||||
|
#ifdef USE_HISTOGRAMS
|
||||||
|
if (config->latency_histogram) {
|
||||||
|
total->latency = hg64_create(HISTOGRAM_SIGBITS);
|
||||||
|
total->conn_latency = hg64_create(HISTOGRAM_SIGBITS);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
for (i = 0; i < config->threads; i++) {
|
for (i = 0; i < config->threads; i++) {
|
||||||
stats_t* stats = &threads[i].stats;
|
stats_t* stats = &threads[i].stats;
|
||||||
|
#ifdef USE_HISTOGRAMS
|
||||||
|
if (config->latency_histogram) {
|
||||||
|
hg64_merge(total->latency, stats->latency);
|
||||||
|
hg64_merge(total->conn_latency, stats->conn_latency);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
for (j = 0; j < 16; j++)
|
for (j = 0; j < DNSPERF_STATS_RCODECOUNTS; j++)
|
||||||
total->rcodecounts[j] += stats->rcodecounts[j];
|
total->rcodecounts[j] += stats->rcodecounts[j];
|
||||||
|
|
||||||
total->num_sent += stats->num_sent;
|
total->num_sent += stats->num_sent;
|
||||||
|
@ -499,6 +631,12 @@ setup(int argc, char** argv, config_t* config)
|
||||||
"suppress messages/warnings, see man-page for list of message types", NULL, &local_suppress);
|
"suppress messages/warnings, see man-page for list of message types", NULL, &local_suppress);
|
||||||
perf_long_opt_add("num-queries-per-conn", perf_opt_uint, "queries",
|
perf_long_opt_add("num-queries-per-conn", perf_opt_uint, "queries",
|
||||||
"Number of queries to send per connection", NULL, &config->num_queries_per_conn);
|
"Number of queries to send per connection", NULL, &config->num_queries_per_conn);
|
||||||
|
perf_long_opt_add("verbose-interval-stats", perf_opt_boolean, NULL,
|
||||||
|
"print detailed statistics for each stats_interval", NULL, &config->verbose_interval_stats);
|
||||||
|
#ifdef USE_HISTOGRAMS
|
||||||
|
perf_long_opt_add("latency-histogram", perf_opt_boolean, NULL,
|
||||||
|
"collect and print detailed latency histograms", NULL, &config->latency_histogram);
|
||||||
|
#endif
|
||||||
|
|
||||||
bool log_stdout = false;
|
bool log_stdout = false;
|
||||||
perf_opt_add('W', perf_opt_boolean, NULL, "log warnings and errors to stdout instead of stderr", NULL, &log_stdout);
|
perf_opt_add('W', perf_opt_boolean, NULL, "log warnings and errors to stdout instead of stderr", NULL, &log_stdout);
|
||||||
|
@ -574,14 +712,18 @@ setup(int argc, char** argv, config_t* config)
|
||||||
* If we run more threads than max-qps, some threads will have
|
* If we run more threads than max-qps, some threads will have
|
||||||
* ->max_qps set to 0, and be unlimited.
|
* ->max_qps set to 0, and be unlimited.
|
||||||
*/
|
*/
|
||||||
if (config->max_qps > 0 && config->threads > config->max_qps)
|
if (config->max_qps > 0 && config->threads > config->max_qps) {
|
||||||
|
perf_log_warning("requested max QPS limit (-Q %u) is lower than number of threads (-T %u), lowering number of threads", config->max_qps, config->threads);
|
||||||
config->threads = config->max_qps;
|
config->threads = config->max_qps;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We also can't run more threads than clients.
|
* We also can't run more threads than clients.
|
||||||
*/
|
*/
|
||||||
if (config->threads > config->clients)
|
if (config->threads > config->clients) {
|
||||||
|
perf_log_warning("requested number of threads (-T %u) exceeds number of clients (-c %u), lowering number of threads\n", config->threads, config->clients);
|
||||||
config->threads = config->clients;
|
config->threads = config->clients;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef HAVE_LDNS
|
#ifndef HAVE_LDNS
|
||||||
if (config->updates) {
|
if (config->updates) {
|
||||||
|
@ -636,6 +778,10 @@ query_move(threadinfo_t* tinfo, query_info* q, query_move_op op)
|
||||||
static inline uint64_t
|
static inline uint64_t
|
||||||
num_outstanding(const stats_t* stats)
|
num_outstanding(const stats_t* stats)
|
||||||
{
|
{
|
||||||
|
/* make sure negative values aren't returned */
|
||||||
|
if (stats->num_completed + stats->num_timedout > stats->num_sent) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return stats->num_sent - stats->num_completed - stats->num_timedout;
|
return stats->num_sent - stats->num_completed - stats->num_timedout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -920,7 +1066,10 @@ recv_one(threadinfo_t* tinfo, int which_sock,
|
||||||
}
|
}
|
||||||
if (!n) {
|
if (!n) {
|
||||||
// Treat connection closed like try again until reconnection features are in
|
// Treat connection closed like try again until reconnection features are in
|
||||||
|
if (!*saved_errnop) {
|
||||||
|
// only set this if there was no error before to allow above error check to overwrite EAGAIN
|
||||||
*saved_errnop = EAGAIN;
|
*saved_errnop = EAGAIN;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
recvd->sock = tinfo->socks[which_sock];
|
recvd->sock = tinfo->socks[which_sock];
|
||||||
|
@ -1006,8 +1155,6 @@ do_recv(void* arg)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bit_set(socketbits, current_socket);
|
bit_set(socketbits, current_socket);
|
||||||
if (saved_errno != EAGAIN)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (j == tinfo->nsocks)
|
if (j == tinfo->nsocks)
|
||||||
break;
|
break;
|
||||||
|
@ -1039,11 +1186,13 @@ do_recv(void* arg)
|
||||||
perf_log_warning("received short response");
|
perf_log_warning("received short response");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (recvd[i].unexpected && !tinfo->config->suppress.unexpected) {
|
if (recvd[i].unexpected) {
|
||||||
|
if (!tinfo->config->suppress.unexpected) {
|
||||||
perf_log_warning("received a response with an "
|
perf_log_warning("received a response with an "
|
||||||
"unexpected (maybe timed out) "
|
"unexpected (maybe timed out) "
|
||||||
"id: %u",
|
"id: %u",
|
||||||
recvd[i].qid);
|
recvd[i].qid);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
latency = recvd[i].when - recvd[i].sent;
|
latency = recvd[i].when - recvd[i].sent;
|
||||||
|
@ -1061,6 +1210,11 @@ do_recv(void* arg)
|
||||||
stats->total_response_size += recvd[i].size;
|
stats->total_response_size += recvd[i].size;
|
||||||
stats->rcodecounts[recvd[i].rcode]++;
|
stats->rcodecounts[recvd[i].rcode]++;
|
||||||
stats->latency_sum += latency;
|
stats->latency_sum += latency;
|
||||||
|
#ifdef USE_HISTOGRAMS
|
||||||
|
if (stats->latency) {
|
||||||
|
hg64_inc(stats->latency, latency);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
stats->latency_sum_squares += (latency * latency);
|
stats->latency_sum_squares += (latency * latency);
|
||||||
if (latency < stats->latency_min || stats->num_completed == 1)
|
if (latency < stats->latency_min || stats->num_completed == 1)
|
||||||
stats->latency_min = latency;
|
stats->latency_min = latency;
|
||||||
|
@ -1097,18 +1251,17 @@ static void*
|
||||||
do_interval_stats(void* arg)
|
do_interval_stats(void* arg)
|
||||||
{
|
{
|
||||||
threadinfo_t* tinfo;
|
threadinfo_t* tinfo;
|
||||||
stats_t total;
|
stats_t total = {};
|
||||||
|
stats_t last = {};
|
||||||
|
stats_t diff = {};
|
||||||
uint64_t now;
|
uint64_t now;
|
||||||
uint64_t last_interval_time;
|
uint64_t last_interval_time;
|
||||||
uint64_t last_completed;
|
|
||||||
uint64_t interval_time;
|
uint64_t interval_time;
|
||||||
uint64_t num_completed;
|
|
||||||
double qps;
|
double qps;
|
||||||
struct perf_net_socket sock = { .mode = sock_pipe, .fd = threadpipe[0] };
|
struct perf_net_socket sock = { .mode = sock_pipe, .fd = threadpipe[0] };
|
||||||
|
|
||||||
tinfo = arg;
|
tinfo = arg;
|
||||||
last_interval_time = tinfo->times->start_time;
|
last_interval_time = tinfo->times->start_time;
|
||||||
last_completed = 0;
|
|
||||||
|
|
||||||
wait_for_start();
|
wait_for_start();
|
||||||
while (perf_os_waituntilreadable(&sock, threadpipe[0],
|
while (perf_os_waituntilreadable(&sock, threadpipe[0],
|
||||||
|
@ -1117,13 +1270,23 @@ do_interval_stats(void* arg)
|
||||||
now = perf_get_time();
|
now = perf_get_time();
|
||||||
sum_stats(tinfo->config, &total);
|
sum_stats(tinfo->config, &total);
|
||||||
interval_time = now - last_interval_time;
|
interval_time = now - last_interval_time;
|
||||||
num_completed = total.num_completed - last_completed;
|
|
||||||
qps = num_completed / (((double)interval_time) / MILLION);
|
if (tinfo->config->verbose_interval_stats) {
|
||||||
|
diff_stats(tinfo->config, &last, &total, &diff);
|
||||||
|
print_statistics(tinfo->config, tinfo->times, &diff, now, interval_time);
|
||||||
|
} else {
|
||||||
|
qps = (total.num_completed - last.num_completed) / (((double)interval_time) / MILLION);
|
||||||
perf_log_printf("%u.%06u: %.6lf",
|
perf_log_printf("%u.%06u: %.6lf",
|
||||||
(unsigned int)(now / MILLION),
|
(unsigned int)(now / MILLION),
|
||||||
(unsigned int)(now % MILLION), qps);
|
(unsigned int)(now % MILLION), qps);
|
||||||
|
}
|
||||||
|
|
||||||
last_interval_time = now;
|
last_interval_time = now;
|
||||||
last_completed = total.num_completed;
|
#ifdef USE_HISTOGRAMS
|
||||||
|
free(last.latency);
|
||||||
|
free(last.conn_latency);
|
||||||
|
#endif
|
||||||
|
last = total;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1189,6 +1352,11 @@ static void perf__net_event(struct perf_net_socket* sock, perf_socket_event_t ev
|
||||||
case perf_socket_event_connected:
|
case perf_socket_event_connected:
|
||||||
stats->num_conn_completed++;
|
stats->num_conn_completed++;
|
||||||
|
|
||||||
|
#ifdef USE_HISTOGRAMS
|
||||||
|
if (stats->conn_latency) {
|
||||||
|
hg64_inc(stats->conn_latency, elapsed_time);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
stats->conn_latency_sum += elapsed_time;
|
stats->conn_latency_sum += elapsed_time;
|
||||||
stats->conn_latency_sum_squares += (elapsed_time * elapsed_time);
|
stats->conn_latency_sum_squares += (elapsed_time * elapsed_time);
|
||||||
if (elapsed_time < stats->conn_latency_min || stats->num_conn_completed == 1)
|
if (elapsed_time < stats->conn_latency_min || stats->num_conn_completed == 1)
|
||||||
|
@ -1218,6 +1386,12 @@ threadinfo_init(threadinfo_t* tinfo, const config_t* config,
|
||||||
|
|
||||||
perf_list_init(tinfo->outstanding_queries);
|
perf_list_init(tinfo->outstanding_queries);
|
||||||
perf_list_init(tinfo->unused_queries);
|
perf_list_init(tinfo->unused_queries);
|
||||||
|
#ifdef USE_HISTOGRAMS
|
||||||
|
if (config->latency_histogram) {
|
||||||
|
tinfo->stats.latency = hg64_create(HISTOGRAM_SIGBITS);
|
||||||
|
tinfo->stats.conn_latency = hg64_create(HISTOGRAM_SIGBITS);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
for (i = 0; i < NQIDS; i++) {
|
for (i = 0; i < NQIDS; i++) {
|
||||||
perf_link_init(&tinfo->queries[i]);
|
perf_link_init(&tinfo->queries[i]);
|
||||||
perf_list_append(tinfo->unused_queries, &tinfo->queries[i]);
|
perf_list_append(tinfo->unused_queries, &tinfo->queries[i]);
|
||||||
|
@ -1240,11 +1414,15 @@ threadinfo_init(threadinfo_t* tinfo, const config_t* config,
|
||||||
/*
|
/*
|
||||||
* We can't have more than 64k outstanding queries per thread.
|
* We can't have more than 64k outstanding queries per thread.
|
||||||
*/
|
*/
|
||||||
if (tinfo->max_outstanding > NQIDS)
|
if (tinfo->max_outstanding > NQIDS) {
|
||||||
|
perf_log_warning("requested number of outstanding queries (-q %u) per single thread (-T) exceeds built-in maximum %u, adjusting\n", tinfo->max_outstanding, NQIDS);
|
||||||
tinfo->max_outstanding = NQIDS;
|
tinfo->max_outstanding = NQIDS;
|
||||||
|
}
|
||||||
|
|
||||||
if (tinfo->nsocks > MAX_SOCKETS)
|
if (tinfo->nsocks > MAX_SOCKETS) {
|
||||||
|
perf_log_warning("requested number of clients (-c %u) per thread (-T) exceeds built-in maximum %u, adjusting\n", tinfo->nsocks, MAX_SOCKETS);
|
||||||
tinfo->nsocks = MAX_SOCKETS;
|
tinfo->nsocks = MAX_SOCKETS;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(tinfo->socks = calloc(tinfo->nsocks, sizeof(*tinfo->socks)))) {
|
if (!(tinfo->socks = calloc(tinfo->nsocks, sizeof(*tinfo->socks)))) {
|
||||||
perf_log_fatal("out of memory");
|
perf_log_fatal("out of memory");
|
||||||
|
@ -1383,7 +1561,7 @@ int main(int argc, char** argv)
|
||||||
print_final_status(&config);
|
print_final_status(&config);
|
||||||
|
|
||||||
sum_stats(&config, &total_stats);
|
sum_stats(&config, &total_stats);
|
||||||
print_statistics(&config, ×, &total_stats);
|
print_statistics(&config, ×, &total_stats, 0, 0);
|
||||||
perf_net_stats_print(config.mode);
|
perf_net_stats_print(config.mode);
|
||||||
|
|
||||||
cleanup(&config);
|
cleanup(&config);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
327
src/ext/hg64.c
Normal file
327
src/ext/hg64.c
Normal file
|
@ -0,0 +1,327 @@
|
||||||
|
/*
|
||||||
|
* hg64 - 64-bit histograms
|
||||||
|
*
|
||||||
|
* Written by Tony Finch <dot@dotat.at> <fanf@isc.org>
|
||||||
|
*
|
||||||
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdatomic.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "hg64.h"
|
||||||
|
|
||||||
|
/* number of bins is same as number of bits in a value */
|
||||||
|
#define BINS 64
|
||||||
|
|
||||||
|
typedef atomic_uint_fast64_t counter;
|
||||||
|
typedef _Atomic(counter*) bin_ptr;
|
||||||
|
|
||||||
|
struct hg64 {
|
||||||
|
unsigned sigbits;
|
||||||
|
bin_ptr bin[BINS];
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline counter*
|
||||||
|
get_bin(hg64* hg, unsigned b)
|
||||||
|
{
|
||||||
|
/* key_to_new_counter() below has the matching store / release */
|
||||||
|
return (atomic_load_explicit(&hg->bin[b], memory_order_acquire));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* when we only care about the histogram precision
|
||||||
|
*/
|
||||||
|
struct hg64p {
|
||||||
|
unsigned sigbits;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __has_attribute
|
||||||
|
#if __has_attribute(__transparent_union__)
|
||||||
|
#define TRANSPARENT __attribute__((__transparent_union__))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TRANSPARENT
|
||||||
|
|
||||||
|
typedef union hg64u {
|
||||||
|
hg64* hg;
|
||||||
|
const struct hg64p* hp;
|
||||||
|
} hg64u TRANSPARENT;
|
||||||
|
|
||||||
|
#define hg64p(hu) ((hu).hp)
|
||||||
|
#else
|
||||||
|
|
||||||
|
typedef void* hg64u;
|
||||||
|
|
||||||
|
#define hg64p(hu) ((const struct hg64p*)(hu))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The bins arrays have a static size for simplicity, but that means We
|
||||||
|
* waste a little extra space that could be saved by omitting the
|
||||||
|
* exponents that land in the denormal number bin. The following macros
|
||||||
|
* calculate (at run time) the exact number of keys when we need to do
|
||||||
|
* accurate bounds checks.
|
||||||
|
*/
|
||||||
|
#define DENORMALS(hp) ((hp)->sigbits - 1)
|
||||||
|
#define EXPONENTS(hp) (BINS - DENORMALS(hp))
|
||||||
|
#define MANTISSAS(hp) (1 << (hp)->sigbits)
|
||||||
|
#define KEYS(hp) (EXPONENTS(hp) * MANTISSAS(hp))
|
||||||
|
|
||||||
|
#define BINSIZE(hp) MANTISSAS(hp)
|
||||||
|
|
||||||
|
/**********************************************************************/
|
||||||
|
|
||||||
|
#define OUTARG(ptr, val) (void)(((ptr) != NULL) && (bool)(*(ptr) = (val)))
|
||||||
|
|
||||||
|
/**********************************************************************/
|
||||||
|
|
||||||
|
hg64* hg64_create(unsigned sigbits)
|
||||||
|
{
|
||||||
|
if (sigbits < 1 || 15 < sigbits) {
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
hg64* hg = malloc(sizeof(*hg));
|
||||||
|
hg->sigbits = sigbits;
|
||||||
|
/*
|
||||||
|
* it is probably portable to zero-initialize atomics but the
|
||||||
|
* C standard says we shouldn't rely on it; but this loop
|
||||||
|
* should optimize to memset() on most target systems
|
||||||
|
*/
|
||||||
|
for (unsigned b = 0; b < BINS; b++) {
|
||||||
|
atomic_init(&hg->bin[b], NULL);
|
||||||
|
}
|
||||||
|
return (hg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hg64_destroy(hg64* hg)
|
||||||
|
{
|
||||||
|
for (unsigned b = 0; b < BINS; b++) {
|
||||||
|
free(get_bin(hg, b));
|
||||||
|
}
|
||||||
|
*hg = (hg64) { 0 };
|
||||||
|
free(hg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************/
|
||||||
|
|
||||||
|
static inline uint64_t
|
||||||
|
key_to_minval(hg64u hu, unsigned key)
|
||||||
|
{
|
||||||
|
unsigned binsize = BINSIZE(hg64p(hu));
|
||||||
|
unsigned exponent = (key / binsize) - 1;
|
||||||
|
uint64_t mantissa = (key % binsize) + binsize;
|
||||||
|
return (key < binsize ? key : mantissa << exponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* don't shift by 64, and don't underflow exponent; instead,
|
||||||
|
* reduce shift by 1 for each hazard and pre-shift UINT64_MAX
|
||||||
|
*/
|
||||||
|
static inline uint64_t
|
||||||
|
key_to_maxval(hg64u hu, unsigned key)
|
||||||
|
{
|
||||||
|
unsigned binsize = BINSIZE(hg64p(hu));
|
||||||
|
unsigned shift = 63 - (key / binsize);
|
||||||
|
uint64_t range = UINT64_MAX / 4 >> shift;
|
||||||
|
return (key_to_minval(hu, key) + range);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This branchless conversion is due to Paul Khuong: see bin_down_of() in
|
||||||
|
* https://pvk.ca/Blog/2015/06/27/linear-log-bucketing-fast-versatile-simple/
|
||||||
|
*/
|
||||||
|
static inline unsigned
|
||||||
|
value_to_key(hg64u hu, uint64_t value)
|
||||||
|
{
|
||||||
|
/* fast path */
|
||||||
|
const struct hg64p* hp = hg64p(hu);
|
||||||
|
/* ensure that denormal numbers are all in the same bin */
|
||||||
|
uint64_t binned = value | BINSIZE(hp);
|
||||||
|
int clz = __builtin_clzll((unsigned long long)(binned));
|
||||||
|
/* actually 1 less than the exponent except for denormals */
|
||||||
|
unsigned exponent = 63 - hp->sigbits - clz;
|
||||||
|
/* mantissa has leading bit set except for denormals */
|
||||||
|
unsigned mantissa = value >> exponent;
|
||||||
|
/* leading bit of mantissa adds one to exponent */
|
||||||
|
return ((exponent << hp->sigbits) + mantissa);
|
||||||
|
}
|
||||||
|
|
||||||
|
static counter*
|
||||||
|
key_to_new_counter(hg64* hg, unsigned key)
|
||||||
|
{
|
||||||
|
/* slow path */
|
||||||
|
unsigned binsize = BINSIZE(hg);
|
||||||
|
unsigned b = key / binsize;
|
||||||
|
unsigned c = key % binsize;
|
||||||
|
counter* old_bp = NULL;
|
||||||
|
counter* new_bp = malloc(sizeof(counter) * binsize);
|
||||||
|
/* see comment in hg64_create() above */
|
||||||
|
for (unsigned i = 0; i < binsize; i++) {
|
||||||
|
atomic_init(new_bp + i, 0);
|
||||||
|
}
|
||||||
|
bin_ptr* bpp = &hg->bin[b];
|
||||||
|
if (atomic_compare_exchange_strong_explicit(bpp, &old_bp, new_bp,
|
||||||
|
memory_order_acq_rel, memory_order_acquire)) {
|
||||||
|
return (new_bp + c);
|
||||||
|
} else {
|
||||||
|
/* lost the race, so use the winner's counters */
|
||||||
|
free(new_bp);
|
||||||
|
return (old_bp + c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline counter*
|
||||||
|
key_to_counter(hg64* hg, unsigned key)
|
||||||
|
{
|
||||||
|
/* fast path */
|
||||||
|
unsigned binsize = BINSIZE(hg);
|
||||||
|
unsigned b = key / binsize;
|
||||||
|
unsigned c = key % binsize;
|
||||||
|
counter* bp = get_bin(hg, b);
|
||||||
|
return (bp == NULL ? NULL : bp + c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t
|
||||||
|
get_key_count(hg64* hg, unsigned key)
|
||||||
|
{
|
||||||
|
counter* ctr = key_to_counter(hg, key);
|
||||||
|
return (ctr == NULL ? 0 : atomic_load_explicit(ctr, memory_order_relaxed));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
add_key_count(hg64* hg, unsigned key, uint64_t inc)
|
||||||
|
{
|
||||||
|
if (inc == 0)
|
||||||
|
return;
|
||||||
|
counter* ctr = key_to_counter(hg, key);
|
||||||
|
ctr = ctr ? ctr : key_to_new_counter(hg, key);
|
||||||
|
atomic_fetch_add_explicit(ctr, inc, memory_order_relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************/
|
||||||
|
|
||||||
|
void hg64_inc(hg64* hg, uint64_t value)
|
||||||
|
{
|
||||||
|
add_key_count(hg, value_to_key(hg, value), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hg64_get(hg64* hg, unsigned key,
|
||||||
|
uint64_t* pmin, uint64_t* pmax, uint64_t* pcount)
|
||||||
|
{
|
||||||
|
if (key < KEYS(hg)) {
|
||||||
|
OUTARG(pmin, key_to_minval(hg, key));
|
||||||
|
OUTARG(pmax, key_to_maxval(hg, key));
|
||||||
|
OUTARG(pcount, get_key_count(hg, key));
|
||||||
|
return (true);
|
||||||
|
} else {
|
||||||
|
return (false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
hg64_next(hg64* hg, unsigned key)
|
||||||
|
{
|
||||||
|
key++;
|
||||||
|
while (key < KEYS(hg) && (key & (BINSIZE(hg) - 1)) == 0 && key_to_counter(hg, key) == NULL) {
|
||||||
|
key += BINSIZE(hg);
|
||||||
|
}
|
||||||
|
return (key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* https://fanf2.user.srcf.net/hermes/doc/antiforgery/stats.pdf
|
||||||
|
*/
|
||||||
|
void hg64_mean_variance(hg64* hg, double* pmean, double* pvar)
|
||||||
|
{
|
||||||
|
double pop = 0.0;
|
||||||
|
double mean = 0.0;
|
||||||
|
double sigma = 0.0;
|
||||||
|
uint64_t min, max, count;
|
||||||
|
for (unsigned key = 0;
|
||||||
|
hg64_get(hg, key, &min, &max, &count);
|
||||||
|
key = hg64_next(hg, key)) {
|
||||||
|
double delta = (double)min / 2.0 + (double)max / 2.0 - mean;
|
||||||
|
if (count != 0) { /* avoid division by zero */
|
||||||
|
pop += count;
|
||||||
|
mean += count * delta / pop;
|
||||||
|
sigma += count * delta * (min + max - mean);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OUTARG(pmean, mean);
|
||||||
|
OUTARG(pvar, sigma / pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************/
|
||||||
|
|
||||||
|
void hg64_merge(hg64* target, hg64* source)
|
||||||
|
{
|
||||||
|
uint64_t count;
|
||||||
|
for (unsigned skey = 0;
|
||||||
|
hg64_get(source, skey, NULL, NULL, &count);
|
||||||
|
skey = hg64_next(source, skey)) {
|
||||||
|
uint64_t svmin = key_to_minval(source, skey);
|
||||||
|
uint64_t svmax = key_to_maxval(source, skey);
|
||||||
|
unsigned tkmin = value_to_key(target, svmin);
|
||||||
|
unsigned tkmax = value_to_key(target, svmax);
|
||||||
|
unsigned keys = tkmax - tkmin + 1;
|
||||||
|
/* is there a more cunning way to spread out the remainder? */
|
||||||
|
uint64_t div = count / keys;
|
||||||
|
uint64_t rem = count % keys;
|
||||||
|
for (unsigned tkey = tkmin; tkey <= tkmax; tkey++) {
|
||||||
|
uint64_t inc = div + (uint64_t)(tkey < rem);
|
||||||
|
add_key_count(target, tkey, inc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hg64_diff(hg64* a, hg64* b, hg64* diff)
|
||||||
|
{
|
||||||
|
assert((a->sigbits == b->sigbits) && (b->sigbits == diff->sigbits));
|
||||||
|
uint64_t count_a = 0;
|
||||||
|
uint64_t count_b = 0;
|
||||||
|
for (unsigned key = 0;
|
||||||
|
hg64_get(a, key, NULL, NULL, &count_a);
|
||||||
|
key++) {
|
||||||
|
hg64_get(b, key, NULL, NULL, &count_b);
|
||||||
|
add_key_count(diff, key, count_a - count_b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned hg64_min_key(hg64* hg)
|
||||||
|
{
|
||||||
|
uint64_t pcount;
|
||||||
|
for (unsigned key = 0;
|
||||||
|
hg64_get(hg, key, NULL, NULL, &pcount);
|
||||||
|
key = hg64_next(hg, key)) {
|
||||||
|
if (pcount > 0)
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned hg64_max_key(hg64* hg)
|
||||||
|
{
|
||||||
|
unsigned last_key = 0;
|
||||||
|
uint64_t pcount;
|
||||||
|
for (unsigned key = 0;
|
||||||
|
hg64_get(hg, key, NULL, NULL, &pcount);
|
||||||
|
key = hg64_next(hg, key)) {
|
||||||
|
if (pcount > 0)
|
||||||
|
last_key = key;
|
||||||
|
}
|
||||||
|
return last_key;
|
||||||
|
}
|
88
src/ext/hg64.h
Normal file
88
src/ext/hg64.h
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* hg64 - 64-bit histograms
|
||||||
|
*
|
||||||
|
* Written by Tony Finch <dot@dotat.at> <fanf@isc.org>
|
||||||
|
*
|
||||||
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HG64_H
|
||||||
|
#define HG64_H 1
|
||||||
|
|
||||||
|
typedef struct hg64 hg64;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate a new histogram. `sigbits` must be between 1 and 15
|
||||||
|
* inclusive; it is the number of significant bits of each value
|
||||||
|
* to use when mapping values to buckets.
|
||||||
|
*/
|
||||||
|
hg64* hg64_create(unsigned sigbits);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free the memory used by a histogram
|
||||||
|
*/
|
||||||
|
void hg64_destroy(hg64* hg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add 1 to the value's bucket
|
||||||
|
*/
|
||||||
|
void hg64_inc(hg64* hg, uint64_t value);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get information about a bucket. This can be used as an iterator,
|
||||||
|
* by initializing `key` to zero and incrementing by one or using
|
||||||
|
* `hg64_next()` until `hg64_get()` returns `false`. The number of
|
||||||
|
* iterations is a little less than `1 << (6 + sigbits)`.
|
||||||
|
*
|
||||||
|
* If `pmin` is non-NULL it is set to the bucket's minimum inclusive value.
|
||||||
|
*
|
||||||
|
* If `pmax` is non-NULL it is set to the bucket's maximum inclusive value.
|
||||||
|
*
|
||||||
|
* If `pcount` is non-NULL it is set to the bucket's counter, which
|
||||||
|
* can be zero. (Empty buckets are included in the iterator.)
|
||||||
|
*/
|
||||||
|
bool hg64_get(hg64* hg, unsigned key,
|
||||||
|
uint64_t* pmin, uint64_t* pmax, uint64_t* pcount);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip to the next key, omitting groups of nonexistent buckets.
|
||||||
|
*/
|
||||||
|
unsigned hg64_next(hg64* hg, unsigned key);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get summary statistics about the histogram.
|
||||||
|
*
|
||||||
|
* If `pmean` is non-NULL it is set to the mean of the recorded data.
|
||||||
|
*
|
||||||
|
* If `pvar` is non-NULL it is set to the variance of the recorded
|
||||||
|
* data. The standard deviation is the square root of the variance.
|
||||||
|
*/
|
||||||
|
void hg64_mean_variance(hg64* hg, double* pmean, double* pvar);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Increase the counts in `target` by the counts recorded in `source`
|
||||||
|
*/
|
||||||
|
void hg64_merge(hg64* target, hg64* source);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* diff = a - b
|
||||||
|
*/
|
||||||
|
void hg64_diff(hg64* a, hg64* b, hg64* diff);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get highest key with non-zero value. Returns 0 if all values are 0.
|
||||||
|
*/
|
||||||
|
unsigned hg64_max_key(hg64* hg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get lowest key with non-zero value. Returns 0 if all values are 0.
|
||||||
|
*/
|
||||||
|
unsigned hg64_min_key(hg64* hg);
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
|
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "edns.h"
|
#include "edns.h"
|
||||||
#include "parse_uri.h"
|
#include "ext/parse_uri.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "strerror.h"
|
#include "strerror.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
@ -324,6 +324,8 @@ static ssize_t perf__doh_recv(struct perf_net_socket* sock, void* buf, size_t le
|
||||||
return -1;
|
return -1;
|
||||||
case SSL_ERROR_SYSCALL:
|
case SSL_ERROR_SYSCALL:
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
|
case EBADF:
|
||||||
|
// treat this as a retry, can happen if sendto is reconnecting
|
||||||
case ECONNREFUSED:
|
case ECONNREFUSED:
|
||||||
case ECONNRESET:
|
case ECONNRESET:
|
||||||
case ENOTCONN:
|
case ENOTCONN:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
@ -177,6 +177,8 @@ static ssize_t perf__dot_recv(struct perf_net_socket* sock, void* buf, size_t le
|
||||||
break;
|
break;
|
||||||
case SSL_ERROR_SYSCALL:
|
case SSL_ERROR_SYSCALL:
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
|
case EBADF:
|
||||||
|
// treat this as a retry, can happen if sendto is reconnecting
|
||||||
case ECONNREFUSED:
|
case ECONNREFUSED:
|
||||||
case ECONNRESET:
|
case ECONNRESET:
|
||||||
case ENOTCONN:
|
case ENOTCONN:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
@ -171,6 +171,8 @@ static ssize_t perf__tcp_recv(struct perf_net_socket* sock, void* buf, size_t le
|
||||||
return 0;
|
return 0;
|
||||||
} else if (n < 0) {
|
} else if (n < 0) {
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
|
case EBADF:
|
||||||
|
// treat this as a retry, can happen if sendto is reconnecting
|
||||||
case ECONNREFUSED:
|
case ECONNREFUSED:
|
||||||
case ECONNRESET:
|
case ECONNRESET:
|
||||||
case ENOTCONN:
|
case ENOTCONN:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
34
src/opt.c
34
src/opt.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
@ -238,39 +238,57 @@ static int perf_opt_long_parse(char* optarg)
|
||||||
ssize_t optlen;
|
ssize_t optlen;
|
||||||
char* arg;
|
char* arg;
|
||||||
|
|
||||||
// TODO: Allow boolean not to have =/value
|
if ((arg = strchr(optarg, '='))) {
|
||||||
if (!(arg = strchr(optarg, '='))) {
|
arg++;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
optlen = arg - optarg;
|
optlen = arg - optarg;
|
||||||
if (optlen < 1) {
|
if (optlen < 1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
arg++;
|
} else {
|
||||||
|
optlen = strlen(optarg);
|
||||||
|
}
|
||||||
|
|
||||||
long_opt_t* opt = longopts;
|
long_opt_t* opt = longopts;
|
||||||
while (opt) {
|
while (opt) {
|
||||||
if (!strncmp(optarg, opt->name, optlen)) {
|
if (!strncmp(optarg, opt->name, optlen)) {
|
||||||
switch (opt->type) {
|
switch (opt->type) {
|
||||||
case perf_opt_string:
|
case perf_opt_string:
|
||||||
|
if (!arg) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
*opt->u.stringp = arg;
|
*opt->u.stringp = arg;
|
||||||
break;
|
break;
|
||||||
case perf_opt_boolean:
|
case perf_opt_boolean:
|
||||||
*opt->u.boolp = true;
|
*opt->u.boolp = true;
|
||||||
break;
|
break;
|
||||||
case perf_opt_uint:
|
case perf_opt_uint:
|
||||||
|
if (!arg) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
*opt->u.uintp = parse_uint(opt->desc, arg, 1, 0xFFFFFFFF);
|
*opt->u.uintp = parse_uint(opt->desc, arg, 1, 0xFFFFFFFF);
|
||||||
break;
|
break;
|
||||||
case perf_opt_zpint:
|
case perf_opt_zpint:
|
||||||
|
if (!arg) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
*opt->u.uintp = parse_uint(opt->desc, arg, 0, 0xFFFFFFFF);
|
*opt->u.uintp = parse_uint(opt->desc, arg, 0, 0xFFFFFFFF);
|
||||||
break;
|
break;
|
||||||
case perf_opt_timeval:
|
case perf_opt_timeval:
|
||||||
|
if (!arg) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
*opt->u.uint64p = parse_timeval(opt->desc, arg);
|
*opt->u.uint64p = parse_timeval(opt->desc, arg);
|
||||||
break;
|
break;
|
||||||
case perf_opt_double:
|
case perf_opt_double:
|
||||||
|
if (!arg) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
*opt->u.doublep = parse_double(opt->desc, arg);
|
*opt->u.doublep = parse_double(opt->desc, arg);
|
||||||
break;
|
break;
|
||||||
case perf_opt_port:
|
case perf_opt_port:
|
||||||
|
if (!arg) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
*opt->u.portp = parse_uint(opt->desc, arg, 0, 0xFFFF);
|
*opt->u.portp = parse_uint(opt->desc, arg, 0, 0xFFFF);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -284,10 +302,10 @@ static int perf_opt_long_parse(char* optarg)
|
||||||
|
|
||||||
void perf_long_opt_usage(void)
|
void perf_long_opt_usage(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: %s ... -O <name>=<value> ...\n\nAvailable long options:\n", progname);
|
fprintf(stderr, "Usage: %s ... -O <name>[=<value>] ...\n\nAvailable long options:\n", progname);
|
||||||
long_opt_t* opt = longopts;
|
long_opt_t* opt = longopts;
|
||||||
while (opt) {
|
while (opt) {
|
||||||
fprintf(stderr, " %s: %s", opt->name, opt->help);
|
fprintf(stderr, " %s%s: %s", opt->name, opt->type != perf_opt_boolean ? "=<val>" : "", opt->help);
|
||||||
if (opt->defval) {
|
if (opt->defval) {
|
||||||
fprintf(stderr, " (default: %s)", opt->defval);
|
fprintf(stderr, " (default: %s)", opt->defval);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
2
src/os.c
2
src/os.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
2
src/os.h
2
src/os.h
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# Copyright 2019-2022 OARC, Inc.
|
# Copyright 2019-2023 OARC, Inc.
|
||||||
# Copyright 2017-2018 Akamai Technologies
|
# Copyright 2017-2018 Akamai Technologies
|
||||||
# Copyright 2006-2016 Nominum, Inc.
|
# Copyright 2006-2016 Nominum, Inc.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
.\" Copyright 2019-2022 OARC, Inc.
|
.\" Copyright 2019-2023 OARC, Inc.
|
||||||
.\" Copyright 2017-2018 Akamai Technologies
|
.\" Copyright 2017-2018 Akamai Technologies
|
||||||
.\" Copyright 2006-2016 Nominum, Inc.
|
.\" Copyright 2006-2016 Nominum, Inc.
|
||||||
.\" All rights reserved.
|
.\" All rights reserved.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -2,3 +2,8 @@
|
||||||
|
|
||||||
../dnsperf -h
|
../dnsperf -h
|
||||||
../resperf -h
|
../resperf -h
|
||||||
|
|
||||||
|
! ../dnsperf -O suppress
|
||||||
|
! ../dnsperf -O suppress=
|
||||||
|
! ../resperf -O suppress
|
||||||
|
! ../resperf -O suppress=
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2019-2022 OARC, Inc.
|
* Copyright 2019-2023 OARC, Inc.
|
||||||
* Copyright 2017-2018 Akamai Technologies
|
* Copyright 2017-2018 Akamai Technologies
|
||||||
* Copyright 2006-2016 Nominum, Inc.
|
* Copyright 2006-2016 Nominum, Inc.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|
Loading…
Add table
Reference in a new issue