2 #######################################################################
\r
6 #######################################################################
\r
8 """This script run test cases with O-DU and O-RU
\r
17 from itertools import dropwhile
\r
18 from datetime import datetime
\r
22 # 5MHz 10MHz 15MHz 20 MHz 25 MHz 30 MHz 40 MHz 50MHz 60 MHz 70 MHz 80 MHz 90 MHz 100 MHz
\r
23 [25, 52, 79, 106, 133, 160, 216, 270, 0, 0, 0, 0, 0], # Numerology 0 (15KHz)
\r
24 [11, 24, 38, 51, 65, 78, 106, 133, 162, 0, 217, 245, 273], # Numerology 1 (30KHz)
\r
25 [0, 11, 18, 24, 31, 38, 51, 65, 79, 0, 107, 121, 135] # Numerology 2 (60KHz)
\r
29 # 50Mhz 100MHz 200MHz 400MHz
\r
30 [66, 132, 264, 0], # Numerology 2 (60KHz)
\r
31 [32, 66, 132, 264] # Numerology 3 (120KHz)
\r
35 nRChBwOptions_keys = ['5','10','15','20', '25', '30', '40', '50', '60','70', '80', '90', '100', '200', '400']
\r
36 nRChBwOptions_values = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14]
\r
37 nRChBwOptions = dict(zip(nRChBwOptions_keys, nRChBwOptions_values))
\r
39 nRChBwOptions_keys_mu2and3 = ['50', '100', '200', '400']
\r
40 nRChBwOptions_values_mu2and3 = [0,1,2,3]
\r
41 nRChBwOptions_mu2and3 = dict(zip(nRChBwOptions_keys_mu2and3, nRChBwOptions_values_mu2and3))
\r
43 # table of all test cases
\r
44 # (cat, mu, bw, test case)
\r
45 all_test_cases = [(0, 0, 5, 0),
\r
52 """ all_test_cases = [(1, 1, 100, 0),
\r
59 #(1, 1, 100, 106), 25G not enough
\r
62 #(1, 1, 100, 109), 25G not enough
\r
64 #(1, 1, 100, 202), 25G not enough
\r
70 #(1, 1, 100, 212), 25G not enough
\r
77 dic_dir = dict({0:'DL', 1:'UL'})
\r
78 dic_xu = dict({0:'o-du', 1:'o-ru'})
\r
80 def init_logger(console_level, logfile_level):
\r
81 """Initializes console and logfile logger with given logging levels"""
\r
83 logging.basicConfig(filename="runtests.log",
\r
85 format="%(asctime)s: %(levelname)s: %(message)s",
\r
86 level=logfile_level)
\r
88 logger = logging.getLogger()
\r
89 handler = logging.StreamHandler()
\r
90 handler.setLevel(console_level)
\r
91 formatter = logging.Formatter("%(levelname)s: %(message)s")
\r
92 handler.setFormatter(formatter)
\r
93 logger.addHandler(handler)
\r
95 def parse_args(args):
\r
96 """Configures parser and parses command line configuration"""
\r
97 # Parser configuration
\r
98 parser = argparse.ArgumentParser(description="Run test cases: category numerology bandwidth test_num")
\r
100 parser.add_argument("--cat", type=int, default=0, help="Category: 0 (A) or 1 (B)", metavar="cat", dest="category")
\r
101 parser.add_argument("--mu", type=int, default=0, help="numerology [0,1,3]", metavar="num", dest="numerology")
\r
102 parser.add_argument("--bw", type=int, default=20, help="bandwidth [5,10,20,100]", metavar="bw", dest="bandwidth")
\r
103 parser.add_argument("--testcase", type=int, default=0, help="test case number", metavar="testcase", dest="testcase")
\r
106 options = parser.parse_args(args)
\r
107 #parser.print_help()
\r
108 logging.debug("Options: category=%d num=%d bw=%d testcase=%d",
\r
109 options.category, options.numerology, options.bandwidth, options.testcase)
\r
113 """ function to check if a line
\r
114 starts with some character.
\r
117 # return true if a line starts with #
\r
118 return s.startswith('#')
\r
120 class GetOutOfLoops( Exception ):
\r
123 def compare_resuts(cat, mu, bw, tcase, xran_path, test_cfg, direction):
\r
127 nDlRB = nNumRbsPerSymF1[mu][nRChBwOptions.get(str(nDLBandwidth))]
\r
128 nUlRB = nNumRbsPerSymF1[mu][nRChBwOptions.get(str(nULBandwidth))]
\r
129 elif (mu >=2) & (mu <= 3):
\r
130 nDlRB = nNumRbsPerSymF2[mu - 2][nRChBwOptions_mu2and3.get(str(nDLBandwidth))]
\r
131 nUlRB = nNumRbsPerSymF2[mu - 2][nRChBwOptions_mu2and3.get(str(nULBandwidth))]
\r
132 print(nDlRB, nUlRB)
\r
134 print("Incorrect arguments\n")
\r
138 if 'compression' in globals():
\r
143 print("compare results: {} [compression {}]\n".format(dic_dir.get(direction), comp))
\r
146 # print("WARNING: Skip checking IQs and BF Weights for CAT B for now\n");
\r
150 if nFrameDuplexType == 1:
\r
152 for i in range(nTddPeriod):
\r
154 SlotConfig.insert(i, sSlotConfig0)
\r
156 SlotConfig.insert(i, sSlotConfig1)
\r
158 SlotConfig.insert(i, sSlotConfig2)
\r
160 SlotConfig.insert(i, sSlotConfig3)
\r
162 SlotConfig.insert(i, sSlotConfig4)
\r
164 SlotConfig.insert(i, sSlotConfig5)
\r
166 SlotConfig.insert(i, sSlotConfig6)
\r
168 SlotConfig.insert(i, sSlotConfig7)
\r
170 SlotConfig.insert(i, sSlotConfig8)
\r
172 SlotConfig.insert(i, sSlotConfig9)
\r
174 raise Exception('i should not exceed nTddPeriod %d. The value of i was: {}'.format(nTddPeriod, i))
\r
175 #print(SlotConfig, type(sSlotConfig0))
\r
178 if (direction == 1) & (cat == 1): #UL
\r
179 flowId = ccNum*antNumUL
\r
181 flowId = ccNum*antNum
\r
183 for i in range(0, flowId):
\r
184 #read ref and test files
\r
190 file_tst = xran_path+"/app/logs/"+"o-ru-rx_log_ant"+str(i)+".txt"
\r
191 file_ref = xran_path+"/app/logs/"+"o-du-play_ant"+str(i)+".txt"
\r
192 elif direction == 1:
\r
195 file_tst = xran_path+"/app/logs/"+"o-du-rx_log_ant"+str(i)+".txt"
\r
196 file_ref = xran_path+"/app/logs/"+"o-ru-play_ant"+str(i)+".txt"
\r
198 raise Exception('Direction is not supported %d'.format(direction))
\r
200 print("test result :", file_tst)
\r
201 print("test reference:", file_ref)
\r
202 if os.path.exists(file_tst):
\r
204 file_tst = open(file_tst, 'r')
\r
206 print ("Could not open/read file:", file_tst)
\r
209 print(file_tst, "doesn't exist")
\r
212 if os.path.exists(file_ref):
\r
214 file_ref = open(file_ref, 'r')
\r
216 print ("Could not open/read file:", file_ref)
\r
219 print(file_tst, "doesn't exist")
\r
223 tst = file_tst.readlines()
\r
224 ref = file_ref.readlines()
\r
234 for slot_idx in range(0, numSlots):
\r
235 for sym_idx in range(0, 14):
\r
236 if nFrameDuplexType==1:
\r
240 sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
\r
243 elif direction == 1:
\r
245 sym_dir = SlotConfig[slot_idx%nTddPeriod][sym_idx]
\r
249 #print("Check:","[",i,"]", slot_idx, sym_idx)
\r
250 for line_idx in range(0, nRB*12):
\r
251 offset = (slot_idx*nRB*12*14) + sym_idx*nRB*12 + line_idx
\r
252 line_tst = tst[offset].rstrip()
\r
253 line_ref = ref[offset].rstrip()
\r
255 # discard LSB bits as BFP compression is not Bit Exact
\r
256 tst_i_value = int(line_tst.split(" ")[0]) & 0xFF80
\r
257 tst_q_value = int(line_tst.split(" ")[1]) & 0xFF80
\r
258 ref_i_value = int(line_ref.split(" ")[0]) & 0xFF80
\r
259 ref_q_value = int(line_ref.split(" ")[1]) & 0xFF80
\r
261 print("check:","ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx,":","tst: ", tst_i_value, " ", tst_q_value, " " , "ref: ", ref_i_value, " ", ref_q_value, " ")
\r
262 if (tst_i_value != ref_i_value) or (tst_q_value != ref_q_value) :
\r
263 print("FAIL:","ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx,":","tst: ", tst_i_value, " ", tst_q_value, " " , "ref: ", ref_i_value, " ", ref_q_value, " ")
\r
265 raise GetOutOfLoops
\r
268 #print("Check:", offset,"[",i,"]", slot_idx, sym_idx,":",line_tst, line_ref)
\r
269 if line_ref != line_tst:
\r
270 print("FAIL:","ant:[",i,"]:",offset, slot_idx, sym_idx, line_idx,":","tst:", line_tst, "ref:", line_ref)
\r
272 raise GetOutOfLoops
\r
273 except GetOutOfLoops:
\r
278 def parse_dat_file(cat, mu, bw, tcase, xran_path, test_cfg):
\r
279 #parse config files
\r
280 logging.info("parse config files %s\n", test_cfg[0])
\r
283 with open(test_cfg[0],'r') as fh:
\r
284 for curline in dropwhile(is_comment, fh):
\r
285 my_line = curline.rstrip().split(sep, 1)[0].strip()
\r
287 lineList.append(my_line)
\r
291 for line in lineList:
\r
292 exe_line = line.replace(":", ",")
\r
293 if exe_line.find("/") > 0 :
\r
294 exe_line = exe_line.replace('./', "'")
\r
295 exe_line = exe_line+"'"
\r
297 code = compile(str(exe_line), '<string>', 'exec')
\r
298 exec (code, global_env, local_env)
\r
300 for k, v in local_env.items():
\r
306 def make_copy_mlog(cat, mu, bw, tcase, xran_path):
\r
309 src_bin = xran_path+"/app/mlog-o-du-c0.bin"
\r
310 src_csv = xran_path+"/app/mlog-o-du-hist.csv"
\r
311 dst_bin = xran_path+"/app/mlog-o-du-c0-cat"+str(cat)+"-mu"+str(mu)+"-bw"+str(bw)+"-tcase"+str(tcase)+".bin"
\r
312 dst_csv = xran_path+"/app/mlog-o-du-hist-cat"+str(cat)+"-mu"+str(mu)+"-bw"+str(bw)+"-tcase"+str(tcase)+".csv"
\r
315 d_bin = shutil.copyfile(src_bin, dst_bin)
\r
316 d_csv = shutil.copyfile(src_csv, dst_csv)
\r
318 logging.info("MLog is not present\n")
\r
321 logging.info("Mlog was copied\n")
\r
323 print("Destination path:", d_bin)
\r
324 print("Destination path:", d_csv)
\r
326 d_bin = shutil.copyfile(src_bin, dst_bin)
\r
327 d_csv = shutil.copyfile(src_csv, dst_csv)
\r
329 #print("After copying file:")
\r
330 #print(os.listdir(xran_path+"/app/"))
\r
332 #print("Destination path:", d_bin)
\r
333 #print("Destination path:", d_csv)
\r
335 src_bin = xran_path+"/app/mlog-o-ru-c0.bin"
\r
336 src_csv = xran_path+"/app/mlog-o-ru-hist.csv"
\r
337 dst_bin = xran_path+"/app/mlog-o-ru-c0-cat"+str(cat)+"-mu"+str(mu)+"-bw"+str(bw)+"-tcase"+str(tcase)+".bin"
\r
338 dst_csv = xran_path+"/app/mlog-o-ru-hist-cat"+str(cat)+"-mu"+str(mu)+"-bw"+str(bw)+"-tcase"+str(tcase)+".csv"
\r
340 d_bin = shutil.copyfile(src_bin, dst_bin)
\r
341 d_csv = shutil.copyfile(src_csv, dst_csv)
\r
343 #print("After copying file:")
\r
344 #print(os.listdir(xran_path+"/app/"))
\r
346 #print("Destination path:", d_bin)
\r
347 #print("Destination path:", d_csv)
\r
350 d_bin = shutil.copyfile(src_bin, dst_bin)
\r
351 d_csv = shutil.copyfile(src_csv, dst_csv)
\r
353 logging.info("MLog is not present\n")
\r
356 logging.info("Mlog was copied\n")
\r
358 #print("After copying file:")
\r
359 #print(os.listdir(xran_path+"/app/"))
\r
361 #print("Destination path:", d_bin)
\r
362 #print("Destination path:", d_csv)
\r
367 def run_tcase(cat, mu, bw, tcase, xran_path):
\r
369 test_config = xran_path+"/app/usecase/cat_b/mu{0:d}_{1:d}mhz".format(mu, bw)
\r
371 test_config = xran_path+"/app/usecase/mu{0:d}_{1:d}mhz".format(mu, bw)
\r
373 print("Incorrect arguments\n")
\r
376 test_config = test_config+"/"+str(tcase)
\r
378 app = xran_path+"/app/build/sample-app"
\r
380 logging.debug("run: %s %s", app, test_config)
\r
381 logging.debug("Started script: master.py, XRAN path %s", xran_path)
\r
384 #TODO: add detection of ETH ports
\r
385 eth_cp_dev = ["0000:22:02.1", "0000:22:0a.1"]
\r
386 eth_up_dev = ["0000:22:02.0", "0000:22:0a.0"]
\r
388 test_cfg.append(test_config+"/config_file_o_du.dat")
\r
389 test_cfg.append(test_config+"/config_file_o_ru.dat")
\r
392 os.chdir(xran_path+"/app/")
\r
398 os.system('rm -rf ./logs')
\r
401 log_file_name.append("sampleapp_log_{}_cat_{}_mu{}_{}mhz_tst_{}.log".format(dic_xu.get(i),cat, mu, bw, tcase))
\r
402 with open(log_file_name[i], "w") as f:
\r
403 #, stdout=f, stderr=f
\r
404 p = subprocess.Popen([app, test_cfg[i], eth_up_dev[i], eth_cp_dev[i]], stdout=f, stderr=f)
\r
405 logfile_xu.insert(i, f)
\r
406 processes.append((p, logfile_xu[i]))
\r
408 logging.info("Running O-DU and O-RU see output in: %s %s\n", logfile_xu[0].name, logfile_xu[1].name)
\r
409 for p, f in processes:
\r
412 if p.returncode != 0:
\r
413 print("Application {} failed p.returncode:{}".format(dic_xu.get(i), p.returncode))
\r
415 logging.info("FAIL\n")
\r
417 sys.exit(p.returncode)
\r
421 logging.info("O-DU and O-RU are done\n")
\r
423 make_copy_mlog(cat, mu, bw, tcase, xran_path)
\r
425 usecase_cfg = parse_dat_file(cat, mu, bw, tcase, xran_path, test_cfg)
\r
427 res = compare_resuts(cat, mu, bw, tcase, xran_path, test_cfg, 0)
\r
433 res = compare_resuts(cat, mu, bw, tcase, xran_path, test_cfg, 1)
\r
445 test_executed_total = 0
\r
451 """Processes input files to produce IACA files"""
\r
452 # Find path to XRAN
\r
453 xran_path = os.getenv("XRAN_DIR")
\r
455 # Set up logging with given level (DEBUG, INFO, ERROR) for console end logfile
\r
456 init_logger(logging.INFO, logging.DEBUG)
\r
457 logging.info("Started script: master.py, XRAN path %s", xran_path)
\r
459 # Parse input arguments
\r
460 if len(sys.argv) == 1 :
\r
461 run_total = len(all_test_cases)
\r
463 print("Run All test cases {}\n".format(run_total))
\r
465 options = parse_args(sys.argv[1:])
\r
466 cat = options.category
\r
467 mu = options.numerology
\r
468 bw = options.bandwidth
\r
469 tcase = options.testcase
\r
473 for test_run_ix in range(0, run_total):
\r
474 cat = all_test_cases[test_run_ix][0]
\r
475 mu = all_test_cases[test_run_ix][1]
\r
476 bw = all_test_cases[test_run_ix][2]
\r
477 tcase = all_test_cases[test_run_ix][3]
\r
479 res = run_tcase(cat, mu, bw, tcase, xran_path)
\r
481 test_results.append((cat, mu, bw, tcase,'FAIL'))
\r
484 test_results.append((cat, mu, bw, tcase,'PASS'))
\r
486 res = run_tcase(cat, mu, bw, tcase, xran_path)
\r
488 test_results.append((cat, mu, bw, tcase,'FAIL'))
\r
489 test_results.append((cat, mu, bw, tcase,'PASS'))
\r
491 with open('testresult.txt', 'w') as reshandle:
\r
492 json.dump(test_results, reshandle)
\r
496 if __name__ == '__main__':
\r
497 START_TIME = datetime.now()
\r
499 END_TIME = datetime.now()
\r
500 logging.debug("Start time: %s, end time: %s", START_TIME, END_TIME)
\r
501 logging.info("Execution time: %s", END_TIME - START_TIME)
\r