diff --git a/ci-scripts/datalog_rt_stats.yaml b/ci-scripts/datalog_rt_stats.yaml
new file mode 100644
index 0000000000..692962ed35
--- /dev/null
+++ b/ci-scripts/datalog_rt_stats.yaml
@@ -0,0 +1,30 @@
+Title : Processing Time (us)
+ColNames :
+ - Metric
+ - Average
+ - Max
+ - Deviation (Avg vs Ref)
+Ref :
+ feprx : 60.0
+ feptx_prec : 8.0
+ feptx_ofdm : 85.0
+ feptx_total : 75.0
+ L1 Tx processing : 300.0
+ DLSCH encoding : 230.0
+ L1 Rx processing : 175.0
+ PUSCH inner-receiver : 100.0
+ PUSCH decoding : 140.0
+ DL & UL scheduling timing stats : 15.0
+ UL Indication : 20.0
+Threshold :
+ feprx : 1.25
+ feptx_prec : 1.25
+ feptx_ofdm : 1.25
+ feptx_total : 1.25
+ L1 Tx processing : 1.25
+ DLSCH encoding : 1.25
+ L1 Rx processing : 1.25
+ PUSCH inner-receiver : 1.25
+ PUSCH decoding : 1.25
+ DL & UL scheduling timing stats : 1.25
+ UL Indication : 1.25
\ No newline at end of file
diff --git a/ci-scripts/html.py b/ci-scripts/html.py
index a0ac638573..aca717c0d4 100644
--- a/ci-scripts/html.py
+++ b/ci-scripts/html.py
@@ -446,6 +446,37 @@ class HTMLManagement():
self.htmlFile.write(' \n')
self.htmlFile.close()
+ #for the moment it is limited to 4 columns, to be made generic later
+ def CreateHtmlDataLogTable(self, DataLog):
+ if (self.htmlFooterCreated or (not self.htmlHeaderCreated)):
+ return
+ self.htmlFile = open('test_results.html', 'a')
+
+ # TabHeader
+ self.htmlFile.write('
\n')
+ self.htmlFile.write(' | ---- ' + DataLog['Title'] + ' ---- | \n')
+ self.htmlFile.write('
\n')
+ self.htmlFile.write(' \n')
+ self.htmlFile.write(' | '+ DataLog['ColNames'][0] +' | \n')
+ self.htmlFile.write(' ' + DataLog['ColNames'][1] + ' | \n')
+ self.htmlFile.write(' ' + DataLog['ColNames'][2] + ' | \n')
+ self.htmlFile.write(' '+ DataLog['ColNames'][3] +' | \n')
+ self.htmlFile.write('
\n')
+
+ for k in DataLog['Data']:
+ # TestRow
+ self.htmlFile.write(' \n')
+ self.htmlFile.write(' | ' + k + ' | \n')
+ self.htmlFile.write(' ' + DataLog['Data'][k][0] + ' | \n')
+ self.htmlFile.write(' ' + DataLog['Data'][k][1] + ' | \n')
+ if float(DataLog['Data'][k][2])> DataLog['Threshold'][k]:
+ self.htmlFile.write(' ' + DataLog['Data'][k][2] + ' ('+str(DataLog['Threshold'][k])+') ' + ' | \n')
+ else:
+ self.htmlFile.write(' ' + DataLog['Data'][k][2] + ' ('+str(DataLog['Threshold'][k])+') ' + ' | \n')
+ self.htmlFile.write('
\n')
+ self.htmlFile.close()
+
+
def CreateHtmlTestRowQueue(self, options, status, ue_status, ue_queue):
if ((not self.htmlFooterCreated) and (self.htmlHeaderCreated)):
self.htmlFile = open('test_results.html', 'a')
diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py
index f1f79a2435..8e378afbe9 100644
--- a/ci-scripts/ran.py
+++ b/ci-scripts/ran.py
@@ -37,6 +37,8 @@ import logging
import os
import time
from multiprocessing import Process, Lock, SimpleQueue
+import yaml
+
#-----------------------------------------------------------
# OAI Testing modules
@@ -90,6 +92,7 @@ class RANManagement():
self.testCase_id = ''
self.epcPcapFile = ''
self.runtime_stats= ''
+ self.datalog_rt_stats={}
@@ -633,6 +636,8 @@ class RANManagement():
HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
else:
HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK)
+ if len(self.datalog_rt_stats)!=0:
+ HTML.CreateHtmlDataLogTable(self.datalog_rt_stats)
self.eNBmbmsEnables[int(self.eNB_instance)] = False
self.eNBstatuses[int(self.eNB_instance)] = -1
@@ -699,6 +704,21 @@ class RANManagement():
#count "problem receiving samples" msg
pb_receiving_samples_cnt = 0
+ #the datalog config file has to be loaded
+ datalog_rt_stats_file='datalog_rt_stats.yaml'
+ if (os.path.isfile(datalog_rt_stats_file)):
+ yaml_file=datalog_rt_stats_file
+ elif (os.path.isfile('ci-scripts/'+datalog_rt_stats_file)):
+ yaml_file='ci-scripts/'+datalog_rt_stats_file
+ else:
+ logging.error("Datalog RT stats yaml file cannot be found")
+ sys.exit("Datalog RT stats yaml file cannot be found")
+
+ with open(yaml_file,'r') as f:
+ datalog_rt_stats = yaml.load(f,Loader=yaml.FullLoader)
+ rt_keys = datalog_rt_stats['Ref'] #we use the keys from the Ref field
+
+
for line in enb_log_file.readlines():
# Runtime statistics
result = re.search('Run time:' ,str(line))
@@ -857,21 +877,21 @@ class RANManagement():
#keys below are the markers we are loooking for, loop over this keys list
#everytime these markers are found in the log file, the previous ones are overwritten in the dict
#eventually we record and print only the last occurence
- keys = {'UE ID','dlsch_rounds','dlsch_total_bytes','ulsch_rounds','ulsch_total_bytes_scheduled', 'scheduling timing stats'}
+ keys = {'UE ID','dlsch_rounds','dlsch_total_bytes','ulsch_rounds','ulsch_total_bytes_scheduled'}
for k in keys:
result = re.search(k, line)
if result is not None:
#remove 1- all useless char before relevant info (ulsch or dlsch) 2- trailing char
dlsch_ulsch_stats[k]=re.sub(r'^.*\]\s+', r'' , line.rstrip())
- #real time statistics
- #same method as above
- keys = {'feprx','feptx_prec','feptx_ofdm','feptx_total','L1 Tx processing','DLSCH encoding','L1 Rx processing','PUSCH inner-receiver','PUSCH decoding'}
- for k in keys:
+ #real time statistics for gNB
+ for k in rt_keys:
result = re.search(k, line)
if result is not None:
#remove 1- all useless char before relevant info 2- trailing char
+ line=line.replace('[0m','')
tmp=re.match(rf'^.*?(\b{k}\b.*)',line.rstrip()) #from python 3.6 we can use literal string interpolation for the variable k, using rf' in the regex
real_time_stats[k]=tmp.group(1)
+
#count "problem receiving samples" msg
result = re.search('\[PHY\]\s+problem receiving samples', str(line))
if result is not None:
@@ -920,13 +940,30 @@ class RANManagement():
logging.debug(dlsch_ulsch_stats[key])
htmleNBFailureMsg += statMsg
- #real time statistics statistics
+ #real time statistics (old but working version)
+ #if len(real_time_stats)!=0: #check if dictionary is not empty
+ # statMsg=''
+ # for k in real_time_stats:
+ # tmp=re.match(r'^(?P.*):\s+(?P\d+\.\d+) us;\s+\d+;\s+(?P\d+\.\d+) us;',real_time_stats[k])
+ # if tmp is not None:
+ # metric=tmp.group('metric')
+ # avg=tmp.group('avg')
+ # max=tmp.group('max')
+ # statMsg += metric + ' : avg = ' + avg + 'us ; max = ' + max +'us\n'
+ # htmleNBFailureMsg += statMsg
+
+ #real time statistics
+ datalog_rt_stats['Data']={}
if len(real_time_stats)!=0: #check if dictionary is not empty
- statMsg=''
- for key in real_time_stats: #for each dictionary key
- statMsg += real_time_stats[key] + '\n'
- logging.debug(real_time_stats[key])
- htmleNBFailureMsg += statMsg
+ for k in real_time_stats:
+ tmp=re.match(r'^(?P.*):\s+(?P\d+\.\d+) us;\s+\d+;\s+(?P\d+\.\d+) us;',real_time_stats[k])
+ if tmp is not None:
+ metric=tmp.group('metric')
+ avg=float(tmp.group('avg'))
+ max=float(tmp.group('max'))
+ datalog_rt_stats['Data'][metric]=["{:.0f}".format(avg),"{:.0f}".format(max),"{:.2f}".format(avg/datalog_rt_stats['Ref'][metric])]
+ #store the data as a class attribute to build a dedicated HTML table afterward
+ self.datalog_rt_stats=datalog_rt_stats
else:
statMsg = 'No real time stats found in the log file\n'
logging.debug('No real time stats found in the log file')