]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Separate out stat_h into a .hh file and make it a template in the pdns namespace.
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Fri, 11 Sep 2020 09:53:15 +0000 (11:53 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 21 Jan 2021 13:48:24 +0000 (14:48 +0100)
13 files changed:
pdns/dnsdist-cache.hh
pdns/dnsdist-carbon.cc
pdns/dnsdist-lua-inspection.cc
pdns/dnsdist-lua.cc
pdns/dnsdist-rings.hh
pdns/dnsdist-snmp.cc
pdns/dnsdist-web.cc
pdns/dnsdist.cc
pdns/dnsdist.hh
pdns/dnsdistdist/Makefile.am
pdns/dnsdistdist/stat_t.hh [new symlink]
pdns/doh.hh
pdns/stat_t.hh [new file with mode: 0644]

index 3b4b14038abb4f69f5cd5fa8a439b68efe147b35..a640326162c9688cc2d132b176ecb30eae2bc4f4 100644 (file)
@@ -27,6 +27,7 @@
 #include "iputils.hh"
 #include "lock.hh"
 #include "noinitvector.hh"
+#include "stat_t.hh"
 
 struct DNSQuestion;
 
@@ -126,13 +127,13 @@ private:
 
   std::vector<CacheShard> d_shards;
 
-  std::atomic<uint64_t> d_deferredLookups{0};
-  std::atomic<uint64_t> d_deferredInserts{0};
-  std::atomic<uint64_t> d_hits{0};
-  std::atomic<uint64_t> d_misses{0};
-  std::atomic<uint64_t> d_insertCollisions{0};
-  std::atomic<uint64_t> d_lookupCollisions{0};
-  std::atomic<uint64_t> d_ttlTooShorts{0};
+  pdns::stat_t d_deferredLookups{0};
+  pdns::stat_t d_deferredInserts{0};
+  pdns::stat_t d_hits{0};
+  pdns::stat_t d_misses{0};
+  pdns::stat_t d_insertCollisions{0};
+  pdns::stat_t d_lookupCollisions{0};
+  pdns::stat_t d_ttlTooShorts{0};
 
   size_t d_maxEntries;
   uint32_t d_expungeIndex{0};
index b22e7dc58194790056ccef3f086ef2773d03e402..05ed9f62a5455a10fbd90607528e6c2d4d6af013 100644 (file)
@@ -78,7 +78,7 @@ void carbonDumpThread()
           time_t now=time(0);
           for(const auto& e : g_stats.entries) {
             str<<namespace_name<<"."<<hostname<<"."<<instance_name<<"."<<e.first<<' ';
-            if(const auto& val = boost::get<DNSDistStats::stat_t*>(&e.second))
+            if(const auto& val = boost::get<pdns::stat_t*>(&e.second))
               str<<(*val)->load();
             else if (const auto& dval = boost::get<double*>(&e.second))
               str<<**dval;
@@ -201,7 +201,7 @@ void carbonDumpThread()
                 ++(dupPair.first->second);
               }
 
-              vector<pair<const char*, const std::atomic<uint64_t>&>> v{
+              vector<pair<const char*, const pdns::stat_t&>> v{
                 {"http-connects", doh->d_httpconnects},
                 {"http1-queries", doh->d_http1Stats.d_nbQueries},
                 {"http2-queries", doh->d_http2Stats.d_nbQueries},
index 3cdc790d917b70b3765c0e06341242027fb4890a..918dba5c31523ebb0c89baf4f72766a83afdf073 100644 (file)
@@ -656,7 +656,7 @@ void setupLuaInspection(LuaContext& luaCtx)
       boost::format flt("    %9.1f");
       for(const auto& e : entries) {
        string second;
-       if(const auto& val = boost::get<DNSDistStats::stat_t*>(&e.second))
+       if(const auto& val = boost::get<pdns::stat_t*>(&e.second))
          second=std::to_string((*val)->load());
        else if (const auto& dval = boost::get<double*>(&e.second))
          second=(flt % (**dval)).str();
index 87e7a11783406a850bb01bcb209d33d028fe1366..a65be53b70f78f3179741d8302c4f9674003c26d 100644 (file)
@@ -1652,7 +1652,7 @@ static void setupLuaConfig(LuaContext& luaCtx, bool client, bool configCheck)
       setLuaNoSideEffect();
       std::unordered_map<string,uint64_t> res;
       for(const auto& entry : g_stats.entries) {
-        if(const auto& val = boost::get<DNSDistStats::stat_t*>(&entry.second))
+        if(const auto& val = boost::get<pdns::stat_t*>(&entry.second))
           res[entry.first] = (*val)->load();
       }
       return res;
index 511c522c1cd9ce4d50fdbf0010285960628430db..3678235634974cda588adb685a24ac6f121d371c 100644 (file)
@@ -30,6 +30,7 @@
 #include "circular_buffer.hh"
 #include "dnsname.hh"
 #include "iputils.hh"
+#include "stat_t.hh"
 
 
 struct Rings {
@@ -196,10 +197,10 @@ struct Rings {
   size_t loadFromFile(const std::string& filepath, const struct timespec& now);
 
   std::vector<std::unique_ptr<Shard> > d_shards;
-  std::atomic<uint64_t> d_blockingQueryInserts;
-  std::atomic<uint64_t> d_blockingResponseInserts;
-  std::atomic<uint64_t> d_deferredQueryInserts;
-  std::atomic<uint64_t> d_deferredResponseInserts;
+  pdns::stat_t d_blockingQueryInserts;
+  pdns::stat_t d_blockingResponseInserts;
+  pdns::stat_t d_deferredQueryInserts;
+  pdns::stat_t d_deferredResponseInserts;
 
 private:
   size_t getShardId()
index 53ac8051bdeaff1c5f5d2cb86792634b1f2e0684..6aedb06ee62058750fd223b7acd0d559ecbbf47f 100644 (file)
@@ -80,14 +80,14 @@ static int handleCounter64Stats(netsnmp_mib_handler* handler,
     return SNMP_ERR_GENERR;
   }
 
-  if (const auto& val = boost::get<DNSDistStats::stat_t*>(&it->second)) {
+  if (const auto& val = boost::get<pdns::stat_t*>(&it->second)) {
     return DNSDistSNMPAgent::setCounter64Value(requests, (*val)->load());
   }
 
   return SNMP_ERR_GENERR;
 }
 
-static void registerCounter64Stat(const char* name, const oid statOID[], size_t statOIDLength, DNSDistStats::stat_t* ptr)
+static void registerCounter64Stat(const char* name, const oid statOID[], size_t statOIDLength, pdns::stat_t* ptr)
 {
   if (statOIDLength != OID_LENGTH(queriesOID)) {
     errlog("Invalid OID for SNMP Counter64 statistic %s", name);
index 668aa7ce38e52addce64900b0484744f33b52069..3f1b90c40e7ee6cecbd92bfb56d7d391e5426428 100644 (file)
@@ -375,7 +375,7 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp)
     output << "# TYPE " << prometheusMetricName << " " << prometheusTypeName << "\n";
     output << prometheusMetricName << " ";
 
-    if (const auto& val = boost::get<DNSDistStats::stat_t*>(&std::get<1>(e)))
+    if (const auto& val = boost::get<pdns::stat_t*>(&std::get<1>(e)))
       output << (*val)->load();
     else if (const auto& dval = boost::get<double*>(&std::get<1>(e)))
       output << **dval;
@@ -740,7 +740,7 @@ static void handleJSONStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
     for (const auto& e : g_stats.entries) {
       if (e.first == "special-memory-usage")
         continue; // Too expensive for get-all
-      if(const auto& val = boost::get<DNSDistStats::stat_t*>(&e.second))
+      if(const auto& val = boost::get<pdns::stat_t*>(&e.second))
         obj.insert({e.first, (double)(*val)->load()});
       else if (const auto& dval = boost::get<double*>(&e.second))
         obj.insert({e.first, (**dval)});
@@ -1050,7 +1050,7 @@ static void handleStatsOnly(const YaHTTP::Request& req, YaHTTP::Response& resp)
     if (item.first == "special-memory-usage")
       continue; // Too expensive for get-all
 
-    if(const auto& val = boost::get<DNSDistStats::stat_t*>(&item.second)) {
+    if(const auto& val = boost::get<pdns::stat_t*>(&item.second)) {
       doc.push_back(Json::object {
           { "type", "StatisticItem" },
           { "name", item.first },
index 0731ee9a95a175d36e8c48b59f6138826d19c980..375f51a0a844a89dd219abea93f07db767544151 100644 (file)
@@ -82,7 +82,6 @@
    On the C++ side, both could be inherited from a class Rule and a class Action, 
    on the Lua side we can't do that. */
 
-using std::atomic;
 using std::thread;
 bool g_verbose;
 
@@ -1585,8 +1584,8 @@ uint16_t getRandomDNSID()
 }
 
 boost::optional<uint64_t> g_maxTCPClientThreads{boost::none};
-std::atomic<uint16_t> g_cacheCleaningDelay{60};
-std::atomic<uint16_t> g_cacheCleaningPercentage{100};
+pdns::stat16_t g_cacheCleaningDelay{60};
+pdns::stat16_t g_cacheCleaningPercentage{100};
 
 static void maintThread()
 {
index 3ac73f9ac4a6446dd5c6b69a750c066893c765c0..79349414ec2d6f090c56efe144179d46bab2bed9 100644 (file)
@@ -23,7 +23,6 @@
 #include "config.h"
 #include "ext/luawrapper/include/LuaContext.hpp"
 
-#include <atomic>
 #include <mutex>
 #include <string>
 #include <thread>
@@ -51,6 +50,7 @@
 #include "tcpiohandler.hh"
 #include "uuid-utils.hh"
 #include "proxy-protocol.hh"
+#include "stat_t.hh"
 
 void carbonDumpThread();
 uint64_t uptimeOfProcess(const std::string& str);
@@ -297,43 +297,10 @@ extern vector<pair<struct timeval, std::string> > g_confDelta;
 
 extern uint64_t getLatencyCount(const std::string&);
 
+using pdns::stat_t;
+
 struct DNSDistStats
 {
-#define CPU_LEVEL1_DCACHE_LINESIZE 64 // Until we know better via configure/getconf
-
-  class stat_t {
-  public:
-    typedef uint64_t base_t;
-    typedef std::atomic<base_t> atomic_t;
-    stat_t() : stat_t(0) {
-    }
-    stat_t(const base_t x) {
-      new(&counter) atomic_t(x);
-    }
-    ~stat_t() {
-      reinterpret_cast<atomic_t *>(&counter)->~atomic_t();
-    }
-    stat_t(const stat_t&) = delete;
-    base_t operator++(int) {
-      return (*reinterpret_cast<atomic_t *>(&counter))++;
-    }
-    base_t operator++() {
-      return ++(*reinterpret_cast<atomic_t *>(&counter));
-    }
-    base_t operator+=(const stat_t& v) {
-      return (*reinterpret_cast<atomic_t *>(&counter)) += *reinterpret_cast<const atomic_t *>(&v.counter);
-    }
-    base_t load() const {
-      return reinterpret_cast<const atomic_t *>(&counter)->load();
-    }
-    operator base_t() const {
-      return reinterpret_cast<const atomic_t *>(&counter)->load();
-    }
-    //const atomic_t& operator()() { return *reinterpret_cast<const atomic_t*>(&counter); }
-  private:
-    typename std::aligned_storage<sizeof(base_t), CPU_LEVEL1_DCACHE_LINESIZE>::type counter;
-  };
-
   stat_t responses{0};
   stat_t servfailResponses{0};
   stat_t queries{0};
@@ -745,26 +712,26 @@ struct ClientState
   std::shared_ptr<TLSFrontend> tlsFrontend{nullptr};
   std::shared_ptr<DOHFrontend> dohFrontend{nullptr};
   std::string interface;
-  std::atomic<uint64_t> queries{0};
-  mutable std::atomic<uint64_t> responses{0};
-  std::atomic<uint64_t> tcpDiedReadingQuery{0};
-  std::atomic<uint64_t> tcpDiedSendingResponse{0};
-  std::atomic<uint64_t> tcpGaveUp{0};
-  std::atomic<uint64_t> tcpClientTimeouts{0};
-  std::atomic<uint64_t> tcpDownstreamTimeouts{0};
-  std::atomic<uint64_t> tcpCurrentConnections{0};
-  std::atomic<uint64_t> tlsNewSessions{0}; // A new TLS session has been negotiated, no resumption
-  std::atomic<uint64_t> tlsResumptions{0}; // A TLS session has been resumed, either via session id or via a TLS ticket
-  std::atomic<uint64_t> tlsUnknownTicketKey{0}; // A TLS ticket has been presented but we don't have the associated key (might have expired)
-  std::atomic<uint64_t> tlsInactiveTicketKey{0}; // A TLS ticket has been successfully resumed but the key is no longer active, we should issue a new one
-  std::atomic<uint64_t> tls10queries{0};   // valid DNS queries received via TLSv1.0
-  std::atomic<uint64_t> tls11queries{0};   // valid DNS queries received via TLSv1.1
-  std::atomic<uint64_t> tls12queries{0};   // valid DNS queries received via TLSv1.2
-  std::atomic<uint64_t> tls13queries{0};   // valid DNS queries received via TLSv1.3
-  std::atomic<uint64_t> tlsUnknownqueries{0};   // valid DNS queries received via unknown TLS version
-  std::atomic<double> tcpAvgQueriesPerConnection{0.0};
+  stat_t queries{0};
+  mutable stat_t responses{0};
+  stat_t tcpDiedReadingQuery{0};
+  stat_t tcpDiedSendingResponse{0};
+  stat_t tcpGaveUp{0};
+  stat_t tcpClientTimeouts{0};
+  stat_t tcpDownstreamTimeouts{0};
+  stat_t tcpCurrentConnections{0};
+  stat_t tlsNewSessions{0}; // A new TLS session has been negotiated, no resumption
+  stat_t tlsResumptions{0}; // A TLS session has been resumed, either via session id or via a TLS ticket
+  stat_t tlsUnknownTicketKey{0}; // A TLS ticket has been presented but we don't have the associated key (might have expired)
+  stat_t tlsInactiveTicketKey{0}; // A TLS ticket has been successfully resumed but the key is no longer active, we should issue a new one
+  stat_t tls10queries{0};   // valid DNS queries received via TLSv1.0
+  stat_t tls11queries{0};   // valid DNS queries received via TLSv1.1
+  stat_t tls12queries{0};   // valid DNS queries received via TLSv1.2
+  stat_t tls13queries{0};   // valid DNS queries received via TLSv1.3
+  stat_t tlsUnknownqueries{0};   // valid DNS queries received via unknown TLS version
+  pdns::stat_t_trait<double> tcpAvgQueriesPerConnection{0.0};
   /* in ms */
-  std::atomic<double> tcpAvgConnectionDuration{0.0};
+  pdns::stat_t_trait<double> tcpAvgConnectionDuration{0.0};
   size_t d_maxInFlightQueriesPerConn{1};
   int udpFD{-1};
   int tcpFD{-1};
@@ -839,9 +806,9 @@ struct ClientState
 
 class TCPClientCollection {
   std::vector<int> d_tcpclientthreads;
-  std::atomic<uint64_t> d_numthreads{0};
-  std::atomic<uint64_t> d_pos{0};
-  std::atomic<uint64_t> d_queued{0};
+  stat_t d_numthreads{0};
+  stat_t d_pos{0};
+  stat_t d_queued{0};
   const uint64_t d_maxthreads{0};
   std::mutex d_mutex;
   int d_singlePipe[2];
@@ -925,25 +892,25 @@ struct DownstreamState
   QType checkType{QType::A};
   uint16_t checkClass{QClass::IN};
   std::atomic<uint64_t> idOffset{0};
-  std::atomic<uint64_t> sendErrors{0};
-  std::atomic<uint64_t> outstanding{0};
-  std::atomic<uint64_t> reuseds{0};
-  std::atomic<uint64_t> queries{0};
-  std::atomic<uint64_t> responses{0};
+  stat_t sendErrors{0};
+  stat_t outstanding{0};
+  stat_t reuseds{0};
+  stat_t queries{0};
+  stat_t responses{0};
   struct {
-    std::atomic<uint64_t> sendErrors{0};
-    std::atomic<uint64_t> reuseds{0};
-    std::atomic<uint64_t> queries{0};
+    stat_t sendErrors{0};
+    stat_t reuseds{0};
+    stat_t queries{0};
   } prev;
-  std::atomic<uint64_t> tcpDiedSendingQuery{0};
-  std::atomic<uint64_t> tcpDiedReadingResponse{0};
-  std::atomic<uint64_t> tcpGaveUp{0};
-  std::atomic<uint64_t> tcpReadTimeouts{0};
-  std::atomic<uint64_t> tcpWriteTimeouts{0};
-  std::atomic<uint64_t> tcpCurrentConnections{0};
-  std::atomic<double> tcpAvgQueriesPerConnection{0.0};
+  stat_t tcpDiedSendingQuery{0};
+  stat_t tcpDiedReadingResponse{0};
+  stat_t tcpGaveUp{0};
+  stat_t tcpReadTimeouts{0};
+  stat_t tcpWriteTimeouts{0};
+  stat_t tcpCurrentConnections{0};
+  pdns::stat_t_trait<double> tcpAvgQueriesPerConnection{0.0};
   /* in ms */
-  std::atomic<double> tcpAvgConnectionDuration{0.0};
+  pdns::stat_t_trait<double> tcpAvgConnectionDuration{0.0};
   size_t socketsOffset{0};
   size_t d_maxInFlightQueriesPerConn{1};
   double queryLoad{0.0};
@@ -1048,7 +1015,7 @@ public:
   }
   virtual bool matches(const DNSQuestion* dq) const =0;
   virtual string toString() const = 0;
-  mutable std::atomic<uint64_t> d_matches{0};
+  mutable stat_t d_matches{0};
 };
 
 struct ServerPool
@@ -1212,8 +1179,8 @@ extern uint64_t g_maxTCPQueuedConnections;
 extern size_t g_maxTCPQueriesPerConn;
 extern size_t g_maxTCPConnectionDuration;
 extern size_t g_maxTCPConnectionsPerClient;
-extern std::atomic<uint16_t> g_cacheCleaningDelay;
-extern std::atomic<uint16_t> g_cacheCleaningPercentage;
+extern pdns::stat16_t g_cacheCleaningDelay;
+extern pdns::stat16_t g_cacheCleaningPercentage;
 extern uint32_t g_staleCacheEntriesTTL;
 extern bool g_apiReadWrite;
 extern std::string g_apiConfigDirectory;
index dd8d2e3bd131278ad0b87025200a348cf84fecd1..06586f494b7b99ecb7f769112e919ec81dc06403 100644 (file)
@@ -205,6 +205,7 @@ dnsdist_SOURCES = \
        sodcrypto.cc sodcrypto.hh \
        sstuff.hh \
        statnode.cc statnode.hh \
+       stat_t.hh \
        svc-records.cc svc-records.hh \
        tcpiohandler-mplexer.hh \
        tcpiohandler.cc tcpiohandler.hh \
@@ -258,6 +259,7 @@ testrunner_SOURCES = \
        sodcrypto.cc \
        sstuff.hh \
        statnode.cc statnode.hh \
+       stat_t.hh \
        svc-records.cc svc-records.hh \
        test-base64_cc.cc \
        test-delaypipe_hh.cc \
diff --git a/pdns/dnsdistdist/stat_t.hh b/pdns/dnsdistdist/stat_t.hh
new file mode 120000 (symlink)
index 0000000..0b8289c
--- /dev/null
@@ -0,0 +1 @@
+../stat_t.hh
\ No newline at end of file
index 09fcc71042fc5ea0d0fa931d8268b08c986158fc..eba05c80401d0409754d69e871e757c0e805b23a 100644 (file)
@@ -23,6 +23,7 @@
 #include "iputils.hh"
 #include "libssl.hh"
 #include "noinitvector.hh"
+#include "stat_t.hh"
 
 struct DOHServerConfig;
 
@@ -81,23 +82,23 @@ struct DOHFrontend
   uint32_t d_idleTimeout{30};             // HTTP idle timeout in seconds
   std::vector<std::string> d_urls;
 
-  std::atomic<uint64_t> d_httpconnects{0};   // number of TCP/IP connections established
-  std::atomic<uint64_t> d_getqueries{0};     // valid DNS queries received via GET
-  std::atomic<uint64_t> d_postqueries{0};    // valid DNS queries received via POST
-  std::atomic<uint64_t> d_badrequests{0};     // request could not be converted to dns query
-  std::atomic<uint64_t> d_errorresponses{0}; // dnsdist set 'error' on response
-  std::atomic<uint64_t> d_redirectresponses{0}; // dnsdist set 'redirect' on response
-  std::atomic<uint64_t> d_validresponses{0}; // valid responses sent out
+  pdns::stat_t d_httpconnects{0};   // number of TCP/IP connections established
+  pdns::stat_t d_getqueries{0};     // valid DNS queries received via GET
+  pdns::stat_t d_postqueries{0};    // valid DNS queries received via POST
+  pdns::stat_t d_badrequests{0};     // request could not be converted to dns query
+  pdns::stat_t d_errorresponses{0}; // dnsdist set 'error' on response
+  pdns::stat_t d_redirectresponses{0}; // dnsdist set 'redirect' on response
+  pdns::stat_t d_validresponses{0}; // valid responses sent out
 
   struct HTTPVersionStats
   {
-    std::atomic<uint64_t> d_nbQueries{0}; // valid DNS queries received
-    std::atomic<uint64_t> d_nb200Responses{0};
-    std::atomic<uint64_t> d_nb400Responses{0};
-    std::atomic<uint64_t> d_nb403Responses{0};
-    std::atomic<uint64_t> d_nb500Responses{0};
-    std::atomic<uint64_t> d_nb502Responses{0};
-    std::atomic<uint64_t> d_nbOtherResponses{0};
+    pdns::stat_t d_nbQueries{0}; // valid DNS queries received
+    pdns::stat_t d_nb200Responses{0};
+    pdns::stat_t d_nb400Responses{0};
+    pdns::stat_t d_nb403Responses{0};
+    pdns::stat_t d_nb500Responses{0};
+    pdns::stat_t d_nb502Responses{0};
+    pdns::stat_t d_nbOtherResponses{0};
   };
 
   HTTPVersionStats d_http1Stats;
diff --git a/pdns/stat_t.hh b/pdns/stat_t.hh
new file mode 100644 (file)
index 0000000..2a765c2
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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
+
+#define CPU_LEVEL1_DCACHE_LINESIZE 64 // Until we know better via configure/getconf
+
+namespace pdns {
+  template <typename T>
+  class stat_t_trait {
+  public:
+    typedef T base_t;
+    typedef std::atomic<base_t> atomic_t;
+
+    stat_t_trait() : stat_t_trait(base_t(0)) {
+    }
+    stat_t_trait(const base_t x) {
+      new(&counter) atomic_t(x);
+    }
+    ~stat_t_trait() {
+      reinterpret_cast<atomic_t *>(&counter)->~atomic_t();
+    }
+    stat_t_trait(const stat_t_trait&) = delete;
+    base_t operator++(int) {
+      return (*reinterpret_cast<atomic_t *>(&counter))++;
+    }
+    base_t operator++() {
+      return ++(*reinterpret_cast<atomic_t *>(&counter));
+    }
+    base_t operator--(int) {
+      return (*reinterpret_cast<atomic_t *>(&counter))--;
+    }
+    base_t operator--() {
+      return --(*reinterpret_cast<atomic_t *>(&counter));
+    }
+    base_t operator+=(const stat_t_trait& v) {
+      return *reinterpret_cast<atomic_t *>(&counter) += *reinterpret_cast<const atomic_t *>(&v.counter);
+    }
+    base_t operator-=(const stat_t_trait& v) {
+      return *reinterpret_cast<atomic_t *>(&counter) -= *reinterpret_cast<const atomic_t *>(&v.counter);
+    }
+    base_t load() const {
+      return reinterpret_cast<const atomic_t *>(&counter)->load();
+    }
+    void store(base_t v) {
+      reinterpret_cast<atomic_t *>(&counter)->store(v);
+    }
+    operator base_t() const {
+      return reinterpret_cast<const atomic_t *>(&counter)->load();
+    }
+
+  private:
+    typename std::aligned_storage<sizeof(base_t), CPU_LEVEL1_DCACHE_LINESIZE>::type counter;
+  };
+
+  typedef stat_t_trait<uint64_t> stat_t;
+  typedef stat_t_trait<uint32_t> stat32_t;
+  typedef stat_t_trait<uint16_t> stat16_t;
+}