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
diff --git a/src/osmo_gsm_tester/obj/enb.py b/src/osmo_gsm_tester/obj/enb.py
index 32ead69..15a0033 100644
--- a/src/osmo_gsm_tester/obj/enb.py
+++ b/src/osmo_gsm_tester/obj/enb.py
@@ -356,4 +356,8 @@
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
\ No newline at end of file
diff --git a/src/osmo_gsm_tester/obj/enb_amarisoft.py b/src/osmo_gsm_tester/obj/enb_amarisoft.py
index e97bb90..01aed18 100644
--- a/src/osmo_gsm_tester/obj/enb_amarisoft.py
+++ b/src/osmo_gsm_tester/obj/enb_amarisoft.py
@@ -260,6 +260,9 @@
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:
diff --git a/src/osmo_gsm_tester/obj/enb_srs.py b/src/osmo_gsm_tester/obj/enb_srs.py
index aee3f61..83df5ed 100644
--- a/src/osmo_gsm_tester/obj/enb_srs.py
+++ b/src/osmo_gsm_tester/obj/enb_srs.py
@@ -101,7 +101,7 @@
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 @@
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:
diff --git a/src/osmo_gsm_tester/obj/epc.py b/src/osmo_gsm_tester/obj/epc.py
index 6f056fc..aaa96b7 100644
--- a/src/osmo_gsm_tester/obj/epc.py
+++ b/src/osmo_gsm_tester/obj/epc.py
@@ -116,4 +116,8 @@
def run_node(self):
return self._run_node
+ @abstractmethod
+ def get_kpis(self):
+ pass
+
# vim: expandtab tabstop=4 shiftwidth=4
diff --git a/src/osmo_gsm_tester/obj/epc_amarisoft.py b/src/osmo_gsm_tester/obj/epc_amarisoft.py
index 1291891..4c3bf07 100644
--- a/src/osmo_gsm_tester/obj/epc_amarisoft.py
+++ b/src/osmo_gsm_tester/obj/epc_amarisoft.py
@@ -199,4 +199,7 @@
# TODO: set proper addr
return '192.168.4.1'
+ def get_kpis(self):
+ return {}
+
# vim: expandtab tabstop=4 shiftwidth=4
diff --git a/src/osmo_gsm_tester/obj/epc_srs.py b/src/osmo_gsm_tester/obj/epc_srs.py
index 6a7a20e..6a0a7bb 100644
--- a/src/osmo_gsm_tester/obj/epc_srs.py
+++ b/src/osmo_gsm_tester/obj/epc_srs.py
@@ -219,4 +219,7 @@
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
diff --git a/src/osmo_gsm_tester/obj/ms_srs.py b/src/osmo_gsm_tester/obj/ms_srs.py
index 2f19f3f..aaeeca5 100644
--- a/src/osmo_gsm_tester/obj/ms_srs.py
+++ b/src/osmo_gsm_tester/obj/ms_srs.py
@@ -126,7 +126,7 @@
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', [])
diff --git a/src/osmo_gsm_tester/obj/srslte_common.py b/src/osmo_gsm_tester/obj/srslte_common.py
index 21001b7..cbc360f 100644
--- a/src/osmo_gsm_tester/obj/srslte_common.py
+++ b/src/osmo_gsm_tester/obj/srslte_common.py
@@ -27,7 +27,9 @@
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 @@
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.")
\ No newline at end of file