diff --git a/calyx-py/calyx/nwc_simple_oracle.py b/calyx-py/calyx/nwc_simple_oracle.py index a9e42d97d4..3b1e3e9823 100644 --- a/calyx-py/calyx/nwc_simple_oracle.py +++ b/calyx-py/calyx/nwc_simple_oracle.py @@ -7,5 +7,5 @@ max_cmds, len = int(sys.argv[1]), int(sys.argv[2]) keepgoing = "--keepgoing" in sys.argv queue = queues.NWCSimple(len) - ans = queues.operate_queue(queue, max_cmds, commands, values, ranks, keepgoing=keepgoing, times=times) + ans = queues.operate_queue(queue, max_cmds, commands, values, ranks, times=times, keepgoing=keepgoing) queue_util.dump_json(commands, values, ans, ranks, times) \ No newline at end of file diff --git a/calyx-py/calyx/pcq_oracle.py b/calyx-py/calyx/pcq_oracle.py index ac88f44b97..1030c9e53a 100644 --- a/calyx-py/calyx/pcq_oracle.py +++ b/calyx-py/calyx/pcq_oracle.py @@ -7,5 +7,5 @@ max_cmds, len = int(sys.argv[1]), int(sys.argv[2]) keepgoing = "--keepgoing" in sys.argv pcq = queues.PCQ(len) - ans = queues.operate_queue(pcq, max_cmds, commands, values, ranks, keepgoing=keepgoing, times=times) + ans = queues.operate_queue(pcq, max_cmds, commands, values, ranks, times=times, keepgoing=keepgoing) queue_util.dump_json(commands, values, ans, ranks, times) \ No newline at end of file diff --git a/calyx-py/calyx/pieo_oracle.py b/calyx-py/calyx/pieo_oracle.py index 5db89e3c8c..e703aee340 100644 --- a/calyx-py/calyx/pieo_oracle.py +++ b/calyx-py/calyx/pieo_oracle.py @@ -7,5 +7,5 @@ max_cmds, len = int(sys.argv[1]), int(sys.argv[2]) keepgoing = "--keepgoing" in sys.argv pieo = queues.Pieo(len) - ans = queues.operate_queue(pieo, max_cmds, commands, values, ranks, keepgoing=keepgoing, times=times) + ans = queues.operate_queue(pieo, max_cmds, commands, values, ranks, times=times, keepgoing=keepgoing) queue_util.dump_json(commands, values, ans, ranks, times) \ No newline at end of file diff --git a/calyx-py/calyx/queue_data_gen.py b/calyx-py/calyx/queue_data_gen.py index f3dec49179..83fa113e11 100644 --- a/calyx-py/calyx/queue_data_gen.py +++ b/calyx-py/calyx/queue_data_gen.py @@ -85,12 +85,14 @@ def dump_json(num_cmds, no_err: bool, queue_size: Optional[int]=None, nwc=False, 3 : pop by value 4 : peek by value - If the `no_err` flag is set and the policy of work-conserving, + If the `no_err` flag is set and the policy is work-conserving, then items are chosen from 0 and 2 using a helper. - If the `always-true` flag is set to True for non-work-conserving policies, + If the `nwc` is set to False and the policy is set as work-conserving, then the predicate is treated as though always true. + Otherwise, the user has the option to + - The `values` memory has `num_cmds` items: random values between 0 and 400. - The `ranks` memory has `num_cmds` items: @@ -100,6 +102,11 @@ def dump_json(num_cmds, no_err: bool, queue_size: Optional[int]=None, nwc=False, - The `ans_mem` memory has `num_cmds` items, all zeroes. - Each memory has a `format` field, which is a format object for a bitvector. """ + + #For work-conserving policies, the predicate should be set as though always true + if not nwc: + always_true = True + commands = { "commands": { "data": ( diff --git a/calyx-py/calyx/queues.py b/calyx-py/calyx/queues.py index 6f21532477..a174e786b9 100644 --- a/calyx-py/calyx/queues.py +++ b/calyx-py/calyx/queues.py @@ -203,20 +203,27 @@ def push(self, val, rank=0, time=0) -> None: if len(self.data) >= self.max_len: raise QueueError("Overflow") + # Left-shift the rank by 32 and add in the insertion count. + # With every push, we modify the insertion count as to reduce any possible duplicate ranks. + heapq.heappush(self.data, RankValue(((rank << 32) + self.insertion_count), (val, time))) self.insertion_count += 1 - def ripe(self, time) -> bool: + def is_ripe(self, time) -> bool: return self.data[0].value[1] <= time def query(self, time=0, val=None, remove=False) -> Optional[int]: if len(self.data) == 0: raise QueueError("Underflow") + #Cache popped values from heap while searching for the first eligible one temp = [] while len(self.data) > 0: - if self.ripe(time) and (val is None or self.data[0].value[0] == val): + #Check for eligibility + if self.is_ripe(time) and (val is None or self.data[0].value[0] == val): + + #If eligible, we pop the element and push all cached elements back into the heap result = heapq.heappop(self.data) if remove else self.data[0] for elem in temp: @@ -224,8 +231,10 @@ def query(self, time=0, val=None, remove=False) -> Optional[int]: return result.value[0] + #After each iteration, pop the current element so we can scan down the heap temp.append(heapq.heappop(self.data)) + #If no eligible elements are found, repopulate the data heap with cached elements for elem in temp: heapq.heappush(self.data, elem) raise QueueError("Underflow") @@ -292,7 +301,7 @@ def __init__(self, max_len: int): self.data = [] self.insertion_count = 0 - def ripe(self, element, time): + def is_ripe(self, element, time): """Check that an element is 'ripe' - i.e. its ready time has passed""" return element["time"] <= time @@ -357,7 +366,7 @@ def query(self, time=0, val=None, remove=False, return_rank=False) -> Optional[i if val is None: #Iterate until we find the first 'ripe' (time-ready) element for x in range(len(self.data)): - if self.ripe(self.data[x], time): + if self.is_ripe(self.data[x], time): if return_rank: return self.data.pop(x) if remove else self.data[x] return self.data.pop(x)["val"] if remove else self.data[x]["val"] @@ -367,7 +376,7 @@ def query(self, time=0, val=None, remove=False, return_rank=False) -> Optional[i #Otherwise, the first element that matches the queried value & is 'ripe' for x in range(len(self.data)): - if self.data[x]["val"] == val and self.ripe(self.data[x], time): + if self.data[x]["val"] == val and self.is_ripe(self.data[x], time): if return_rank: return self.data.pop(x) if remove else self.data[x] return self.data.pop(x)["val"] if remove else self.data[x]["val"] @@ -725,9 +734,11 @@ def __len__(self) -> int: return self.pifo_len -def operate_queue(queue, max_cmds, commands, values, ranks=None, keepgoing=None, times=None): - """Given the four lists: - - One of commands, one of values, one of ranks, one of times: +def operate_queue(queue, max_cmds, commands, values, ranks=None, times=None, keepgoing=None): + """Given the four lists + (One of commands, one of values, one of ranks, one of times): + - Note that `commands` and `values` are required, + while `ranks` and `times` are optional lists depending on the queue type. - Feed these into our queue, and return the answer memory. - Commands correspond to: 0 : pop (for non-work-conserving queues, pop by predicate)