summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--scripts/automation/trex_control_plane/stl/console/trex_tui.py26
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py24
-rw-r--r--scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py111
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py14
-rwxr-xr-xsrc/bp_sim.cpp77
-rwxr-xr-xsrc/bp_sim.h11
-rw-r--r--src/internal_api/trex_platform_api.h7
-rw-r--r--src/main_dpdk.cpp29
-rw-r--r--src/rpc-server/commands/trex_rpc_cmd_general.cpp23
-rw-r--r--src/rpc-server/commands/trex_rpc_cmds.h1
-rw-r--r--src/rpc-server/trex_rpc_cmds_table.cpp1
-rw-r--r--src/trex_defs.h4
-rwxr-xr-xsrc/utl_cpuu.cpp31
-rwxr-xr-xsrc/utl_cpuu.h17
14 files changed, 297 insertions, 79 deletions
diff --git a/scripts/automation/trex_control_plane/stl/console/trex_tui.py b/scripts/automation/trex_control_plane/stl/console/trex_tui.py
index d3be4435..a2ffcad6 100644
--- a/scripts/automation/trex_control_plane/stl/console/trex_tui.py
+++ b/scripts/automation/trex_control_plane/stl/console/trex_tui.py
@@ -210,7 +210,7 @@ class TrexTUILatencyStats(TrexTUIPanel):
super(TrexTUILatencyStats, self).__init__(mng, "lstats")
self.key_actions = OrderedDict()
self.key_actions['c'] = {'action': self.action_clear, 'legend': 'clear', 'show': True}
- self.key_actions['t'] = {'action': self.action_toggle_histogram, 'legend': 'toggle histogram', 'show': True}
+ self.key_actions['h'] = {'action': self.action_toggle_histogram, 'legend': 'histogram toggle', 'show': True}
self.is_histogram = False
@@ -238,6 +238,23 @@ class TrexTUILatencyStats(TrexTUIPanel):
self.stateless_client.latency_stats.clear_stats()
return ""
+
+# utilization stats
+class TrexTUIUtilizationStats(TrexTUIPanel):
+ def __init__ (self, mng):
+ super(TrexTUIUtilizationStats, self).__init__(mng, "ustats")
+ self.key_actions = {}
+
+ def show (self):
+ stats = self.stateless_client._get_formatted_stats(port_id_list = None, stats_mask = trex_stl_stats.UT_COMPAT)
+ # print stats to screen
+ for stat_type, stat_data in stats.items():
+ text_tables.print_table_with_header(stat_data.text_table, stat_type)
+
+ def get_key_actions (self):
+ return self.key_actions
+
+
# log
class TrexTUILog():
def __init__ (self):
@@ -270,12 +287,14 @@ class TrexTUIPanelManager():
self.panels['dashboard'] = TrexTUIDashBoard(self)
self.panels['sstats'] = TrexTUIStreamsStats(self)
self.panels['lstats'] = TrexTUILatencyStats(self)
+ self.panels['ustats'] = TrexTUIUtilizationStats(self)
self.key_actions = OrderedDict()
self.key_actions['q'] = {'action': self.action_quit, 'legend': 'quit', 'show': True}
self.key_actions['d'] = {'action': self.action_show_dash, 'legend': 'dashboard', 'show': True}
self.key_actions['s'] = {'action': self.action_show_sstats, 'legend': 'streams', 'show': True}
self.key_actions['l'] = {'action': self.action_show_lstats, 'legend': 'latency', 'show': True}
+ self.key_actions['u'] = {'action': self.action_show_ustats, 'legend': 'util', 'show': True}
# start with dashboard
self.main_panel = self.panels['dashboard']
@@ -392,6 +411,11 @@ class TrexTUIPanelManager():
self.init(self.show_log)
return ""
+ def action_show_ustats(self):
+ self.main_panel = self.panels['ustats']
+ self.init(self.show_log)
+ return ""
+
# shows a textual top style window
class TrexTUI():
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py
index 6dec6fa7..38a18d16 100755
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py
@@ -555,14 +555,17 @@ class STLClient(object):
self.latency_stats = trex_stl_stats.CLatencyStats(self.ports)
+ self.util_stats = trex_stl_stats.CUtilStats(self)
+
self.stats_generator = trex_stl_stats.CTRexInfoGenerator(self.global_stats,
self.ports,
self.flow_stats,
self.latency_stats,
+ self.util_stats,
self.async_client.monitor)
-
+
############# private functions - used by the class itself ###########
@@ -1662,6 +1665,23 @@ class STLClient(object):
if not rc:
raise STLError(rc)
+ @__api_check(True)
+ def get_util_stats(self):
+ """
+ Get utilization stats:
+ History of TRex CPU utilization per thread (list of lists)
+ MBUFs memory consumption per CPU socket.
+
+ :parameters:
+ None
+
+ :raises:
+ + :exc:`STLError`
+
+ """
+ self.logger.pre_cmd('Getting Utilization stats')
+ return self.util_stats.get_stats()
+
@__api_check(True)
def reset(self, ports = None):
@@ -1876,8 +1896,6 @@ class STLClient(object):
raise STLError(rc)
-
-
@__api_check(True)
def stop (self, ports = None, rx_delay_ms = 10):
"""
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py
index 88a94865..8e8388fd 100644
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_stats.py
@@ -11,7 +11,6 @@ import datetime
import time
import re
import math
-import copy
import threading
import pprint
@@ -22,13 +21,16 @@ PORT_STATUS = 'ps'
STREAMS_STATS = 's'
LATENCY_STATS = 'ls'
LATENCY_HISTOGRAM = 'lh'
+CPU_STATS = 'c'
+MBUF_STATS = 'm'
-ALL_STATS_OPTS = [GLOBAL_STATS, PORT_STATS, PORT_STATUS, STREAMS_STATS, LATENCY_STATS, PORT_GRAPH, LATENCY_HISTOGRAM]
+ALL_STATS_OPTS = [GLOBAL_STATS, PORT_STATS, PORT_STATUS, STREAMS_STATS, LATENCY_STATS, PORT_GRAPH, LATENCY_HISTOGRAM, CPU_STATS, MBUF_STATS]
COMPACT = [GLOBAL_STATS, PORT_STATS]
GRAPH_PORT_COMPACT = [GLOBAL_STATS, PORT_GRAPH]
SS_COMPAT = [GLOBAL_STATS, STREAMS_STATS] # stream stats
LS_COMPAT = [GLOBAL_STATS, LATENCY_STATS] # latency stats
LH_COMPAT = [GLOBAL_STATS, LATENCY_HISTOGRAM] # latency histogram
+UT_COMPAT = [GLOBAL_STATS, CPU_STATS, MBUF_STATS] # utilization
ExportableStats = namedtuple('ExportableStats', ['raw_data', 'text_table'])
@@ -104,6 +106,13 @@ def calculate_diff_raw (samples):
return total
+get_number_of_bytes_cache = {}
+# get number of bytes: '64b'->64, '9kb'->9000 etc.
+def get_number_of_bytes(val):
+ if val not in get_number_of_bytes_cache:
+ get_number_of_bytes_cache[val] = int(val[:-1].replace('k', '000'))
+ return get_number_of_bytes_cache[val]
+
# a simple object to keep a watch over a field
class WatchedField(object):
@@ -138,11 +147,12 @@ class CTRexInfoGenerator(object):
STLClient and the ports.
"""
- def __init__(self, global_stats_ref, ports_dict_ref, rx_stats_ref, latency_stats_ref, async_monitor):
+ def __init__(self, global_stats_ref, ports_dict_ref, rx_stats_ref, latency_stats_ref, util_stats_ref, async_monitor):
self._global_stats = global_stats_ref
self._ports_dict = ports_dict_ref
self._rx_stats_ref = rx_stats_ref
self._latency_stats_ref = latency_stats_ref
+ self._util_stats_ref = util_stats_ref
self._async_monitor = async_monitor
def generate_single_statistic(self, port_id_list, statistic_type):
@@ -167,6 +177,12 @@ class CTRexInfoGenerator(object):
elif statistic_type == LATENCY_HISTOGRAM:
return self._generate_latency_histogram()
+ elif statistic_type == CPU_STATS:
+ return self._generate_cpu_util_stats()
+
+ elif statistic_type == MBUF_STATS:
+ return self._generate_mbuf_util_stats()
+
else:
# ignore by returning empty object
return {}
@@ -404,6 +420,73 @@ class CTRexInfoGenerator(object):
stats_table.header(header)
return {"latency_histogram": ExportableStats(None, stats_table)}
+ def _generate_cpu_util_stats(self):
+ util_stats = self._util_stats_ref.get_stats(use_1sec_cache = True)
+ stats_table = text_tables.TRexTextTable()
+ if util_stats:
+ if 'cpu' not in util_stats:
+ raise Exception("Excepting 'cpu' section in stats %s" % util_stats)
+ cpu_stats = util_stats['cpu']
+ hist_len = len(cpu_stats[0])
+ avg_len = min(5, hist_len)
+ show_len = min(15, hist_len)
+ stats_table.header(['Thread', 'Avg', 'Latest'] + list(range(-1, 0 - show_len, -1)))
+ stats_table.set_cols_align(['l'] + ['r'] * (show_len + 1))
+ stats_table.set_cols_width([8, 3, 6] + [3] * (show_len - 1))
+ stats_table.set_cols_dtype(['t'] * (show_len + 2))
+ for i in range(min(14, len(cpu_stats))):
+ avg = int(round(sum(cpu_stats[i][:avg_len]) / avg_len))
+ stats_table.add_row([i, avg] + cpu_stats[i][:show_len])
+ else:
+ stats_table.add_row(['No Data.'])
+ return {'cpu_util(%)': ExportableStats(None, stats_table)}
+
+ def _generate_mbuf_util_stats(self):
+ util_stats = self._util_stats_ref.get_stats(use_1sec_cache = True)
+ stats_table = text_tables.TRexTextTable()
+ if util_stats:
+ if 'mbuf_stats' not in util_stats:
+ raise Exception("Excepting 'mbuf_stats' section in stats %s" % util_stats)
+ mbuf_stats = util_stats['mbuf_stats']
+ for mbufs_per_socket in mbuf_stats.values():
+ first_socket_mbufs = mbufs_per_socket
+ break
+ if not self._util_stats_ref.mbuf_types_list:
+ mbuf_keys = list(first_socket_mbufs.keys())
+ mbuf_keys.sort(key = get_number_of_bytes)
+ self._util_stats_ref.mbuf_types_list = mbuf_keys
+ types_len = len(self._util_stats_ref.mbuf_types_list)
+ stats_table.set_cols_align(['l'] + ['r'] * (types_len + 1))
+ stats_table.set_cols_width([10] + [7] * (types_len + 1))
+ stats_table.set_cols_dtype(['t'] * (types_len + 2))
+ stats_table.header([''] + self._util_stats_ref.mbuf_types_list + ['RAM(MB)'])
+ total_list = []
+ sum_totals = 0
+ for mbuf_type in self._util_stats_ref.mbuf_types_list:
+ sum_totals += first_socket_mbufs[mbuf_type][1] * get_number_of_bytes(mbuf_type) + 64
+ total_list.append(first_socket_mbufs[mbuf_type][1])
+ sum_totals *= len(list(mbuf_stats.values()))
+ total_list.append(int(sum_totals/1e6))
+ stats_table.add_row(['Total:'] + total_list)
+ stats_table.add_row(['Used:'] + [''] * (types_len + 1))
+ for socket_name in sorted(list(mbuf_stats.keys())):
+ mbufs = mbuf_stats[socket_name]
+ socket_show_name = socket_name.replace('cpu-', '').replace('-', ' ').capitalize() + ':'
+ sum_used = 0
+ used_list = []
+ percentage_list = []
+ for mbuf_type in self._util_stats_ref.mbuf_types_list:
+ used = mbufs[mbuf_type][1] - mbufs[mbuf_type][0]
+ sum_used += used * get_number_of_bytes(mbuf_type) + 64
+ used_list.append(used)
+ percentage_list.append('%s%%' % int(100 * used / mbufs[mbuf_type][1]))
+ used_list.append(int(sum_used/1e6))
+ stats_table.add_row([socket_show_name] + used_list)
+ stats_table.add_row(['Percent:'] + percentage_list + [''])
+ else:
+ stats_table.add_row(['No Data.'])
+ return {'mbuf_util': ExportableStats(None, stats_table)}
+
@staticmethod
def _get_rational_block_char(value, range_start, interval):
# in Konsole, utf-8 is sometimes printed with artifacts, return ascii for now
@@ -1282,7 +1365,27 @@ class CRxStats(CTRexStats):
return stats
-
+class CUtilStats(CTRexStats):
+
+ def __init__(self, client):
+ super(CUtilStats, self).__init__()
+ self.client = client
+ self.history = deque(maxlen = 1)
+ self.mbuf_types_list = None
+ self.last_update_ts = 0
+
+ def get_stats(self, use_1sec_cache = False):
+ time_now = time.time()
+ if self.last_update_ts + 1 < time_now or not self.history or not use_1sec_cache:
+ if self.client.is_connected():
+ rc = self.client._transmit('get_utilization')
+ if not rc:
+ raise Exception(rc)
+ self.last_update_ts = time_now
+ self.history.append(rc.data())
+ else:
+ self.history.append({})
+ return self.history[-1]
if __name__ == "__main__":
pass
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
index bb28d3af..ceaf1af8 100755
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
@@ -39,6 +39,8 @@ PORT_STATS = 51
PORT_STATUS = 52
STREAMS_STATS = 53
STATS_MASK = 54
+CPU_STATS = 55
+MBUF_STATS = 56
STREAMS_MASK = 60
# ALL_STREAMS = 61
@@ -340,6 +342,14 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
{'action': 'store_true',
'help': "Fetch only streams stats"}),
+ CPU_STATS: ArgumentPack(['-c'],
+ {'action': 'store_true',
+ 'help': "Fetch only CPU utilization stats"}),
+
+ MBUF_STATS: ArgumentPack(['-m'],
+ {'action': 'store_true',
+ 'help': "Fetch only MBUF utilization stats"}),
+
STREAMS_MASK: ArgumentPack(['--streams'],
{"nargs": '+',
'dest':'streams',
@@ -365,7 +375,9 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
STATS_MASK: ArgumentGroup(MUTEX, [GLOBAL_STATS,
PORT_STATS,
PORT_STATUS,
- STREAMS_STATS],
+ STREAMS_STATS,
+ CPU_STATS,
+ MBUF_STATS],
{})
}
diff --git a/src/bp_sim.cpp b/src/bp_sim.cpp
index f9e96b6b..6b5acd42 100755
--- a/src/bp_sim.cpp
+++ b/src/bp_sim.cpp
@@ -498,40 +498,23 @@ void CRteMemPool::dump_in_case_of_error(FILE *fd){
dump(fd);
}
-std::string CRteMemPool::add_to_json(
- std::string name,
- rte_mempool_t * pool,
- bool last){
+void CRteMemPool::add_to_json(Json::Value &json, std::string name, rte_mempool_t * pool){
uint32_t p_free = rte_mempool_count(pool);
uint32_t p_size = pool->size;
- char buff[200];
- sprintf(buff,"\"%s\":[%llu,%llu]",name.c_str(),(unsigned long long)p_free,(unsigned long long)p_size);
- std::string json = std::string(buff) + (last?std::string(""):std::string(","));
- return (json);
+ json[name].append((unsigned long long)p_free);
+ json[name].append((unsigned long long)p_size);
}
-std::string CRteMemPool::dump_as_json(uint8_t id,bool last){
-
- char buff[200];
- sprintf(buff,"\"socket-%d\":{", (int)id);
-
- std::string json=std::string(buff);
-
- json+=add_to_json("64b",m_small_mbuf_pool);
- json+=add_to_json("128b",m_mbuf_pool_128);
- json+=add_to_json("256b",m_mbuf_pool_256);
- json+=add_to_json("512b",m_mbuf_pool_512);
- json+=add_to_json("1024b",m_mbuf_pool_1024);
- json+=add_to_json("2048b",m_mbuf_pool_2048);
- json+=add_to_json("4096b",m_mbuf_pool_4096);
- json+=add_to_json("9kb",m_mbuf_pool_9k,true);
-
- json+="}" ;
- if (last==false) {
- json+="," ;
- }
- return (json);
+void CRteMemPool::dump_as_json(Json::Value &json){
+ add_to_json(json, "64b", m_small_mbuf_pool);
+ add_to_json(json, "128b", m_mbuf_pool_128);
+ add_to_json(json, "256b", m_mbuf_pool_256);
+ add_to_json(json, "512b", m_mbuf_pool_512);
+ add_to_json(json, "1024b", m_mbuf_pool_1024);
+ add_to_json(json, "2048b", m_mbuf_pool_2048);
+ add_to_json(json, "4096b", m_mbuf_pool_4096);
+ add_to_json(json, "9kb", m_mbuf_pool_9k);
}
@@ -548,30 +531,24 @@ void CRteMemPool::dump(FILE *fd){
DUMP_MBUF("mbuf_9k",m_mbuf_pool_9k);
}
-////////////////////////////////////////
+////////////////////////////////////////
-std::string CGlobalInfo::dump_pool_as_json(void){
-
- std::string json="\"mbuf_stats\":{";
+void CGlobalInfo::dump_pool_as_json(Json::Value &json){
CPlatformSocketInfo * lpSocket =&m_socket;
- int last_socket=-1;
- /* calc the last socket */
- int i;
- for (i=0; i<(int)MAX_SOCKETS_SUPPORTED; i++) {
+ for (int i=0; i<(int)MAX_SOCKETS_SUPPORTED; i++) {
if (lpSocket->is_sockets_enable((socket_id_t)i)) {
- last_socket=i;
+ std::string socket_id = "cpu-socket-" + std::to_string(i);
+ m_mem_pool[i].dump_as_json(json["mbuf_stats"][socket_id]);
}
}
+}
- for (i=0; i<(int)MAX_SOCKETS_SUPPORTED; i++) {
- if (lpSocket->is_sockets_enable((socket_id_t)i)) {
- json+=m_mem_pool[i].dump_as_json(i,last_socket==i?true:false);
- }
- }
- json+="},";
- return json;
+std::string CGlobalInfo::dump_pool_as_json_str(void){
+ Json::Value json;
+ dump_pool_as_json(json);
+ return (json.toStyledString());
}
void CGlobalInfo::free_pools(){
@@ -4517,6 +4494,16 @@ double CFlowGenList::GetCpuUtil(){
return (c/m_threads_info.size());
}
+double CFlowGenList::GetCpuUtilRaw(){
+ int i;
+ double c=0.0;
+ for (i=0; i<(int)m_threads_info.size(); i++) {
+ CFlowGenListPerThread * lp=m_threads_info[i];
+ c+=lp->m_cpu_cp_u.GetValRaw();
+ }
+ return (c/m_threads_info.size());
+}
+
void CFlowGenList::UpdateFast(){
diff --git a/src/bp_sim.h b/src/bp_sim.h
index 1f35faba..8a38beb7 100755
--- a/src/bp_sim.h
+++ b/src/bp_sim.h
@@ -1158,13 +1158,10 @@ public:
void dump_in_case_of_error(FILE *fd);
- std::string dump_as_json(uint8_t id,bool last);
+ void dump_as_json(Json::Value &json);
private:
- std::string add_to_json(std::string name,
- rte_mempool_t * pool,
- bool last=false);
-
+ void add_to_json(Json::Value &json, std::string name, rte_mempool_t * pool);
public:
rte_mempool_t * m_small_mbuf_pool; /* pool for start packets */
@@ -1258,7 +1255,8 @@ public:
}
- static std::string dump_pool_as_json(void);
+ static void dump_pool_as_json(Json::Value &json);
+ static std::string dump_pool_as_json_str(void);
public:
@@ -3855,6 +3853,7 @@ public:
void DumpPktSize();
void UpdateFast();
double GetCpuUtil();
+ double GetCpuUtilRaw();
public:
double get_total_kcps();
diff --git a/src/internal_api/trex_platform_api.h b/src/internal_api/trex_platform_api.h
index a52f9e60..b0294883 100644
--- a/src/internal_api/trex_platform_api.h
+++ b/src/internal_api/trex_platform_api.h
@@ -28,6 +28,7 @@ limitations under the License.
#include <string.h>
#include "flow_stat_parser.h"
#include "trex_defs.h"
+#include <json/json.h>
/**
* Global stats
@@ -156,6 +157,8 @@ public:
virtual bool get_promiscuous(uint8_t port_id) const = 0;
virtual void flush_dp_messages() const = 0;
virtual int get_active_pgids(flow_stat_active_t &result) const = 0;
+ virtual int get_cpu_util_full(cpu_util_full_t &result) const = 0;
+ virtual int get_mbuf_util(Json::Value &result) const = 0;
virtual CFlowStatParser *get_flow_stat_parser() const = 0;
virtual ~TrexPlatformApi() {}
};
@@ -188,6 +191,8 @@ public:
bool get_promiscuous(uint8_t port_id) const;
void flush_dp_messages() const;
int get_active_pgids(flow_stat_active_t &result) const;
+ int get_cpu_util_full(cpu_util_full_t &result) const;
+ int get_mbuf_util(Json::Value &result) const;
CFlowStatParser *get_flow_stat_parser() const;
};
@@ -252,6 +257,8 @@ public:
void flush_dp_messages() const {
}
int get_active_pgids(flow_stat_active_t &result) const {return 0;}
+ int get_cpu_util_full(cpu_util_full_t &result) const {return 0;}
+ int get_mbuf_util(Json::Value &result) const {return 0;}
CFlowStatParser *get_flow_stat_parser() const {return new CFlowStatParser();}
private:
diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp
index dcef2f38..eb65ede3 100644
--- a/src/main_dpdk.cpp
+++ b/src/main_dpdk.cpp
@@ -2435,6 +2435,7 @@ public:
float m_active_flows;
float m_open_flows;
float m_cpu_util;
+ float m_cpu_util_raw;
float m_rx_cpu_util;
float m_bw_per_core;
uint8_t m_threads;
@@ -2444,7 +2445,7 @@ public:
public:
void Dump(FILE *fd,DumpFormat mode);
void DumpAllPorts(FILE *fd);
- void dump_json(std::string & json, bool baseline,uint32_t stats_tick);
+ void dump_json(std::string & json, bool baseline);
private:
std::string get_field(std::string name,float &f);
std::string get_field(std::string name,uint64_t &f);
@@ -2484,7 +2485,7 @@ std::string CGlobalStats::get_field_port(int port,std::string name,uint64_t &f){
}
-void CGlobalStats::dump_json(std::string & json, bool baseline,uint32_t stats_tick){
+void CGlobalStats::dump_json(std::string & json, bool baseline){
/* refactor this to JSON */
json="{\"name\":\"trex-global\",\"type\":0,";
@@ -2502,6 +2503,7 @@ void CGlobalStats::dump_json(std::string & json, bool baseline,uint32_t stats_ti
#define GET_FIELD_PORT(p,f) get_field_port(p,std::string(#f),lp->f)
json+=GET_FIELD(m_cpu_util);
+ json+=GET_FIELD(m_cpu_util_raw);
json+=GET_FIELD(m_bw_per_core);
json+=GET_FIELD(m_rx_cpu_util);
json+=GET_FIELD(m_platform_factor);
@@ -2551,10 +2553,6 @@ void CGlobalStats::dump_json(std::string & json, bool baseline,uint32_t stats_ti
json+=GET_FIELD_PORT(i,m_total_rx_pps);
}
json+=m_template.dump_as_json("template");
- if ( stats_tick %4==0){
- json+=CGlobalInfo::dump_pool_as_json(); /* no need a feq update beacuse it trash the cores D cache, once in 2 sec */
- }
-
json+="\"unknown\":0}}" ;
}
@@ -3572,6 +3570,7 @@ void CGlobalTRex::get_stats(CGlobalStats & stats){
stats.m_num_of_ports = m_max_ports;
stats.m_cpu_util = m_fl.GetCpuUtil();
+ stats.m_cpu_util_raw = m_fl.GetCpuUtilRaw();
if (get_is_stateless()) {
stats.m_rx_cpu_util = m_rx_sl.get_cpu_util();
}
@@ -3803,7 +3802,7 @@ CGlobalTRex::publish_async_data(bool sync_now, bool baseline) {
get_stats(m_stats);
}
- m_stats.dump_json(json, baseline,m_stats_cnt);
+ m_stats.dump_json(json, baseline);
m_zmq_publisher.publish_json(json);
/* generator json , all cores are the same just sample the first one */
@@ -3897,7 +3896,7 @@ CGlobalTRex::handle_slow_path(bool &was_stopped) {
if (m_io_modes.m_g_mode == CTrexGlobalIoMode::gMem) {
if ( m_stats_cnt%4==0) {
- fprintf (stdout," %s \n",CGlobalInfo::dump_pool_as_json().c_str());
+ fprintf (stdout," %s \n",CGlobalInfo::dump_pool_as_json_str().c_str());
}
}
@@ -5776,6 +5775,20 @@ int TrexDpdkPlatformApi::get_active_pgids(flow_stat_active_t &result) const {
return g_trex.m_trex_stateless->m_rx_flow_stat.get_active_pgids(result);
}
+int TrexDpdkPlatformApi::get_cpu_util_full(cpu_util_full_t &cpu_util_full) const {
+ cpu_util_full.resize((int)g_trex.m_fl.m_threads_info.size());
+ for (int thread_id=0; thread_id<(int)g_trex.m_fl.m_threads_info.size(); thread_id++) {
+ CFlowGenListPerThread * lp=g_trex.m_fl.m_threads_info[thread_id];
+ lp->m_cpu_cp_u.GetHistory(cpu_util_full[thread_id]);
+ }
+ return 0;
+}
+
+int TrexDpdkPlatformApi::get_mbuf_util(Json::Value &mbuf_pool) const {
+ CGlobalInfo::dump_pool_as_json(mbuf_pool);
+ return 0;
+}
+
CFlowStatParser *TrexDpdkPlatformApi::get_flow_stat_parser() const {
return CTRexExtendedDriverDb::Ins()->get_drv()->get_flow_stat_parser();
}
diff --git a/src/rpc-server/commands/trex_rpc_cmd_general.cpp b/src/rpc-server/commands/trex_rpc_cmd_general.cpp
index 68ea2587..27010e0e 100644
--- a/src/rpc-server/commands/trex_rpc_cmd_general.cpp
+++ b/src/rpc-server/commands/trex_rpc_cmd_general.cpp
@@ -157,6 +157,29 @@ TrexRpcCmdGetActivePGIds::_run(const Json::Value &params, Json::Value &result) {
return (TREX_RPC_CMD_OK);
}
+// get utilization of CPU per thread with up to 20 latest values + mbufs per socket
+trex_rpc_cmd_rc_e
+TrexRpcCmdGetUtilization::_run(const Json::Value &params, Json::Value &result) {
+ cpu_util_full_t cpu_util_full;
+
+ Json::Value &section = result["result"];
+
+ if (get_stateless_obj()->get_platform_api()->get_mbuf_util(section) != 0) {
+ return TREX_RPC_CMD_INTERNAL_ERR;
+ }
+
+ if (get_stateless_obj()->get_platform_api()->get_cpu_util_full(cpu_util_full) != 0) {
+ return TREX_RPC_CMD_INTERNAL_ERR;
+ }
+
+ for (int thread_id = 0; thread_id < cpu_util_full.size(); thread_id++) {
+ for (int history_id = 0; history_id < cpu_util_full[thread_id].size(); history_id++) {
+ section["cpu"][thread_id].append(cpu_util_full[thread_id][history_id]);
+ }
+ }
+ return (TREX_RPC_CMD_OK);
+}
+
/**
* get the CPU model
*
diff --git a/src/rpc-server/commands/trex_rpc_cmds.h b/src/rpc-server/commands/trex_rpc_cmds.h
index affa65c1..2776727d 100644
--- a/src/rpc-server/commands/trex_rpc_cmds.h
+++ b/src/rpc-server/commands/trex_rpc_cmds.h
@@ -67,6 +67,7 @@ TREX_RPC_CMD_DEFINE(TrexRpcPublishNow, "publish_now", 2, false,
TREX_RPC_CMD_DEFINE(TrexRpcCmdGetCmds, "get_supported_cmds", 0, false, APIClass::API_CLASS_TYPE_CORE);
TREX_RPC_CMD_DEFINE(TrexRpcCmdGetVersion, "get_version", 0, false, APIClass::API_CLASS_TYPE_CORE);
TREX_RPC_CMD_DEFINE(TrexRpcCmdGetActivePGIds, "get_active_pgids", 0, false, APIClass::API_CLASS_TYPE_CORE);
+TREX_RPC_CMD_DEFINE(TrexRpcCmdGetUtilization, "get_utilization", 0, false, APIClass::API_CLASS_TYPE_CORE);
TREX_RPC_CMD_DEFINE_EXTENDED(TrexRpcCmdGetSysInfo, "get_system_info", 0, false, APIClass::API_CLASS_TYPE_CORE,
diff --git a/src/rpc-server/trex_rpc_cmds_table.cpp b/src/rpc-server/trex_rpc_cmds_table.cpp
index 7104792e..6144d265 100644
--- a/src/rpc-server/trex_rpc_cmds_table.cpp
+++ b/src/rpc-server/trex_rpc_cmds_table.cpp
@@ -39,6 +39,7 @@ TrexRpcCommandsTable::TrexRpcCommandsTable() {
register_command(new TrexRpcCmdGetCmds());
register_command(new TrexRpcCmdGetVersion());
register_command(new TrexRpcCmdGetActivePGIds());
+ register_command(new TrexRpcCmdGetUtilization());
register_command(new TrexRpcCmdGetSysInfo());
register_command(new TrexRpcCmdGetOwner());
register_command(new TrexRpcCmdAcquire());
diff --git a/src/trex_defs.h b/src/trex_defs.h
index 665c1edc..bbf3f3ba 100644
--- a/src/trex_defs.h
+++ b/src/trex_defs.h
@@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#include <set>
+#include <queue>
+#include <vector>
#ifndef __TREX_DEFS_H__
#define __TREX_DEFS_H__
@@ -36,5 +38,7 @@ limitations under the License.
typedef std::set<uint32_t> flow_stat_active_t;
typedef std::set<uint32_t>::iterator flow_stat_active_it_t;
+typedef std::vector<std::vector<uint8_t>> cpu_util_full_t;
+typedef std::vector<uint8_t> cpu_vct_t;
#endif
diff --git a/src/utl_cpuu.cpp b/src/utl_cpuu.cpp
index 4d75cf6f..7786356e 100755
--- a/src/utl_cpuu.cpp
+++ b/src/utl_cpuu.cpp
@@ -25,7 +25,9 @@ limitations under the License.
void CCpuUtlCp::Create(CCpuUtlDp * cdp){
m_dpcpu=cdp;
- m_cpu_util=0.0;
+ memset(m_cpu_util, 0, sizeof(m_cpu_util));
+ m_history_latest_index = 0;
+ m_cpu_util_lpf=0.0;
m_ticks=0;
m_work=0;
}
@@ -41,17 +43,34 @@ void CCpuUtlCp::Update(){
m_work++;
}
if (m_ticks==100) {
- double window_cpu_u = ((double)m_work/(double)m_ticks);
/* LPF*/
- m_cpu_util = (m_cpu_util*0.75)+(window_cpu_u*0.25);
+ m_cpu_util_lpf = (m_cpu_util_lpf*0.75)+((double)m_work*0.25);
+ AppendHistory(m_work);
m_ticks=0;
m_work=0;
-
}
}
-/* return cpu % */
+/* return cpu % Smoothed */
double CCpuUtlCp::GetVal(){
- return (m_cpu_util*100);
+ return (m_cpu_util_lpf);
+}
+
+/* return cpu % Raw */
+uint8_t CCpuUtlCp::GetValRaw(){
+ return (m_cpu_util[m_history_latest_index]);
}
+/* get cpu % utilization history */
+void CCpuUtlCp::GetHistory(cpu_vct_t &cpu_vct){
+ cpu_vct.clear();
+ for (int i = m_history_latest_index + m_history_size; i > m_history_latest_index; i--) {
+ cpu_vct.push_back(m_cpu_util[i % m_history_size]);
+ }
+}
+
+/* save last CPU % util in history */
+void CCpuUtlCp::AppendHistory(uint8_t val){
+ m_history_latest_index = (m_history_latest_index + 1) % m_history_size;
+ m_cpu_util[m_history_latest_index] = val;
+}
diff --git a/src/utl_cpuu.h b/src/utl_cpuu.h
index e5305783..109fff4f 100755
--- a/src/utl_cpuu.h
+++ b/src/utl_cpuu.h
@@ -22,6 +22,8 @@ limitations under the License.
*/
#include <stdint.h>
+#include <cstring>
+#include "trex_defs.h"
#include "os_time.h"
#include "mbuf.h"
@@ -56,13 +58,18 @@ public:
void Update();
/* return cpu % */
double GetVal();
-
+ uint8_t GetValRaw();
+ void GetHistory(cpu_vct_t &cpu_vct);
private:
- CCpuUtlDp * m_dpcpu;
- uint16_t m_ticks;
- uint16_t m_work;
+ void AppendHistory(uint8_t);
+ CCpuUtlDp * m_dpcpu;
+ uint8_t m_ticks;
+ uint8_t m_work;
- double m_cpu_util;
+ static const int m_history_size=20;
+ uint8_t m_cpu_util[m_history_size]; // history as cyclic array
+ uint8_t m_history_latest_index;
+ double m_cpu_util_lpf;
};
#endif