]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
teach dnstcpbench to emit some nice statistics, plus document them
authorbert hubert <bert.hubert@netherlabs.nl>
Wed, 3 Jul 2013 10:05:46 +0000 (12:05 +0200)
committerPeter van Dijk <peter.van.dijk@netherlabs.nl>
Thu, 4 Jul 2013 11:33:07 +0000 (13:33 +0200)
pdns/dnstcpbench.cc
pdns/docs/dnstcpbench.1.txt

index 67a0512b0890d95931f81a3aee2fb3eee4f35660..34754abf2895d08ef3e81cfa9bb8eeba099ba5d0 100644 (file)
     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;
@@ -35,19 +43,24 @@ unsigned int g_timeoutMsec;
 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
 {
@@ -56,6 +69,9 @@ try
   int res;
   string reply;
 
+  struct timeval tv, now;
+  gettimeofday(&tv, 0);
+
   if(!g_onlyTCP) {
     Socket udpsock((AddressFamily)g_dest.sin4.sin_family, Datagram);
     
@@ -70,6 +86,11 @@ try
     }
 
     udpsock.recvFrom(reply, origin);
+
+    gettimeofday(&now, 0);
+    q->udpUsec = makeUsec(now - tv);
+    tv=now;
+
     MOADNSParser mdp(reply);
     if(!mdp.d_header.tc)
       return;
@@ -116,6 +137,10 @@ try
   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)
@@ -140,7 +165,6 @@ AtomicCounter g_pos;
 
 vector<BenchQuery> g_queries;
 
-
 static void* worker(void*)
 {
   for(;;) {
@@ -235,6 +259,34 @@ try
     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;
index af3fb9a34ccfc956e0e8757d1ea33578fbb80f04..4393a8f0729256fac1461f87c4eaf79e49fb3fe1 100644 (file)
@@ -30,6 +30,7 @@ performed by running:
 \r
 The equivalent for IPv6 is not known.\r
 \r
+\r
 OPTIONS
 -------
 \r
@@ -56,12 +57,21 @@ OPTIONS
 \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>