Ejemplo n.º 1
0
    def _delta_put(self, item: QueueMessage, block=True, timeout=None):
        """Add item to this queue.

        ``None`` is not added to the queue.

        If the queue is full, a Full exception is raised after a timeout so
        that the node pushing to it becomes unblocked to check for an exit
        signal.
        """
        if not isinstance(item, QueueMessage):
            raise TypeError("Only QueueMessage objects can be put on queues")

        if item.msg is not None:
            if not self._type.is_packable(item.msg):
                raise TypeError(
                    f"Message {item.msg} cannot be packed into {self._type}")

            item.msg = self._type.unpack(self._type.pack(item.msg))
            if item.msg is None:
                raise TypeError(
                    f"Message {item.msg} was not packed into {self._type}")

            if timeout is None:
                Queue.put(self, item, block, timeout=self._queue_interval)
            else:
                Queue.put(self, item, block, timeout=timeout)
Ejemplo n.º 2
0
    def setUp(self):
        # obligatory and optional ports
        g = DeltaGraph()
        out_port_obl = OutPort(
            'out',
            Int(),
            InPort(None, Int(), None, 0),
            RealNode(g, [], name='node_name'),
        )
        out_port_opt = OutPort(
            'out',
            Int(),
            InPort(None, Optional(Int()), None, 0),
            RealNode(g, [], name='node_name'),
        )

        # 4 types of queues
        self.delta_queue_obl = DeltaQueue(out_port_obl)
        self.delta_queue_opt = DeltaQueue(out_port_opt)
        self.const_queue_obl = ConstQueue(out_port_obl)
        self.const_queue_opt = ConstQueue(out_port_opt)

        # test messages
        self.msg1 = QueueMessage(1)
        self.msg2 = QueueMessage(2)
        self.msg_with_none = QueueMessage(None)
        self.msg_unpackable = QueueMessage("abcde")

        # these messages should be received
        self.msg1_answer = QueueMessage(1)
        self.msg2_answer = QueueMessage(2)
        self.msg_with_none_answer = QueueMessage(None)
Ejemplo n.º 3
0
    def setUp(self):
        # obligatory and optional ports
        out_port_obl = OutPort(
            NamespacedName("port_name", None),
            DInt(),
            InPort(NamespacedName("port_name", None),
                   DInt(), None, 0),
            None
        )
        out_port_opt = OutPort(
            NamespacedName("port_name", None),
            DInt(),
            InPort(NamespacedName("port_name", None),
                   DOptional(DInt()), None, 0),
            None
        )

        # 4 types of queues
        self.delta_queue_obl = DeltaQueue(out_port_obl)
        self.delta_queue_opt = DeltaQueue(out_port_opt)
        self.const_queue_obl = ConstQueue(out_port_obl)
        self.const_queue_opt = ConstQueue(out_port_opt)

        # test messages
        self.msg1 = QueueMessage(1)
        self.msg2 = QueueMessage(2)
        self.msg_with_none = QueueMessage(None)
        self.msg_unpackable = QueueMessage("abcde")

        # these messages should be received
        self.msg1_answer = QueueMessage(1)
        self.msg2_answer = QueueMessage(2)
        self.msg_with_none_answer = QueueMessage(None)
Ejemplo n.º 4
0
    def get(self) -> QueueMessage:
        """Overwrite ``DeltaQueue.get``, block and timeout are unavailable."""
        if self.empty():
            if self.optional:
                return QueueMessage(None, clk=0)

            raise Empty

        return deepcopy(self._saved_value)
Ejemplo n.º 5
0
    def test_eq(self):
        self.assertEqual(QueueMessage("test", 5), QueueMessage("test", 5))

        self.assertEqual(QueueMessage("test", 5), QueueMessage("test", 1))

        self.assertNotEqual(QueueMessage("test1", 6), QueueMessage("test2", 6))

        self.assertEqual(hash(QueueMessage("blah-blah", 6)), hash("blah-blah"))
Ejemplo n.º 6
0
    def get(self, block=True, timeout=None) -> QueueMessage:
        """If the queue is optional and empty return ``None``,
        otherwise return the item.
        """
        if self.optional and self.empty():
            return QueueMessage(None, clk=0)

        item = Queue.get(self, block=block, timeout=timeout)

        return item
Ejemplo n.º 7
0
            def transfer_pa_to_queue(pa, queue):
                """Emulates the movement of data from the PA to a DeltaQueue
                """
                if not queue.full():

                    # read a single entry from the PA FIFO (the first entry)
                    yield pa.rd_ready_in.eq(1)
                    yield
                    self.assertEqual((yield pa.rd_valid_out), 1)
                    # write to the queue
                    queue.put(QueueMessage((yield pa.rd_data_out)))
                    yield pa.rd_ready_in.eq(0)
                    yield
Ejemplo n.º 8
0
    def test_simulated_run(self):
        """Test if the Interactive Node performs correctly by simulating
        the runtime and the other node.
        """
        inter_node: PythonNode = self.graph.find_node_by_name("blah")
        in_q = self.runtime.in_queues[inter_node.name]["num"]
        out_q = self.runtime.out_queues[inter_node.name][None]

        thread = threading.Thread(target=inter_node.thread_worker,
                                  args=(self.runtime, ))
        thread.start()

        self.assertEqual(out_q.get().msg, 3)
        in_q.put(QueueMessage("3"))
        self.assertEqual(out_q.get().msg, 4)

        thread.join()
        self.assertFalse(thread.is_alive())
Ejemplo n.º 9
0
    def send(self, ret: Union[object, Tuple]):
        """Sends the node's output(s) via out ports.

        If sending is blocked this method will lock the execution of the node
        until unblocked or a stop signal is raised, which shall stop
        the execution of the node.

        Parameters
        ----------
        ret : Union[object, Tuple]
            The return value. It is implied by construction that if it is a
            single object then the node has only one out port, otherwise
            a named tuple is used, with the names of the fields matching
            the names of the out ports.
        """
        # Log only non-trivial output(s)
        if not ((isinstance(ret, Tuple) and all(map(lambda x: x is None, ret)))
                or ret is None):
            self.log.info(f"-> {ret}")

        self._clock += 1
        message = QueueMessage(ret, clk=self._clock)

        for out_q in self.out_queues.values():
            while True:
                try:
                    out_q.put(message)
                    self.check_stop()
                    break
                except Full:
                    self.check_stop()
                except:
                    raise

        # let the Python GIL take a look at the other threads
        sleep(1e-9)
Ejemplo n.º 10
0
    def _index_and_put(self,
                       item: QueueMessage,
                       block=True,
                       timeout=None) -> QueueMessage:
        """In case of ForkedReturn only the requested indexed element will
        be put to the queue, otherwise the entire item.

        ``None`` is not added to the queue.

        If the queue is full, a Full exception is raised after a timeout so
        that the node pushing to it becomes unblocked to check for an exit
        signal.

        Returns a reference to the object added to the queue, which is used
        by ConstQueue for caching.
        """
        if not isinstance(item, QueueMessage):
            raise TypeError("Only QueueMessage objects can be put on queues")

        if self._index is not None:
            msg = item.msg
            to_put_msg = msg[msg._fields.index(self._index)]
            to_put = QueueMessage(msg=to_put_msg, clk=item.clk)
        else:
            to_put = item

        if to_put.msg is not None:
            if not self._type.is_packable(to_put.msg):
                raise TypeError(
                    f"Message {to_put.msg} cannot be packed into {self._type}")
            if timeout is None:
                Queue.put(self, to_put, block, timeout=self._queue_interval)
            else:
                Queue.put(self, to_put, block, timeout=timeout)

        return to_put
Ejemplo n.º 11
0
        def tb_deltaqueue_to_pa(pa):
            def transfer_queue_to_pa(queue, pa):
                """Emulates the movement of data from the DeltaQueue to a PA
                """
                if (yield pa.almost_full) != 1:

                    # write to the PA FIFO
                    yield
                    yield pa.wr_valid_in.eq(1)
                    yield pa.wr_data_in.eq(queue.get().msg)
                    yield
                    yield pa.wr_valid_in.eq(0)
                    yield

            # First create a DeltaQueue object
            # Hack: OutPort needs a "node" object with full_name attribute
            mock_parent_node = SimpleNamespace()
            mock_parent_node.full_name = "parent_node"

            in_port = InPort("in", dl.Int(), None, self.tb_buf_width)
            in_queue = DeltaQueue(OutPort("out", dl.Int(), in_port,
                                          mock_parent_node),
                                  maxsize=self.tb_buf_depth + 1)

            # fill up the DeltaQueue so it has more items than the PA FIFO
            data = []
            for i in range(self.tb_buf_depth + 1):
                # generate random entry
                d = random.randint(0, pow(2, self.tb_buf_width))
                data.append(d)  # add entry to reference data for checking
                in_queue.put(QueueMessage(d))

            # check size of DeltaQueue
            self.assertEqual(in_queue.qsize(), self.tb_buf_depth + 1)

            # ensure PA is ready for consuming
            yield
            self.assertEqual((yield pa.rd_valid_out), 0)
            self.assertEqual((yield pa.wr_ready_out), 1)
            self.assertEqual((yield pa.rd_data_out), 0)

            yield pa.rd_ready_in.eq(0)

            # fill up the PA FIFO from the DeltaQueue until its full
            for i in range(in_queue.qsize()):
                yield from transfer_queue_to_pa(in_queue, pa)

            # check PA FIFO is full
            self.assertEqual((yield pa.fifo.dout), data[0])
            self.assertEqual((yield pa.fifo.we), 0)
            self.assertEqual((yield pa.almost_full), 1)
            self.assertEqual((yield pa.num_fifo_elements), self.tb_buf_depth)
            # check size of DeltaQueue
            self.assertEqual(in_queue.qsize(), 1)

            # read a single entry from the PA FIFO (the first entry)
            yield pa.rd_ready_in.eq(1)
            yield
            self.assertEqual((yield pa.rd_valid_out), 1)
            self.assertEqual((yield pa.rd_data_out), data[0])
            yield pa.rd_ready_in.eq(0)
            yield
            data.pop(0)  # remove first entry from reference data

            # try and add remaining DeltaQueue data to the PA FIFO
            for i in range(in_queue.qsize()):

                if (yield pa.almost_full) != 1:
                    yield from transfer_queue_to_pa(in_queue, pa)

            # check PA FIFO count hasn't changed
            self.assertEqual((yield pa.almost_full), 1)
            self.assertEqual((yield pa.num_fifo_elements), self.tb_buf_depth)
            # check size of DeltaQueue
            self.assertEqual(in_queue.qsize(), 0)

            # check original first entry in PA FIFO is gone and all others remain
            for d in data:
                yield pa.rd_ready_in.eq(1)
                yield
                self.assertEqual((yield pa.rd_data_out), d)
                yield pa.rd_ready_in.eq(0)
                yield
Ejemplo n.º 12
0
 def flush(self):
     """Overwrite ``DeltaQueue.flush``"""
     if self.empty():
         self._saved_value = QueueMessage(Flusher(), clk=-1)
         Queue.put(self, self._saved_value)
Ejemplo n.º 13
0
 def flush(self):
     """Unblock any thread waiting for this queue."""
     if self.empty():
         Queue.put(self, QueueMessage(Flusher(), clk=-1))
Ejemplo n.º 14
0
    def send(self, *args, **kwargs):
        """Sends the node's output(s) via out ports.

        If sending is blocked this method will lock the execution of the node
        until unblocked or a stop signal is raised, which shall stop
        the execution of the node.

        Parameters
        ----------
        ret : typing.Union[object, typing.Tuple]
            The return value. It is implied by construction that if it is a
            single object then the node has only one out port, otherwise
            a named tuple is used, with the names of the fields matching
            the names of the out ports.
        """
        def check_stop_send(out_q: DeltaQueue, message: QueueMessage):
            while True:
                try:
                    out_q.put(message)
                    self.check_stop()
                    break
                except Full:
                    self.check_stop()
                except:
                    raise

        # Log only non-trivial output(s)
        if self.log.isEnabledFor(logging.INFO):
            if args and not all(x is None for x in args):
                self.log.info(f"-> {args}")

            if kwargs and not all(v is None for _, v in kwargs.items()):
                self.log.info(f"-> {kwargs}")

        self._clock += 1

        if len(self.outputs) < len(args) + len(kwargs):
            raise ValueError(
                f"Node {self.full_name} tried to send too many values")

        positional_indicies = []
        for index, send_val in zip(self.outputs.keys(), args):
            positional_indicies.append(index)
            if index in self.out_queues:
                out_q = self.out_queues[index]
                check_stop_send(out_q, QueueMessage(send_val, clk=self._clock))

        for index, send_val in kwargs.items():
            if index not in self.outputs:
                raise NameError(
                    f"Node {self.full_name} tried to send value with "
                    f"invalid keyword {index}")
            if index in positional_indicies:
                raise ValueError(
                    f"Node {self.full_name} tried to send the same "
                    "output positionaly and by keyword.")
            if index in self.out_queues:
                out_q = self.out_queues[index]
                check_stop_send(out_q, QueueMessage(send_val, clk=self._clock))

        # let the Python GIL take a look at the other threads
        sleep(1e-9)