/******************************************************************************* * gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/ * Copyright (C) 2014 SVS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. *******************************************************************************/ package userGeneratedContent.simulatorPlugIns.plugins.delayBox; import staticContent.evaluation.simulator.Simulator; import staticContent.evaluation.simulator.annotations.plugin.Plugin; import staticContent.evaluation.simulator.annotations.property.IntSimulationProperty; import userGeneratedContent.simulatorPlugIns.pluginRegistry.DelayBox; @Plugin(pluginKey = "BASIC_DELAY_BOX", pluginName = "Basic delay" ) public class BasicDelayBox extends DelayBoxImpl { @IntSimulationProperty( name = "Packet Size (byte)", key = "NETWORK_PACKET_PAYLOAD_SIZE", min = 0, max = 9000) // Jumboframe Ethernet frame size private int packetSize = new Integer(Simulator.settings.getProperty("NETWORK_PACKET_PAYLOAD_SIZE")); private class SimplexDelayBox { private final static int NOT_SCHEDULED = -100; private final static int NOT_SET = -101; private int freeSpaceInPacket = this.packetSize; private boolean isBusy; private long lastPulse = NOT_SET; private final int latency; // in ms private int packetSize; private double sendInterval; // abstand in dem pakete geschickt werden // können private long timeOfOutputForNextNotFullPacket; public SimplexDelayBox(int bandwidth, int latency, int packetSize) { this.packetSize = packetSize; this.latency = latency; if (bandwidth != DelayBox.UNLIMITD_BANDWIDTH) { double packetsPerSecond = Math.round((double) bandwidth / (double) this.packetSize); this.sendInterval = 1000 / packetsPerSecond; if (this.sendInterval < 1) { this.sendInterval = 1; this.packetSize = (int) Math.round(bandwidth / 1000d); } } } public long getDelay(int numberOfBytesToSend) { int packetsTransmittedSinceLastCall; long transmitDuration; // when sending begins; see // "delayTillTransmitBegins" long delayTillTransmitBegins; if (numberOfBytesToSend == 0) { return 0; } // Vergangene Zeit seit letztem Aufruf berücksichtigen packetsTransmittedSinceLastCall = this .getNumberOfPacketsTransmittedSinceLastCall(); if (this.timeOfOutputForNextNotFullPacket < Simulator.getNow()) { // Leitung // ist // wieder // frei this.timeOfOutputForNextNotFullPacket = NOT_SCHEDULED; this.freeSpaceInPacket = this.packetSize; this.lastPulse = NOT_SET; this.isBusy = false; } else if (packetsTransmittedSinceLastCall > 0) { this.lastPulse += Math.round(packetsTransmittedSinceLastCall * this.sendInterval); } if (!this.isBusy) { // Leitung frei -> neues Paket aufmachen if (numberOfBytesToSend < this.freeSpaceInPacket) { // kein // neues // Paket // nötig // (Daten // passen in // ein Paket // und // fällen // dieses // nicht // komplett) transmitDuration = 0; delayTillTransmitBegins = Math.round(this.sendInterval); this.freeSpaceInPacket -= numberOfBytesToSend; this.timeOfOutputForNextNotFullPacket = Simulator.getNow() + delayTillTransmitBegins; this.lastPulse = Simulator.getNow(); this.isBusy = true; } else { // neues Paket nötig int packetsNeeded = (int) Math .floor((double) numberOfBytesToSend / (double) this.packetSize); // counts only // full // packets this.freeSpaceInPacket = this.packetSize - (numberOfBytesToSend % this.packetSize); delayTillTransmitBegins = Math.round(this.sendInterval); this.timeOfOutputForNextNotFullPacket = Simulator.getNow() + Math.round(packetsNeeded * this.sendInterval); if (this.freeSpaceInPacket == this.packetSize) { transmitDuration = Math.round(packetsNeeded * this.sendInterval); } else { transmitDuration = Math .round(((double) packetsNeeded + (double) 1) * this.sendInterval); } this.lastPulse = Simulator.getNow(); this.isBusy = true; } } else { // Leitung nicht frei delayTillTransmitBegins = this.timeOfOutputForNextNotFullPacket - Simulator.getNow(); if (delayTillTransmitBegins < 0) { throw new RuntimeException( "ERROR: delayTillTransmitBegins < 0!"); } if (numberOfBytesToSend < this.freeSpaceInPacket) { // kein // neues // Paket // nötig // (Daten // passen in // ein Paket // und // fällen // dieses // nicht // komplett) transmitDuration = 0; this.freeSpaceInPacket -= numberOfBytesToSend; } else { // neues Paket nötig numberOfBytesToSend -= this.freeSpaceInPacket; int packetsNeeded = 1 + (int) Math .floor((double) numberOfBytesToSend / (double) this.packetSize); // counts only // full // packets // ("1 +" // weil // aktuelles // nicht // volles // Paket // auch // gez�hlt // werden // muss) this.freeSpaceInPacket = this.packetSize - (numberOfBytesToSend % this.packetSize); long timeTillNextPulse = Math.round(this.lastPulse + this.sendInterval) - Simulator.getNow(); this.timeOfOutputForNextNotFullPacket += timeTillNextPulse + Math.round(packetsNeeded * this.sendInterval); if (this.freeSpaceInPacket == this.packetSize) { transmitDuration = timeTillNextPulse + Math.round(packetsNeeded * this.sendInterval); } else { transmitDuration = Math .round(((double) packetsNeeded + (double) 1) * this.sendInterval); } } } return delayTillTransmitBegins + transmitDuration + this.latency; } private int getNumberOfPacketsTransmittedSinceLastCall() { int result; if (this.lastPulse == NOT_SET) { result = 0; } else { result = (int) Math.floor((Simulator.getNow() - this.lastPulse) / this.sendInterval); } if (result < 0) { throw new RuntimeException( "ERROR: numberOfPacketsTransmittedSinceLastCall < 0!"); } return result; } } private final boolean hasUnlimitedBandwidthReceive; private final boolean hasUnlimitedBandwidthSend; private final SimplexDelayBox receiveDelayBox; private final SimplexDelayBox sendDelayBox; // bandwidth in MBit/sec // latency in ms public BasicDelayBox(int bandwidthSend, int bandwidthReceive, int latency) { super(); this.sendDelayBox = new SimplexDelayBox(bandwidthSend, latency, packetSize); this.receiveDelayBox = new SimplexDelayBox(bandwidthReceive, latency, packetSize); this.hasUnlimitedBandwidthSend = bandwidthSend == DelayBox.UNLIMITD_BANDWIDTH; this.hasUnlimitedBandwidthReceive = bandwidthReceive == DelayBox.UNLIMITD_BANDWIDTH; } @Override public int getReceiveDelay(int numberOfBytesToReceive) { if (this.hasUnlimitedBandwidthReceive) { return this.receiveDelayBox.latency; } else { int delay = (int) this.receiveDelayBox .getDelay(numberOfBytesToReceive); // System.out.println("reveiceDelay: " +delay); return delay; } } @Override public int getSendDelay(int numberOfBytesToSend) { if (this.hasUnlimitedBandwidthSend) { return this.sendDelayBox.latency; } else { int delay = (int) this.sendDelayBox.getDelay(numberOfBytesToSend); // System.out.println("reveiceDelay: " +delay); return delay; } } /** * Comment * * @param args * Not used. */ /* * public static void main(String[] args) { * * Settings.initialize("properties.txt"); Simulator s = new Simulator(null); * BasicDelayBox sdb = new BasicDelayBox(s, 100, 100, 10); * sdb.getSendDelay(100000000); s.setNow(10000); * sdb.getSendDelay(100000000); s.setNow(14000); * sdb.getSendDelay(100000000); s.setNow(100000); * sdb.getSendDelay(100000000); sdb.getSendDelay(100000000); * sdb.getSendDelay(100000000); sdb.getSendDelay(100000000); * s.setNow(1000000); * sdb.getSendDelay(100000000+100000000+100000000+100000000); * s.setNow(1020000); * sdb.getSendDelay(100000000+100000000+100000000+100000000); * s.setNow(2000000); sdb.getSendDelay(1); sdb.getSendDelay(1); * sdb.getSendDelay(1); sdb.getSendDelay(1); sdb.getSendDelay(1); * sdb.getSendDelay(1); sdb.getSendDelay(1); sdb.getSendDelay(1); * sdb.getSendDelay(1); sdb.getSendDelay(1); s.setNow(2000001); * sdb.getSendDelay(1); sdb.getSendDelay(1); sdb.getSendDelay(1); * sdb.getSendDelay(1); sdb.getSendDelay(1); s.setNow(2000002); * sdb.getSendDelay(1); sdb.getSendDelay(1); sdb.getSendDelay(1); * sdb.getSendDelay(1); sdb.getSendDelay(1); } */ }