enb,epc,ms: refactor KPI API
we previously mixed component specific and component agnostic APIs (stdout vs. log file for example) for setting and retrieving KPI. This patch propose to use a single abstract get_kpis() method for all components that can be enriched with component-specific stuff as desired. In the case of srsLTE blocks, the main implementation will remain in srslte_common() and is shared among srsENB/srsUE/srsEPC. The KPI analyzer in srslte_common() extract and also manages all three KPI sources (log, csv and stdout) independently. In addition to the get_kpis() method that always returns a flat dictionary, it also exposes get_kpi_tree() that return a dict of KPI dicts that will be used for the Junit.xml generation. Change-Id: I4bacc6b8a0cb92a581edfb947100b57022265265
This commit is contained in:
parent
6231c3c657
commit
3ce672594f
|
@ -356,4 +356,8 @@ class eNodeB(log.Origin, metaclass=ABCMeta):
|
|||
def get_counter(self, counter_name):
|
||||
pass
|
||||
|
||||
# vim: expandtab tabstop=4 shiftwidth=4
|
||||
@abstractmethod
|
||||
def get_kpis(self):
|
||||
pass
|
||||
|
||||
# vim: expandtab tabstop=4 shiftwidth=4
|
|
@ -260,6 +260,9 @@ class AmarisoftENB(enb.eNodeB):
|
|||
return self.process.get_counter_stdout('PRACH:')
|
||||
raise log.Error('counter %s not implemented!' % counter_name)
|
||||
|
||||
def get_kpis(self):
|
||||
return {}
|
||||
|
||||
def get_rfemu(self, cell=0, dl=True):
|
||||
cell_list = self.gen_conf['enb'].get('cell_list', None)
|
||||
if cell_list is None or len(cell_list) < cell + 1:
|
||||
|
|
|
@ -101,7 +101,7 @@ class srsENB(enb.eNodeB, srslte_common):
|
|||
self.log(repr(e))
|
||||
|
||||
# Collect KPIs for each TC
|
||||
self.testenv.test().set_kpis(self.get_kpis())
|
||||
self.testenv.test().set_kpis(self.get_kpi_tree())
|
||||
# Clean up for parent class:
|
||||
super().cleanup()
|
||||
|
||||
|
@ -267,6 +267,9 @@ class srsENB(enb.eNodeB, srslte_common):
|
|||
return self.process.get_counter_stdout('RACH:')
|
||||
raise log.Error('counter %s not implemented!' % counter_name)
|
||||
|
||||
def get_kpis(self):
|
||||
return srslte_common.get_kpis(self)
|
||||
|
||||
def get_rfemu(self, cell=0, dl=True):
|
||||
cell_list = self.gen_conf['enb'].get('cell_list', None)
|
||||
if cell_list is None or len(cell_list) < cell + 1:
|
||||
|
|
|
@ -116,4 +116,8 @@ class EPC(log.Origin, metaclass=ABCMeta):
|
|||
def run_node(self):
|
||||
return self._run_node
|
||||
|
||||
@abstractmethod
|
||||
def get_kpis(self):
|
||||
pass
|
||||
|
||||
# vim: expandtab tabstop=4 shiftwidth=4
|
||||
|
|
|
@ -199,4 +199,7 @@ class AmarisoftEPC(epc.EPC):
|
|||
# TODO: set proper addr
|
||||
return '192.168.4.1'
|
||||
|
||||
def get_kpis(self):
|
||||
return {}
|
||||
|
||||
# vim: expandtab tabstop=4 shiftwidth=4
|
||||
|
|
|
@ -219,4 +219,7 @@ class srsEPC(epc.EPC, srslte_common):
|
|||
def tun_addr(self):
|
||||
return '172.16.0.1'
|
||||
|
||||
def get_kpis(self):
|
||||
return srslte_common.get_kpis(self)
|
||||
|
||||
# vim: expandtab tabstop=4 shiftwidth=4
|
||||
|
|
|
@ -126,7 +126,7 @@ class srsUE(MS, srslte_common):
|
|||
self.log(repr(e))
|
||||
|
||||
# Collect KPIs for each TC
|
||||
self.testenv.test().set_kpis(self.get_kpis())
|
||||
self.testenv.test().set_kpis(self.get_kpi_tree())
|
||||
|
||||
def features(self):
|
||||
return self._conf.get('features', [])
|
||||
|
|
|
@ -27,7 +27,9 @@ class srslte_common(): # don't inherit from log.Origin here but instead use .nam
|
|||
self.process = None
|
||||
self.metrics_file = None
|
||||
self.stop_sleep_time = 6 # We require at most 5s to stop
|
||||
self.kpis = None
|
||||
self.log_kpi = None
|
||||
self.stdout_kpi = None
|
||||
self.csv_kpi = None
|
||||
|
||||
def sleep_after_stop(self):
|
||||
# Only sleep once
|
||||
|
@ -42,61 +44,50 @@ class srslte_common(): # don't inherit from log.Origin here but instead use .nam
|
|||
self.sleep_after_stop()
|
||||
|
||||
def get_kpis(self):
|
||||
''' Return all KPI '''
|
||||
if self.kpis is None:
|
||||
self.extract_kpis()
|
||||
return self.kpis
|
||||
''' Merge all KPI and return as flat dict '''
|
||||
self.extract_kpis()
|
||||
kpi_flat = {}
|
||||
kpi_flat.update(self.log_kpi)
|
||||
kpi_flat.update(self.stdout_kpi)
|
||||
kpi_flat.update(self.csv_kpi)
|
||||
return kpi_flat
|
||||
|
||||
def get_log_kpis(self):
|
||||
''' Return KPIs extracted from log '''
|
||||
if self.kpis is None:
|
||||
self.extract_kpis()
|
||||
|
||||
# Use log KPIs if they exist for this node
|
||||
if "log_" + self.name() in self.kpis:
|
||||
log_kpi = self.kpis["log_" + self.name()]
|
||||
else:
|
||||
log_kpi = {}
|
||||
|
||||
# Make sure we have the errors and warnings counter in the dict
|
||||
if 'total_errors' not in log_kpi:
|
||||
log_kpi['total_errors'] = 0
|
||||
if 'total_warnings' not in log_kpi:
|
||||
log_kpi['total_warnings'] = 0
|
||||
return log_kpi
|
||||
def get_kpi_tree(self):
|
||||
''' Return all KPI as dict of dict in which the source (e.g. stdout_srsue1) is the key of the first dict '''
|
||||
self.extract_kpis()
|
||||
kpi_tree = {}
|
||||
kpi_tree["log_" + self.name()] = self.log_kpi
|
||||
kpi_tree["csv_" + self.name()] = self.csv_kpi
|
||||
kpi_tree["stdout_" + self.name()] = self.stdout_kpi
|
||||
return kpi_tree
|
||||
|
||||
def extract_kpis(self):
|
||||
''' Use the srsLTE KPI analyzer module (part of srsLTE.git) if available to collect KPIs '''
|
||||
|
||||
# Make sure this only runs once
|
||||
if self.csv_kpi is not None or self.log_kpi is not None or self.stdout_kpi is not None:
|
||||
return
|
||||
|
||||
# Start with empty KPIs
|
||||
self.log_kpi = {}
|
||||
self.stdout_kpi = {}
|
||||
self.csv_kpi = {}
|
||||
|
||||
# Stop application, copy back logs and process them
|
||||
if self.running():
|
||||
self.stop()
|
||||
self.cleanup()
|
||||
|
||||
self.kpis = {}
|
||||
try:
|
||||
# Please make sure the srsLTE scripts folder is included in your PYTHONPATH env variable
|
||||
from kpi_analyzer import kpi_analyzer
|
||||
analyzer = kpi_analyzer(self.name())
|
||||
if self.log_file is not None:
|
||||
self.kpis["log_" + self.name()] = analyzer.get_kpi_from_logfile(self.log_file)
|
||||
self.log_kpi = analyzer.get_kpi_from_logfile(self.log_file)
|
||||
if self.process.get_output_file('stdout') is not None:
|
||||
self.kpis["stdout_" + self.name()] = analyzer.get_kpi_from_stdout(self.process.get_output_file('stdout'))
|
||||
self.stdout_kpi = analyzer.get_kpi_from_stdout(self.process.get_output_file('stdout'))
|
||||
if self.metrics_file is not None:
|
||||
self.kpis["csv_" + self.name()] = analyzer.get_kpi_from_csv(self.metrics_file)
|
||||
self.csv_kpi = analyzer.get_kpi_from_csv(self.metrics_file)
|
||||
# PHY errors for either UE or eNB components from parsed KPI vector as extra entry in dict
|
||||
self.log_kpi["num_phy_errors"] = analyzer.get_num_phy_errors(self.log_kpi)
|
||||
except ImportError:
|
||||
self.log("Can't load KPI analyzer module.")
|
||||
self.kpis = {}
|
||||
|
||||
return self.kpis
|
||||
|
||||
def get_num_phy_errors(self, kpi):
|
||||
""" Use KPI analyzer to calculate the number PHY errors for either UE or eNB components from parsed KPI vector """
|
||||
try:
|
||||
# Same as above, make sure the srsLTE scripts folder is included in your PYTHONPATH env variable
|
||||
from kpi_analyzer import kpi_analyzer
|
||||
analyzer = kpi_analyzer(self.name())
|
||||
return analyzer.get_num_phy_errors(kpi)
|
||||
except ImportError:
|
||||
self.log("Can't load KPI analyzer module.")
|
||||
return 0
|
||||
self.log("Can't load KPI analyzer module.")
|
Loading…
Reference in New Issue