From: Oleksii Shumeiko -X (oshumeik - SOFTSERVE INC at Cisco) Date: Wed, 17 May 2023 09:04:50 +0000 (+0000) Subject: Pull request #3843: profiler: add json formatter X-Git-Tag: 3.1.62.0~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e36570339b5ccade7eaa37362bde076baa810c1b;p=thirdparty%2Fsnort3.git Pull request #3843: profiler: add json formatter Merge in SNORT/snort3 from ~ANOROKH/snort3:add_json_formatter to master Squashed commit of the following: commit 94832c6e4e72b9a95e644288b349eacf0560f056 Author: Anna Norokh Date: Wed May 3 16:55:55 2023 +0300 profiler: add json formatter * separated table output; * added json formatter; * added output argument to rule_dump() command; * added function to put termination to json output in json_stream class; --- diff --git a/src/helpers/json_stream.cc b/src/helpers/json_stream.cc index 246d9f283..a0b26a739 100644 --- a/src/helpers/json_stream.cc +++ b/src/helpers/json_stream.cc @@ -166,3 +166,7 @@ void JsonStream::split() sep = true; } +void JsonStream::put_eol() +{ + out << std::endl; +} diff --git a/src/helpers/json_stream.h b/src/helpers/json_stream.h index 59af30d59..046cc85aa 100644 --- a/src/helpers/json_stream.h +++ b/src/helpers/json_stream.h @@ -48,6 +48,8 @@ public: void put_true(const char* key); void put_false(const char* key); + void put_eol(); + private: void split(); diff --git a/src/profiler/CMakeLists.txt b/src/profiler/CMakeLists.txt index fe47fd228..f13d66abc 100644 --- a/src/profiler/CMakeLists.txt +++ b/src/profiler/CMakeLists.txt @@ -10,22 +10,26 @@ set ( PROFILER_INCLUDES set ( PROFILER_SOURCES active_context.h + json_view.cc + json_view.h memory_context.cc memory_profiler.cc memory_profiler.h profiler.cc + profiler_module.cc + profiler_module.h + profiler_nodes.cc + profiler_nodes.h profiler_printer.h profiler_stats_table.cc profiler_stats_table.h profiler_tree_builder.h - profiler_nodes.cc - profiler_nodes.h rule_profiler.cc rule_profiler.h + table_view.cc + table_view.h time_profiler.cc time_profiler.h - profiler_module.cc - profiler_module.h ) add_library ( profiler OBJECT diff --git a/src/profiler/json_view.cc b/src/profiler/json_view.cc new file mode 100644 index 000000000..bd2a90bcd --- /dev/null +++ b/src/profiler/json_view.cc @@ -0,0 +1,116 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2023-2023 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. +//-------------------------------------------------------------------------- + +// json_view.cc author Anna Norokh + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include "json_view.h" + +#include +#include + +#include "control/control.h" +#include "helpers/json_stream.h" +#include "main/snort_config.h" +#include "utils/stats.h" + +#include "profiler_printer.h" +#include "rule_profiler.h" + +#define PRECISION 5 + +using namespace snort; + +static void print_single_entry(ControlConn* ctrlcon, const rule_stats::View& v, unsigned n, + unsigned count, double total_time_usec) +{ + using std::chrono::duration_cast; + using std::chrono::microseconds; + + std::ostringstream ss; + JsonStream json(ss); + + json.open(); + json.put("gid", v.sig_info.gid); + json.put("sid", v.sig_info.sid); + json.put("rev", v.sig_info.rev); + + json.put("checks", v.checks()); + json.put("matches", v.matches()); + json.put("alerts", v.alerts()); + + json.put("timeUs", clock_usecs(TO_USECS(v.elapsed()))); + json.put("avgCheck", clock_usecs(TO_USECS(v.avg_check()))); + json.put("avgMatch", clock_usecs(TO_USECS(v.avg_match()))); + json.put("avgNonMatch", clock_usecs(TO_USECS(v.avg_no_match()))); + + json.put("timeouts", v.timeouts()); + json.put("suspends", v.suspends()); + json.put("ruleTimePercentage", v.rule_time_per(total_time_usec), PRECISION); + json.close(); + + + if ( n < count ) + ss << ", "; + + LogRespond(ctrlcon, "%s", ss.str().c_str()); +} + +void print_json_entries(ControlConn* ctrlcon, std::vector& entries, + ProfilerSorter& sort, unsigned count) +{ + std::ostringstream ss; + JsonStream json(ss); + + RuleContext::set_end_time(get_time_curr()); + RuleContext::count_total_time(); + + double start_time_usec = + RuleContext::get_start_time()->tv_sec * 1000000.0 + RuleContext::get_start_time()->tv_usec; + double end_time_usec = + RuleContext::get_end_time()->tv_sec * 1000000.0 + RuleContext::get_end_time()->tv_usec; + double total_time_usec = + RuleContext::get_total_time()->tv_sec * 1000000.0 + RuleContext::get_total_time()->tv_usec; + + json.open(); + json.put("startTime", start_time_usec); + json.put("endTime", end_time_usec); + json.open_array("rules"); + json.put_eol(); + + LogRespond(ctrlcon, "%s", ss.str().c_str()); + + if ( !count || count > entries.size() ) + count = entries.size(); + + if ( sort ) + std::partial_sort(entries.begin(), entries.begin() + count, entries.end(), sort); + + for ( unsigned i = 0; i < count; ++i ) + print_single_entry(ctrlcon, entries[i], i + 1, count, total_time_usec); + + //clean the stream from previous data + ss.str(""); + json.close_array(); + json.close(); + + LogRespond(ctrlcon, "%s", ss.str().c_str()); +} diff --git a/src/profiler/json_view.h b/src/profiler/json_view.h new file mode 100644 index 000000000..1e8e59a20 --- /dev/null +++ b/src/profiler/json_view.h @@ -0,0 +1,33 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2023-2023 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. +//-------------------------------------------------------------------------- + +// json_view.h author Anna Norokh + +#ifndef JSON_VIEW_H +#define JSON_VIEW_H + +#include + +#include "main/snort_config.h" + +#include "profiler_printer.h" +#include "rule_profiler.h" + +void print_json_entries(ControlConn*, std::vector&, ProfilerSorter&, unsigned); + +#endif diff --git a/src/profiler/profiler_module.cc b/src/profiler/profiler_module.cc index 51c5b0958..66c6a4b5e 100644 --- a/src/profiler/profiler_module.cc +++ b/src/profiler/profiler_module.cc @@ -27,14 +27,15 @@ #include "control/control.h" #include "hash/xhash.h" #include "log/messages.h" +#include "lua/lua.h" #include "main/analyzer_command.h" #include "main/reload_tuner.h" #include "main/snort.h" #include "main/snort_config.h" #include "managers/module_manager.h" -#include "profiler/rule_profiler.h" -#include "profiler/rule_profiler_defs.h" +#include "rule_profiler.h" +#include "rule_profiler_defs.h" using namespace snort; @@ -86,8 +87,8 @@ private: class ProfilerRuleDump : public AnalyzerCommand { public: - ProfilerRuleDump(ControlConn* conn) - : AnalyzerCommand(conn), nodes(), stats() + ProfilerRuleDump(ControlConn* conn, OutType out_type) + : AnalyzerCommand(conn), nodes(), stats(), out_type(out_type) { const SnortConfig* sc = SnortConfig::get_conf(); assert(sc); @@ -108,7 +109,7 @@ public: const auto* config = SnortConfig::get_conf()->get_profiler(); assert(config); - print_rule_profiler_stats(config->rule, stats, ctrlcon); + print_rule_profiler_stats(config->rule, stats, ctrlcon, out_type); } bool execute(Analyzer&, void**) override @@ -123,6 +124,7 @@ public: private: std::vector nodes; std::unordered_map stats; + OutType out_type; }; class ProfilerRuleReset : public AnalyzerCommand @@ -213,11 +215,42 @@ static int rule_profiling_dump(lua_State* L) return 0; } - main_broadcast_command(new ProfilerRuleDump(ctrlcon), ctrlcon); + const int num_of_args = lua_gettop(L); + + if (!L or (num_of_args == 0)) + { + main_broadcast_command(new ProfilerRuleDump(ctrlcon, OutType::OUTPUT_TABLE), ctrlcon); + return 0; + } + + if (num_of_args > 1) + { + LogRespond(ctrlcon, "Too many arguments for rule_dump(output) command\n"); + return 0; + } + + const char* arg = lua_tostring(L, 1); + + if (strcmp(arg, "json") == 0) + main_broadcast_command(new ProfilerRuleDump(ctrlcon, OutType::OUTPUT_JSON), ctrlcon); + + else if (strcmp(arg, "table") == 0) + main_broadcast_command(new ProfilerRuleDump(ctrlcon, OutType::OUTPUT_TABLE), ctrlcon); + + else + LogRespond(ctrlcon, "Invalid usage of rule_dump(output), argument can be 'table' or 'json'\n"); return 0; } +static const Parameter profiler_dump_params[] = +{ + { "output", Parameter::PT_ENUM, "table | json", + "table", "print rule statistics in table or json format" }, + + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + static const Command profiler_cmds[] = { { "rule_start", rule_profiling_start, @@ -230,7 +263,7 @@ static const Command profiler_cmds[] = nullptr, "print rule profiler status" }, { "rule_dump", rule_profiling_dump, - nullptr, "print rule statistics" }, + profiler_dump_params, "print rule statistics" }, { nullptr, nullptr, nullptr, nullptr } }; diff --git a/src/profiler/profiler_module.h b/src/profiler/profiler_module.h index d53add5f0..237a52176 100644 --- a/src/profiler/profiler_module.h +++ b/src/profiler/profiler_module.h @@ -23,7 +23,7 @@ #include "framework/module.h" -#include "profiler/profiler.h" +#include "profiler.h" class ProfilerModule : public snort::Module { diff --git a/src/profiler/rule_profiler.cc b/src/profiler/rule_profiler.cc index c28508977..5d84ee1c0 100644 --- a/src/profiler/rule_profiler.cc +++ b/src/profiler/rule_profiler.cc @@ -30,12 +30,12 @@ #include #include +#include "control/control.h" // this include eventually leads to possible issues with std::chrono: // 1. Undefined or garbage value returned to caller (rep count()) // 2. The left expression of the compound assignment is an uninitialized value. // The computed value will also be garbage (duration& operator+=(const duration& __d)) #include "detection/detection_options.h" // ... FIXIT-W -#include "control/control.h" #include "detection/treenodes.h" #include "hash/ghash.h" #include "hash/xhash.h" @@ -43,12 +43,14 @@ #include "main/thread_config.h" #include "parser/parser.h" #include "target_based/snort_protocols.h" -#include "utils/stats.h" #include "time/timersub.h" +#include "utils/stats.h" +#include "json_view.h" #include "profiler_printer.h" #include "profiler_stats_table.h" #include "rule_profiler_defs.h" +#include "table_view.h" #ifdef UNIT_TEST #include "catch/snort_catch.h" @@ -66,90 +68,6 @@ struct timeval RuleContext::total_time = {0, 0}; namespace rule_stats { -static const StatsTable::Field fields[] = -{ - { "#", 5, '\0', 0, std::ios_base::left }, - { "gid", 6, '\0', 0, std::ios_base::fmtflags() }, - { "sid", 6, '\0', 0, std::ios_base::fmtflags() }, - { "rev", 4, '\0', 0, std::ios_base::fmtflags() }, - { "checks", 10, '\0', 0, std::ios_base::fmtflags() }, - { "matches", 8, '\0', 0, std::ios_base::fmtflags() }, - { "alerts", 7, '\0', 0, std::ios_base::fmtflags() }, - { "time (us)", 10, '\0', 0, std::ios_base::fmtflags() }, - { "avg/check", 10, '\0', 1, std::ios_base::fmtflags() }, - { "avg/match", 10, '\0', 1, std::ios_base::fmtflags() }, - { "avg/non-match", 14, '\0', 1, std::ios_base::fmtflags() }, - { "timeouts", 9, '\0', 0, std::ios_base::fmtflags() }, - { "suspends", 9, '\0', 0, std::ios_base::fmtflags() }, - { "rule_time (%)", 14, '\0', 5, std::ios_base::fmtflags() }, - { nullptr, 0, '\0', 0, std::ios_base::fmtflags() } -}; - -struct View -{ - OtnState state; - SigInfo sig_info; - - hr_duration elapsed() const - { return state.elapsed; } - - hr_duration elapsed_match() const - { return state.elapsed_match; } - - hr_duration elapsed_no_match() const - { return elapsed() - elapsed_match(); } - - uint64_t checks() const - { return state.checks; } - - uint64_t matches() const - { return state.matches; } - - uint64_t no_matches() const - { return checks() - matches(); } - - uint64_t alerts() const - { return state.alerts; } - - uint64_t timeouts() const - { return state.latency_timeouts; } - - uint64_t suspends() const - { return state.latency_suspends; } - - hr_duration time_per(hr_duration d, uint64_t v) const - { - if ( v == 0 ) - return CLOCK_ZERO; - - return hr_duration(d / v); - } - - hr_duration avg_match() const - { return time_per(elapsed_match(), matches()); } - - hr_duration avg_no_match() const - { return time_per(elapsed_no_match(), no_matches()); } - - hr_duration avg_check() const - { return time_per(elapsed(), checks()); } - - double rule_time_per(double total_time_usec) const - { - if (total_time_usec < 1.) - return 100.0; - return clock_usecs(TO_USECS(elapsed())) / total_time_usec * 100; - } - - View(const OtnState& otn_state, const SigInfo* si = nullptr) : - state(otn_state) - { - if ( si ) - // FIXIT-L does sig_info need to be initialized otherwise? - sig_info = *si; - } -}; - static const ProfilerSorter sorters[] = { { "", nullptr }, @@ -201,89 +119,10 @@ static std::vector build_entries(const std::unordered_map& entries, - ProfilerSorter& sort, unsigned count) -{ - std::ostringstream ss; - RuleContext::set_end_time(get_time_curr()); - RuleContext::count_total_time(); - - double total_time_usec = - RuleContext::get_total_time()->tv_sec * 1000000.0 + RuleContext::get_total_time()->tv_usec; - - { - StatsTable table(fields, ss); - - table << StatsTable::SEP; - - table << s_rule_table_title; - if ( count ) - table << " (worst " << count; - else - table << " (all"; - - if ( sort ) - table << ", sorted by " << sort.name; - - table << ")\n"; - - table << StatsTable::HEADER; - } - - LogRespond(ctrlcon, "%s", ss.str().c_str()); - - if ( !count || count > entries.size() ) - count = entries.size(); - - if ( sort ) - std::partial_sort(entries.begin(), entries.begin() + count, entries.end(), sort); - - for ( unsigned i = 0; i < count; ++i ) - print_single_entry(ctrlcon, entries[i], i + 1, total_time_usec); -} - } void print_rule_profiler_stats(const RuleProfilerConfig& config, const std::unordered_map& stats, - ControlConn* ctrlcon) + ControlConn* ctrlcon, OutType out_type) { auto entries = rule_stats::build_entries(stats); @@ -294,7 +133,11 @@ void print_rule_profiler_stats(const RuleProfilerConfig& config, const std::unor auto sort = rule_stats::sorters[config.sort]; // FIXIT-L do we eventually want to be able print rule totals, too? - print_entries(ctrlcon, entries, sort, config.count); + if ( out_type == OutType::OUTPUT_TABLE ) + print_entries(ctrlcon, entries, sort, config.count); + + else if ( out_type == OutType::OUTPUT_JSON ) + print_json_entries(ctrlcon, entries, sort, config.count); } void show_rule_profiler_stats(const RuleProfilerConfig& config) diff --git a/src/profiler/rule_profiler.h b/src/profiler/rule_profiler.h index 36b9d7601..5c83eb4af 100644 --- a/src/profiler/rule_profiler.h +++ b/src/profiler/rule_profiler.h @@ -21,10 +21,15 @@ #ifndef RULE_PROFILER_H #define RULE_PROFILER_H -#include "detection/treenodes.h" #include #include +#include "detection/treenodes.h" +#include "main/snort_config.h" +#include "main/thread_config.h" + +#include "rule_profiler_defs.h" + struct RuleProfilerConfig; class ControlConn; namespace snort @@ -33,9 +38,79 @@ namespace snort } void prepare_rule_profiler_stats(std::vector&, std::unordered_map&, unsigned); -void print_rule_profiler_stats(const RuleProfilerConfig&, const std::unordered_map&, ControlConn* = nullptr); +void print_rule_profiler_stats(const RuleProfilerConfig&, const std::unordered_map&, + ControlConn* = nullptr, OutType = OutType::OUTPUT_TABLE); void show_rule_profiler_stats(const RuleProfilerConfig&); void reset_rule_profiler_stats(); void reset_thread_rule_profiler_stats(std::vector&, unsigned); +namespace rule_stats +{ + +struct View +{ + OtnState state; + SigInfo sig_info; + + hr_duration elapsed() const + { return state.elapsed; } + + hr_duration elapsed_match() const + { return state.elapsed_match; } + + hr_duration elapsed_no_match() const + { return elapsed() - elapsed_match(); } + + uint64_t checks() const + { return state.checks; } + + uint64_t matches() const + { return state.matches; } + + uint64_t no_matches() const + { return checks() - matches(); } + + uint64_t alerts() const + { return state.alerts; } + + uint64_t timeouts() const + { return state.latency_timeouts; } + + uint64_t suspends() const + { return state.latency_suspends; } + + hr_duration time_per(hr_duration d, uint64_t v) const + { + if ( v == 0 ) + return CLOCK_ZERO; + + return hr_duration(d / v); + } + + hr_duration avg_match() const + { return time_per(elapsed_match(), matches()); } + + hr_duration avg_no_match() const + { return time_per(elapsed_no_match(), no_matches()); } + + hr_duration avg_check() const + { return time_per(elapsed(), checks()); } + + double rule_time_per(double total_time_usec) const + { + if (total_time_usec < 1.) + return 100.0; + return clock_usecs(TO_USECS(elapsed())) / total_time_usec * 100; + } + + View(const OtnState& otn_state, const SigInfo* si = nullptr) : + state(otn_state) + { + if ( si ) + // FIXIT-L does sig_info need to be initialized otherwise? + sig_info = *si; + } +}; + +} #endif diff --git a/src/profiler/rule_profiler_defs.h b/src/profiler/rule_profiler_defs.h index 109276370..ee0307ce5 100644 --- a/src/profiler/rule_profiler_defs.h +++ b/src/profiler/rule_profiler_defs.h @@ -26,6 +26,12 @@ struct dot_node_state_t; +enum OutType +{ + OUTPUT_TABLE = 0, + OUTPUT_JSON +}; + struct RuleProfilerConfig { enum Sort diff --git a/src/profiler/table_view.cc b/src/profiler/table_view.cc new file mode 100644 index 000000000..675a03423 --- /dev/null +++ b/src/profiler/table_view.cc @@ -0,0 +1,137 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2023 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. +//-------------------------------------------------------------------------- + +// table_view.cc author Joel Cornett + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include "table_view.h" + +#include +#include + +#include "control/control.h" +#include "detection/treenodes.h" +#include "utils/stats.h" + +#include "profiler_printer.h" +#include "profiler_stats_table.h" +#include "rule_profiler.h" + +#define s_rule_table_title "rule profile" + +using namespace snort; + +const StatsTable::Field fields[] = +{ + { "#", 5, '\0', 0, std::ios_base::left }, + { "gid", 6, '\0', 0, std::ios_base::fmtflags() }, + { "sid", 6, '\0', 0, std::ios_base::fmtflags() }, + { "rev", 4, '\0', 0, std::ios_base::fmtflags() }, + { "checks", 10, '\0', 0, std::ios_base::fmtflags() }, + { "matches", 8, '\0', 0, std::ios_base::fmtflags() }, + { "alerts", 7, '\0', 0, std::ios_base::fmtflags() }, + { "time (us)", 10, '\0', 0, std::ios_base::fmtflags() }, + { "avg/check", 10, '\0', 1, std::ios_base::fmtflags() }, + { "avg/match", 10, '\0', 1, std::ios_base::fmtflags() }, + { "avg/non-match", 14, '\0', 1, std::ios_base::fmtflags() }, + { "timeouts", 9, '\0', 0, std::ios_base::fmtflags() }, + { "suspends", 9, '\0', 0, std::ios_base::fmtflags() }, + { "rule_time (%)", 14, '\0', 5, std::ios_base::fmtflags() }, + { nullptr, 0, '\0', 0, std::ios_base::fmtflags() } +}; + +// FIXIT-L logic duplicated from ProfilerPrinter +static void print_single_entry(ControlConn* ctrlcon, const rule_stats::View& v, unsigned n, + double total_time_usec) +{ + using std::chrono::duration_cast; + using std::chrono::microseconds; + + std::ostringstream ss; + + { + StatsTable table(fields, ss); + + table << StatsTable::ROW; + + table << n; // # + + table << v.sig_info.gid; + table << v.sig_info.sid; + table << v.sig_info.rev; + + table << v.checks(); + table << v.matches(); + table << v.alerts(); + + table << clock_usecs(TO_USECS(v.elapsed())); + table << clock_usecs(TO_USECS(v.avg_check())); + table << clock_usecs(TO_USECS(v.avg_match())); + table << clock_usecs(TO_USECS(v.avg_no_match())); + + table << v.timeouts(); + table << v.suspends(); + table << v.rule_time_per(total_time_usec); + } + + LogRespond(ctrlcon, "%s", ss.str().c_str()); +} + +// FIXIT-L logic duplicated from ProfilerPrinter +void print_entries(ControlConn* ctrlcon, std::vector& entries, + ProfilerSorter& sort, unsigned count) +{ + std::ostringstream ss; + RuleContext::set_end_time(get_time_curr()); + RuleContext::count_total_time(); + + double total_time_usec = + RuleContext::get_total_time()->tv_sec * 1000000.0 + RuleContext::get_total_time()->tv_usec; + + StatsTable table(fields, ss); + + table << StatsTable::SEP; + + table << s_rule_table_title; + if ( count ) + table << " (worst " << count; + else + table << " (all"; + + if ( sort ) + table << ", sorted by " << sort.name; + + table << ")\n"; + + table << StatsTable::HEADER; + + LogRespond(ctrlcon, "%s", ss.str().c_str()); + + if ( !count || count > entries.size() ) + count = entries.size(); + + if ( sort ) + std::partial_sort(entries.begin(), entries.begin() + count, entries.end(), sort); + + for ( unsigned i = 0; i < count; ++i ) + print_single_entry(ctrlcon, entries[i], i + 1, total_time_usec); + +} diff --git a/src/profiler/table_view.h b/src/profiler/table_view.h new file mode 100644 index 000000000..2dc7fff36 --- /dev/null +++ b/src/profiler/table_view.h @@ -0,0 +1,33 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2023 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. +//-------------------------------------------------------------------------- + +// table_view.h author Joel Cornett + +#ifndef TABLE_VIEW_H +#define TABLE_VIEW_H + +#include + +#include "main/snort_config.h" + +#include "profiler_printer.h" +#include "rule_profiler.h" + +void print_entries(ControlConn*, std::vector&, ProfilerSorter&, unsigned); + +#endif