Пример #1
0
class QueueingSystem(Model):
    """QueueingSystem model represents a simple queue */*/1/N or */*/1,
    where any distribution can be used for arrival and service times.

    This model consists of four children:
    - `queue`: a model representing the packets queue (`Queue`)
    - `source`: a model representing the packets source (`Source`)
    - `server`: a model representing the packets server (`Server`)
    - `sink`: a model which collects served packets (`Sink`)
    """
    def __init__(self, sim):
        super().__init__(sim)

        arrival = sim.params.arrival
        service = sim.params.service
        queue_capacity = sim.params.queue_capacity

        self.children['queue'] = Queue(sim, queue_capacity)
        self.children['source'] = Source(sim, arrival, index=0)
        self.children['server'] = Server(sim, service)
        self.children['sink'] = Sink(sim)

        # Building connections:
        self.source.connections['queue'] = self.queue
        self.queue.connections['server'] = self.server
        self.server.connections['queue'] = self.queue
        self.server.connections['next'] = self.sink

        # Statistics:
        self.system_size_trace = Trace()
        self.system_size_trace.record(self.sim.stime, 0)
        self.system_wait_intervals = Statistic()

    @property
    def queue(self):
        return self.children['queue']

    @property
    def source(self):
        return self.children['source']

    @property
    def server(self):
        return self.children['server']

    @property
    def sink(self):
        return self.children['sink']

    @property
    def system_size(self):
        return self.queue.size + (1 if self.server.busy else 0)

    def update_system_size(self, index=0):
        assert index == 0
        self.system_size_trace.record(self.sim.stime, self.system_size)

    def add_system_wait_interval(self, value, index=0):
        assert index == 0
        self.system_wait_intervals.append(value)
Пример #2
0
def test_lag_k_estimation_for_positive_k():
    data = [-1, 0, 1, 0] * 10
    st = Statistic(data)
    np.testing.assert_almost_equal(st.lag(0), 1)
    np.testing.assert_almost_equal(st.lag(1), 0)
    np.testing.assert_almost_equal(st.lag(2), -1)
    np.testing.assert_almost_equal(st.lag(3), 0)
Пример #3
0
 def __init__(self, sim, service_mean):
     super().__init__(sim)
     self.__service_mean = service_mean
     self.__busy = False
     # Statistics:
     self.delays = Statistic()
     self.busy_trace = Trace()
     self.busy_trace.record(self.sim.stime, 0)
Пример #4
0
def test_statistic_can_be_created_from_list():
    data = [1, 2, 3]
    st = Statistic(data)
    assert len(st) == 3
    assert not st.empty
    assert st.as_list() == [1, 2, 3]
    assert st.as_tuple() == tuple(data)
    assert st.as_list() is not data  # check that data was copied
Пример #5
0
def test_lag_0_is_always_1():
    st1 = Statistic([10])
    st2 = Statistic([-1, 1] * 5)
    st3 = Statistic(np.random.exponential(1, 7))
    assert st1.lag(0) == 1
    assert st2.lag(0) == 1
    assert st3.lag(0) == 1
Пример #6
0
def test_statistic_mean():
    st = Statistic()
    with pytest.raises(ValueError) as excinfo:
        st.mean()
    assert 'no data' in str(excinfo.value).lower()

    st = Statistic([1])
    assert st.mean() == 1

    st.extend([2, 3])
    assert st.mean() == 2
Пример #7
0
def test_statistic_var():
    st = Statistic()
    with pytest.raises(ValueError) as excinfo:
        st.var()
    assert 'no data' in str(excinfo.value).lower()

    st = Statistic([1])
    assert st.var() == 0

    st.extend([2, 3])
    np.testing.assert_allclose(st.var(), 2 / 3, atol=0.001)
Пример #8
0
class Server(Model):
    """Server module represents a packet server with exponential service time.

    Connections: queue, sink

    Handlers:
    - on_service_end(): called upon service timeout

    Methods:
    - start_service(): start new packet service; generate error if busy.

    Statistics:
    - delays: `Statistic`, stores a set of service intervals
    - busy_trace: `Trace`, stores a vector of server busy status

    Parent: `QueueingSystem`
    """
    def __init__(self, sim, service_mean):
        super().__init__(sim)
        self.__service_mean = service_mean
        self.__busy = False
        # Statistics:
        self.delays = Statistic()
        self.busy_trace = Trace()
        self.busy_trace.record(self.sim.stime, 0)
    
    @property
    def service_mean(self):
        return self.__service_mean
    
    @property
    def busy(self):
        return self.__busy
    
    def on_service_end(self):
        assert self.__busy
        queue = self.connections['queue'].module
        self.__busy = False
        self.busy_trace.record(self.sim.stime, 0)
        if queue.size > 0:
            queue.pop()
            self.start_service()
        self.connections['sink'].module.receive_packet()
        self.parent.update_system_size()

    def start_service(self):
        assert not self.__busy
        delay = exponential(self.service_mean)
        self.sim.schedule(delay, self.on_service_end)
        self.delays.append(delay)
        self.__busy = True
        self.busy_trace.record(self.sim.stime, 1)
Пример #9
0
 def __init__(self, sim, capacity, index=0):
     super().__init__(sim)
     self.__capacity = capacity
     self.packets = deque()
     self.index = index
     # Statistics:
     self.size_trace = Trace()
     self.size_trace.record(self.sim.stime, 0)
     self.num_dropped = 0
     self.arrival_intervals = Intervals()
     self.arrival_intervals.record(sim.stime)
     self.num_arrived = 0
     self.wait_intervals = Statistic()
Пример #10
0
    def __init__(self, sim, service_time, index=0):
        super().__init__(sim)
        self.service_time = service_time
        self.packet = None
        self.index = index

        # Statistics:
        self.service_intervals = Statistic()
        self.busy_trace = Trace()
        self.busy_trace.record(self.sim.stime, 0)
        self.departure_intervals = Intervals()
        self.departure_intervals.record(sim.stime)
        self.num_served = 0
Пример #11
0
 def __init__(self, sim):
     super().__init__(sim)
     self.__source_delays_data = {}
     self.__source_delays = ReadOnlyDict(self.__source_delays_data)
     self.__arrival_intervals = Intervals()
     self.__data_size_stat = Statistic()
     self.__num_packets_received = 0
Пример #12
0
def test_random_source_provides_statistics():
    """Validate that `RandomSource` provides statistics.
    """
    intervals = (10, 12, 15, 17)
    data_size = (123, 453, 245, 321)

    class TestModel(Model):
        def __init__(self, sim):
            super().__init__(sim)
            self.source = RandomSource(
                sim,
                source_id=34,
                dest_addr=13,
                data_size=Mock(side_effect=data_size),
                interval=Mock(side_effect=(intervals + (1000, ))),
            )
            self.network = DummyModel(sim, 'Network')
            self.source.connections['network'] = self.network

    ret = simulate(TestModel, stime_limit=sum(intervals))

    assert ret.data.source.arrival_intervals.as_tuple() == intervals
    assert ret.data.source.data_size_stat.as_tuple() == data_size

    # Also check that we can not replace statistics:
    with pytest.raises(AttributeError):
        from pydesim import Intervals
        ret.data.source.arrival_intervals = Intervals()
    with pytest.raises(AttributeError):
        from pydesim import Statistic
        ret.data.source.data_size_stat = Statistic()

    # Check that source records the number of packets being sent:
    assert ret.data.source.num_packets_sent == 4
Пример #13
0
 def handle_message(self, app_data, sender=None, connection=None):
     sid = app_data.source_id
     if sid not in self.source_delays:
         self.__source_delays_data[sid] = Statistic()
     self.source_delays[sid].append(self.sim.stime - app_data.created_at)
     self.arrival_intervals.record(self.sim.stime)
     self.data_size_stat.append(app_data.size)
     self.__num_packets_received += 1
     self.sim.logger.debug(f'received {app_data}', src=self)
Пример #14
0
def test_statistic_moment_raises_error_when_passed_zero_negative_or_float():
    st = Statistic([1, 2, 3])
    with pytest.raises(ValueError) as excinfo:
        st.moment(0)
    assert 'positive integer expected' in str(excinfo.value).lower()

    with pytest.raises(ValueError) as excinfo:
        st.moment(-1)
    assert 'positive integer expected' in str(excinfo.value).lower()

    with pytest.raises(ValueError) as excinfo:
        st.moment(1.5)
    assert 'positive integer expected' in str(excinfo.value).lower()
Пример #15
0
    def __init__(self, sim, arrival, index):
        super().__init__(sim)
        self.arrival = arrival
        self.index = index

        # Statistics:
        self.intervals = Intervals()
        self.num_generated = 0
        self.delays = Statistic()

        # Initialize:
        self._schedule_next_arrival()
Пример #16
0
    def __init__(self, sim):
        super().__init__(sim)

        arrival = sim.params.arrival
        service = sim.params.service
        queue_capacity = sim.params.queue_capacity

        self.children['queue'] = Queue(sim, queue_capacity)
        self.children['source'] = Source(sim, arrival, index=0)
        self.children['server'] = Server(sim, service)
        self.children['sink'] = Sink(sim)

        # Building connections:
        self.source.connections['queue'] = self.queue
        self.queue.connections['server'] = self.server
        self.server.connections['queue'] = self.queue
        self.server.connections['next'] = self.sink

        # Statistics:
        self.system_size_trace = Trace()
        self.system_size_trace.record(self.sim.stime, 0)
        self.system_wait_intervals = Statistic()
Пример #17
0
def test_lag_k_raises_error_when_passed_negative_or_float():
    st = Statistic([1, 2, 3])
    with pytest.raises(ValueError) as excinfo:
        st.lag(-1)
    assert 'non-negative integer expected' in str(excinfo.value).lower()
    with pytest.raises(ValueError) as excinfo:
        st.lag(2.5)
    assert 'non-negative integer expected' in str(excinfo.value).lower()
Пример #18
0
def test_statistic_moment_evaluation():
    st = Statistic([1])
    assert st.moment(1) == 1
    assert st.moment(2) == 1

    st.extend([2, 3, 4])
    assert st.moment(1) == 2.5
    assert st.moment(2) == 7.5
Пример #19
0
def test_controlled_source_provides_statistics():
    """Validate that `ControlledSource` provides statistics.
    """
    intervals = (10, 12, 15, 17)
    data_size = (123, 453, 245, 321)

    class SourceController(Model):
        def __init__(self, sim, src):
            super().__init__(sim)
            self.iterator = iter(intervals)
            self.src = src
            self.sim.schedule(next(self.iterator), self.handle_timeout)

        def handle_timeout(self):
            self.src.get_next()
            try:
                interval = next(self.iterator)
            except StopIteration:
                pass
            else:
                self.sim.schedule(interval, self.handle_timeout)

    class TestModel(Model):
        def __init__(self, sim):
            super().__init__(sim)
            self.source = ControlledSource(
                sim,
                source_id=34,
                dest_addr=13,
                data_size=Mock(side_effect=data_size),
            )
            self.network = DummyModel(sim, 'Network')
            self.source.connections['network'] = self.network
            self.controller = SourceController(sim, self.source)

    ret = simulate(TestModel, stime_limit=sum(intervals))

    assert ret.data.source.data_size_stat.as_tuple() == data_size
    assert ret.data.source.arrival_intervals.as_tuple() == intervals

    # Also check that we can not replace statistics:
    with pytest.raises(AttributeError):
        from pydesim import Intervals
        ret.data.source.arrival_intervals = Intervals()
    with pytest.raises(AttributeError):
        from pydesim import Statistic
        ret.data.source.data_size_stat = Statistic()

    # Check that source records the number of packets being sent:
    assert ret.data.source.num_packets_sent == 4
Пример #20
0
def test_lag_k_raises_error_when_k_greater_then_length():
    st = Statistic([1, 2])
    error_message = 'statistic has too few samples'
    with pytest.raises(ValueError) as excinfo1:
        st.lag(2)
    with pytest.raises(ValueError) as excinfo2:
        st.lag(3)
    assert error_message in str(excinfo1.value).lower()
    assert error_message in str(excinfo2.value).lower()
Пример #21
0
 def __init__(self, sim, bitrate=inf, header_size=0, preamble=0, ifs=0):
     super().__init__(sim)
     self.bitrate = bitrate
     self.header_size = header_size
     self.preamble = preamble
     self.ifs = ifs
     # State variables:
     self.__started = False
     self.__tx_frame = None
     self.__wait_ifs = False
     self.__rx_frame = None
     # Statistics:
     self.__num_received_frames = 0
     self.__num_received_bits = 0
     self.__rx_busy_trace = Trace()
     self.__rx_busy_trace.record(0, 0)
     self.__num_transmitted_packets = 0
     self.__num_transmitted_bits = 0
     self.__tx_busy_trace = Trace()
     self.__tx_busy_trace.record(0, 0)
     self.__service_time = Statistic()
     self.__service_started_at = None
     # Initialization:
     self.sim.schedule(self.sim.stime, self.start)
Пример #22
0
        def __init__(self, arrival_mean, service_mean):
            # Parameters:
            self.arrival_mean = arrival_mean
            self.service_mean = service_mean

            # System state:
            self.queue_size = 0
            self.server_busy = False

            # Statistics:
            self.system_size_trace = Trace()
            self.server_busy_trace = Trace()
            self.service_intervals = Statistic()
            self.arrivals = Intervals()
            self.departures = Intervals()
Пример #23
0
    def __init__(self, sim):
        super().__init__(sim)

        arrivals = sim.params.arrivals
        services = sim.params.services
        queue_capacity = sim.params.queue_capacity
        n = sim.params.num_stations
        active_sources = {i for i, ar in enumerate(arrivals) if ar is not None}

        if n < 1:
            raise ValueError('num_stations must be >= 1')

        self.queues, self.sources, self.servers = [], [], []
        for i in range(n):
            self.queues.append(Queue(sim, queue_capacity, i))
            self.servers.append(Server(sim, services[i], i))
            if i in active_sources:
                self.sources.append(Source(sim, arrivals[i], i))
            else:
                self.sources.append(None)
        self.sink = Sink(sim)
        self.children['queue'] = self.queues
        self.children['server'] = self.servers
        self.children['sink'] = self.sink
        self.children['sources'] = [src for src in self.sources if src]

        # Connecting modules:
        for i in range(n):
            self.queues[i].connections['server'] = self.servers[i]
            self.servers[i].connections['queue'] = self.queues[i]
            if self.sources[i]:
                self.sources[i].connections['queue'] = self.queues[i]
            if i < n - 1:
                self.servers[i].connections['next'] = self.queues[i + 1]
            else:
                self.servers[i].connections['next'] = self.sink

        # Statistics:
        self.system_size_trace = [Trace() for _ in range(n)]
        for i in range(n):
            self.system_size_trace[i].record(sim.stime, 0)
        self.system_wait_intervals = [Statistic() for _ in range(n)]
Пример #24
0
    def __init__(
        self,
        sim,
        address=None,
        phy_header_size=None,
        mac_header_size=None,
        ack_size=None,
        bitrate=None,
        preamble=None,
        max_propagation=0,
    ):
        super().__init__(sim)

        # Properties:
        self.__address = address
        self.__phy_header_size = (phy_header_size if phy_header_size
                                  is not None else sim.params.phy_header_size)
        self.__mac_header_size = (mac_header_size if mac_header_size
                                  is not None else sim.params.mac_header_size)
        self.__bitrate = bitrate if bitrate is not None else sim.params.bitrate
        self.__preamble = (preamble
                           if preamble is not None else sim.params.preamble)
        self.__max_propagation = max_propagation
        self.__ack_size = (ack_size
                           if ack_size is not None else sim.params.ack_size)

        # State variables:
        self.timeout = None
        self.cw = 65536
        self.backoff = -1
        self.num_retries = None
        self.pdu = None
        self.__state = Transmitter.State.IDLE
        self.__seqn = 0

        # Statistics:
        self.backoff_vector = Statistic()
        self.__start_service_time = None
        self.service_time = Statistic()
        self.num_sent = 0
        self.num_retries_vector = Statistic()
        self.__busy_trace = Trace()
        self.__busy_trace.record(sim.stime, 0)

        # Initialize:
        sim.schedule(0, self.start)
Пример #25
0
    def __init__(self, sim, data_size, source_id, dest_addr):
        """Constructor.

        :param sim: `pydesim.Simulator` object;
        :param data_size: callable without arguments, iterable or constant;
            represents application data size distribution;
        :param source_id: this source ID (more like IP address, not MAC)
        :param dest_addr: destination MAC address.
        """
        super().__init__(sim)
        self.__data_size = data_size
        self.__source_id = source_id
        self.__dest_addr = dest_addr

        # Attempt to build iterators for data size and intervals:
        try:
            self.__data_size_iter = iter(self.__data_size)
        except TypeError:
            self.__data_size_iter = None

        # Statistics:
        self.__arrival_intervals = Intervals()
        self.__data_size_stat = Statistic()
        self.__num_packets_sent = 0
Пример #26
0
def test_statistic_moment_raises_error_when_called_for_empty_statistic():
    st = Statistic()
    with pytest.raises(ValueError) as excinfo:
        st.moment(1)
    assert 'no data' in str(excinfo.value).lower()
Пример #27
0
def test_statistic_append_adds_values():
    st = Statistic()
    st.append(1)
    st.append(20)
    assert st.as_tuple() == (1, 20)
Пример #28
0
def test_statistic_extend_adds_all_items():
    st = Statistic([1])
    st.extend([2, 3])
    assert st.as_tuple() == (1, 2, 3)
Пример #29
0
def test_statistic_is_initially_empty():
    st = Statistic()
    assert len(st) == 0
    assert st.empty
    assert st.as_list() == []
    assert st.as_tuple() == ()
Пример #30
0
def test_statistic_extend_raises_error_when_noniterable_passed():
    st = Statistic()
    with pytest.raises(TypeError) as excinfo:
        st.extend(1)
    assert 'not iterable' in str(excinfo.value).lower()