/** Executa a simulação, em Loop. */ public void run() { while (!confidenceNotAcceptable()) { setFirstEvents(); // Os dados desta fase são subtraídos das estatísticas finais. TransientPhaseData transientPhaseData = transientPhase(); for (int i = 0; i < SimulationProperties.getEventsInARow(); i++) { // Usado no cenário 1. mapCurrentTimePerCwndMSS.put( currentTime, getSystem().getTxs().get(0).getCongestionWindow() / SimulationProperties.getMSS().doubleValue()); // Armazena dados de vazão ao longo do tempo, para cada Tx. populateFlowPerTx(); handleEvents(); } for (int i = 0; i < getSystem().getRxs().size(); i++) { double a = getSystem().getRxs().get(i).getNextExpectedByte() - transientPhaseData.getExpectedBytes().get(i); double b = currentTime - transientPhaseData.getTransientPhaseEndingTime(); statisticsPerTx.get(i).addSample((a * 8) / (b * 1E-3)); } } }
/** Construtor. Seta valores iniciais e parâmetros iniciais. */ public Simulation() { random = new SimulatedRandom(); for (int i = 0; i < SimulationProperties.getQuantityOfG1() + SimulationProperties.getQuantityOfG2(); i++) { statisticsPerTx.add(new Statistics()); flowPerTx.add(new TreeMap<Double, Double>()); } }
private void handleTxPacketIntoRouter(Event event) { // Sempre que o roteador fica vazio, um novo envio é agendado. if (getSystem().getRouter().getBuffer().quantityOfRemainingPackets().intValue() == 0) { Event sendPack = new Event(EventType.RouterSuccessfullySentPacket); double packTransmission = packTransmission(SimulationProperties.getMSS()); sendPack.setTime(currentTime + packTransmission); getEvents().add(sendPack); } getSystem().getRouter().receivePacket(event.getPack(), currentTime); }
/** * Executa a fase transiente. * * @return Tempo de término da fase e a sequência de bytes esperados nos receptores. */ public TransientPhaseData transientPhase() { for (int i = 0; i < SimulationProperties.getTransientPhaseEvents(); i++) handleEvents(); double transientPhaseEndingTime = currentTime; ArrayList<Long> expectedBytes = new ArrayList<Long>(); for (Rx rx : getSystem().getRxs()) expectedBytes.add(rx.getNextExpectedByte()); return new TransientPhaseData(transientPhaseEndingTime, expectedBytes); }
private void handleRouterSuccessfullySentPacket(Event event) { SACK sack = getSystem().getRouter().sendPackToRx(currentTime); if (sack != null) { // Tráfego de fundo se perde int ackPropagation = getSystem().getTxs().get(sack.getDestination()).getGroup().equals(Group.Group1) ? SimulationProperties.getAckG1PropagationTime() : SimulationProperties.getAckG2PropagationTime(); Event sendSack = new Event(EventType.SackArrives); sendSack.setTime(currentTime + ackPropagation); sendSack.setSack(sack); getEvents().add(sendSack); } // Mais um pacote sai do roteador para um Rx. if (getSystem().getRouter().getBuffer().quantityOfRemainingPackets().intValue() >= 1) { Event sendPack = new Event(EventType.RouterSuccessfullySentPacket); double packTransmission = packTransmission(SimulationProperties.getMSS()); sendPack.setTime(currentTime + packTransmission); getEvents().add(sendPack); } }
/** * A fila de eventos precisa ser setada com eventos iniciais. Este método seta envios de pacotes * de congestionamento (tráfego de fundo) e também envios de pacotes vindo dos Txs. */ private void setFirstEvents() { resetSimulation(); // Prepara o tráfego de fundo. if (SimulationProperties.isWithCongestion()) { Event firstCongestionPack = new Event( EventType .CongestionPacketIntoRouter); // Evento "Pacote de Tráfego de Fundo chegar ao // roteador" firstCongestionPack.setTime(random.generateExponential(1.0 / congestionPacketFrequency)); getEvents().add(firstCongestionPack); } // Prepara os servidores para transmissão de Tx-Rx. for (Tx tx : getSystem().getTxs()) { double propagationDelay = setPropagationDelay(tx); // Fator aleatório além da propagação e da transmissão. // É zero por padrão, mas este intervalo muda nos cenários 2 e 3. double randTime = random.generateDouble() * SimulationProperties.getAssyncInterval(); Event packSent = new Event(EventType.TxPacketHeadsToRouter); // Evento "Pacote sair do Tx" packSent.setTime(randTime + transmissionTime); packSent.setTxIndex(tx.getIndex()); getEvents().add(packSent); Pack pack = tx.sendPacket(randTime); Event firstTcpPack = new Event(EventType.TxPacketIntoRouter); // Evento "Pacote TCP chegar ao roteador" firstTcpPack.setTime(randTime + transmissionTime + propagationDelay); firstTcpPack.setPack(pack); getEvents().add(firstTcpPack); Event possibleTimeout = new Event(EventType.Timeout); // Evento "Possível Timeout do pacote" possibleTimeout.setTime(randTime + tx.getRTO()); possibleTimeout.setTxIndex(tx.getIndex()); pack.setTimeout(possibleTimeout); getEvents().add(possibleTimeout); } }
private void handleCongestionPacketIntoRouterEvent(Event event) { double scheduleTime = random.generateExponential(1.0 / congestionPacketFrequency); Event scheduleNextCongestionPack = new Event(EventType.CongestionPacketIntoRouter); scheduleNextCongestionPack.setTime(currentTime + scheduleTime); getEvents().add(scheduleNextCongestionPack); if (getSystem().getRouter().getBuffer().quantityOfRemainingPackets().equals(0)) { Event sendPack = new Event(EventType.RouterSuccessfullySentPacket); double packTransmission = packTransmission(SimulationProperties.getMSS()); sendPack.setTime(currentTime + packTransmission); getEvents().add(sendPack); } long numberOfCongestionPacks = Math.round(random.generateGeometric(1.0 / congestionPacketFrequency)); for (long i = 0; i < numberOfCongestionPacks; i++) getSystem().getRouter().receivePacket(new Pack(PackType.Congestion, 0), currentTime); }
/** Reseta a lista de eventos e o sistema. */ private void resetSimulation() { system = new Sys(SimulationProperties.getRouterType()); events = new PriorityQueue<Event>(); currentTime = 0.0; }
public double packTransmission(long size) { return 1E3 * size * (8 / SimulationProperties.getCg()); }
/** Responsável pelo loop de simulação. */ public class Simulation { // ------------------------------------------------------------------- // Dados armazenados para os cenários. /** Armazena o valor de Cwnd/MSS ao longo do tempo de simulação. */ private TreeMap<Double, Double> mapCurrentTimePerCwndMSS = new TreeMap<Double, Double>(); /** Armazena (próximo byte esperado)/tempo x tempo para cada TX. */ private ArrayList<TreeMap<Double, Double>> flowPerTx = new ArrayList<TreeMap<Double, Double>>(); // ------------------------------------------------------------------- /** * Engloba todos os Tx e Rx do sistema, e também o roteador, cuja disciplina é passada por * parâmetro. */ private Sys system = new Sys(SimulationProperties.getRouterType()); /** Tempo atual, que muda ao longo da simulação. */ private double currentTime = 0.0; /** * Fila de eventos. É priorizada sobre o tempo de ocorrência. Veja o compareTo() da classe Event. */ private PriorityQueue<Event> events = new PriorityQueue<Event>(); /** Gerador de números aleatórios. */ private SimulatedRandom random; /** Intervalo médio entre chegadas Poisson de tráfego de fundo. 24ms. */ private final int congestionPacketFrequency = 24; private double transmissionTime = SimulationProperties.getMSS() / SimulationProperties.getCs(); private double transmissionTimeMs = transmissionTime * (8 / 1E-3); /** Cada conexão Tx-Rx terá suas estatísticas estimadas */ private ArrayList<Statistics> statisticsPerTx = new ArrayList<Statistics>(); /** Construtor. Seta valores iniciais e parâmetros iniciais. */ public Simulation() { random = new SimulatedRandom(); for (int i = 0; i < SimulationProperties.getQuantityOfG1() + SimulationProperties.getQuantityOfG2(); i++) { statisticsPerTx.add(new Statistics()); flowPerTx.add(new TreeMap<Double, Double>()); } } /** Reseta a lista de eventos e o sistema. */ private void resetSimulation() { system = new Sys(SimulationProperties.getRouterType()); events = new PriorityQueue<Event>(); currentTime = 0.0; } /** * Avalia a qualidade dos resultados com confiança de 90%. * * @return True se é satisfatório. */ private boolean confidenceNotAcceptable() { for (Statistics s : statisticsPerTx) { if (s.getQuantityOfSamples() == 0 || s.getQuantityOfSamples() == 1 || // 2 * significa = Toda a distância, do limite inferior ao superior. (2 * s.getAverageConfidenceIntervalDistance(0.9) > 0.1 * s.estimateAverage())) return false; } return true; } /** * Informa o atraso de propagação de um Tx, com base em seu grupo. * * @param tx O servidor em análise. * @return O atraso de propagação. */ private double setPropagationDelay(Tx tx) { if (tx.getGroup().equals(Group.Group1)) return SimulationProperties.getTP1(); else if (tx.getGroup().equals(Group.Group2)) return SimulationProperties.getTP2(); else // Significa que existe um terceiro grupo. O programa deveria finalizar. throw new RuntimeException(); } /** * A fila de eventos precisa ser setada com eventos iniciais. Este método seta envios de pacotes * de congestionamento (tráfego de fundo) e também envios de pacotes vindo dos Txs. */ private void setFirstEvents() { resetSimulation(); // Prepara o tráfego de fundo. if (SimulationProperties.isWithCongestion()) { Event firstCongestionPack = new Event( EventType .CongestionPacketIntoRouter); // Evento "Pacote de Tráfego de Fundo chegar ao // roteador" firstCongestionPack.setTime(random.generateExponential(1.0 / congestionPacketFrequency)); getEvents().add(firstCongestionPack); } // Prepara os servidores para transmissão de Tx-Rx. for (Tx tx : getSystem().getTxs()) { double propagationDelay = setPropagationDelay(tx); // Fator aleatório além da propagação e da transmissão. // É zero por padrão, mas este intervalo muda nos cenários 2 e 3. double randTime = random.generateDouble() * SimulationProperties.getAssyncInterval(); Event packSent = new Event(EventType.TxPacketHeadsToRouter); // Evento "Pacote sair do Tx" packSent.setTime(randTime + transmissionTime); packSent.setTxIndex(tx.getIndex()); getEvents().add(packSent); Pack pack = tx.sendPacket(randTime); Event firstTcpPack = new Event(EventType.TxPacketIntoRouter); // Evento "Pacote TCP chegar ao roteador" firstTcpPack.setTime(randTime + transmissionTime + propagationDelay); firstTcpPack.setPack(pack); getEvents().add(firstTcpPack); Event possibleTimeout = new Event(EventType.Timeout); // Evento "Possível Timeout do pacote" possibleTimeout.setTime(randTime + tx.getRTO()); possibleTimeout.setTxIndex(tx.getIndex()); pack.setTimeout(possibleTimeout); getEvents().add(possibleTimeout); } } /** * Executa a fase transiente. * * @return Tempo de término da fase e a sequência de bytes esperados nos receptores. */ public TransientPhaseData transientPhase() { for (int i = 0; i < SimulationProperties.getTransientPhaseEvents(); i++) handleEvents(); double transientPhaseEndingTime = currentTime; ArrayList<Long> expectedBytes = new ArrayList<Long>(); for (Rx rx : getSystem().getRxs()) expectedBytes.add(rx.getNextExpectedByte()); return new TransientPhaseData(transientPhaseEndingTime, expectedBytes); } /** Executa a simulação, em Loop. */ public void run() { while (!confidenceNotAcceptable()) { setFirstEvents(); // Os dados desta fase são subtraídos das estatísticas finais. TransientPhaseData transientPhaseData = transientPhase(); for (int i = 0; i < SimulationProperties.getEventsInARow(); i++) { // Usado no cenário 1. mapCurrentTimePerCwndMSS.put( currentTime, getSystem().getTxs().get(0).getCongestionWindow() / SimulationProperties.getMSS().doubleValue()); // Armazena dados de vazão ao longo do tempo, para cada Tx. populateFlowPerTx(); handleEvents(); } for (int i = 0; i < getSystem().getRxs().size(); i++) { double a = getSystem().getRxs().get(i).getNextExpectedByte() - transientPhaseData.getExpectedBytes().get(i); double b = currentTime - transientPhaseData.getTransientPhaseEndingTime(); statisticsPerTx.get(i).addSample((a * 8) / (b * 1E-3)); } } } private void populateFlowPerTx() { for (int i = 0; i < flowPerTx.size(); i++) { flowPerTx.get(i).put(currentTime, system.getRxs().get(i).getNextExpectedByte() / currentTime); } } /** Retira o próximo evento da fila de prioridades, e o trata. */ public void handleEvents() { // Não é esperado que esta lista esteja vazia... if (getEvents().isEmpty()) throw new RuntimeException(); // Evento é retornado e deletado da fila. Event event = getEvents().poll(); currentTime = event.getTime(); switch (event.getType()) { case CongestionPacketIntoRouter: handleCongestionPacketIntoRouterEvent(event); break; case TxPacketIntoRouter: handleTxPacketIntoRouter(event); break; case Timeout: handleTimeout(event); break; case RouterSuccessfullySentPacket: handleRouterSuccessfullySentPacket(event); break; case TxPacketHeadsToRouter: handleTxPacketHeadsToRouter(event); break; case SackArrives: handleSackArrives(event); break; default: throw new RuntimeException(); // Não deve existir outro evento... } } private void handleSackArrives(Event event) { SACK sack = event.getSack(); Tx tx = getSystem().getTxs().get(sack.getDestination()); tx.receiveSack(sack, currentTime); if (!tx.isTransmiting()) if (tx.getNextPacketToSend() < tx.getOldestNotReceivedPacket() + tx.getCongestionWindow()) newTxPacketHeadsToRouter(tx); removeTimeouts(sack, tx); } private void removeTimeouts(SACK sack, Tx tx) { getEvents().remove(sack.getTimeout()); ArrayList<Pack> packs = new ArrayList<Pack>(); for (Pack pack : tx.getNotDeliveredPacks()) packs.add(pack); for (Pack pack : packs) { if (pack.getEndingByte() < sack.getNextExpectedByte()) { getEvents().remove(pack.getTimeout()); tx.getNotDeliveredPacks().remove(pack); } } } private void handleTxPacketHeadsToRouter(Event event) { Tx tx = getSystem().getTxs().get(event.getTxIndex()); if (tx.getNextPacketToSend() < tx.getOldestNotReceivedPacket() + tx.getCongestionWindow()) newTxPacketHeadsToRouter(tx); else tx.setTransmiting(false); } /** * Agenda eventos de envio e de chegada de pacote no roteador. * * @param tx Servidor de saída do pacote. */ private void newTxPacketHeadsToRouter(Tx tx) { Pack nextTcpPack = tx.sendPacket(currentTime); tx.setTransmiting(true); double propagation = setPropagationDelay(tx); Event endOfTransmition = new Event(EventType.TxPacketHeadsToRouter); endOfTransmition.setTime(currentTime + transmissionTimeMs); endOfTransmition.setTxIndex(tx.getIndex()); getEvents().add(endOfTransmition); Event routerReceivesTcp = new Event(EventType.TxPacketIntoRouter); routerReceivesTcp.setTime(currentTime + transmissionTimeMs + propagation); routerReceivesTcp.setPack(nextTcpPack); getEvents().add(routerReceivesTcp); Event timeout = new Event(EventType.Timeout); timeout.setTime(currentTime + tx.getRTO()); timeout.setTxIndex(tx.getIndex()); nextTcpPack.setTimeout(timeout); getEvents().add(timeout); if (tx.getNotDeliveredPacks().contains(nextTcpPack)) { int index = tx.getNotDeliveredPacks().indexOf(nextTcpPack); Pack p = tx.getNotDeliveredPacks().get(index); getEvents().remove(p.getTimeout()); tx.getNotDeliveredPacks().remove(index); } tx.getNotDeliveredPacks().add(nextTcpPack); } private void handleRouterSuccessfullySentPacket(Event event) { SACK sack = getSystem().getRouter().sendPackToRx(currentTime); if (sack != null) { // Tráfego de fundo se perde int ackPropagation = getSystem().getTxs().get(sack.getDestination()).getGroup().equals(Group.Group1) ? SimulationProperties.getAckG1PropagationTime() : SimulationProperties.getAckG2PropagationTime(); Event sendSack = new Event(EventType.SackArrives); sendSack.setTime(currentTime + ackPropagation); sendSack.setSack(sack); getEvents().add(sendSack); } // Mais um pacote sai do roteador para um Rx. if (getSystem().getRouter().getBuffer().quantityOfRemainingPackets().intValue() >= 1) { Event sendPack = new Event(EventType.RouterSuccessfullySentPacket); double packTransmission = packTransmission(SimulationProperties.getMSS()); sendPack.setTime(currentTime + packTransmission); getEvents().add(sendPack); } } public double packTransmission(long size) { return 1E3 * size * (8 / SimulationProperties.getCg()); } private void handleTimeout(Event event) { Tx tx = getSystem().getTxs().get(event.getTxIndex()); if (!tx.isTransmiting()) { tx.handleTimeOutEvent(); newTxPacketHeadsToRouter(tx); } else tx.handleTimeOutEvent(); } private void handleTxPacketIntoRouter(Event event) { // Sempre que o roteador fica vazio, um novo envio é agendado. if (getSystem().getRouter().getBuffer().quantityOfRemainingPackets().intValue() == 0) { Event sendPack = new Event(EventType.RouterSuccessfullySentPacket); double packTransmission = packTransmission(SimulationProperties.getMSS()); sendPack.setTime(currentTime + packTransmission); getEvents().add(sendPack); } getSystem().getRouter().receivePacket(event.getPack(), currentTime); } private void handleCongestionPacketIntoRouterEvent(Event event) { double scheduleTime = random.generateExponential(1.0 / congestionPacketFrequency); Event scheduleNextCongestionPack = new Event(EventType.CongestionPacketIntoRouter); scheduleNextCongestionPack.setTime(currentTime + scheduleTime); getEvents().add(scheduleNextCongestionPack); if (getSystem().getRouter().getBuffer().quantityOfRemainingPackets().equals(0)) { Event sendPack = new Event(EventType.RouterSuccessfullySentPacket); double packTransmission = packTransmission(SimulationProperties.getMSS()); sendPack.setTime(currentTime + packTransmission); getEvents().add(sendPack); } long numberOfCongestionPacks = Math.round(random.generateGeometric(1.0 / congestionPacketFrequency)); for (long i = 0; i < numberOfCongestionPacks; i++) getSystem().getRouter().receivePacket(new Pack(PackType.Congestion, 0), currentTime); } public Sys getSystem() { return system; } public PriorityQueue<Event> getEvents() { return events; } public TreeMap<Double, Double> getMapCurrentTimePerCwndMSS() { return mapCurrentTimePerCwndMSS; } public ArrayList<Statistics> getStatisticsPerTx() { return statisticsPerTx; } public ArrayList<TreeMap<Double, Double>> getFlowPerTx() { return flowPerTx; } }
/** * Informa o atraso de propagação de um Tx, com base em seu grupo. * * @param tx O servidor em análise. * @return O atraso de propagação. */ private double setPropagationDelay(Tx tx) { if (tx.getGroup().equals(Group.Group1)) return SimulationProperties.getTP1(); else if (tx.getGroup().equals(Group.Group2)) return SimulationProperties.getTP2(); else // Significa que existe um terceiro grupo. O programa deveria finalizar. throw new RuntimeException(); }