#!/usr/bin/env python3 """ Licensed to the OpenAirInterface (OAI) Software Alliance under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The OpenAirInterface Software Alliance licenses this file to You under the OAI Public License, Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.openairinterface.org/?page_id=698 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ------------------------------------------------------------------------------ For more information about the OpenAirInterface (OAI) Software Alliance: contact@openairinterface.org --------------------------------------------------------------------- """ import argparse import logging import re import sys import time import matplotlib.pyplot as plt import common.python.cls_cmd as cls_cmd logging.basicConfig( level=logging.INFO, stream=sys.stdout, format="[%(asctime)s] %(levelname)8s: %(message)s" ) LOOP_INTERVAL = 5 NB_GNBSIM_INSTANCES = 8 NB_PROFILES = [1, 1, 1, 1, 1, 1, 1, 1] def main() -> None: #Parse arguments args = _parse_args() start_time = time.time() myCmds = cls_cmd.LocalCmd() plt.set_loglevel("info") logging.info('\033[0;32m OMEC gnbsim RAN emulator started, checking if all profiles finished... takes few secs\033[0m....') # First using docker ps to see which images were used. cmd = 'docker ps -a' res = myCmds.run(cmd) print(res.stdout) notSilentForFirstTime = False status = -1 # Stats Arrays amfTimeX = [] amfMemY = [] amfCpuY = [] nrfTimeX = [] nrfMemY = [] nrfCpuY = [] ausfTimeX = [] ausfMemY = [] ausfCpuY = [] udmTimeX = [] udmMemY = [] udmCpuY = [] udrTimeX = [] udrMemY = [] udrCpuY = [] smfTimeX = [] smfCpuY = [] smfMemY = [] upfTimeX = [] upfMemY = [] upfCpuY = [] x = 0 while True: # Performing some statistics measurements on CPU and Memory usages for each NF stats = myCmds.run('docker stats --no-stream', silent=notSilentForFirstTime) for line in stats.stdout.split('\n'): if line.count('oai-amf') > 0: result = re.search(' (?P<cpu_usage>[0-9\.]+)% *(?P<memory_usage>[0-9\.]+)MiB / ', line) if result is not None: amfTimeX.append(x * LOOP_INTERVAL) amfCpuY.append(float(result.group('cpu_usage'))) amfMemY.append(float(result.group('memory_usage'))) if line.count('oai-nrf') > 0: result = re.search(' (?P<cpu_usage>[0-9\.]+)% *(?P<memory_usage>[0-9\.]+)MiB / ', line) if result is not None: nrfTimeX.append(x * LOOP_INTERVAL) nrfCpuY.append(float(result.group('cpu_usage'))) nrfMemY.append(float(result.group('memory_usage'))) if line.count('oai-ausf') > 0: result = re.search(' (?P<cpu_usage>[0-9\.]+)% *(?P<memory_usage>[0-9\.]+)MiB / ', line) if result is not None: ausfTimeX.append(x * LOOP_INTERVAL) ausfCpuY.append(float(result.group('cpu_usage'))) ausfMemY.append(float(result.group('memory_usage'))) if line.count('oai-udm') > 0: result = re.search(' (?P<cpu_usage>[0-9\.]+)% *(?P<memory_usage>[0-9\.]+)MiB / ', line) if result is not None: udmTimeX.append(x * LOOP_INTERVAL) udmCpuY.append(float(result.group('cpu_usage'))) udmMemY.append(float(result.group('memory_usage'))) if line.count('oai-udr') > 0: result = re.search(' (?P<cpu_usage>[0-9\.]+)% *(?P<memory_usage>[0-9\.]+)MiB / ', line) if result is not None: udrTimeX.append(x * LOOP_INTERVAL) udrCpuY.append(float(result.group('cpu_usage'))) udrMemY.append(float(result.group('memory_usage'))) if line.count('oai-smf') > 0: result = re.search(' (?P<cpu_usage>[0-9\.]+)% *(?P<memory_usage>[0-9\.]+)MiB / ', line) if result is not None: smfTimeX.append(x * LOOP_INTERVAL) smfCpuY.append(float(result.group('cpu_usage'))) smfMemY.append(float(result.group('memory_usage'))) if line.count('oai-upf') > 0: result = re.search(' (?P<cpu_usage>[0-9\.]+)% *(?P<memory_usage>[0-9\.]+)MiB / ', line) if result is not None: upfTimeX.append(x * LOOP_INTERVAL) upfCpuY.append(float(result.group('cpu_usage'))) upfMemY.append(float(result.group('memory_usage'))) # Checking the status of each gnbsim container ret = [] for idx in range(NB_GNBSIM_INSTANCES): cmd = f'docker logs omec-gnbsim-{idx} 2>&1 | egrep --colour=never "Summary|ERRO" || true' tmpRet = myCmds.run(cmd, silent=notSilentForFirstTime) if tmpRet is None: exit(f'\033[0;31m Incorrect/Unsupported executing command "{cmd}"') ret.append(str(tmpRet.stdout)) notSilentForFirstTime = True allFinished = True allPassing = True failingForAMFnilAddress = 0 for idx in range(NB_GNBSIM_INSTANCES): cnt = ret[idx].count('Profile Status:') passing = ret[idx].count('Profile Status: PASS') failingForAMFnilAddress += ret[idx].count('endToPeer failed: AMF IP address is nil') if cnt != NB_PROFILES[idx]: allFinished = False if passing != NB_PROFILES[idx]: allPassing = False if allFinished: logging.info('\033[0;32m All profiles finished\033[0m....') if allPassing: logging.info('\033[0;32m All profiles passed\033[0m....') status = 0 elif failingForAMFnilAddress == 1: logging.info('\033[0;32m One profile failed on a single UE (maybe a gnbsim issue).\033[0m....') status = 0 else: logging.error('\033[0;32m Some profiles failed\033[0m....') status = -1 for idx in range(NB_GNBSIM_INSTANCES): print(ret[idx]) break run_time = time.time() - start_time if int(run_time) > args.timeout: logging.error('\033[0;32m TimeOut\033[0m....') status = -2 break time.sleep(LOOP_INTERVAL) x += 1 cmd = 'docker ps -a' res = myCmds.run(cmd) print (res.stdout) myCmds.close() logging.info('Generating a plot for memory usage') # Generating a plot for memory usage plt.plot(amfTimeX, amfMemY, label='AMF') plt.plot(nrfTimeX, nrfMemY, label='NRF') plt.plot(ausfTimeX, ausfMemY, label='AUSF') plt.plot(udmTimeX, udmMemY, label='UDM') plt.plot(udrTimeX, udrMemY, label='UDR') plt.plot(smfTimeX, smfMemY, label='SMF') if len(upfTimeX) > 0: plt.plot(upfTimeX, upfMemY, label='UPF') plt.legend() plt.title('Memory Usage per NF') plt.ylabel('MiB') plt.xlabel('seconds') plt.savefig('oai-cn5g-memory.png') plt.cla() plt.clf() logging.info('Generating a plot for CPU usage') # Generating a plot for cpu usage plt.plot(amfTimeX, amfCpuY, label='AMF') plt.plot(nrfTimeX, nrfCpuY, label='NRF') plt.plot(ausfTimeX, ausfCpuY, label='AUSF') plt.plot(udmTimeX, udmCpuY, label='UDM') plt.plot(udrTimeX, udrCpuY, label='UDR') plt.plot(smfTimeX, smfCpuY, label='SMF') plt.plot(upfTimeX, upfCpuY, label='UPF') plt.legend() plt.title('CPU Usage per NF') plt.ylabel('%age') plt.xlabel('seconds') plt.savefig('oai-cn5g-cpu.png') if not allFinished: logging.error('\033[0;31m Some profiles could not finish\033[0m....') for idx in range(NB_GNBSIM_INSTANCES): print(ret[idx]) sys.exit(-1) sys.exit(status) def _parse_args() -> argparse.Namespace: """Parse the command line args Returns: argparse.Namespace: the created parser """ parser = argparse.ArgumentParser(description='Script to check if OMEC-gnbsim deployment went OK.') # Time out in seconds parser.add_argument( '--timeout', '-t', action='store', type=int, default=30, help='Time-Out before leaving (in seconds)', ) return parser.parse_args() if __name__ == '__main__': main()