From 44ff436e1adbd018065ea3557543ffd90e67167f Mon Sep 17 00:00:00 2001 From: Edwin Joy Date: Fri, 15 Apr 2022 13:29:19 +0530 Subject: [PATCH 1/3] Default value of no-count changed --- riscv_isac/coverage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/riscv_isac/coverage.py b/riscv_isac/coverage.py index 5bec5478..ca80bf1e 100644 --- a/riscv_isac/coverage.py +++ b/riscv_isac/coverage.py @@ -986,7 +986,7 @@ def compute_per_line(queue, event, cgf_queue, stats_queue, cgf, xlen, addr_pairs stats_queue.close() def compute(trace_file, test_name, cgf, parser_name, decoder_name, detailed, xlen, addr_pairs - , dump, cov_labels, sig_addrs, window_size, no_count=True, procs=1): + , dump, cov_labels, sig_addrs, window_size, no_count=False, procs=1): '''Compute the Coverage''' global arch_state From 8a575e4d888fc97a2688f2f94e9b465c8c0d15d6 Mon Sep 17 00:00:00 2001 From: Edwin Joy Date: Mon, 18 Apr 2022 12:21:39 +0530 Subject: [PATCH 2/3] Code Cleanup --- riscv_isac/coverage.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/riscv_isac/coverage.py b/riscv_isac/coverage.py index ca80bf1e..e24e7aff 100644 --- a/riscv_isac/coverage.py +++ b/riscv_isac/coverage.py @@ -2,9 +2,6 @@ # See LICENSE.incore for details # See LICENSE.iitm for details -from itertools import islice -import pprint -import time import ruamel from ruamel.yaml import YAML import riscv_isac.utils as utils @@ -22,6 +19,7 @@ import riscv_isac.plugins as plugins from riscv_isac.plugins.specification import * import math +from itertools import islice import multiprocessing as mp from collections.abc import MutableMapping @@ -1093,19 +1091,16 @@ def compute(trace_file, test_name, cgf, parser_name, decoder_name, detailed, xle #Start processes for each in process_list: each.start() - queue_time = 0 for instrObj_temp in iterator: instr = instrObj_temp.instr if instr is None: continue instrObj = (decoder.decode(instrObj_temp = instrObj_temp))[0] - - start_queue = time.time() + # Pass instrObjs to queue for each in queue_list: each.put_nowait(instrObj) - end_queue = time.time() - queue_time = queue_time + (end_queue - start_queue) + logger.debug(instrObj) cross_cover_queue.append(instrObj) if(len(cross_cover_queue)>=window_size): From b4213bd50f6868afe6f9540be2e3777ec5e6d8c8 Mon Sep 17 00:00:00 2001 From: Edwin Joy Date: Mon, 18 Apr 2022 12:41:17 +0530 Subject: [PATCH 3/3] Comments --- riscv_isac/coverage.py | 48 ++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/riscv_isac/coverage.py b/riscv_isac/coverage.py index e24e7aff..83c6f805 100644 --- a/riscv_isac/coverage.py +++ b/riscv_isac/coverage.py @@ -534,7 +534,7 @@ def compute_per_line(queue, event, cgf_queue, stats_queue, cgf, xlen, addr_pairs ''' This function checks if the current instruction under scrutiny matches a particular coverpoint of interest. If so, it updates the coverpoints and - return the same. + returns the same. :param queue: A queue thread to push instructionObject :param event: Event object to signal completion of decoding @@ -567,7 +567,11 @@ def compute_per_line(queue, event, cgf_queue, stats_queue, cgf, xlen, addr_pairs hit_covpts = [] rcgf = copy.deepcopy(cgf) + # Enter the loop only when Event is not set or when the + # instruction object queue is not empty while (event.is_set() == False) or (queue.empty() == False): + + # If there are instructions in queue, compute coverage if queue.empty() is False: instr = queue.get_nowait() @@ -589,16 +593,16 @@ def compute_per_line(queue, event, cgf_queue, stats_queue, cgf, xlen, addr_pairs # create signed/unsigned conversion params if xlen == 32: - unsgn_sz = '>I' sgn_sz = '>i' else: unsgn_sz = '>Q' sgn_sz = '>q' + # if instruction is empty then return if instr is None: - return cgf + # check if instruction lies within the valid region of interest if addr_pairs: @@ -610,7 +614,6 @@ def compute_per_line(queue, event, cgf_queue, stats_queue, cgf, xlen, addr_pairs enable=True # capture the operands and their values from the regfile if instr.rs1 is not None: - rs1 = instr.rs1[0] rs1_type = instr.rs1[1] if instr.rs2 is not None: @@ -621,19 +624,17 @@ def compute_per_line(queue, event, cgf_queue, stats_queue, cgf, xlen, addr_pairs rs3_type = instr.rs3[1] if instr.rd is not None: rd = instr.rd[0] - is_rd_valid = True rd_type = instr.rd[1] else: is_rd_valid = False if instr.imm is not None: imm_val = instr.imm - if instr.shamt is not None: imm_val = instr.shamt + # special value conversion based on signed/unsigned operations if instr.instr_name in unsgn_rs1: - rs1_val = struct.unpack(unsgn_sz, bytes.fromhex(arch_state.x_rf[rs1]))[0] elif instr.is_rvp: rs1_val = struct.unpack(unsgn_sz, bytes.fromhex(arch_state.x_rf[rs1]))[0] @@ -648,9 +649,9 @@ def compute_per_line(queue, event, cgf_queue, stats_queue, cgf, xlen, addr_pairs rs1_val = struct.unpack(sgn_sz, bytes.fromhex(arch_state.f_rf[rs1]))[0] if instr.instr_name in ["fadd.s","fsub.s","fmul.s","fdiv.s","fsqrt.s","fmadd.s","fmsub.s","fnmadd.s","fnmsub.s","fmax.s","fmin.s","feq.s","flt.s","fle.s","fmv.x.w","fmv.w.x","fcvt.wu.s","fcvt.s.wu","fcvt.w.s","fcvt.s.w","fsgnj.s","fsgnjn.s","fsgnjx.s","fclass.s"]: rs1_val = '0x' + (arch_state.f_rf[rs1]).lower() + if instr.instr_name in unsgn_rs2: rs2_val = struct.unpack(unsgn_sz, bytes.fromhex(arch_state.x_rf[rs2]))[0] - elif instr.is_rvp: rs2_val = struct.unpack(unsgn_sz, bytes.fromhex(arch_state.x_rf[rs2]))[0] if instr.rs2_nregs == 2: @@ -974,11 +975,14 @@ def compute_per_line(queue, event, cgf_queue, stats_queue, cgf, xlen, addr_pairs else: hit_covpts = [] else: + # if no_count option is set, return rcgf + # else return cgf if not no_count: cgf_queue.put_nowait(cgf) else: cgf_queue.put_nowait(rcgf) + # Pass statistics back to main process stats_queue.put_nowait(stats) cgf_queue.close() stats_queue.close() @@ -1051,26 +1055,26 @@ def compute(trace_file, test_name, cgf, parser_name, decoder_name, detailed, xle iterator = iter(parser.__iter__()[0]) - # If number of processors to be spawned is more than that available + + # If number of processes to be spawned is more than that available, + # allot number of processes to be equal to one less than maximum available_cores = mp.cpu_count() if procs > available_cores: procs = available_cores - 1 - - # Partiton cgf to chunks - chunk_len = math.ceil(len(cgf) / procs) - chunks = [{k:cgf[k] for k in islice(iter(cgf), chunk_len)} for i in range(0, len(cgf), chunk_len)] # Partiton cgf to chunks chunk_len = math.ceil(len(cgf) / procs) chunks = [{k:cgf[k] for k in islice(iter(cgf), chunk_len)} for i in range(0, len(cgf), chunk_len)] - queue_list = [] - process_list = [] - event_list = [] - cgf_queue_list = [] - stats_queue_list = [] + queue_list = [] # List of queues to pass instructions to daughter processes + process_list = [] # List of processes to be spawned + event_list = [] # List of Event objects to signal exhaustion of instruction list to daughter processes + cgf_queue_list = [] # List of queues to retrieve the updated CGF dictionary from each processes + stats_queue_list = [] # List of queues to retrieve coverpoint hit statistics from each processes - #Initialize processes and queues + # For each chunk of cgf dictionary, spawn a new queue thread to pass instrObj, + # to retrieve updated cgf, to retrieve statistics. An Event object is appended for + # each processes spawned. A Process object is appended against every cgf chunk and initialized. for i in range(len(chunks)): queue_list.append(mp.Queue()) cgf_queue_list.append(mp.Queue()) @@ -1088,16 +1092,18 @@ def compute(trace_file, test_name, cgf, parser_name, decoder_name, detailed, xle ) ) ) - #Start processes + #Start each processes for each in process_list: each.start() + + # This loop facilitates parsing, disassembly and generation of instruction objects for instrObj_temp in iterator: instr = instrObj_temp.instr if instr is None: continue instrObj = (decoder.decode(instrObj_temp = instrObj_temp))[0] - # Pass instrObjs to queue + # Pass instrObjs to queues pertaining to each processes for each in queue_list: each.put_nowait(instrObj)