work in microseconds instead of a mixed set.
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
#pragma once
#include <algorithm>
#include <atomic>
#include <vector>
-#include <sstream>
namespace pdns {
struct Bucket
{
std::string d_name;
- uint64_t d_boundary;
- uint64_t d_count;
+ uint64_t d_boundary{0};
+ uint64_t d_count{0};
};
inline bool operator<(uint64_t b, const Bucket& bu)
struct AtomicBucket
{
- // We need the constrcutors in this case, since atomics have a disabled
- // copy constructor.
+ // We need the constructors in this case, since atomics have a disabled copy constructor.
AtomicBucket() {}
AtomicBucket(std::string name, uint64_t boundary, uint64_t val) : d_name(std::move(name)), d_boundary(boundary), d_count(val) {}
AtomicBucket(const AtomicBucket& rhs) : d_name(rhs.d_name), d_boundary(rhs.d_boundary), d_count(rhs.d_count.load()) {}
std::string d_name;
- uint64_t d_boundary;
- std::atomic<uint64_t> d_count;
+ uint64_t d_boundary{0};
+ std::atomic<uint64_t> d_count{0};
};
inline bool operator<(uint64_t b, const AtomicBucket& bu)
}
d_buckets.reserve(boundaries.size() + 1);
for (auto b: boundaries) {
- // to_string gives too many .00000's
- std::ostringstream str;
- str << prefix << "le-" << b;
- d_buckets.push_back(B{str.str(), b, 0});
+ std::string str = prefix + "le-" + std::to_string(b);
+ d_buckets.push_back(B{str, b, 0});
}
- // everything above last boundary, plus NaN, Inf etc
+ // everything above last boundary
d_buckets.push_back(B{prefix + "le-max", std::numeric_limits<uint64_t>::max(), 0});
}
{
return tv.tv_sec + tv.tv_usec/1000000.0f;
}
-inline double makeDouble(const struct timeval& tv)
+inline uint64_t uSec(const struct timeval& tv)
{
- return tv.tv_sec + tv.tv_usec/1000000.0;
+ return tv.tv_sec * 1000000 + tv.tv_usec;
}
inline bool operator<(const struct timeval& lhs, const struct timeval& rhs)
finishTCPReply(dc, hadError, true);
}
- double spent = makeDouble(sr.getNow() - dc->d_now);
+ // Originally this code used a mix of floats, doubles, uint64_t with different units.
+ // Now it always uses an integral number of microseconds, expect for avarages, which are using doubles
+ uint64_t spentUsec = uSec(sr.getNow() - dc->d_now);
if (!g_quiet) {
g_log<<Logger::Error<<t_id<<" ["<<MT->getTid()<<"/"<<MT->numProcesses()<<"] answer to "<<(dc->d_mdp.d_header.rd?"":"non-rd ")<<"question '"<<dc->d_mdp.d_qname<<"|"<<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype);
g_log<<"': "<<ntohs(pw.getHeader()->ancount)<<" answers, "<<ntohs(pw.getHeader()->arcount)<<" additional, took "<<sr.d_outqueries<<" packets, "<<
- sr.d_totUsec/1000.0<<" netw ms, "<< spent*1000.0<<" tot ms, "<<
+ sr.d_totUsec/1000.0<<" netw ms, "<< spentUsec/1000.0<<" tot ms, "<<
sr.d_throttledqueries<<" throttled, "<<sr.d_timeouts<<" timeouts, "<<sr.d_tcpoutqueries<<" tcp connections, rcode="<< res;
if(!shouldNotValidate && sr.isDNSSECValidationRequested()) {
g_recCache->cacheHits++;
}
- if (spent < 0.001)
- g_stats.answers0_1++;
- else if(spent < 0.01)
- g_stats.answers1_10++;
- else if(spent < 0.1)
- g_stats.answers10_100++;
- else if(spent < 1.0)
- g_stats.answers100_1000++;
- else
- g_stats.answersSlow++;
+ g_stats.answers(spentUsec);
- double newLat = spent * 1000000.0;
+ double newLat = spentUsec;
newLat = min(newLat, g_networkTimeoutMsec * 1000.0); // outliers of several minutes exist..
g_stats.avgLatencyUsec = (1.0 - 1.0 / g_latencyStatSize) * g_stats.avgLatencyUsec + newLat / g_latencyStatSize;
// no worries, we do this for packet cache hits elsewhere
- double ourtime = 1000.0 * spent - sr.d_totUsec / 1000.0; // in msec
- if(ourtime < 1)
- g_stats.ourtime0_1++;
- else if(ourtime < 2)
- g_stats.ourtime1_2++;
- else if(ourtime < 4)
- g_stats.ourtime2_4++;
- else if(ourtime < 8)
- g_stats.ourtime4_8++;
- else if(ourtime < 16)
- g_stats.ourtime8_16++;
- else if(ourtime < 32)
- g_stats.ourtime16_32++;
- else {
- g_stats.ourtimeSlow++;
- }
-
- if (ourtime >= 0) {
- newLat = ourtime * 1000.0; // usec
+ if (spentUsec >= sr.d_totUsec) {
+ uint64_t ourtime = spentUsec - sr.d_totUsec;
+ g_stats.ourtime(ourtime);
+ newLat = ourtime; // usec
g_stats.avgLatencyOursUsec = (1.0 - 1.0 / g_latencyStatSize) * g_stats.avgLatencyOursUsec + newLat / g_latencyStatSize;
}
}
g_stats.avgLatencyUsec = (1.0 - 1.0 / g_latencyStatSize) * g_stats.avgLatencyUsec + 0.0; // we assume 0 usec
g_stats.avgLatencyOursUsec = (1.0 - 1.0 / g_latencyStatSize) * g_stats.avgLatencyOursUsec + 0.0; // we assume 0 usec
+#if 0
+ // XXX changes behaviour compared to old code!
+ g_stats.answers(0);
+ g_stats.ourtime(0);
+#endif
}
return cacheHit;
}
return g_recCache->size();
}
-static uint64_t doGetAvgLatencyUsec()
-{
- return (uint64_t) g_stats.avgLatencyUsec;
-}
-
static uint64_t doGetCacheBytes()
{
return g_recCache->bytes();
addGetStat("truncated-drops", &g_stats.truncatedDrops);
addGetStat("query-pipe-full-drops", &g_stats.queryPipeFullDrops);
- addGetStat("answers0-1", &g_stats.answers0_1);
- addGetStat("answers1-10", &g_stats.answers1_10);
- addGetStat("answers10-100", &g_stats.answers10_100);
- addGetStat("answers100-1000", &g_stats.answers100_1000);
- addGetStat("answers-slow", &g_stats.answersSlow);
-
- addGetStat("x-ourtime0-1", &g_stats.ourtime0_1);
- addGetStat("x-ourtime1-2", &g_stats.ourtime1_2);
- addGetStat("x-ourtime2-4", &g_stats.ourtime2_4);
- addGetStat("x-ourtime4-8", &g_stats.ourtime4_8);
- addGetStat("x-ourtime8-16", &g_stats.ourtime8_16);
- addGetStat("x-ourtime16-32", &g_stats.ourtime16_32);
- addGetStat("x-ourtime-slow", &g_stats.ourtimeSlow);
-
- addGetStat("auth4-answers0-1", &g_stats.auth4Answers0_1);
- addGetStat("auth4-answers1-10", &g_stats.auth4Answers1_10);
- addGetStat("auth4-answers10-100", &g_stats.auth4Answers10_100);
- addGetStat("auth4-answers100-1000", &g_stats.auth4Answers100_1000);
- addGetStat("auth4-answers-slow", &g_stats.auth4AnswersSlow);
-
- addGetStat("auth6-answers0-1", &g_stats.auth6Answers0_1);
- addGetStat("auth6-answers1-10", &g_stats.auth6Answers1_10);
- addGetStat("auth6-answers10-100", &g_stats.auth6Answers10_100);
- addGetStat("auth6-answers100-1000", &g_stats.auth6Answers100_1000);
- addGetStat("auth6-answers-slow", &g_stats.auth6AnswersSlow);
-
-
- addGetStat("qa-latency", doGetAvgLatencyUsec);
+ addGetStat("answers0-1", []() { return g_stats.answers.getCount(0); });
+ addGetStat("answers1-10", []() { return g_stats.answers.getCount(1); });
+ addGetStat("answers10-100", []() { return g_stats.answers.getCount(2); });
+ addGetStat("answers100-1000", []() { return g_stats.answers.getCount(3); });
+ addGetStat("answers-slow", []() { return g_stats.answers.getCount(4); });
+
+ addGetStat("x-ourtime0-1", []() { return g_stats.ourtime.getCount(0); });
+ addGetStat("x-ourtime1-2", []() { return g_stats.ourtime.getCount(1); });
+ addGetStat("x-ourtime2-4", []() { return g_stats.ourtime.getCount(2); });
+ addGetStat("x-ourtime4-8", []() { return g_stats.ourtime.getCount(3); });
+ addGetStat("x-ourtime8-16", []() { return g_stats.ourtime.getCount(4); });
+ addGetStat("x-ourtime16-32", []() { return g_stats.ourtime.getCount(5); });
+ addGetStat("x-ourtime-slow", []() { return g_stats.ourtime.getCount(6); });
+
+ addGetStat("auth4-answers0-1", []() { return g_stats.auth4Answers.getCount(0); });
+ addGetStat("auth4-answers1-10", []() { return g_stats.auth4Answers.getCount(1); });
+ addGetStat("auth4-answers10-100", []() { return g_stats.auth4Answers.getCount(2); });
+ addGetStat("auth4-answers100-1000", []() { return g_stats.auth4Answers.getCount(3); });
+ addGetStat("auth4-answers-slow", []() { return g_stats.auth4Answers.getCount(4); });
+
+ addGetStat("auth6-answers0-1", []() { return g_stats.auth6Answers.getCount(0); });
+ addGetStat("auth6-answers1-10", []() { return g_stats.auth6Answers.getCount(1); });
+ addGetStat("auth6-answers10-100", []() { return g_stats.auth6Answers.getCount(2); });
+ addGetStat("auth6-answers100-1000", []() { return g_stats.auth6Answers.getCount(3); });
+ addGetStat("auth6-answers-slow", []() { return g_stats.auth6Answers.getCount(4); });
+
+ addGetStat("qa-latency", []() { return g_stats.avgLatencyUsec.load(); });
addGetStat("x-our-latency", []() { return g_stats.avgLatencyOursUsec.load(); });
addGetStat("unexpected-packets", &g_stats.unexpectedCount);
addGetStat("case-mismatches", &g_stats.caseMismatchCount);
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_NO_MAIN
#define LOG(x) if(d_lm == Log) { g_log <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
-static void accountAuthLatency(int usec, int family)
+static inline void accountAuthLatency(uint64_t usec, int family)
{
- if(family == AF_INET) {
- if(usec < 1000)
- g_stats.auth4Answers0_1++;
- else if(usec < 10000)
- g_stats.auth4Answers1_10++;
- else if(usec < 100000)
- g_stats.auth4Answers10_100++;
- else if(usec < 1000000)
- g_stats.auth4Answers100_1000++;
- else
- g_stats.auth4AnswersSlow++;
+ if (family == AF_INET) {
+ g_stats.auth4Answers(usec);
} else {
- if(usec < 1000)
- g_stats.auth6Answers0_1++;
- else if(usec < 10000)
- g_stats.auth6Answers1_10++;
- else if(usec < 100000)
- g_stats.auth6Answers10_100++;
- else if(usec < 1000000)
- g_stats.auth6Answers100_1000++;
- else
- g_stats.auth6AnswersSlow++;
+ g_stats.auth6Answers(usec);
}
-
}
accountAuthLatency(lwr.d_usec, remoteIP.sin4.sin_family);
if (fromCache)
*fromCache = true;
-
+
// filter out the good stuff from lwr.result()
if (resolveRet == LWResult::Result::Success) {
for(const auto& rec : lwr.d_records) {
#include "negcache.hh"
#include "proxy-protocol.hh"
#include "sholder.hh"
+#include "histogram.hh"
#ifdef HAVE_CONFIG_H
#include "config.h"
std::atomic<uint64_t> servFails;
std::atomic<uint64_t> nxDomains;
std::atomic<uint64_t> noErrors;
- std::atomic<uint64_t> answers0_1, answers1_10, answers10_100, answers100_1000, answersSlow;
- std::atomic<uint64_t> auth4Answers0_1, auth4Answers1_10, auth4Answers10_100, auth4Answers100_1000, auth4AnswersSlow;
- std::atomic<uint64_t> auth6Answers0_1, auth6Answers1_10, auth6Answers10_100, auth6Answers100_1000, auth6AnswersSlow;
- std::atomic<uint64_t> ourtime0_1, ourtime1_2, ourtime2_4, ourtime4_8, ourtime8_16, ourtime16_32, ourtimeSlow;
+ pdns::AtomicHistogram<uint64_t> answers;
+ pdns::AtomicHistogram<uint64_t> auth4Answers;
+ pdns::AtomicHistogram<uint64_t> auth6Answers;
+ pdns::AtomicHistogram<uint64_t> ourtime;
std::atomic<double> avgLatencyUsec;
std::atomic<double> avgLatencyOursUsec;
std::atomic<uint64_t> qcounter; // not increased for unauth packets
std::atomic<uint64_t> rebalancedQueries{0};
std::atomic<uint64_t> proxyProtocolInvalidCount{0};
std::atomic<uint64_t> nodLookupsDroppedOversize{0};
+
+ RecursorStats() :
+ answers("answers", { 1000, 10000, 100000, 1000000 }),
+ auth4Answers("answers", { 1000, 10000, 100000, 1000000 }),
+ auth6Answers("answers", { 1000, 10000, 100000, 1000000 }),
+ ourtime("ourtime", { 1000, 2000, 4000, 8000, 16000, 32000 })
+ {
+ }
};
//! represents a running TCP/IP client session