struct Packet;
struct ProfileStats;
}
-struct Event;
-struct RuleFpList;
-struct RuleTreeNode;
extern THREAD_LOCAL snort::ProfileStats eventqPerfStats;
bool snort_log(snort::Packet*);
// alerts
-void CallLogFuncs(snort::Packet*, ListHead*, Event*, const char*);
+void CallLogFuncs(snort::Packet*, ListHead*, struct Event*, const char*);
void CallLogFuncs(snort::Packet*, const OptTreeNode*, ListHead*);
void CallAlertFuncs(snort::Packet*, const OptTreeNode*, ListHead*);
if ( p->flow ? p->flow->context_chain.front() : sw->non_flow_chain.front() )
{
+ Profile profile(mpsePerfStats);
p->context->searches.search_sync();
sw->suspend();
pc.offload_suspends++;
void DetectionEngine::onload()
{
+ Profile profile(mpsePerfStats);
Packet* p;
+
while (offloader->count() and offloader->get(p))
{
- trace_logf(detection, TRACE_DETECTION_ENGINE, "%" PRIu64 " de::onload %" PRIu64 " (r=%d)\n",
+ trace_logf(detection, TRACE_DETECTION_ENGINE,
+ "%" PRIu64 " de::onload %" PRIu64 " (r=%d)\n",
p->context->packet_number, p->context->context_num, offloader->count());
p->clear_offloaded();
- IpsContextChain& chain = p->flow ? p->flow->context_chain : Analyzer::get_switcher()->non_flow_chain;
+ IpsContextChain& chain = p->flow ? p->flow->context_chain :
+ Analyzer::get_switcher()->non_flow_chain;
resume_ready_suspends(chain);
}
int fp_eval_option(void* v, Cursor& c, Packet* p)
{
IpsOption* opt = (IpsOption*)v;
- // FIXIT-L use this with RuleProfile enabled in profiler_defs.h
- // all ips options should be double counted w/o this exclude but
- // this causes rule_eval to underflow.
- //ProfileExclude exclude(rulePerfStats);
return opt->eval(c, p);
}
void MpseRegexOffload::put(snort::Packet* p)
{
+ Profile profile(mpsePerfStats);
+
assert(p);
assert(!idle.empty());
assert(p->context->searches.items.size() > 0);
bool MpseRegexOffload::get(snort::Packet*& p)
{
+ Profile profile(mpsePerfStats);
assert(!busy.empty());
snort::Mpse::MpseRespType resp_ret;
void ThreadRegexOffload::put(snort::Packet* p)
{
+ Profile profile(mpsePerfStats);
+
assert(p);
assert(!idle.empty());
assert(p->context->searches.items.size() > 0);
bool ThreadRegexOffload::get(snort::Packet*& p)
{
+ Profile profile(mpsePerfStats);
assert(!busy.empty());
for ( auto i = busy.begin(); i != busy.end(); i++ )
static MainHook_f main_hook = snort_ignore;
-THREAD_LOCAL ProfileStats totalPerfStats;
THREAD_LOCAL ProfileStats daqPerfStats;
static THREAD_LOCAL Analyzer* local_analyzer = nullptr;
void Analyzer::process_daq_pkt_msg(DAQ_Msg_h msg, bool retry)
{
- Profile profile(totalPerfStats);
const DAQ_PktHdr_t* pkthdr = daq_msg_get_pkthdr(msg);
set_default_policy();
void Analyzer::finalize_daq_message(DAQ_Msg_h msg, DAQ_Verdict verdict)
{
- // FIXIT-L excluding daqPerfStats profile here because it needs to
- // be excluded by stream_tcp which requires some refactoring.
- // Instead the profiler could automatically exclude from current
- // context if new scope has no parent but that requires additional
- // plumbing.
- // Profile profile(daqPerfStats);
+ Profile profile(daqPerfStats);
daq_instance->finalize_message(msg, verdict);
}
void Analyzer::init_unprivileged()
{
// using dummy values until further integration
+ // FIXIT-H max_contexts must be <= DAQ msg pool to avoid permanent stall
+ // condition (polling for packets that won't come to resume ready suspends)
#ifdef REG_TEST
const unsigned max_contexts = 20;
#else
- const unsigned max_contexts = 1024;
+ const unsigned max_contexts = 255;
#endif
switcher = new ContextSwitcher;
};
extern THREAD_LOCAL snort::ProfileStats daqPerfStats;
-extern THREAD_LOCAL snort::ProfileStats totalPerfStats;
#endif
#include "parser/parse_conf.h"
#include "parser/parse_ip.h"
#include "parser/parser.h"
-#include "profiler/profiler_defs.h"
+#include "profiler/profiler.h"
#include "search_engines/pat_stats.h"
#include "side_channel/side_channel_module.h"
#include "sfip/sf_ipvar.h"
bool set(const char*, Value&, SnortConfig*) override;
bool end(const char*, int, SnortConfig*) override;
+ ProfileStats* get_profile(unsigned, const char*&, const char*&) const override;
+
Usage get_usage() const override
{ return GLOBAL; }
};
return true;
}
+ProfileStats* ProfilerModule::get_profile(
+ unsigned index, const char*& name, const char*& parent) const
+{
+ switch ( index )
+ {
+ case 0:
+ name = "total";
+ parent = nullptr;
+ return &totalPerfStats;
+
+ case 1:
+ name = "other";
+ parent = nullptr;
+ return &otherPerfStats;
+ }
+ return nullptr;
+}
+
//-------------------------------------------------------------------------
// classification module
//-------------------------------------------------------------------------
#include "actions/ips_actions.h"
#include "codecs/codec_api.h"
#include "connectors/connectors.h"
-#include "detection/detect.h"
#include "detection/fp_config.h"
-#include "detection/fp_detect.h"
#include "file_api/file_service.h"
#include "filters/rate_filter.h"
#include "filters/sfrf.h"
#include "control_mgmt.h"
#endif
-#include "analyzer.h"
#include "build.h"
#include "snort_config.h"
#include "thread_config.h"
static SnortConfig* snort_cmd_line_conf = nullptr;
static pid_t snort_main_thread_pid = 0;
-//-------------------------------------------------------------------------
-// perf stats
-// FIXIT-M move these to appropriate modules
-//-------------------------------------------------------------------------
-
-static ProfileStats* get_profile(const char* key)
-{
- if ( !strcmp(key, "daq") )
- return &daqPerfStats;
-
- if ( !strcmp(key, "decode") )
- return &decodePerfStats;
-
- if ( !strcmp(key, "mpse") )
- return &mpsePerfStats;
-
- if ( !strcmp(key, "rule_eval") )
- return &rulePerfStats;
-
- if ( !strcmp(key, "eventq") )
- return &eventqPerfStats;
-
- if ( !strcmp(key, "total") )
- return &totalPerfStats;
-
- return nullptr;
-}
-
-static void register_profiles()
-{
- Profiler::register_module("daq", nullptr, get_profile);
- Profiler::register_module("decode", nullptr, get_profile);
- Profiler::register_module("mpse", nullptr, get_profile);
- Profiler::register_module("rule_eval", nullptr, get_profile);
- Profiler::register_module("eventq", nullptr, get_profile);
- Profiler::register_module("total", nullptr, get_profile);
-}
-
//-------------------------------------------------------------------------
// initialization
//-------------------------------------------------------------------------
}
FileService::init();
- register_profiles();
parser_init();
SnortConfig* sc = ParseSnortConf(snort_cmd_line_conf);
#include "snort_module.h"
+#include "detection/detect.h"
+#include "detection/fp_detect.h"
#include "framework/module.h"
#include "framework/parameter.h"
#include "log/messages.h"
#include "main.h"
#include "main/snort_debug.h"
+#include "managers/codec_manager.h"
#include "packet_io/sfdaq_config.h"
#include "packet_io/trough.h"
#include "parser/config_file.h"
#include "catch/unit_test.h"
#endif
+#include "analyzer.h"
#include "help.h"
#include "shell.h"
#include "snort_config.h"
void sum_stats(bool) override
{ } // accumulate externally
+ ProfileStats* get_profile(unsigned, const char*&, const char*&) const override;
+
Usage get_usage() const override
{ return GLOBAL; }
private:
- SFDAQModuleConfig *module_config;
+ SFDAQModuleConfig* module_config;
};
bool SnortModule::begin(const char* fqn, int, SnortConfig*)
return true;
}
+ProfileStats* SnortModule::get_profile(
+ unsigned index, const char*& name, const char*& parent) const
+{
+ switch ( index )
+ {
+ case 0:
+ name = "daq";
+ parent = nullptr;
+ return &daqPerfStats;
+
+ case 1:
+ name = "decode";
+ parent = nullptr;
+ return &decodePerfStats;
+
+ case 2:
+ name = "mpse";
+ parent = nullptr;
+ return &mpsePerfStats;
+
+ case 3:
+ name = "rule_eval";
+ parent = nullptr;
+ return &rulePerfStats;
+
+ case 4:
+ name = "eventq";
+ parent = nullptr;
+ return &eventqPerfStats;
+ }
+ return nullptr;
+}
+
//-------------------------------------------------------------------------
// singleton
//-------------------------------------------------------------------------
{
}
-void Profiler::register_module(const char*, const char*, get_profile_stats_fn)
-{
-}
-
-void Profiler::consolidate_stats()
+void Profiler::consolidate_stats(uint64_t, uint64_t)
{
}
using namespace snort;
+THREAD_LOCAL ProfileStats totalPerfStats;
+THREAD_LOCAL ProfileStats otherPerfStats;
+
+THREAD_LOCAL TimeContext* ProfileContext::curr_time = nullptr;
+
static ProfilerNodeMap s_profiler_nodes;
void Profiler::register_module(Module* m)
{
unsigned i = 0;
const char* n, * pn;
- // const ProfilerStats* ps = nullptr;
const ProfileStats* ps = nullptr;
+
while ( (ps = m->get_profile(i++, n, pn)) )
register_module(n, pn, m);
}
s_profiler_nodes.register_node(n, pn, m);
}
-void Profiler::register_module(const char* n, const char* pn, get_profile_stats_fn fn)
+void Profiler::consolidate_stats(uint64_t num_pkts, uint64_t usecs)
{
- assert(n);
- s_profiler_nodes.register_node(n, pn, fn);
-}
+ totalPerfStats.time.checks = otherPerfStats.time.checks = num_pkts;
+
+#ifdef USE_TSC_CLOCK
+ totalPerfStats.time.elapsed = otherPerfStats.time.elapsed = clock_ticks(usecs);
+#else
+ hr_duration dt = TO_DURATION(dt, usecs);
+ totalPerfStats.time.elapsed = otherPerfStats.time.elapsed = dt;
+#endif
+
+ const ProfilerNode& root = s_profiler_nodes.get_root();
+ auto children = root.get_children();
+
+ for ( auto pn : children )
+ otherPerfStats.time.elapsed -= pn->get_stats().time.elapsed;
-void Profiler::consolidate_stats()
-{
s_profiler_nodes.accumulate_nodes();
MemoryProfiler::consolidate_fallthrough_stats();
}
#ifndef PROFILER_H
#define PROFILER_H
+#include "main/thread.h"
#include "profiler_defs.h"
namespace snort
public:
static void register_module(snort::Module*);
static void register_module(const char*, const char*, snort::Module*);
- static void register_module(const char*, const char*, snort::get_profile_stats_fn);
- // FIXIT-RC do we need to call on main thread? we should know the answer by now.
- // call from packet threads, just before thread termination
- static void consolidate_stats();
+ static void consolidate_stats(uint64_t pkts = 0, uint64_t usecs = 0);
+
static void reset_stats();
static void show_stats();
};
+extern THREAD_LOCAL snort::ProfileStats totalPerfStats;
+extern THREAD_LOCAL snort::ProfileStats otherPerfStats;
#endif
#define PROFILER_DEFS_H
#include "main/snort_types.h"
+#include "main/thread.h"
#include "memory_defs.h"
#include "memory_profiler_defs.h"
#include "rule_profiler_defs.h"
return *this;
}
-class ProfileContext
+class SO_PUBLIC ProfileContext
{
public:
- ProfileContext(ProfileStats& stats) :
- time(stats.time), memory(stats.memory) { }
+ ProfileContext(ProfileStats& stats) : time(stats.time), memory(stats.memory)
+ {
+ prev_time = curr_time;
+ if ( prev_time )
+ prev_time->pause();
+ curr_time = &time;
+ }
+
+ ~ProfileContext()
+ {
+ if ( prev_time )
+ prev_time->resume();
+ curr_time = prev_time;
+ }
private:
TimeContext time;
MemoryContext memory;
-};
-
-class ProfileExclude
-{
-public:
- ProfileExclude(ProfileStats& stats) : ProfileExclude(stats.time, stats.memory) { }
- ProfileExclude(TimeProfilerStats& time, MemoryTracker&) : time(time) { }
-
-private:
- TimeExclude time;
- MemoryExclude memory;
+ TimeContext* prev_time;
+ static THREAD_LOCAL TimeContext* curr_time;
};
using get_profile_stats_fn = ProfileStats* (*)(const char*);
TimeContext time;
};
-class NoMemExclude
-{
-public:
- NoMemExclude(ProfileStats& stats) : NoMemExclude(stats.time, stats.memory) { }
- NoMemExclude(TimeProfilerStats& time, MemoryTracker&) : time(time) { }
-
-private:
- TimeExclude time;
-};
-
class ProfileDisabled
{
public:
#ifdef NO_PROFILER
using Profile = ProfileDisabled;
-using NoProfile = ProfileDisabled;
#else
#ifdef NO_MEM_MGR
using Profile = NoMemContext;
-using NoProfile = NoMemExclude;
#else
using Profile = ProfileContext;
-using NoProfile = ProfileExclude;
#endif
#endif
// developer enable for profiling rule options
-// see also fp_eval_option
//using RuleProfile = ProfileContext;
using RuleProfile = ProfileDisabled;
void ProfilerNodeMap::register_node(const std::string &n, const char* pn, Module* m)
{ setup_node(get_node(n), get_node(pn ? pn : ROOT_NODE), m); }
-void ProfilerNodeMap::register_node(const std::string& n, const char* pn, get_profile_stats_fn fn)
-{ setup_node(get_node(n), get_node(pn ? pn : ROOT_NODE), fn); }
-
void ProfilerNodeMap::accumulate_nodes()
{
static std::mutex stats_mutex;
#ifdef UNIT_TEST
-static ProfileStats* s_profiler_stats = nullptr;
-static const char* s_profiler_name = nullptr;
-
-static ProfileStats* s_profiler_stats_getter(const char* name)
-{
- if ( s_profiler_name && std::string(name) == s_profiler_name )
- return s_profiler_stats;
-
- return nullptr;
-}
-
static ProfilerNode find_node(const ProfilerNodeMap& tree, const std::string& name)
{
for ( const auto& it : tree )
}
}
-TEST_CASE( "get profile functor for function", "[profiler]" )
-{
- ProfileStats the_stats;
- s_profiler_stats = &the_stats;
- s_profiler_name = "foo";
-
- GetProfileFromFunction functor("foo", s_profiler_stats_getter);
- CHECK( functor() == &the_stats );
-
- s_profiler_stats = nullptr;
-}
-
TEST_CASE( "profiler node", "[profiler]" )
{
ProfileStats the_stats;
node.accumulate();
CHECK( node.get_stats() == the_stats );
}
-
- SECTION( "function" )
- {
- ProfilerNode f_node("foo");
- s_profiler_stats = &the_stats;
- s_profiler_name = "foo";
- f_node.set(s_profiler_stats_getter);
- f_node.accumulate();
- CHECK( f_node.get_stats() == the_stats );
- s_profiler_stats = nullptr;
- }
}
SECTION( "accumulate" )
CHECK( !find_node(tree, "foo").name.empty() );
}
- SECTION( "register function")
- {
- tree.register_node("foo", nullptr, s_profiler_stats_getter);
- CHECK( !find_node(tree, "foo").name.empty() );
- }
-
SECTION( "register child -> parent" )
{
tree.register_node("foo", "bar", &m);
{ return nodes.end(); }
void register_node(const std::string&, const char*, snort::Module*);
- void register_node(const std::string&, const char*, snort::get_profile_stats_fn);
void accumulate_nodes();
void reset_nodes();
// delegate to user function
print(table, cur.view);
- // don't need to print %/caller or %/total if root
+ // don't need to print %/caller if root
if ( root == cur )
- table << "--" << "--";
+ table << "--" << total;
else
- table << cur.view.pct_caller() << cur.view.pct_of(root.view.get_stats());
+ {
+ float value = cur.view.pct_of(root.view.get_stats());
+ table << cur.view.pct_caller() << value;
+
+ if ( layer == 1 )
+ total += value;
+ }
}
snort::LogMessage("%s", ss.str().c_str());
const StatsTable::Field* fields;
const PrintFn print;
const Sorter& sort;
+ float total = 0;
};
#endif
stats.update(sw.get());
}
+ void pause()
+ { sw.stop(); }
+
+ void resume()
+ { sw.start(); }
+
bool active() const
{ return !stopped_once; }
via the get_buf() inspector api */
if ((ret == true) && (packet->is_udp()))
{
- {
- NoProfile exclude(dnp3_perf_stats);
- DetectionEngine::detect(packet);
- }
+ DetectionEngine::detect(packet);
/* Since detection was done, reset reassembly state to avoid double alerts
on the last PDU */
ret = check_ftp(FTPsession, p, iInspectMode);
if ( ret == FTPP_SUCCESS )
{
- NoProfile exclude(ftpPerfStats);
-
// FIXIT-L ideally do_detection will look at the cmd & param buffers
// or the rsp & msg buffers. We should call it from inside check_ftp
// each time we process a pipelined FTP command.
FTPP_APPLY_TNC_ERASE_CMDS, false);
if ( ret == FTPP_SUCCESS || ret == FTPP_NORMALIZED )
- {
- NoProfile exclude(telnetPerfStats);
do_detection(p);
- }
}
else
{
- NoProfile exclude(telnetPerfStats);
do_detection(p);
}
tcpStats.rebuilt_packets++;
tcpStats.rebuilt_bytes += flushed_bytes;
- NoProfile exclude(s5TcpPerfStats);
-
if ( !Analyzer::get_local_analyzer()->inspect_rebuilt(pdu) )
last_pdu = pdu;
else
trs.flush_count++;
show_rebuilt_packet(trs, pdu);
- NoProfile exclude(s5TcpPerfStats);
Analyzer::get_local_analyzer()->inspect_rebuilt(pdu);
if ( trs.tracker->splitter )
continue;
}
- int32_t flush_pt;
- {
- NoProfile exclude(s5TcpPerfStats);
- flush_pt = paf_check(
- trs.tracker->splitter, &trs.tracker->paf_state, p, tsn->payload(),
- tsn->c_len, total, tsn->c_seq, flags);
- }
+ int32_t flush_pt = paf_check(
+ trs.tracker->splitter, &trs.tracker->paf_state, p, tsn->payload(),
+ tsn->c_len, total, tsn->c_seq, flags);
if (flush_pt >= 0)
{
size = trs.tracker->r_win_base - tsn->c_seq;
total += size;
- int32_t flush_pt;
- {
- NoProfile exclude(s5TcpPerfStats);
- flush_pt = paf_check(
- trs.tracker->splitter, &trs.tracker->paf_state, p, tsn->payload(),
- size, total, tsn->c_seq, flags);
- }
+
+ int32_t flush_pt = paf_check(
+ trs.tracker->splitter, &trs.tracker->paf_state, p, tsn->payload(),
+ size, total, tsn->c_seq, flags);
if ( flush_pt >= 0 )
{
int TcpSession::process(Packet* p)
{
Profile profile(s5TcpPerfStats);
-
assert(flow->ssn_server);
// FIXIT-H need to do something here to handle check for need to swap trackers??
if ( ( flow->get_session_flags() & SSNFLAG_RESET ) && tsd.get_tcph()->is_syn()
&& !handle_syn_on_reset_session(tsd) )
return ACTION_NOTHING;
+
else
{
if ( tsm->eval(tsd, *talker, *listener) )
gettimeofday(&endtime, nullptr);
}
-static void timing_stats()
+static void timing_stats(uint64_t& num_pkts, uint64_t& usecs)
{
struct timeval difftime;
TIMERSUB(&endtime, &starttime, &difftime);
LogMessage("%25.25s: %02d:%02d:%02d\n", "runtime", hrs, mins, secs);
- LogMessage("%25.25s: %lu.%lu\n", "seconds",
+ LogMessage("%25.25s: %lu.%06lu\n", "seconds",
(unsigned long)difftime.tv_sec, (unsigned long)difftime.tv_usec);
- PegCount num_pkts = ModuleManager::get_module("daq")->get_global_count("received");
+ usecs = (uint64_t)difftime.tv_sec * 1000000 + difftime.tv_usec;
+ num_pkts = (uint64_t)ModuleManager::get_module("daq")->get_global_count("received");
+
LogMessage("%25.25s: " STDu64 "\n", "packets", num_pkts);
uint64_t pps = (num_pkts / total_secs);
void PrintStatistics()
{
DropStats();
- timing_stats();
+
+ PegCount pkts;
+ uint64_t usecs;
+ timing_stats(pkts, usecs);
// FIXIT-L can do flag saving with RAII (much cleaner)
int save_quiet_flag = SnortConfig::get_conf()->logging_flags & LOGGING_FLAG__QUIET;
SnortConfig::get_conf()->logging_flags &= ~LOGGING_FLAG__QUIET;
// once more for the main thread
- Profiler::consolidate_stats();
+ Profiler::consolidate_stats(pkts, usecs);
Profiler::show_stats();
SnortConfig::get_conf()->logging_flags |= save_quiet_flag;