along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <boost/accumulators/statistics/median.hpp>
+#include <boost/accumulators/statistics/mean.hpp>
+#include <boost/accumulators/accumulators.hpp>
+
+#include <boost/accumulators/statistics.hpp>
+
#include "dnsparser.hh"
#include "sstuff.hh"
#include "misc.hh"
#include <netinet/tcp.h>
#include <boost/array.hpp>
#include <boost/program_options.hpp>
+#include <boost/foreach.hpp>
StatBag S;
namespace po = boost::program_options;
+
po::variables_map g_vm;
bool g_verbose;
bool g_onlyTCP;
AtomicCounter g_networkErrors, g_otherErrors, g_OK, g_truncates, g_authAnswers, g_timeOuts;
ComboAddress g_dest;
+unsigned int makeUsec(const struct timeval& tv)
+{
+ return 1000000*tv.tv_sec + tv.tv_usec;
+}
+
/* On Linux, run echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
to prevent running out of free TCP ports */
struct BenchQuery
{
- BenchQuery(const std::string& qname_, uint16_t qtype_) : qname(qname_), qtype(qtype_), udpMsec(0), tcpMsec(0) {}
+ BenchQuery(const std::string& qname_, uint16_t qtype_) : qname(qname_), qtype(qtype_), udpUsec(0), tcpUsec(0), answerSecond(0) {}
BenchQuery(){}
std::string qname;
uint16_t qtype;
- uint16_t udpMsec, tcpMsec;
+ uint32_t udpUsec, tcpUsec;
+ time_t answerSecond;
};
-
void doQuery(BenchQuery* q)
try
{
int res;
string reply;
+ struct timeval tv, now;
+ gettimeofday(&tv, 0);
+
if(!g_onlyTCP) {
Socket udpsock((AddressFamily)g_dest.sin4.sin_family, Datagram);
}
udpsock.recvFrom(reply, origin);
+
+ gettimeofday(&now, 0);
+ q->udpUsec = makeUsec(now - tv);
+ tv=now;
+
MOADNSParser mdp(reply);
if(!mdp.d_header.tc)
return;
reply=string(creply, len);
delete[] creply;
+ gettimeofday(&now, 0);
+ q->tcpUsec = makeUsec(now - tv);
+ q->answerSecond = now.tv_sec;
+
MOADNSParser mdp(reply);
// cout<<"Had correct TCP/IP response, "<<mdp.d_answers.size()<<" answers, aabit="<<mdp.d_header.aa<<endl;
if(mdp.d_header.aa)
vector<BenchQuery> g_queries;
-
static void* worker(void*)
{
for(;;) {
void* status;
pthread_join(workers[n], &status);
}
+
+ using namespace boost::accumulators;
+ typedef accumulator_set<
+ unsigned int
+ , stats<boost::accumulators::tag::median(with_p_square_quantile),
+ boost::accumulators::tag::mean(immediate)
+ >
+ > acc_t;
+
+ acc_t udpspeeds, tcpspeeds, qps;
+
+ typedef map<time_t, uint32_t> counts_t;
+ counts_t counts;
+
+ BOOST_FOREACH(const BenchQuery& bq, g_queries) {
+ counts[bq.answerSecond]++;
+ udpspeeds(bq.udpUsec);
+ tcpspeeds(bq.tcpUsec);
+ }
+
+ BOOST_FOREACH(const counts_t::value_type& val, counts) {
+ qps(val.second);
+ }
+
+ cout<<"Average qps: "<<mean(qps)<<", median qps: "<<median(qps)<<endl;
+ cout<<"Average UDP latency: "<<mean(udpspeeds)<<"usec, median: "<<median(udpspeeds)<<"usec"<<endl;
+ cout<<"Average TCP latency: "<<mean(tcpspeeds)<<"usec, median: "<<median(tcpspeeds)<<"usec"<<endl;
+
cout<<"OK: "<<g_OK<<", network errors: "<<g_networkErrors<<", other errors: "<<g_otherErrors<<endl;
cout<<"Timeouts: "<<g_timeOuts<<endl;
cout<<"Truncateds: "<<g_truncates<<", auth answers: "<<g_authAnswers<<endl;
\r
The equivalent for IPv6 is not known.\r
\r
+\r
OPTIONS
-------
\r
\r
Remote IP address can be IPv4 or IPv6. Remote port defaults to 53.\r
\r
+STATISTICAL OUTPUT\r
+------------------\r
+The program reports both mean and median numbers for queries per second and\r
+UDP and TCP latency. Each query only counts once, even if it is tried over\r
+UDP first. This effectively means that passing '-u' can lower query rates if\r
+many queries get shunted to TCP.\r
+\r
BUGS
----
Currently the timeout code does not actually perform non-blocking connects\r
or writes. So a slow connect or slow writes will still cause low\r
performance and delays. \r
\r
+Median queries per second statistics are reported as 0 for sub-second runs.\r
+\r
AUTHOR
------
Written by PowerDNS.COM BV, bert hubert, <bert.hubert@netherlabs.nl>