mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
Compare commits
1 Commits
issue-1012
...
statsMonit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4509ee7201 |
@@ -4,6 +4,7 @@ To create graphs and pickle from runtime statistics in L1,MAC,RRC,PDCP files
|
||||
|
||||
import subprocess
|
||||
import time
|
||||
from datetime import datetime,timezone,timedelta
|
||||
import shlex
|
||||
import re
|
||||
import sys
|
||||
@@ -12,6 +13,7 @@ import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import yaml
|
||||
import os
|
||||
import copy
|
||||
|
||||
|
||||
class StatMonitor():
|
||||
@@ -20,28 +22,85 @@ class StatMonitor():
|
||||
self.d = yaml.load(file)
|
||||
for node in self.d:#so far we have enb or gnb as nodes
|
||||
for metric_l1 in self.d[node]: #first level of metric keys
|
||||
if metric_l1!="graph": #graph is a reserved word to configure graph paging, so it is disregarded
|
||||
if metric_l1=="ue": #graph is a reserved word to configure graph paging, so it is disregarded
|
||||
if self.d[node][metric_l1] is None:#first level is None -> create array
|
||||
self.d[node][metric_l1]=[]
|
||||
else: #first level is not None -> there is a second level -> create array
|
||||
for metric_l2 in self.d[node][metric_l1]:
|
||||
self.d[node][metric_l1][metric_l2]=[]
|
||||
|
||||
|
||||
self.d[node]['rntis']={}
|
||||
|
||||
def process_gnb (self,node_type,output):
|
||||
rnti='65535'
|
||||
bp_enable = False
|
||||
ts = time.gmtime(0) #Bad, but just creating a date
|
||||
for line in output:
|
||||
tmp=line.decode("utf-8")
|
||||
result=re.match(r'^.*\bdlsch_rounds\b ([0-9]+)\/([0-9]+).*\bdlsch_errors\b ([0-9]+)',tmp)
|
||||
result=re.match(r'^.*\bUE RNTI ([a-zA-Z0-9]+) CU-UE-ID',tmp)
|
||||
if result is not None:
|
||||
self.d[node_type]['dlsch_err'].append(int(result.group(3)))
|
||||
percentage=float(result.group(2))/float(result.group(1))
|
||||
self.d[node_type]['dlsch_err_perc_round_1'].append(percentage)
|
||||
result=re.match(r'^.*\bulsch_rounds\b ([0-9]+)\/([0-9]+).*\bulsch_errors\b ([0-9]+)',tmp)
|
||||
rnti=result.group(1)
|
||||
if not rnti in self.d['gnb']['rntis']:
|
||||
print("Found new RNTI: "+tmp)
|
||||
self.d['gnb']['rntis'][rnti] = copy.deepcopy(self.d['gnb']['ue'])
|
||||
#bp_enable = True
|
||||
continue
|
||||
|
||||
if bp_enable:
|
||||
print(tmp)
|
||||
breakpoint()
|
||||
result=re.match(r'^.*\bdlsch_rounds\b ([0-9]+)\/([0-9]+).*\bdlsch_errors\b ([0-9]+).*\bBLER\b ([0-9]+[.][0-9]+) \bMCS\b \([0-1]\) ([0-9]+)',tmp)
|
||||
if result is not None:
|
||||
self.d[node_type]['ulsch_err'].append(int(result.group(3)))
|
||||
percentage=float(result.group(2))/float(result.group(1))
|
||||
self.d[node_type]['ulsch_err_perc_round_1'].append(percentage)
|
||||
self.d[node_type]['rntis'][rnti]['dlsch_err'].append(int(result.group(3)))
|
||||
try:
|
||||
percentage=100.0*float(result.group(2))/float(result.group(1))
|
||||
except ZeroDivisionError:
|
||||
percentage=0.0
|
||||
self.d[node_type]['rntis'][rnti]['dlsch_err_perc_round_1'].append(percentage)
|
||||
self.d[node_type]['rntis'][rnti]['dlbler'].append(float(result.group(4)))
|
||||
self.d[node_type]['rntis'][rnti]['dlmcs'].append(int(result.group(5)))
|
||||
result=re.match(r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{6}Z)',tmp)
|
||||
if result is not None:
|
||||
ts = datetime.strptime(result.group(1),'%Y-%m-%d %H:%M:%S.%fZ')
|
||||
if sys.version_info[0] == 3 and sys.version_info[1] < 11:
|
||||
ts = ts.replace(tzinfo=timezone.utc)
|
||||
self.d[node_type]['rntis'][rnti]['timestamp'].append(ts)
|
||||
continue
|
||||
|
||||
result=re.match(rf'^.*\b{rnti}\b: \bMAC\b.*\bTX\b +([0-9]+).*\bRX\b +([0-9]+)',tmp)
|
||||
if result is not None:
|
||||
if len(self.d[node_type]['rntis'][rnti]['dlsch_mbps']) == 0:
|
||||
self.d[node_type]['rntis'][rnti]['dlsch_mbps'].append(0)
|
||||
self.d[node_type]['rntis'][rnti]['ulsch_mbps'].append(0)
|
||||
self.d[node_type]['rntis'][rnti]['dlsch_prev_bytes'].append(float(result.group(1)))
|
||||
self.d[node_type]['rntis'][rnti]['ulsch_prev_bytes'].append(float(result.group(2)))
|
||||
else :
|
||||
prev = self.d[node_type]['rntis'][rnti]['dlsch_prev_bytes'].pop()
|
||||
#8 bits per byte, 10^20 Bits per Mbps, subtract bler
|
||||
times =self.d[node_type]['rntis'][rnti]['timestamp'][-2:]
|
||||
#delta_t = times[1]-times[0]
|
||||
delta_t = timedelta(milliseconds=1280)
|
||||
delta = (float(result.group(1)) - prev)*2**3/2**20*(1.0- self.d[node_type]['rntis'][rnti]['dlbler'][-1])/delta_t.total_seconds()
|
||||
self.d[node_type]['rntis'][rnti]['dlsch_mbps'].append(delta)
|
||||
self.d[node_type]['rntis'][rnti]['dlsch_prev_bytes'].append(float(result.group(1)))
|
||||
|
||||
prev = self.d[node_type]['rntis'][rnti]['ulsch_prev_bytes'].pop()
|
||||
#8 bites per byte, 10^20 bits per mbps, subtract bler
|
||||
delta = (float(result.group(2)) - prev)*2**3/2**20*(1.0-self.d[node_type]['rntis'][rnti]['ulbler'][-1])/delta_t.total_seconds()
|
||||
self.d[node_type]['rntis'][rnti]['ulsch_mbps'].append(delta)
|
||||
self.d[node_type]['rntis'][rnti]['ulsch_prev_bytes'].append(float(result.group(2)))
|
||||
continue
|
||||
|
||||
result=re.match(r'^.*\bulsch_rounds\b ([0-9]+)\/([0-9]+).*\bulsch_errors\b ([0-9]+).*\bBLER\b ([0-9]+[.][0-9]+) \bMCS\b \([0-1]\) ([0-9]+)',tmp)
|
||||
if result is not None:
|
||||
self.d[node_type]['rntis'][rnti]['ulsch_err'].append(int(result.group(3)))
|
||||
try:
|
||||
percentage=100.0*float(result.group(2))/float(result.group(1))
|
||||
except ZeroDivisionError:
|
||||
percentage=0.0
|
||||
self.d[node_type]['rntis'][rnti]['ulsch_err_perc_round_1'].append(percentage)
|
||||
self.d[node_type]['rntis'][rnti]['ulbler'].append(float(result.group(4)))
|
||||
self.d[node_type]['rntis'][rnti]['ulmcs'].append(int(result.group(5)))
|
||||
continue
|
||||
|
||||
for k in self.d[node_type]['rt']:
|
||||
result=re.match(rf'^.*\b{k}\b:\s+([0-9\.]+) us;\s+([0-9]+);\s+([0-9\.]+) us;',tmp)
|
||||
@@ -61,18 +120,14 @@ class StatMonitor():
|
||||
|
||||
|
||||
def collect(self,testcase_id,node_type):
|
||||
if node_type=='enb':
|
||||
files = ["L1_stats.log", "MAC_stats.log", "PDCP_stats.log", "RRC_stats.log"]
|
||||
else: #'gnb'
|
||||
files = ["nrL1_stats.log", "nrMAC_stats.log", "nrPDCP_stats.log", "nrRRC_stats.log"]
|
||||
#append each file's contents to another file (prepended with CI-) for debug
|
||||
for f in files:
|
||||
for f in self.d[node_type]['files']:
|
||||
if os.path.isfile(f):
|
||||
cmd = 'cat '+ f + ' >> CI-'+testcase_id+'-'+f
|
||||
subprocess.Popen(cmd,shell=True)
|
||||
#join the files for further processing
|
||||
cmd='cat '
|
||||
for f in files:
|
||||
for f in self.d[node_type]['files']:
|
||||
if os.path.isfile(f):
|
||||
cmd += f+' '
|
||||
process=subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE)
|
||||
@@ -86,34 +141,54 @@ class StatMonitor():
|
||||
def graph(self,testcase_id, node_type):
|
||||
for page in self.d[node_type]['graph']:#work out a set a graphs per page
|
||||
col = 1
|
||||
figure, axis = plt.subplots(len(self.d[node_type]['graph'][page]), col ,figsize=(10, 10))
|
||||
figure, axis = plt.subplots(len(self.d[node_type]['graph'][page]), col ,figsize=(10, 10), sharex=True)
|
||||
i=0
|
||||
for m in self.d[node_type]['graph'][page]:#metric may refer to 1 level or 2 levels
|
||||
metric_path=m.split('.')
|
||||
if len(metric_path)==1:#1 level
|
||||
metric_l1=metric_path[0]
|
||||
major_ticks = np.arange(0, len(self.d[node_type][metric_l1])+1, 1)
|
||||
axis[i].set_xticks(major_ticks)
|
||||
axis[i].set_xticklabels([])
|
||||
axis[i].plot(self.d[node_type][metric_l1],marker='o')
|
||||
axis[i].set_xlabel('time')
|
||||
axis[i].set_ylabel(metric_l1)
|
||||
axis[i].set_title(metric_l1)
|
||||
|
||||
else:#2 levels
|
||||
metric_l1=metric_path[0]
|
||||
metric_l2=metric_path[1]
|
||||
major_ticks = np.arange(0, len(self.d[node_type][metric_l1][metric_l2])+1, 1)
|
||||
axis[i].set_xticks(major_ticks)
|
||||
axis[i].set_xticklabels([])
|
||||
axis[i].plot(self.d[node_type][metric_l1][metric_l2],marker='o')
|
||||
axis[i].set_xlabel('time')
|
||||
axis[i].set_ylabel(metric_l2)
|
||||
axis[i].set_title(metric_l2)
|
||||
metric_l1=metric_path[0]
|
||||
if metric_path[0]=='ue':
|
||||
metric_l2=metric_path[1]
|
||||
major_ticks = np.arange(0, 10, 1)
|
||||
for rnti in self.d[node_type]['rntis']:
|
||||
tput = ''
|
||||
if 'mbps' in metric_l2:
|
||||
n = self.d[node_type]['test_params']['duration']
|
||||
top_n = (sorted(self.d[node_type]['rntis'][rnti][metric_l2])[-n:])
|
||||
tput = str(round(sum(top_n)/n,1))
|
||||
tput = ' '+tput+' Mbps'
|
||||
axis[i].plot(self.d[node_type]['rntis'][rnti][metric_l2],label=rnti+tput)
|
||||
major_ticks = np.arange(0, len(self.d[node_type]['rntis'][rnti][metric_l2])+1, 1)
|
||||
axis[i].set_xticks(major_ticks)
|
||||
axis[i].set_xticklabels([])
|
||||
axis[i].grid(axis='y')
|
||||
axis[i].legend(loc='center left')
|
||||
axis[i].set_xlabel('time (s)')
|
||||
axis[i].set_ylabel(metric_l2)
|
||||
|
||||
else:
|
||||
if len(metric_path)==1:#1 level
|
||||
major_ticks = np.arange(0, len(self.d[node_type][metric_l1])+1, 1)
|
||||
axis[i].set_xticks(major_ticks)
|
||||
axis[i].set_xticklabels([])
|
||||
axis[i].plot(self.d[node_type][metric_l1],marker='o')
|
||||
axis[i].set_xlabel('time')
|
||||
axis[i].set_ylabel(metric_l1)
|
||||
axis[i].set_title(metric_l1)
|
||||
|
||||
else:#2 levels
|
||||
metric_l2=metric_path[1]
|
||||
major_ticks = np.arange(0, len(self.d[node_type][metric_l1][metric_l2])+1, 1)
|
||||
axis[i].set_xticks(major_ticks)
|
||||
axis[i].set_xticklabels([])
|
||||
axis[i].plot(self.d[node_type][metric_l1][metric_l2],marker='o')
|
||||
axis[i].set_xlabel('time')
|
||||
axis[i].set_ylabel(metric_l2)
|
||||
axis[i].set_title(metric_l2)
|
||||
i+=1
|
||||
|
||||
plt.tight_layout()
|
||||
#save as png
|
||||
#plt.show()
|
||||
plt.savefig(node_type+'_stats_monitor_'+testcase_id+'_'+page+'.png')
|
||||
|
||||
|
||||
@@ -128,11 +203,13 @@ if __name__ == "__main__":
|
||||
CMD='ps aux | grep modem | grep -v grep'
|
||||
process=subprocess.Popen(CMD, shell=True, stdout=subprocess.PIPE)
|
||||
output = process.stdout.readlines()
|
||||
while len(output)!=0 :
|
||||
while True:
|
||||
mon.collect(testcase_id,node)
|
||||
process=subprocess.Popen(CMD, shell=True, stdout=subprocess.PIPE)
|
||||
output = process.stdout.readlines()
|
||||
time.sleep(1)
|
||||
if len(output)==0 :
|
||||
break;
|
||||
print('Process stopped')
|
||||
with open(node+'_stats_monitor.pickle', 'wb') as handle:
|
||||
pickle.dump(mon.d, handle, protocol=pickle.HIGHEST_PROTOCOL)
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
enb :
|
||||
files: ["L1_stats.log", "MAC_stats.log", "PDCP_stats.log", "RRC_stats.log"]
|
||||
test_params:
|
||||
duration: 10 #Number of samples to average over for throughput
|
||||
PHR:
|
||||
bler:
|
||||
mcsoff:
|
||||
@@ -11,10 +14,25 @@ enb :
|
||||
mcs:
|
||||
|
||||
gnb :
|
||||
dlsch_err:
|
||||
dlsch_err_perc_round_1:
|
||||
ulsch_err:
|
||||
ulsch_err_perc_round_1:
|
||||
#files: ["nrL1_stats.log", "nrMAC_stats.log", "nrPDCP_stats.log", "nrRRC_stats.log"]
|
||||
files: ["oai.log"]
|
||||
test_params:
|
||||
duration: 10 #Number of samples to average over for throughput
|
||||
ue :
|
||||
timestamp:
|
||||
dlsch_bler:
|
||||
dlsch_mbps:
|
||||
dlsch_prev_bytes:
|
||||
dlmcs:
|
||||
dlbler:
|
||||
dlsch_err:
|
||||
dlsch_err_perc_round_1:
|
||||
ulmcs:
|
||||
ulbler:
|
||||
ulsch_mbps:
|
||||
ulsch_prev_bytes:
|
||||
ulsch_err:
|
||||
ulsch_err_perc_round_1:
|
||||
rt :
|
||||
feprx:
|
||||
feptx_prec:
|
||||
@@ -29,10 +47,14 @@ gnb :
|
||||
Slot Indication:
|
||||
graph :
|
||||
page1:
|
||||
dlsch_err:
|
||||
dlsch_err_perc_round_1:
|
||||
ulsch_err:
|
||||
ulsch_err_perc_round_1:
|
||||
ue.dlsch_mbps:
|
||||
#ue.dlsch_err:
|
||||
ue.dlmcs:
|
||||
ue.dlsch_err_perc_round_1:
|
||||
ue.ulsch_mbps:
|
||||
ue.ulmcs:
|
||||
#ue.ulsch_err:
|
||||
ue.ulsch_err_perc_round_1:
|
||||
page2:
|
||||
rt.feprx:
|
||||
rt.feptx_prec:
|
||||
|
||||
Reference in New Issue
Block a user