#include <iomanip>
#include <sstream>
#include <queue>
+#include <algorithm>
#include "appid_session.h"
#include "appid_cpu_profile_table.h"
using namespace snort;
-static const char* table_header = "AppId Performance Statistics (all)\n===========================================================================================================================================================\n";
-static const char* columns = " AppId App Name Usecs Pkts AvgUsecs/Pkt Sessions AvgUsecs/Sess MaxPkts/Sess MaxUsecs/Sess\n";
-static const char* partition = "-----------------------------------------------------------------------------------------------------------------------------------------------------------\n";
+#define TABLE_HEADER(num_rows) "AppId Performance Statistics (top %d appids)\n===================================================================================================================================================\n", num_rows
+static const char* columns = " AppId App Name Usecs Pkts AvgUsecs/Pkt Sessions AvgUsecs/Sess MaxPkts/Sess MaxUsecs/Sess %%/Total\n";
+static const char* partition = "---------------------------------------------------------------------------------------------------------------------------------------------------\n";
static std::string FormatWithCommas(uint64_t value)
{
// Comparator for priority queue based on avg_processing_time/session
struct CompareByAvgProcessingTime {
bool operator()(const std::pair<AppId, AppidCPUProfilerStats>& a, const std::pair<AppId, AppidCPUProfilerStats>& b) const {
- if (a.second.per_appid_sessions == 0 or b.second.per_appid_sessions == 0)
+ if (!a.second.per_appid_sessions or !b.second.per_appid_sessions)
return false;
return a.second.processing_time/a.second.per_appid_sessions < b.second.processing_time/b.second.per_appid_sessions;
if (bucket != appid_cpu_profiling_table.end())
{
- appid_log(nullptr, TRACE_INFO_LEVEL, table_header);
+ appid_log(nullptr, TRACE_INFO_LEVEL, TABLE_HEADER(1));
appid_log(nullptr, TRACE_INFO_LEVEL, columns);
appid_log(nullptr, TRACE_INFO_LEVEL, partition);
- appid_log(nullptr, TRACE_INFO_LEVEL, " %5d %-25.25s %14.14s %9.9s %17.17s %12.12s %14.14s %15.14s %17.16s\n",
+ appid_log(nullptr, TRACE_INFO_LEVEL, " %5d %-15.15s %14.14s %10.10s %15.14s %11.11s %16.14s %15.14s %15.14s %10.2f\n",
appid, bucket->second.app_name.c_str(), FormatWithCommas(bucket->second.processing_time).c_str(), FormatWithCommas(bucket->second.processed_packets).c_str(),
FormatWithCommas(bucket->second.processing_time/bucket->second.processed_packets).c_str(), FormatWithCommas(bucket->second.per_appid_sessions).c_str(),
FormatWithCommas(bucket->second.processing_time/bucket->second.per_appid_sessions).c_str(), FormatWithCommas(bucket->second.max_processed_pkts_per_session).c_str(),
- FormatWithCommas(bucket->second.max_processing_time_per_session).c_str());
+ FormatWithCommas(bucket->second.max_processing_time_per_session).c_str(), (static_cast<float>(bucket->second.processing_time)/total_processing_time)*100);
}
else
{
return DISPLAY_SUCCESS;
}
-AppidCpuTableDisplayStatus AppidCPUProfilingManager::display_appid_cpu_profiler_table(OdpContext& odp_ctxt, bool override_running_flag)
+AppidCpuTableDisplayStatus AppidCPUProfilingManager::display_appid_cpu_profiler_table(OdpContext& odp_ctxt, uint32_t display_rows_limit, bool override_running_flag)
{
if (odp_ctxt.is_appid_cpu_profiler_running() and !override_running_flag)
return DISPLAY_ERROR_APPID_PROFILER_RUNNING;
for (const auto& entry : appid_cpu_profiling_table)
sorted_appid_cpu_profiler_table.push(entry);
- appid_log(nullptr, TRACE_INFO_LEVEL, table_header);
+ display_rows_limit = static_cast<uint32_t>(std::min({static_cast<size_t>(display_rows_limit), sorted_appid_cpu_profiler_table.size(), static_cast<size_t>(APPID_CPU_PROFILER_MAX_DISPLAY_ROWS)}));
+ appid_log(nullptr, TRACE_INFO_LEVEL, TABLE_HEADER(display_rows_limit));
appid_log(nullptr, TRACE_INFO_LEVEL, columns);
appid_log(nullptr, TRACE_INFO_LEVEL, partition);
- while (!sorted_appid_cpu_profiler_table.empty())
+ uint32_t rows_displayed = 0;
+
+ while (!sorted_appid_cpu_profiler_table.empty() and rows_displayed < display_rows_limit)
{
auto entry = sorted_appid_cpu_profiler_table.top();
sorted_appid_cpu_profiler_table.pop();
if (!entry.second.processed_packets or !entry.second.per_appid_sessions)
continue;
- appid_log(nullptr, TRACE_INFO_LEVEL, " %5d %-25.25s %14.14s %9.9s %17.17s %12.12s %14.14s %15.14s %17.16s\n",
+ appid_log(nullptr, TRACE_INFO_LEVEL, " %5d %-15.15s %14.14s %10.10s %15.14s %11.11s %16.14s %15.14s %15.14s %10.2f\n",
entry.first, entry.second.app_name.c_str(), FormatWithCommas(entry.second.processing_time).c_str(), FormatWithCommas(entry.second.processed_packets).c_str(),
FormatWithCommas(entry.second.processing_time/entry.second.processed_packets).c_str(), FormatWithCommas(entry.second.per_appid_sessions).c_str(),
- FormatWithCommas(entry.second.processing_time/entry.second.per_appid_sessions).c_str(), FormatWithCommas(entry.second.max_processed_pkts_per_session).c_str(),
- FormatWithCommas(entry.second.max_processing_time_per_session).c_str());
+ FormatWithCommas(entry.second.processing_time/entry.second.per_appid_sessions).c_str(), FormatWithCommas(entry.second.max_processed_pkts_per_session).c_str(),
+ FormatWithCommas(entry.second.max_processing_time_per_session).c_str(), (static_cast<float>(entry.second.processing_time)/total_processing_time)*100);
+
+ rows_displayed += 1;
}
+
+ appid_log(nullptr, TRACE_INFO_LEVEL, partition);
+
+ appid_log(nullptr, TRACE_INFO_LEVEL, "Totals(all_sessions) : %15.15s %10.10s %15.14s %10.10s %15.15s %15.14s %16.15s %9d\n",
+ FormatWithCommas(total_processing_time).c_str(), FormatWithCommas(total_processed_packets).c_str(), FormatWithCommas(total_processing_time/total_processed_packets).c_str(),
+ FormatWithCommas(total_per_appid_sessions).c_str(), FormatWithCommas(total_processing_time/total_per_appid_sessions).c_str(),
+ FormatWithCommas(max_processed_pkts_per_session).c_str(), FormatWithCommas(max_processing_time_per_session).c_str(), 100);
+
return DISPLAY_SUCCESS;
}
{
std::lock_guard<std::mutex> lock(appid_cpu_profiler_mutex);
appid_cpu_profiling_table.clear();
+ total_processing_time = 0;
+ total_processed_packets = 0;
+ total_per_appid_sessions = 0;
+ max_processing_time_per_session = 0;
+ max_processed_pkts_per_session = 0;
+}
+
+void AppidCPUProfilingManager::update_totals(const AppidCPUProfilerStats& stats)
+{
+ total_processing_time += stats.processing_time;
+ total_processed_packets += stats.processed_packets;
+ total_per_appid_sessions += stats.per_appid_sessions;
+ if (stats.max_processed_pkts_per_session >= max_processed_pkts_per_session)
+ max_processed_pkts_per_session = stats.max_processed_pkts_per_session;
+ if (stats.max_processing_time_per_session >= max_processing_time_per_session)
+ max_processing_time_per_session = stats.max_processing_time_per_session;
}
void AppidCPUProfilingManager::insert_appid_cpu_profiler_record(AppId appId, const AppidCPUProfilerStats& stats)
if (stats.processing_time > it->second.max_processing_time_per_session)
it->second.max_processing_time_per_session = stats.processing_time;
}
+ update_totals(stats);
}
void AppidCPUProfilingManager::check_appid_cpu_profiler_table_entry(const AppIdSession* asd, AppId payload_id)
class AppIdSession;
class OdpContext;
+#define APPID_CPU_PROFILER_DEFAULT_DISPLAY_ROWS 100
+#define APPID_CPU_PROFILER_MAX_DISPLAY_ROWS 2000
+
enum AppidCpuTableDisplayStatus {
DISPLAY_SUCCESS = 0,
DISPLAY_ERROR_TABLE_EMPTY,
using AppidCPUProfilingTable = std::unordered_map<AppId, AppidCPUProfilerStats>;
AppidCPUProfilingTable appid_cpu_profiling_table;
std::mutex appid_cpu_profiler_mutex;
+ uint64_t total_processing_time = 0;
+ uint64_t total_processed_packets = 0;
+ uint32_t total_per_appid_sessions = 0;
+ uint64_t max_processing_time_per_session = 0;
+ uint64_t max_processed_pkts_per_session = 0;
public:
AppidCPUProfilingManager() = default;
void insert_appid_cpu_profiler_record(AppId appId, const AppidCPUProfilerStats& stats);
void check_appid_cpu_profiler_table_entry(const AppIdSession* asd, AppId service_id, AppId client_id, AppId payload_id, AppId misc_id);
void check_appid_cpu_profiler_table_entry(const AppIdSession* asd, AppId payload_id);
+ void update_totals(const AppidCPUProfilerStats& stats);
- AppidCpuTableDisplayStatus display_appid_cpu_profiler_table(OdpContext&, bool override_running_flag = false);
+ AppidCpuTableDisplayStatus display_appid_cpu_profiler_table(OdpContext&, uint32_t display_rows_limit = APPID_CPU_PROFILER_DEFAULT_DISPLAY_ROWS, bool override_running_flag = false);
AppidCpuTableDisplayStatus display_appid_cpu_profiler_table(AppId, OdpContext&);
void cleanup_appid_cpu_profiler_table();
static int show_cpu_profiler_stats(lua_State* L)
{
int appid = luaL_optint(L, 1, 0);
+ int display_rows_limit = luaL_optint(L, 2, APPID_CPU_PROFILER_DEFAULT_DISPLAY_ROWS);
+
ControlConn* ctrlcon = ControlConn::query_from_lua(L);
AppIdInspector* inspector = (AppIdInspector*) InspectorManager::get_inspector(MOD_NAME);
if (!inspector)
AppidCpuTableDisplayStatus displayed = DISPLAY_SUCCESS;
ctrlcon->respond("== showing appid cpu profiler table\n");
if (!appid)
- displayed = odp_ctxt.get_appid_cpu_profiler_mgr().display_appid_cpu_profiler_table(odp_ctxt);
+ {
+ if (display_rows_limit > APPID_CPU_PROFILER_MAX_DISPLAY_ROWS)
+ ctrlcon->respond("given number of rows exceeds maximum limit of %d, limiting to %d\n",
+ APPID_CPU_PROFILER_MAX_DISPLAY_ROWS, APPID_CPU_PROFILER_MAX_DISPLAY_ROWS);
+ displayed = odp_ctxt.get_appid_cpu_profiler_mgr().display_appid_cpu_profiler_table(odp_ctxt, display_rows_limit);
+ }
else
displayed = odp_ctxt.get_appid_cpu_profiler_mgr().display_appid_cpu_profiler_table(appid, odp_ctxt);
static const Parameter appid_cpu_params[] =
{
- { "appid", Parameter::PT_INT, nullptr, nullptr, "show appid cpu profiling stats" },
+ { "appid", Parameter::PT_INT, nullptr, "0", "show appid cpu profiling stats" },
+ { "display_rows_limit", Parameter::PT_INT, "1:2000", "100", "num of rows to be displayed" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};