From: Michael Altizer (mialtize) Date: Tue, 13 Sep 2016 21:06:30 +0000 (-0400) Subject: Merge pull request #620 in SNORT/snort3 from tsc_clock to master X-Git-Tag: 3.0.0-233~263^2~15 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8088da91d58428bd6f48e310ad9d588cc44a012d;p=thirdparty%2Fsnort3.git Merge pull request #620 in SNORT/snort3 from tsc_clock to master Squashed commit of the following: commit e2bd893a5333968fe1899d2e67b19b98e2a65668 Author: Russ Combs Date: Tue Sep 13 16:00:05 2016 -0400 add cmake support for --enable-tsc-clock commit 170d01c6bbf086b2ea08dc26c96619a18a5eaf4b Author: Russ Combs Date: Mon Sep 12 22:40:10 2016 -0400 add --enable-tsc-clock to build/use TSC register tweak link order so time methods are found clean up some fp_detect cruft update latency to use ticks during runtime fix stream profile stats parents remove unused cpuclock.h --- diff --git a/cmake/configure_options.cmake b/cmake/configure_options.cmake index b4ec0b5c5..d11657638 100644 --- a/cmake/configure_options.cmake +++ b/cmake/configure_options.cmake @@ -12,6 +12,7 @@ if ( NOT ENABLE_COREFILES ) endif ( NOT ENABLE_COREFILES ) set ( _LARGEFILE_SOURCE ${ENABLE_LARGE_PCAP} ) +set ( USE_TSC_CLOCK ${ENABLE_TSC_CLOCK} ) if ( ENABLE_LARGE_PCAP ) set ( _FILE_OFFSET_BITS 64 ) diff --git a/cmake/create_options.cmake b/cmake/create_options.cmake index 24b4d6b18..a7438f462 100644 --- a/cmake/create_options.cmake +++ b/cmake/create_options.cmake @@ -22,6 +22,7 @@ option ( ENABLE_PIGLET "enable piglet test harness" OFF ) option ( ENABLE_COREFILES "Prevent Snort from generating core files" ON ) option ( ENABLE_INTEL_SOFT_CPM "Enable Intel Soft CPM support" OFF ) option ( ENABLE_LARGE_PCAP "Enable support for pcaps larger than 2 GB" OFF ) +option ( ENABLE_TSC_CLOCK "Use timestamp counter register clock (x86 only)" OFF ) # documentation option ( MAKE_HTML_DOC "Create the HTML documentation" ON ) diff --git a/config.cmake.h.in b/config.cmake.h.in index 6d912c481..9649829e8 100644 --- a/config.cmake.h.in +++ b/config.cmake.h.in @@ -100,6 +100,8 @@ #cmakedefine _LARGEFILE_SOURCE 1 #cmakedefine _FILE_OFFSET_BITS @_FILE_OFFSET_BITS@ +/* enable ha capable build */ +#cmakedefine USE_TSC_CLOCK 1 /* platforms */ diff --git a/configure.ac b/configure.ac index 53eaef708..c50576c77 100644 --- a/configure.ac +++ b/configure.ac @@ -377,6 +377,14 @@ if test "x$enable_shell" = "xyes"; then AC_DEFINE(SHELL, [1], [enable shell support]) fi +AC_ARG_ENABLE(tsc-clock, + AS_HELP_STRING([--enable-tsc-clock],[use timestamp counter register clock (x86 only)]), + enable_tsc_clock="$enableval", enable_tsc_clock="no") + +if test "x$enable_tsc_clock" = "xyes"; then + AC_DEFINE(USE_TSC_CLOCK, [1], [enable tsc clock]) +fi + AC_ARG_ENABLE(large-pcap, AS_HELP_STRING([--enable-large-pcap],[enable support for pcaps larger than 2 GB]), enable_large_pcap="$enableval", enable_large_pcap="no") diff --git a/configure_cmake.sh b/configure_cmake.sh index fabb5f307..bf47415bd 100755 --- a/configure_cmake.sh +++ b/configure_cmake.sh @@ -40,6 +40,7 @@ Optional Features: --disable-static-codecs do not include codecs in binary --enable-shell enable command line shell support --enable-large-pcap enable support for pcaps larger than 2 GB + --enable-tsc-clock use timestamp counter register clock (x86 only) --enable-debug-msgs enable debug printing options (bugreports and developers only) --enable-debug enable debugging options (bugreports and developers @@ -217,6 +218,9 @@ while [ $# -ne 0 ]; do --enable-large-pcap) append_cache_entry ENABLE_LARGE_PCAP BOOL true ;; + --enable-tsc-clock) + append_cache_entry ENABLE_TSC_CLOCK BOOL true + ;; --disable-large-pcap) append_cache_entry ENABLE_LARGE_PCAP BOOL false ;; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 769c5fe98..fc78cf39e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -133,9 +133,9 @@ target_link_libraries( snort detection framework file_api - time latency profiler + time ips_actions events hash diff --git a/src/Makefile.am b/src/Makefile.am index a9227f301..a2e3ca2af 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -90,9 +90,9 @@ filters/libfilter.a \ detection/libdetection.a \ framework/libframework.a \ file_api/libfile_api.a \ -time/libtime.a \ latency/liblatency.a \ profiler/libprofiler.a \ +time/libtime.a \ actions/libips_actions.a \ events/libevents.a \ hash/libhash.a \ diff --git a/src/detection/detect.cc b/src/detection/detect.cc index 1ba081b09..4aec779b3 100644 --- a/src/detection/detect.cc +++ b/src/detection/detect.cc @@ -71,7 +71,6 @@ void snort_inspect(Packet* p) { { PacketLatency::Context pkt_latency_ctx { p }; - bool inspected = false; // If the packet has errors, we won't analyze it. diff --git a/src/detection/fp_detect.cc b/src/detection/fp_detect.cc index 8f66153a9..edaf00780 100644 --- a/src/detection/fp_detect.cc +++ b/src/detection/fp_detect.cc @@ -88,7 +88,7 @@ THREAD_LOCAL ProfileStats ruleNFPEvalPerfStats; THREAD_LOCAL uint64_t rule_eval_pkt_count = 0; -THREAD_LOCAL OTNX_MATCH_DATA t_omd; +static THREAD_LOCAL OTNX_MATCH_DATA t_omd; /* initialize the global OTNX_MATCH_DATA variable */ void otnx_match_data_init(int num_rule_types) @@ -111,14 +111,10 @@ void otnx_match_data_term() static inline void InitMatchInfo(OTNX_MATCH_DATA* o) { - int i = 0; + for ( int i = 0; i < o->iMatchInfoArraySize; i++ ) + o->matchInfo[i].iMatchCount = 0; - for (i = 0; i < o->iMatchInfoArraySize; i++) - { - o->matchInfo[i].iMatchCount = 0; - o->matchInfo[i].iMatchIndex = 0; - o->matchInfo[i].iMatchMaxLen = 0; - } + o->have_match = false; } // called by fpLogEvent(), which does the filtering etc. @@ -270,14 +266,10 @@ int fpLogEvent(const RuleTreeNode* rtn, const OptTreeNode* otn, Packet* p) ** int - 1 max_events variable hit, 0 successful. ** */ -int fpAddMatch(OTNX_MATCH_DATA* omd_local, int pLen, const OptTreeNode* otn) +int fpAddMatch(OTNX_MATCH_DATA* omd_local, int /*pLen*/, const OptTreeNode* otn) { - MATCH_INFO* pmi; - int evalIndex; - int i; RuleTreeNode* rtn = getRuntimeRtnFromOtn(otn); - - evalIndex = rtn->listhead->ruleListNode->evalIndex; + int evalIndex = rtn->listhead->ruleListNode->evalIndex; /* bounds check index */ if ( evalIndex >= omd_local->iMatchInfoArraySize ) @@ -285,7 +277,7 @@ int fpAddMatch(OTNX_MATCH_DATA* omd_local, int pLen, const OptTreeNode* otn) pc.match_limit++; return 1; } - pmi = &omd_local->matchInfo[evalIndex]; + MATCH_INFO* pmi = &omd_local->matchInfo[evalIndex]; /* ** If we hit the max number of unique events for any rule type alert, @@ -298,43 +290,18 @@ int fpAddMatch(OTNX_MATCH_DATA* omd_local, int pLen, const OptTreeNode* otn) return 1; } - /* Check that we are not storing the same otn again */ - for ( i=0; i< pmi->iMatchCount; i++ ) + // don't store the same otn again + for ( int i=0; i< pmi->iMatchCount; i++ ) { if ( pmi->MatchArray[ i ] == otn ) - { - //LogMessage("fpAddMatch: storing the same otn...\n"); return 0; - } } - /* - ** Add the event to the appropriate list - */ + // add the event to the appropriate list pmi->MatchArray[ pmi->iMatchCount ] = otn; - /* - ** This means that we are adding a NC rule - ** and we only set the index to this rule - ** if there is no content rules in the - ** same array. - */ - if (pLen > 0) - { - /* - ** Event Comparison Function - ** Here the largest content match is the - ** priority - */ - if ( pmi->iMatchMaxLen < pLen ) - { - pmi->iMatchMaxLen = pLen; - pmi->iMatchIndex = pmi->iMatchCount; - } - } - pmi->iMatchCount++; - + omd_local->have_match = true; return 0; } @@ -702,6 +669,9 @@ static inline int fpSessionAlerted(Packet* p, const OptTreeNode* otn) */ static inline int fpFinalSelectEvent(OTNX_MATCH_DATA* o, Packet* p) { + if ( !o->have_match ) + return 0; + int i; int j; int k; diff --git a/src/detection/fp_detect.h b/src/detection/fp_detect.h index 6efd95614..da9236f83 100644 --- a/src/detection/fp_detect.h +++ b/src/detection/fp_detect.h @@ -96,6 +96,7 @@ struct OTNX_MATCH_DATA unsigned size; int check_ports; + bool have_match; MATCH_INFO* matchInfo; int iMatchInfoArraySize; diff --git a/src/latency/latency_module.cc b/src/latency/latency_module.cc index 3b7092fd8..c38c30ff3 100644 --- a/src/latency/latency_module.cc +++ b/src/latency/latency_module.cc @@ -113,8 +113,10 @@ static inline bool latency_set(Value& v, PacketLatencyConfig& config) using std::chrono::microseconds; if ( v.is("max_time") ) - config.max_time = - duration_cast(microseconds(v.get_long())); + { + long t = clock_ticks(v.get_long()); + config.max_time = duration_cast(microseconds(t)); + } else if ( v.is("fastpath") ) config.fastpath = v.get_bool(); @@ -136,9 +138,10 @@ static inline bool latency_set(Value& v, RuleLatencyConfig& config) using std::chrono::milliseconds; if ( v.is("max_time") ) - config.max_time = - duration_cast(microseconds(v.get_long())); - + { + long t = clock_ticks(v.get_long()); + config.max_time = duration_cast(microseconds(t)); + } else if ( v.is("suspend") ) config.suspend = v.get_bool(); @@ -146,9 +149,10 @@ static inline bool latency_set(Value& v, RuleLatencyConfig& config) config.suspend_threshold = v.get_long(); else if ( v.is("max_suspend_time") ) - config.max_suspend_time = - duration_cast(milliseconds(v.get_long())); - + { + long t = clock_ticks(v.get_long()); + config.max_suspend_time = duration_cast(milliseconds(t)); + } else if ( v.is("action") ) config.action = static_cast(v.get_long()); diff --git a/src/latency/packet_latency.cc b/src/latency/packet_latency.cc index 2e7f4087e..e770dca85 100644 --- a/src/latency/packet_latency.cc +++ b/src/latency/packet_latency.cc @@ -29,6 +29,7 @@ #include "protocols/packet.h" #include "sfip/sf_ip.h" #include "time/clock_defs.h" + #include "latency_config.h" #include "latency_timer.h" #include "latency_util.h" @@ -49,13 +50,11 @@ namespace packet_latency // helpers // ----------------------------------------------------------------------------- -using DefaultClock = hr_clock; - struct Event { const Packet* packet; bool fastpathed; - typename DefaultClock::duration elapsed; + typename SnortClock::duration elapsed; }; template @@ -91,7 +90,7 @@ static inline std::ostream& operator<<(std::ostream& os, const Event& e) os << ": "; - os << duration_cast(e.elapsed).count() << " usec, ["; + os << clock_usecs(duration_cast(e.elapsed).count()) << " usec, ["; os << e.packet->ptrs.ip_api.get_src() << " -> " << e.packet->ptrs.ip_api.get_dst() << "]"; @@ -102,7 +101,7 @@ static inline std::ostream& operator<<(std::ostream& os, const Event& e) // implementation // ----------------------------------------------------------------------------- -template +template class Impl { public: @@ -152,7 +151,7 @@ inline bool Impl::pop(const Packet* p) if ( config->action & PacketLatencyConfig::LOG ) log_handler.handle(e); - if ( timer.marked_as_fastpathed and (config->action & PacketLatencyConfig::ALERT) ) + if ( config->action & PacketLatencyConfig::ALERT ) event_handler.handle(e); } diff --git a/src/latency/rule_latency.cc b/src/latency/rule_latency.cc index 3cdc883c6..a9a1aab4d 100644 --- a/src/latency/rule_latency.cc +++ b/src/latency/rule_latency.cc @@ -32,6 +32,7 @@ #include "events/event_queue.h" #include "log/messages.h" #include "main/snort_config.h" + #include "latency_config.h" #include "latency_rules.h" #include "latency_stats.h" @@ -49,8 +50,6 @@ namespace rule_latency // helpers // ----------------------------------------------------------------------------- -using DefaultClock = hr_clock; - struct Event { enum Type @@ -61,7 +60,7 @@ struct Event }; Type type; - typename DefaultClock::duration elapsed; + typename SnortClock::duration elapsed; detection_option_tree_root_t* root; }; @@ -96,7 +95,7 @@ static inline std::ostream& operator<<(std::ostream& os, const Event& e) os << ": "; - os << duration_cast(e.elapsed).count() << " usec, "; + os << clock_usecs(duration_cast(e.elapsed).count()) << " usec, "; } // FIXIT-L clean up rule latency logging; delete or make useful @@ -175,7 +174,7 @@ struct DefaultRuleInterface // implementation // ----------------------------------------------------------------------------- -template +template class Impl { public: diff --git a/src/profiler/memory_profiler.cc b/src/profiler/memory_profiler.cc index 82e950171..a8059d7c9 100644 --- a/src/profiler/memory_profiler.cc +++ b/src/profiler/memory_profiler.cc @@ -40,7 +40,7 @@ // show statistics // ----------------------------------------------------------------------------- -#define s_memory_table_title "Memory Profile Statistics" +#define s_memory_table_title "memory profile" namespace memory_stats { diff --git a/src/profiler/profiler_stats_table.cc b/src/profiler/profiler_stats_table.cc index e8020e489..f1dff874f 100644 --- a/src/profiler/profiler_stats_table.cc +++ b/src/profiler/profiler_stats_table.cc @@ -32,7 +32,7 @@ #include "catch/catch.hpp" #endif -static constexpr unsigned WIDTH = 40; +static constexpr unsigned WIDTH = 50; static constexpr char ENDL = '\n'; const StatsTable::Header StatsTable::HEADER { '=' }; diff --git a/src/profiler/rule_profiler_defs.h b/src/profiler/rule_profiler_defs.h index d2aa9b469..515dca833 100644 --- a/src/profiler/rule_profiler_defs.h +++ b/src/profiler/rule_profiler_defs.h @@ -67,7 +67,7 @@ public: private: dot_node_state_t& stats; - Stopwatch sw; + Stopwatch sw; bool finished = false; }; diff --git a/src/profiler/time_profiler.cc b/src/profiler/time_profiler.cc index 77a5ff7bc..fdcd693db 100644 --- a/src/profiler/time_profiler.cc +++ b/src/profiler/time_profiler.cc @@ -38,7 +38,7 @@ #include "catch/catch.hpp" #endif -#define s_time_table_title "Module Profile Statistics" +#define s_time_table_title "module profile" namespace time_stats { @@ -131,7 +131,7 @@ static void print_fn(StatsTable& t, const View& v) t << v.checks(); // total time - t << duration_cast(v.elapsed()).count(); + t << clock_usecs(duration_cast(v.elapsed()).count()); // avg/check t << duration_cast(v.avg_check()).count(); diff --git a/src/profiler/time_profiler_defs.h b/src/profiler/time_profiler_defs.h index 372a3d607..eaeaff7b2 100644 --- a/src/profiler/time_profiler_defs.h +++ b/src/profiler/time_profiler_defs.h @@ -113,7 +113,7 @@ public: private: TimeProfilerStats& stats; - Stopwatch sw; + Stopwatch sw; bool stopped_once = false; }; diff --git a/src/stream/icmp/icmp_module.cc b/src/stream/icmp/icmp_module.cc index 33cbaefe0..9d9205e0b 100644 --- a/src/stream/icmp/icmp_module.cc +++ b/src/stream/icmp/icmp_module.cc @@ -43,8 +43,16 @@ StreamIcmpModule::StreamIcmpModule() : config = nullptr; } -ProfileStats* StreamIcmpModule::get_profile() const -{ return &icmp_perf_stats; } +ProfileStats* StreamIcmpModule::get_profile( + unsigned index, const char*& name, const char*& parent) const +{ + if ( index ) + return nullptr; + + name = MOD_NAME; + parent = "stream"; + return &icmp_perf_stats; +} StreamIcmpConfig* StreamIcmpModule::get_data() { diff --git a/src/stream/icmp/icmp_module.h b/src/stream/icmp/icmp_module.h index 447bdf51f..712d2f536 100644 --- a/src/stream/icmp/icmp_module.h +++ b/src/stream/icmp/icmp_module.h @@ -54,7 +54,7 @@ public: bool begin(const char*, int, SnortConfig*) override; bool end(const char*, int, SnortConfig*) override; - ProfileStats* get_profile() const override; + ProfileStats* get_profile(unsigned, const char*&, const char*&) const override; const PegInfo* get_pegs() const override; PegCount* get_counts() const override; diff --git a/src/stream/ip/ip_module.cc b/src/stream/ip/ip_module.cc index 13dbb4dd2..352d63abd 100644 --- a/src/stream/ip/ip_module.cc +++ b/src/stream/ip/ip_module.cc @@ -140,7 +140,7 @@ ProfileStats* StreamIpModule::get_profile( { case 0: name = "stream_ip"; - parent = nullptr; + parent = "stream"; return &ip_perf_stats; case 1: diff --git a/src/stream/stream_api.cc b/src/stream/stream_api.cc index e50dc80d0..e735bfb43 100644 --- a/src/stream/stream_api.cc +++ b/src/stream/stream_api.cc @@ -160,7 +160,7 @@ void Stream::check_session_closed(Packet* p) { Flow* flow = p->flow; - if (!p || !flow) + if ( !flow ) return; if (flow->session_state & STREAM_STATE_CLOSED) diff --git a/src/stream/tcp/tcp_module.cc b/src/stream/tcp/tcp_module.cc index 39250f92a..c8beec63b 100644 --- a/src/stream/tcp/tcp_module.cc +++ b/src/stream/tcp/tcp_module.cc @@ -228,8 +228,8 @@ ProfileStats* StreamTcpModule::get_profile( switch ( index ) { case 0: - name = "stream_tcp"; - parent = nullptr; + name = MOD_NAME; + parent = "stream"; return &s5TcpPerfStats; case 1: diff --git a/src/stream/udp/udp_module.cc b/src/stream/udp/udp_module.cc index 952817e7a..f8062ad71 100644 --- a/src/stream/udp/udp_module.cc +++ b/src/stream/udp/udp_module.cc @@ -46,8 +46,14 @@ StreamUdpModule::StreamUdpModule() : config = nullptr; } -ProfileStats* StreamUdpModule::get_profile() const +ProfileStats* StreamUdpModule::get_profile( + unsigned index, const char*& name, const char*& parent) const { + if ( index ) + return nullptr; + + name = MOD_NAME; + parent = "stream"; return &udp_perf_stats; } diff --git a/src/stream/udp/udp_module.h b/src/stream/udp/udp_module.h index 8f4c96566..31847c0f8 100644 --- a/src/stream/udp/udp_module.h +++ b/src/stream/udp/udp_module.h @@ -57,7 +57,7 @@ public: bool begin(const char*, int, SnortConfig*) override; bool end(const char*, int, SnortConfig*) override; - ProfileStats* get_profile() const override; + ProfileStats* get_profile(unsigned, const char*&, const char*&) const override; const PegInfo* get_pegs() const override; PegCount* get_counts() const override; StreamUdpConfig* get_data(); diff --git a/src/time/CMakeLists.txt b/src/time/CMakeLists.txt index ec5dd24a5..db8e2e06e 100644 --- a/src/time/CMakeLists.txt +++ b/src/time/CMakeLists.txt @@ -4,6 +4,7 @@ set ( TIME_INTERNAL_SOURCES periodic.cc periodic.h timersub.h + tsc_clock.cc ) if ( ENABLE_UNIT_TESTS ) @@ -11,9 +12,9 @@ if ( ENABLE_UNIT_TESTS ) endif ( ENABLE_UNIT_TESTS ) set ( TIME_INCLUDES - cpuclock.h clock_defs.h stopwatch.h + tsc_clock.h ) add_library ( time STATIC diff --git a/src/time/Makefile.am b/src/time/Makefile.am index b2f89a364..b32475d07 100644 --- a/src/time/Makefile.am +++ b/src/time/Makefile.am @@ -3,18 +3,19 @@ noinst_LIBRARIES = libtime.a x_includedir = $(pkgincludedir)/time x_include_HEADERS = \ -cpuclock.h \ clock_defs.h \ -stopwatch.h +stopwatch.h \ +tsc_clock.h libtime_a_SOURCES = \ +clock_defs.h \ packet_time.cc \ packet_time.h \ periodic.cc \ periodic.h \ -timersub.h \ -clock_defs.h \ -stopwatch.h +stopwatch.h \ +timersub.h \ +tsc_clock.cc if ENABLE_UNIT_TESTS libtime_a_SOURCES += stopwatch_test.cc diff --git a/src/time/clock_defs.h b/src/time/clock_defs.h index f0f17f5f8..23b1e60de 100644 --- a/src/time/clock_defs.h +++ b/src/time/clock_defs.h @@ -20,11 +20,23 @@ #ifndef CLOCK_DEFS_H #define CLOCK_DEFS_H -#include +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef USE_TSC_CLOCK +#include "time/tsc_clock.h" +using SnortClock = TscClock; +#else +#include using hr_clock = std::chrono::high_resolution_clock; -using hr_duration = hr_clock::duration; -using hr_time = hr_clock::time_point; +using SnortClock = hr_clock; +inline long clock_scale() { return 1.0; } +#endif + +using hr_duration = SnortClock::duration; +using hr_time = SnortClock::time_point; inline constexpr hr_duration operator "" _ticks (unsigned long long int v) { return hr_duration(v); } @@ -39,4 +51,11 @@ struct ClockTraits using time_point = TimePoint; using rep = Rep; }; + +inline long clock_usecs(long ticks) +{ return ticks / clock_scale(); } + +inline long clock_ticks(long usecs) +{ return usecs * clock_scale(); } + #endif diff --git a/src/time/cpuclock.h b/src/time/cpuclock.h deleted file mode 100644 index 91e360928..000000000 --- a/src/time/cpuclock.h +++ /dev/null @@ -1,103 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2014-2016 Cisco and/or its affiliates. All rights reserved. -// Copyright (C) 2006-2013 Sourcefire, Inc. -// -// This program is free software; you can redistribute it and/or modify it -// under the terms of the GNU General Public License Version 2 as published -// by the Free Software Foundation. You may not use, modify or distribute -// this program under any other version of the GNU General Public License. -// -// 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. -//-------------------------------------------------------------------------- - -#ifndef CPUCLOCK_H -#define CPUCLOCK_H - -// Assembly to find clock ticks -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -// INTEL LINUX/BSD/.. -#if (defined(__i386) || defined(__amd64) || defined(__x86_64__)) -#define get_clockticks(val) \ -{ \ - uint32_t a, d; \ - __asm__ __volatile__ ("rdtsc" : "=a" (a), "=d" (d)); \ - val = ((uint64_t)a) | (((uint64_t)d) << 32); \ -} -#else -#if (defined(__ia64) && defined(__GNUC__) ) -#define get_clockticks(val) \ -{ \ - __asm__ __volatile__ ("mov %0=ar.itc" : "=r" (val)); \ -} -#else -#if (defined(__ia64) && defined(__hpux)) -#include -#define get_clockticks(val) \ -{ \ - val = _Asm_mov_from_ar (_AREG_ITC); \ -} -#else -// POWER PC -#if (defined(__GNUC__) && (defined(__powerpc__) || (defined(__ppc__)))) -#define get_clockticks(val) \ -{ \ - uint32_t tbu0, tbu1, tbl; \ - do \ - { \ - __asm__ __volatile__ ("mftbu %0" : "=r" (tbu0)); \ - __asm__ __volatile__ ("mftb %0" : "=r" (tbl)); \ - __asm__ __volatile__ ("mftbu %0" : "=r" (tbu1)); \ - } while (tbu0 != tbu1); \ - val = ((uint64_t)tbl) | (((uint64_t)tbu0) << 32); \ -} -#else -// SPARC -#ifdef SPARCV9 -#ifdef _LP64 -#define get_clockticks(val) \ -{ \ - __asm__ __volatile__ ("rd %%tick, %0" : "=r" (val)); \ -} -#else -#define get_clockticks(val) \ -{ \ - uint32_t a, b; \ - __asm__ __volatile__ ("rd %%tick, %0\n" \ - "srlx %0, 32, %1" \ - : "=r" (a), "=r" (b)); \ - val = ((uint64_t)a) | (((uint64_t)b) << 32); \ -} -#endif // _LP64 -#else -#define get_clockticks(val) -#endif // SPARCV9 -#endif // __GNUC__ && __powerpc__ || __ppc__ -#endif // __ia64 && __hpux -#endif // __ia64 && __GNUC__ -#endif // __i386 || __amd64 || __x86_64__ - -inline double get_ticks_per_usec() -{ - uint64_t start = 0, end = 0; - get_clockticks(start); - - sleep(1); - get_clockticks(end); - - return (double)(end-start)/1e6; -} - -#endif - diff --git a/src/time/stopwatch_test.cc b/src/time/stopwatch_test.cc index b986ec0fa..cad2c27e6 100644 --- a/src/time/stopwatch_test.cc +++ b/src/time/stopwatch_test.cc @@ -25,7 +25,7 @@ namespace t_stopwatch { -struct Clock : public ClockTraits +struct Clock : public ClockTraits { static time_point now() { return time; } diff --git a/src/time/tsc_clock.cc b/src/time/tsc_clock.cc new file mode 100644 index 000000000..9fcad2066 --- /dev/null +++ b/src/time/tsc_clock.cc @@ -0,0 +1,37 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2016-2016 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// 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. +//-------------------------------------------------------------------------- +// tsc_clock.cc author Russ Combs + +#include "tsc_clock.h" +#include + +long clock_scale() +{ + static long tpus = 0; // ticks / usec + + if ( !tpus ) + { + struct timespec one_sec = { 1, 0 }; + uint64_t start = TscClock::counter(); + nanosleep(&one_sec, nullptr); + uint64_t end = TscClock::counter(); + tpus = (long)((end - start)/1e6); + } + return tpus; +} + diff --git a/src/time/tsc_clock.h b/src/time/tsc_clock.h new file mode 100644 index 000000000..848649f87 --- /dev/null +++ b/src/time/tsc_clock.h @@ -0,0 +1,65 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2016-2016 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// 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. +//-------------------------------------------------------------------------- +// tsc_clock.h author Russ Combs + +#ifndef TSC_CLOCK_H +#define TSC_CLOCK_H + +// the STL chrono clocks are kinda heavy so we use the time stamp counter +// where available (x86 with rdtsc support). this wasn't always a good +// choice on multi-core systems but most now have rdtscp, constant_tsc, +// tsc_reliable, and nonstop_tsc. note that we don't worry about exact +// instruction sequencing. +// +// references: +// http://stackoverflow.com/questions/275004/timer-function-to-provide-time-in-nano-seconds-using-c +// http://stackoverflow.com/questions/7935518/is-clock-gettime-adequate-for-submicrosecond-timing +// +// this clock stores ticks, not actual time values. use ticks during runtime +// convert from/to usecs at startup/shutdown. see clock_defs.h. + +#include + +struct TscClock +{ + // this has to be const so we use a nice round number and scale it later + typedef std::ratio<1, 1000000> period; + + typedef uint64_t rep; + typedef std::chrono::duration duration; + typedef std::chrono::time_point time_point; + + static const bool is_steady = true; + + static uint64_t counter() + { + uint32_t lo, hi; + asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); + return ((uint64_t)hi << 32) | lo; + } + + static time_point now() noexcept + { + return time_point(duration(counter())); + } +}; + +long clock_scale(); + +#endif +