コード例 #1
0
    def simulate(self):
        t = 0
        simulationTime = 10000
        simulationLimit = 10000
        arrivalDataRate = self.utilization / 0.00302  # = (6040 bits / 2e+6 bits/s) s   |
        lastDataPackageTime = 0

        maxEventListSize = 1000

        roundSize = 2000  # packages processed
        transientPhaseSize = 2500  #packages processed
        numberOfRounds = 10
        totalSimulationsPackages = (numberOfRounds *
                                    roundSize) + transientPhaseSize

        consumedEvents = []
        eventQueue = EventQueue()
        voiceChannels = []
        voiceQueue = []
        dataQueue = []
        servedPackages = 0

        totalDataWaitingTimePerRound = [0] * numberOfRounds
        WaitingTimeSamplePerRound = []
        for i in range(numberOfRounds):
            WaitingTimeSamplePerRound.append([])

        totalDataProcessingTimePerRound = [0] * numberOfRounds
        ProcessingTimeSamplePerRound = []
        for i in range(numberOfRounds):
            ProcessingTimeSamplePerRound.append([])

        totalVoiceWaitingTimePerRound = [0] * numberOfRounds
        VoiceWaitingTimeSamplePerRound = []
        for i in range(numberOfRounds):
            VoiceWaitingTimeSamplePerRound.append([])

        X2PerRound = [
            0.000256
        ] * numberOfRounds  # voice package processing time is fixed due to voice package size being fixed
        # T1 = W1 + X1 | T2 = W2 + X2
        Nq1PerRound = [0] * numberOfRounds
        Nq2PerRound = [0] * numberOfRounds

        voicePackagesProcessedPerRound = [0] * numberOfRounds

        dataPackagesProcessedPerRound = [0] * numberOfRounds

        averageVoiceWaitingPerRound = []
        averageDataWaitingPerRound = []
        averageDataServingTimePerRound = []

        transmissions = [{}] * (constants.VOICE_CHANNELS * numberOfRounds)

        in_service_package = None

        # Generating voice channels
        for i in range(constants.VOICE_CHANNELS):
            voiceChannels.append(VoiceChannel(i))

        currentEvent = None
        currentRound = -1

        servedDataPackages = 0

        while servedDataPackages < totalSimulationsPackages:  #t < simulationTime and len(consumedEvents) < simulationLimit:

            # print('Served packages: ' + str(servedPackages))

            if servedDataPackages > transientPhaseSize:
                # We're passed transient phase
                if currentRound != (
                    (servedDataPackages - transientPhaseSize) // roundSize):
                    currentRound = (servedDataPackages -
                                    transientPhaseSize) // roundSize
                    #print(currentRound)
                    #print(servedPackages)
                    #print(roundSize)
                    self.log(str(currentRound))

            if currentRound >= 0 and ((
                (servedDataPackages + 1) - transientPhaseSize) //
                                      roundSize) > currentRound:
                Nq1PerRound[currentRound] = len(dataQueue)
                Nq2PerRound[currentRound] = len(voiceQueue)

            self.log('Simulation time\t' + str(t) + 's\nEvent Queue Size:\t' +
                     str(eventQueue.length()))

            if currentEvent is not None:
                consumedEvents.append(currentEvent)
                self.log('Event consumed\t' + str(currentEvent.type))

                # treat evt
                # if the event is a voice package arrival, the package is created and put in the
                # voice package queue
                if currentEvent.type == EventType.CREATE_VOICE_PACKAGE:
                    voiceQueue.append(
                        Package(PackageType.VOICE_PACKAGE, currentEvent.source,
                                t, currentEvent.transmission))
                    self.log('Voice Package from ' +
                             constants.PACKAGE_SOURCE[currentEvent.source] +
                             ' queued')
                # if the event type means a voice package should be moved from queue to processing
                # the first package in the queue is removed and we create an event to finish serving it
                elif currentEvent.type == EventType.VOICE_PACKAGE_PROCESSING:
                    in_service_package = voiceQueue.pop(0)
                    in_service_package.startServingTime = t
                    if currentRound >= 0:
                        totalVoiceWaitingTimePerRound[currentRound] += (
                            in_service_package.startServingTime -
                            in_service_package.arrivalTime)
                        VoiceWaitingTimeSamplePerRound[currentRound].append(
                            in_service_package.startServingTime -
                            in_service_package.arrivalTime)
                        # only for plot purpose
                        averageDataServingTimePerRound.append(
                            sum(totalDataProcessingTimePerRound) /
                            (sum(dataPackagesProcessedPerRound) + 1))
                        averageVoiceWaitingPerRound.append(
                            sum(totalVoiceWaitingTimePerRound) /
                            (sum(voicePackagesProcessedPerRound) + 1))
                        averageDataWaitingPerRound.append(
                            sum(totalDataWaitingTimePerRound) /
                            (sum(dataPackagesProcessedPerRound) + 1))

                    eventQueue.add(
                        Event(
                            t + (in_service_package.size /
                                 float(constants.CHANNEL_SIZE)),
                            EventType.VOICE_PACKAGE_SERVED,
                            in_service_package.source,
                            in_service_package.transmission))
                    self.log(
                        'Voice Package from ' +
                        constants.PACKAGE_SOURCE[in_service_package.source] +
                        'is in the router')
                # if the event is a voice package finishing being served we clear the router/server
                elif currentEvent.type == EventType.VOICE_PACKAGE_SERVED:
                    self.log(
                        'Voice Package from ' +
                        constants.PACKAGE_SOURCE[in_service_package.source] +
                        ' has finished serving')
                    if currentRound >= 0:
                        voicePackagesProcessedPerRound[currentRound] += 1
                    servedPackages += 1

                    if currentRound >= 0 and in_service_package.transmission in transmissions[
                        (in_service_package.source - 1) +
                        (currentRound * constants.VOICE_CHANNELS)].keys():
                        transmission = transmissions[
                            (in_service_package.source - 1) +
                            (currentRound * constants.VOICE_CHANNELS)][
                                in_service_package.transmission]
                        transmission.processedPackages += 1

                        if transmission.size < transmission.processedPackages:
                            transmission.endTime = t

                    in_service_package = None
                # if the event is a data package arrival, the package is created and put in the
                # data package queue
                elif currentEvent.type == EventType.CREATE_DATA_PACKAGE:
                    dataQueue.append(
                        Package(PackageType.DATA_PACKAGE, currentEvent.source,
                                t, currentEvent.transmission))
                    self.log('Data Package from ' +
                             constants.PACKAGE_SOURCE[currentEvent.source] +
                             ' with size ' +
                             str(dataQueue[len(dataQueue) - 1].size) +
                             ' queued')
                    # here we also create the next data package

                # if the event type means a data package should be moved from queue to processing
                # the first package in the queue is removed and we create an event to finish serving it
                elif currentEvent.type == EventType.DATA_PACKAGE_PROCESSING:
                    in_service_package = dataQueue.pop(0)
                    in_service_package.startServingTime = t
                    if currentRound >= 0:
                        totalDataWaitingTimePerRound[currentRound] += (
                            in_service_package.startServingTime -
                            in_service_package.arrivalTime)
                        WaitingTimeSamplePerRound[currentRound].append(
                            in_service_package.startServingTime -
                            in_service_package.arrivalTime)
                        # only for plot purpose
                        averageDataServingTimePerRound.append(
                            sum(totalDataProcessingTimePerRound) /
                            (sum(dataPackagesProcessedPerRound) + 1))
                        averageVoiceWaitingPerRound.append(
                            sum(totalVoiceWaitingTimePerRound) /
                            (sum(voicePackagesProcessedPerRound) + 1))
                        averageDataWaitingPerRound.append(
                            sum(totalDataWaitingTimePerRound) /
                            (sum(dataPackagesProcessedPerRound) + 1))

                    evt = Event(
                        t + (in_service_package.size /
                             float(constants.CHANNEL_SIZE)),
                        EventType.DATA_PACKAGE_SERVED,
                        in_service_package.source,
                        in_service_package.transmission)
                    if self.preemptive:
                        evt.package_reference = in_service_package
                    eventQueue.add(evt)
                    self.log(
                        'Data Package from ' +
                        constants.PACKAGE_SOURCE[in_service_package.source] +
                        ' with size ' + str(in_service_package.size) +
                        ' is in the router')
                # if the event is a data package finishing being served we clear the router/server
                elif currentEvent.type == EventType.DATA_PACKAGE_SERVED:
                    self.log(
                        'Data Package from ' +
                        constants.PACKAGE_SOURCE[in_service_package.source] +
                        ' with size ' + str(in_service_package.size) +
                        ' has finished serving')
                    in_service_package.endServingTime = t
                    if currentRound >= 0:
                        totalDataProcessingTimePerRound[currentRound] += (
                            in_service_package.endServingTime -
                            in_service_package.startServingTime)
                        dataPackagesProcessedPerRound[currentRound] += 1
                        ProcessingTimeSamplePerRound[currentRound].append(
                            in_service_package.endServingTime -
                            in_service_package.startServingTime)
                        # only for plot purpose
                        averageDataServingTimePerRound.append(
                            sum(totalDataProcessingTimePerRound) /
                            (sum(dataPackagesProcessedPerRound) + 1))
                        averageVoiceWaitingPerRound.append(
                            sum(totalVoiceWaitingTimePerRound) /
                            (sum(voicePackagesProcessedPerRound) + 1))
                        averageDataWaitingPerRound.append(
                            sum(totalDataWaitingTimePerRound) /
                            (sum(dataPackagesProcessedPerRound) + 1))

                    servedPackages += 1
                    servedDataPackages += 1

                    in_service_package = None

                # Note: altough voice and data events could be treated together, the separation will make
                # things easier to track and change for the preemptive scenario

            if self.preemptive:
                if len(
                        voiceQueue
                ) > 0 and in_service_package is not None and in_service_package.type == PackageType.DATA_PACKAGE:
                    totalDataProcessingTimePerRound[currentRound] += (
                        t - in_service_package.startServingTime)
                    ProcessingTimeSamplePerRound[currentRound].append(
                        t - in_service_package.startServingTime)
                    pkg = Package(PackageType.DATA_PACKAGE, 0, t + 0.000256, 0)
                    pkg.size = in_service_package.size  # - (( t - in_service_package.startServingTime ) * constants.CHANNEL_SIZE)
                    dataQueue.insert(0, pkg)
                    eventQueue.remove_with_package(in_service_package)
                    in_service_package = None
                    if pkg.size < 0:
                        print("ERROR SIZE")

            # if there's no package being processed
            if in_service_package is None:
                # we check if there's any voice packages waiting to be processed
                if len(voiceQueue) > 0:
                    eventQueue.add(
                        Event(t, EventType.VOICE_PACKAGE_PROCESSING,
                              voiceQueue[0].source,
                              voiceQueue[0].transmission))
                # in case there's no voice package to be processed we check if there's any data package
                # to process
                # Note: this is due to the fact voice packages have the priority
                elif len(dataQueue) > 0:
                    eventQueue.add(
                        Event(t, EventType.DATA_PACKAGE_PROCESSING, 0, 0))

            # Generate voice arrivals
            self.log('==================================')
            for i in range(len(voiceChannels)):
                if t >= voiceChannels[
                        i].nextTransmission:  # and eventQueue.length() < maxEventListSize:
                    evtTimes = voiceChannels[i].getEventTimes(t)[1:]
                    transmissionId = 0
                    if currentRound >= 0 and len(evtTimes) > 0:
                        transmission = Transmission(evtTimes[0], 0,
                                                    (len(evtTimes) - 1), 0)
                        transmissionId = len(
                            transmissions[i +
                                          (currentRound *
                                           constants.VOICE_CHANNELS)].keys())
                        transmissions[i +
                                      (currentRound * constants.VOICE_CHANNELS
                                       )][transmissionId] = transmission
                    for evtTime in evtTimes:
                        evt = Event(evtTime + t,
                                    EventType.CREATE_VOICE_PACKAGE, i + 1,
                                    transmissionId)
                        # self.log('Voice evt added in ' + str(evt.eventTime) + 's', 0.005)
                        eventQueue.add(evt)
            self.log('==================================')

            # Generate data arrivals
            if t >= lastDataPackageTime:
                evtTime = lastDataPackageTime + np.random.exponential(
                    1 / arrivalDataRate)
                eventQueue.add(
                    Event(evtTime, EventType.CREATE_DATA_PACKAGE, 0, 0))
                lastDataPackageTime = evtTime
                self.log('Data evt added in ' + str(evtTime) + 's')
                #print('Data evt added in ' + str(evtTime) + 's')

            # self.log('---------')
            # for i in range(eventQueue.length()):
            #     self.log(str(eventQueue.get(i).type) + ' ' + str(eventQueue.get(i).eventTime))
            # self.log('---------')

            # getting next event in simulation time and setting simulation time to event's time
            currentEvent = eventQueue.pop()
            # self.log('--------- next event ---------')
            # self.log(str(currentEvent.type) + ' ' + str(currentEvent.eventTime))
            # self.log('---------')
            t = currentEvent.eventTime

        # GENERATE STATISTICS

        finalW1 = 0
        finalStdW1 = 0
        finalW2 = 0
        finalStdW2 = 0
        finalX1 = 0
        finalStdX1 = 0
        finalX2 = 0
        finalStdX2 = 0
        finalT1 = 0
        finalStdT1 = 0
        finalT2 = 0
        finalStdT2 = 0
        finalNq1 = 0
        finalStdNq1 = 0
        finalNq2 = 0
        finalStdNq2 = 0

        delta = 0

        if (self.PLOT):
            if (not (os.path.exists("images"))):
                os.mkdir("images")

            plt.plot(averageDataWaitingPerRound)
            plt.ylabel('E[W1]')
            plt.ylabel('Pacotes servidos')
            plt.title("V.A. W1 com valor rho1 = " + str(self.utilization))
            plt.xlim(xmax=servedPackages)
            plt.savefig('images/W1-' + str(self.utilization) + '.png')
            plt.clf()

            plt.plot(averageDataServingTimePerRound)
            plt.ylabel('E[X1]')
            plt.ylabel('Pacotes servidos')
            plt.title("V.A. X1 com valor rho1 = " + str(self.utilization))
            plt.xlim(xmax=servedPackages)
            plt.savefig('images/X1-' + str(self.utilization) + '.png')
            plt.clf()

            plt.plot(averageVoiceWaitingPerRound)
            plt.ylabel('E[W2]')
            plt.ylabel('Pacotes servidos')
            plt.title("V.A. W2 com valor rho1 = " + str(self.utilization))
            plt.xlim(xmax=servedPackages)
            plt.savefig('images/W2-' + str(self.utilization) + '.png')
            plt.clf()

        stdW1perRound = []
        stdW2perRound = []
        stdX1perRound = []
        stdX2perRound = []
        stdT1perRound = []
        stdT2perRound = []
        stdNq1perRound = []
        stdNq2perRound = []

        for i in range(numberOfRounds):
            W1 = totalDataWaitingTimePerRound[
                i] / dataPackagesProcessedPerRound[i]
            X1 = totalDataProcessingTimePerRound[
                i] / dataPackagesProcessedPerRound[i]
            T1 = X1 + W1
            stdT1perRound.append(T1)
            W2 = totalVoiceWaitingTimePerRound[
                i] / voicePackagesProcessedPerRound[i]
            X2 = X2PerRound[i]
            T2 = X2 + W2
            stdT2perRound.append(T2)
            #print('Round ' + str(i) + ':\nW1: ' + str(W1) + '\tX1: ' + str(X1) + '\tT1: ' + str(T1))
            #print('W2: ' + str(W2) + '\tX2: ' + str(X2) + '\tT2: ' + str(T2) + '\n')

            dt = 0
            dt2 = 0
            dts = [0] * constants.VOICE_CHANNELS
            for j in range(len(transmissions) // constants.VOICE_CHANNELS):
                for k in transmissions[j +
                                       (i * constants.VOICE_CHANNELS)].keys():
                    transmission = transmissions[
                        j + (i * constants.VOICE_CHANNELS)].get(k)
                    if transmission.endTime > 0:
                        dt += (
                            (transmission.endTime - transmission.startTime) /
                            (len(transmissions[j +
                                               (i * constants.VOICE_CHANNELS)])
                             - 1))
                dts[j] = dt

            for j in range(len(transmissions) // constants.VOICE_CHANNELS):
                for k in transmissions[j +
                                       (i * constants.VOICE_CHANNELS)].keys():
                    transmission = transmissions[
                        j + (i * constants.VOICE_CHANNELS)].get(k)
                    if transmission.endTime > 0:
                        dt2 += (
                            ((transmission.endTime - transmission.startTime) -
                             dts[j])**2) / (len(transmissions[
                                 j + (i * constants.VOICE_CHANNELS)]) - 1)

            finalW1 += W1 / numberOfRounds
            stdW1perRound.append(std(WaitingTimeSamplePerRound[i]))

            finalW2 += W2 / numberOfRounds
            stdW2perRound.append(std(VoiceWaitingTimeSamplePerRound[i]))

            finalX1 += X1 / numberOfRounds
            stdX1perRound.append(std(ProcessingTimeSamplePerRound[i]))

            finalX2 += X2 / numberOfRounds

            finalT1 += T1 / numberOfRounds

            finalT2 += T2 / numberOfRounds
            finalNq1 += dataPackagesProcessedPerRound[i] / numberOfRounds
            finalNq2 += voicePackagesProcessedPerRound[i] / numberOfRounds
            dt /= (constants.M1 * numberOfRounds)
            dt2 /= (constants.M2 / (constants.M3 * self.utilization) *
                    numberOfRounds)

        finalNq1 = arrivalDataRate * finalW1
        finalNq2 = constants.VOICE_PACKAGE_ARRIVAL_RATE * finalW2

        finalStdW1 = std(stdW1perRound)
        finalStdW2 = std(stdW2perRound)
        finalStdX1 = std(stdX1perRound)
        finalStdX2 = std(X2PerRound)

        finalStdNq1 = std(dataPackagesProcessedPerRound)
        finalStdNq2 = std(voicePackagesProcessedPerRound)

        finalStdT1 = std(stdT1perRound)

        finalStdT2 = std(stdT2perRound)

        print('E[W1]: ' + str(finalW1))
        print('Std[W1]: ' + str(finalStdW1))
        print('IC para W1: ' +
              str(stats.norm.interval(0.9, loc=finalW1, scale=finalStdW1)))
        print('E[W2]: ' + str(finalW2))
        print('Std[W2]: ' + str(finalStdW2))
        print('IC para W2: ' +
              str(stats.norm.interval(0.9, loc=finalW2, scale=finalStdW2)))
        print('E[X1]: ' + str(finalX1))
        print('Std[X1]: ' + str(finalStdX1))
        print('IC para X1: ' +
              str(stats.norm.interval(0.9, loc=finalX1, scale=finalStdX1)))
        print('E[X2]: ' + str(finalX2))
        print('Std[X2]: ' + str(finalStdX2))
        print('IC para X2: ' +
              str(stats.norm.interval(0.9, loc=finalX2, scale=finalStdX2)))
        print('E[T1]: ' + str(finalT1))
        print('Std[T1]: ' + str(finalStdT1))
        print('IC para T1: ' +
              str(stats.norm.interval(0.9, loc=finalT1, scale=finalStdT1)))
        print('E[T2]: ' + str(finalT2))
        print('Std[T2]: ' + str(finalStdT2))
        print('IC para T2: ' +
              str(stats.norm.interval(0.9, loc=finalT2, scale=finalStdT2)))
        print('E[Nq1]: ' + str(finalNq1))
        print('Std[Nq1]: ' + str(finalStdNq1))
        print('IC para Nq1: ' +
              str(stats.norm.interval(0.9, loc=finalNq1, scale=finalStdNq1)))
        print('E[Nq2]: ' + str(finalNq2))
        print('Std[Nq2]: ' + str(finalStdNq2))
        print('IC para Nq2: ' +
              str(stats.norm.interval(0.9, loc=finalNq2, scale=finalStdNq2)))
        print('E[Delta]: ' + str(dt))
        print('V[Delta]: ' + str(dt2))