1
0
Fork 0

Adding upstream version 2.11.0.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-09 09:05:48 +01:00
parent 6dd69c3878
commit 7ffd64128a
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
50 changed files with 895 additions and 132 deletions

48
CHANGES
View file

@ -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
Release 2.10.0

View file

@ -1,4 +1,4 @@
# Copyright 2019-2022 OARC, Inc.
# Copyright 2019-2023 OARC, Inc.
# Copyright 2017-2018 Akamai Technologies
# Copyright 2006-2016 Nominum, Inc.
# All rights reserved.

View file

@ -14,7 +14,7 @@
@SET_MAKE@
# Copyright 2019-2022 OARC, Inc.
# Copyright 2019-2023 OARC, Inc.
# Copyright 2017-2018 Akamai Technologies
# Copyright 2006-2016 Nominum, Inc.
# All rights reserved.

View file

@ -100,7 +100,7 @@ The contrib directory contains additional software related to `dnsperf` and
## License
```
Copyright 2019-2022 OARC, Inc.
Copyright 2019-2023 OARC, Inc.
Copyright 2017-2018 Akamai Technologies
Copyright 2006-2016 Nominum, Inc.
All rights reserved.

46
configure vendored
View file

@ -1,6 +1,6 @@
#! /bin/sh
# 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>.
#
@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='dnsperf'
PACKAGE_TARNAME='dnsperf'
PACKAGE_VERSION='2.10.0'
PACKAGE_STRING='dnsperf 2.10.0'
PACKAGE_VERSION='2.11.0'
PACKAGE_STRING='dnsperf 2.11.0'
PACKAGE_BUGREPORT='admin@dns-oarc.net'
PACKAGE_URL='https://github.com/DNS-OARC/dnsperf/issues'
@ -649,6 +649,8 @@ libssl_CFLAGS
PKG_CONFIG_LIBDIR
PKG_CONFIG_PATH
PKG_CONFIG
HAVE_STDATOMIC_FALSE
HAVE_STDATOMIC_TRUE
PTHREAD_CFLAGS
PTHREAD_LIBS
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.
# This message is too long to be a string in the A/UX 3.1 sh.
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]...
@ -1431,7 +1433,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of dnsperf 2.10.0:";;
short | recursive ) echo "Configuration of dnsperf 2.11.0:";;
esac
cat <<\_ACEOF
@ -1570,7 +1572,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
dnsperf configure 2.10.0
dnsperf configure 2.11.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -1939,7 +1941,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
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
$ $0 $@
@ -2802,7 +2804,7 @@ fi
# Define the identity of the package.
PACKAGE='dnsperf'
VERSION='2.10.0'
VERSION='2.11.0'
cat >>confdefs.h <<_ACEOF
@ -12891,6 +12893,26 @@ _ACEOF
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
@ -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.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
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}"
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
# values after options handling.
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
CONFIG_FILES = $CONFIG_FILES
@ -14477,7 +14503,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
dnsperf config.status 2.10.0
dnsperf config.status 2.11.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

View file

@ -1,4 +1,4 @@
# Copyright 2019-2022 OARC, Inc.
# Copyright 2019-2023 OARC, Inc.
# Copyright 2017-2018 Akamai Technologies
# Copyright 2006-2016 Nominum, Inc.
# All rights reserved.
@ -16,7 +16,7 @@
# limitations under the License.
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])
AC_CONFIG_SRCDIR([src/dnsperf.c])
AC_CONFIG_HEADER([src/config.h])
@ -56,6 +56,8 @@ AM_EXTRA_RECURSIVE_TARGETS([gcov])
# Checks for support.
AX_PTHREAD
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
PKG_CHECK_MODULES([libssl], [libssl])

View file

@ -1,6 +1,6 @@
#!/usr/bin/env python
#
# Copyright 2019-2022 OARC, Inc.
# Copyright 2019-2023 OARC, Inc.
# Copyright 2017-2018 Akamai Technologies
# Copyright 2006-2016 Nominum, Inc.
# All rights reserved.

View file

@ -1,4 +1,4 @@
.\" Copyright 2019-2022 OARC, Inc.
.\" Copyright 2019-2023 OARC, Inc.
.\" Copyright 2017-2018 Akamai Technologies
.\" Copyright 2006-2016 Nominum, Inc.
.\" All rights reserved.

View file

@ -1,4 +1,4 @@
# Copyright 2019-2022 OARC, Inc.
# Copyright 2019-2023 OARC, Inc.
# Copyright 2017-2018 Akamai Technologies
# Copyright 2006-2016 Nominum, Inc.
# All rights reserved.

View file

@ -1,4 +1,4 @@
# Copyright 2019-2022 OARC, Inc.
# Copyright 2019-2023 OARC, Inc.
# Copyright 2017-2018 Akamai Technologies
# Copyright 2006-2016 Nominum, Inc.
# All rights reserved.
@ -30,9 +30,15 @@ bin_PROGRAMS = dnsperf resperf
dist_bin_SCRIPTS = resperf-report
_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 \
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
dist_dnsperf_SOURCES = $(_libperf_headers)

View file

@ -14,7 +14,7 @@
@SET_MAKE@
# Copyright 2019-2022 OARC, Inc.
# Copyright 2019-2023 OARC, Inc.
# Copyright 2017-2018 Akamai Technologies
# Copyright 2006-2016 Nominum, Inc.
# All rights reserved.
@ -107,6 +107,8 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
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
ACLOCAL_M4 = $(top_srcdir)/aclocal.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)" \
"$(DESTDIR)$(man1dir)"
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) \
qtype.$(OBJEXT) edns.$(OBJEXT) tsig.$(OBJEXT) \
net_udp.$(OBJEXT) net_tcp.$(OBJEXT) net_dot.$(OBJEXT) \
net_doh.$(OBJEXT) parse_uri.$(OBJEXT)
am_dnsperf_OBJECTS = $(am__objects_1) dnsperf.$(OBJEXT)
am__objects_2 =
dist_dnsperf_OBJECTS = $(am__objects_2)
net_doh.$(OBJEXT) ext/parse_uri.$(OBJEXT) $(am__objects_1)
am_dnsperf_OBJECTS = $(am__objects_2) dnsperf.$(OBJEXT)
am__dist_dnsperf_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
am__objects_3 =
am__objects_4 = $(am__objects_3)
dist_dnsperf_OBJECTS = $(am__objects_4)
dnsperf_OBJECTS = $(am_dnsperf_OBJECTS) $(dist_dnsperf_OBJECTS)
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_0 = --silent
am__v_lt_1 =
am_resperf_OBJECTS = $(am__objects_1) resperf.$(OBJEXT)
dist_resperf_OBJECTS = $(am__objects_2)
am__resperf_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 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_DEPENDENCIES = $(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_dot.Po ./$(DEPDIR)/net_tcp.Po \
./$(DEPDIR)/net_udp.Po ./$(DEPDIR)/opt.Po ./$(DEPDIR)/os.Po \
./$(DEPDIR)/parse_uri.Po ./$(DEPDIR)/qtype.Po \
./$(DEPDIR)/resperf.Po ./$(DEPDIR)/strerror.Po \
./$(DEPDIR)/tsig.Po
./$(DEPDIR)/qtype.Po ./$(DEPDIR)/resperf.Po \
./$(DEPDIR)/strerror.Po ./$(DEPDIR)/tsig.Po \
ext/$(DEPDIR)/hg64.Po ext/$(DEPDIR)/parse_uri.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@ -222,8 +239,9 @@ am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(dnsperf_SOURCES) $(dist_dnsperf_SOURCES) \
$(resperf_SOURCES) $(dist_resperf_SOURCES)
DIST_SOURCES = $(dnsperf_SOURCES) $(dist_dnsperf_SOURCES) \
$(resperf_SOURCES) $(dist_resperf_SOURCES)
DIST_SOURCES = $(am__dnsperf_SOURCES_DIST) \
$(am__dist_dnsperf_SOURCES_DIST) $(am__resperf_SOURCES_DIST) \
$(am__dist_resperf_SOURCES_DIST)
RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
ctags-recursive dvi-recursive html-recursive info-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
dist_bin_SCRIPTS = resperf-report
_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
_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
_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 \
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 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
dist_dnsperf_SOURCES = $(_libperf_headers)
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)$$//'`; \
echo " 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)
@rm -f dnsperf$(EXEEXT)
@ -601,6 +628,7 @@ uninstall-dist_binSCRIPTS:
mostlyclean-compile:
-rm -f *.$(OBJEXT)
-rm -f ext/*.$(OBJEXT)
distclean-compile:
-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)/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)/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)/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)/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):
@$(MKDIR_P) $(@D)
@ -893,6 +922,8 @@ clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_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:
@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)/opt.Po
-rm -f ./$(DEPDIR)/os.Po
-rm -f ./$(DEPDIR)/parse_uri.Po
-rm -f ./$(DEPDIR)/qtype.Po
-rm -f ./$(DEPDIR)/resperf.Po
-rm -f ./$(DEPDIR)/strerror.Po
-rm -f ./$(DEPDIR)/tsig.Po
-rm -f ext/$(DEPDIR)/hg64.Po
-rm -f ext/$(DEPDIR)/parse_uri.Po
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-hdr distclean-tags
@ -982,11 +1014,12 @@ maintainer-clean: maintainer-clean-recursive
-rm -f ./$(DEPDIR)/net_udp.Po
-rm -f ./$(DEPDIR)/opt.Po
-rm -f ./$(DEPDIR)/os.Po
-rm -f ./$(DEPDIR)/parse_uri.Po
-rm -f ./$(DEPDIR)/qtype.Po
-rm -f ./$(DEPDIR)/resperf.Po
-rm -f ./$(DEPDIR)/strerror.Po
-rm -f ./$(DEPDIR)/tsig.Po
-rm -f ext/$(DEPDIR)/hg64.Po
-rm -f ext/$(DEPDIR)/parse_uri.Po
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -36,6 +36,9 @@
/* 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. */
#undef HAVE_STDINT_H

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,4 +1,4 @@
.\" Copyright 2019-2022 OARC, Inc.
.\" Copyright 2019-2023 OARC, Inc.
.\" Copyright 2017-2018 Akamai Technologies
.\" Copyright 2006-2016 Nominum, Inc.
.\" All rights reserved.
@ -341,8 +341,9 @@ The default is the loopback address, 127.0.0.1.
\fB-S \fIstats_interval\fR
.br
.RS
If this parameter is specified, a count of the number of queries per second
during the interval will be printed out every stats_interval seconds.
If this parameter is specified, a count of the number of answers received
per second during the interval will be printed out every \fIstats_interval\fR
seconds.
.RE
\fB-t \fItimeout\fR
@ -458,7 +459,6 @@ Following type are available.
.br
\fBunexpected\fR: Suppress messages about answers with an unexpected message ID
.RE
\fBnum-queries-per-conn=\fINUMBER\fR
.br
.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.
Note that this option is only useful for connection oriented protocols.
.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"
\fBresperf\fR(1)
.SH AUTHOR

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.
@ -32,6 +32,10 @@
#include "util.h"
#include "list.h"
#include "buffer.h"
#if HAVE_STDATOMIC_H
#include "ext/hg64.h"
#define USE_HISTOGRAMS
#endif
#include <inttypes.h>
#include <errno.h>
@ -49,6 +53,8 @@
#include <openssl/conf.h>
#include <openssl/err.h>
#define HISTOGRAM_SIGBITS 5 /* about 3 % latency precision */
#define DEFAULT_SERVER_NAME "127.0.0.1"
#define DEFAULT_SERVER_PORT 53
#define DEFAULT_SERVER_DOT_PORT 853
@ -85,6 +91,7 @@ typedef struct {
uint32_t max_outstanding;
uint32_t max_qps;
uint64_t stats_interval;
bool verbose_interval_stats;
bool updates;
bool binary_input;
perf_input_format_t input_format;
@ -92,6 +99,9 @@ typedef struct {
enum perf_net_mode mode;
perf_suppress_t suppress;
size_t num_queries_per_conn;
#ifdef USE_HISTOGRAMS
bool latency_histogram;
#endif
} config_t;
typedef struct {
@ -101,8 +111,9 @@ typedef struct {
struct timespec stop_time_ns;
} times_t;
#define DNSPERF_STATS_RCODECOUNTS 16
typedef struct {
uint64_t rcodecounts[16];
uint64_t rcodecounts[DNSPERF_STATS_RCODECOUNTS];
uint64_t num_sent;
uint64_t num_interrupted;
@ -124,6 +135,11 @@ typedef struct {
uint64_t conn_latency_sum_squares;
uint64_t conn_latency_min;
uint64_t conn_latency_max;
#ifdef USE_HISTOGRAMS
hg64* latency;
hg64* conn_latency;
#endif
} stats_t;
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
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;
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";
run_time = times->end_time - times->start_time;
if (now)
run_time = now - times->start_time;
else
run_time = times->end_time - times->start_time;
printf("Statistics:\n\n");
printf("%sStatistics:\n\n", now ? "Interval " : "");
printf(" %s sent: %" PRIu64 "\n",
units, stats->num_sent);
@ -287,7 +385,7 @@ print_statistics(const config_t* config, const times_t* times, stats_t* stats)
printf(" Response codes: ");
first_rcode = true;
for (i = 0; i < 16; i++) {
for (i = 0; i < DNSPERF_STATS_RCODECOUNTS; i++) {
if (stats->rcodecounts[i] == 0)
continue;
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));
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");
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)(stats->latency_min / MILLION),
(unsigned int)(stats->latency_min % MILLION),
(unsigned int)(stats->latency_max / MILLION),
(unsigned int)(stats->latency_max % 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_max / MILLION),
(unsigned int)(stats->latency_max % MILLION));
} else {
printf("\n");
}
if (stats->num_completed > 1) {
printf(" Latency StdDev (s): %f\n",
stddev(stats->latency_sum_squares, stats->latency_sum,
stats->num_completed)
/ MILLION);
#ifdef USE_HISTOGRAMS
if (config->latency_histogram)
print_histogram(stats->latency, "answer count");
#endif
}
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(" Reconnections: %" PRIu64 "\n\n", stats->num_conn_reconnect);
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)(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)(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_max / MILLION),
(unsigned int)(stats->conn_latency_max % MILLION));
} else {
printf("\n");
}
if (stats->num_conn_completed > 1) {
printf(" Latency StdDev (s): %f\n",
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");
}
/*
* Caller must free() stats->latency and stats->conn_latency.
*/
static void
sum_stats(const config_t* config, stats_t* total)
{
unsigned int i, j;
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++) {
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->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);
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);
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;
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
* ->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;
}
/*
* 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;
}
#ifndef HAVE_LDNS
if (config->updates) {
@ -636,6 +778,10 @@ query_move(threadinfo_t* tinfo, query_info* q, query_move_op op)
static inline uint64_t
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;
}
@ -920,7 +1066,10 @@ recv_one(threadinfo_t* tinfo, int which_sock,
}
if (!n) {
// Treat connection closed like try again until reconnection features are in
*saved_errnop = EAGAIN;
if (!*saved_errnop) {
// only set this if there was no error before to allow above error check to overwrite EAGAIN
*saved_errnop = EAGAIN;
}
return false;
}
recvd->sock = tinfo->socks[which_sock];
@ -1006,8 +1155,6 @@ do_recv(void* arg)
break;
}
bit_set(socketbits, current_socket);
if (saved_errno != EAGAIN)
break;
}
if (j == tinfo->nsocks)
break;
@ -1039,11 +1186,13 @@ do_recv(void* arg)
perf_log_warning("received short response");
continue;
}
if (recvd[i].unexpected && !tinfo->config->suppress.unexpected) {
perf_log_warning("received a response with an "
"unexpected (maybe timed out) "
"id: %u",
recvd[i].qid);
if (recvd[i].unexpected) {
if (!tinfo->config->suppress.unexpected) {
perf_log_warning("received a response with an "
"unexpected (maybe timed out) "
"id: %u",
recvd[i].qid);
}
continue;
}
latency = recvd[i].when - recvd[i].sent;
@ -1061,6 +1210,11 @@ do_recv(void* arg)
stats->total_response_size += recvd[i].size;
stats->rcodecounts[recvd[i].rcode]++;
stats->latency_sum += latency;
#ifdef USE_HISTOGRAMS
if (stats->latency) {
hg64_inc(stats->latency, latency);
}
#endif
stats->latency_sum_squares += (latency * latency);
if (latency < stats->latency_min || stats->num_completed == 1)
stats->latency_min = latency;
@ -1097,18 +1251,17 @@ static void*
do_interval_stats(void* arg)
{
threadinfo_t* tinfo;
stats_t total;
stats_t total = {};
stats_t last = {};
stats_t diff = {};
uint64_t now;
uint64_t last_interval_time;
uint64_t last_completed;
uint64_t interval_time;
uint64_t num_completed;
double qps;
struct perf_net_socket sock = { .mode = sock_pipe, .fd = threadpipe[0] };
tinfo = arg;
last_interval_time = tinfo->times->start_time;
last_completed = 0;
wait_for_start();
while (perf_os_waituntilreadable(&sock, threadpipe[0],
@ -1117,13 +1270,23 @@ do_interval_stats(void* arg)
now = perf_get_time();
sum_stats(tinfo->config, &total);
interval_time = now - last_interval_time;
num_completed = total.num_completed - last_completed;
qps = num_completed / (((double)interval_time) / MILLION);
perf_log_printf("%u.%06u: %.6lf",
(unsigned int)(now / MILLION),
(unsigned int)(now % MILLION), qps);
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",
(unsigned int)(now / MILLION),
(unsigned int)(now % MILLION), qps);
}
last_interval_time = now;
last_completed = total.num_completed;
#ifdef USE_HISTOGRAMS
free(last.latency);
free(last.conn_latency);
#endif
last = total;
}
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:
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_squares += (elapsed_time * elapsed_time);
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->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++) {
perf_link_init(&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.
*/
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;
}
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;
}
if (!(tinfo->socks = calloc(tinfo->nsocks, sizeof(*tinfo->socks)))) {
perf_log_fatal("out of memory");
@ -1383,7 +1561,7 @@ int main(int argc, char** argv)
print_final_status(&config);
sum_stats(&config, &total_stats);
print_statistics(&config, &times, &total_stats);
print_statistics(&config, &times, &total_stats, 0, 0);
perf_net_stats_print(config.mode);
cleanup(&config);

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

327
src/ext/hg64.c Normal file
View 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
View 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

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.
@ -28,7 +28,7 @@
#include "net.h"
#include "edns.h"
#include "parse_uri.h"
#include "ext/parse_uri.h"
#include "log.h"
#include "strerror.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;
case SSL_ERROR_SYSCALL:
switch (errno) {
case EBADF:
// treat this as a retry, can happen if sendto is reconnecting
case ECONNREFUSED:
case ECONNRESET:
case ENOTCONN:

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.
@ -177,6 +177,8 @@ static ssize_t perf__dot_recv(struct perf_net_socket* sock, void* buf, size_t le
break;
case SSL_ERROR_SYSCALL:
switch (errno) {
case EBADF:
// treat this as a retry, can happen if sendto is reconnecting
case ECONNREFUSED:
case ECONNRESET:
case ENOTCONN:

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* 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;
} else if (n < 0) {
switch (errno) {
case EBADF:
// treat this as a retry, can happen if sendto is reconnecting
case ECONNREFUSED:
case ECONNRESET:
case ENOTCONN:

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.
@ -238,39 +238,57 @@ static int perf_opt_long_parse(char* optarg)
ssize_t optlen;
char* arg;
// TODO: Allow boolean not to have =/value
if (!(arg = strchr(optarg, '='))) {
return -1;
if ((arg = strchr(optarg, '='))) {
arg++;
optlen = arg - optarg;
if (optlen < 1) {
return -1;
}
} else {
optlen = strlen(optarg);
}
optlen = arg - optarg;
if (optlen < 1) {
return -1;
}
arg++;
long_opt_t* opt = longopts;
while (opt) {
if (!strncmp(optarg, opt->name, optlen)) {
switch (opt->type) {
case perf_opt_string:
if (!arg) {
return -1;
}
*opt->u.stringp = arg;
break;
case perf_opt_boolean:
*opt->u.boolp = true;
break;
case perf_opt_uint:
if (!arg) {
return -1;
}
*opt->u.uintp = parse_uint(opt->desc, arg, 1, 0xFFFFFFFF);
break;
case perf_opt_zpint:
if (!arg) {
return -1;
}
*opt->u.uintp = parse_uint(opt->desc, arg, 0, 0xFFFFFFFF);
break;
case perf_opt_timeval:
if (!arg) {
return -1;
}
*opt->u.uint64p = parse_timeval(opt->desc, arg);
break;
case perf_opt_double:
if (!arg) {
return -1;
}
*opt->u.doublep = parse_double(opt->desc, arg);
break;
case perf_opt_port:
if (!arg) {
return -1;
}
*opt->u.portp = parse_uint(opt->desc, arg, 0, 0xFFFF);
break;
}
@ -284,10 +302,10 @@ static int perf_opt_long_parse(char* optarg)
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;
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) {
fprintf(stderr, " (default: %s)", opt->defval);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,6 +1,6 @@
#!/bin/sh
#
# Copyright 2019-2022 OARC, Inc.
# Copyright 2019-2023 OARC, Inc.
# Copyright 2017-2018 Akamai Technologies
# Copyright 2006-2016 Nominum, Inc.
# All rights reserved.

View file

@ -1,4 +1,4 @@
.\" Copyright 2019-2022 OARC, Inc.
.\" Copyright 2019-2023 OARC, Inc.
.\" Copyright 2017-2018 Akamai Technologies
.\" Copyright 2006-2016 Nominum, Inc.
.\" All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -2,3 +2,8 @@
../dnsperf -h
../resperf -h
! ../dnsperf -O suppress
! ../dnsperf -O suppress=
! ../resperf -O suppress
! ../resperf -O suppress=

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 OARC, Inc.
* Copyright 2019-2023 OARC, Inc.
* Copyright 2017-2018 Akamai Technologies
* Copyright 2006-2016 Nominum, Inc.
* All rights reserved.