//Title: Adaptive Cprobing Measurement for available network bandwidth //Function: Using the last measured bandwidth plus a small margin to send the current probing Message // One round of the probing is two probing messages, If the gap between two probing return messages // is changed in a range by 15% of the sending time gap, we think this probing round did not cause // the congestion, so we need Cprobing to measure it again. //Version: //Copyright: Copyright (c) 1998 //Author: xhe //Company: UCCS package Simulator; import javax.swing.*; import java.io.*; import java.util.*; import java.lang.Runnable; public class AdaptiveCprobingMeasurement extends Measurement implements Runnable { double LastMeasuredBandwidth = -1.0; // remember the last time measured available bandwidth double firstReiceptTime = 0; public AdaptiveCprobingMeasurement(JPanel ch,String trafficpattern,double smt,double emt,double tmi, double pmi, boolean trafficoutput) { try { super.ThreadInit(ch,trafficpattern,smt,emt,tmi,pmi,trafficoutput); jbInit(); } catch (Exception e) { e.printStackTrace(); } } private void jbInit() throws Exception { // initilize the newwork topology based on configure file StringTokenizer t; Double DTemp; try { BufferedReader ifile = new BufferedReader(new FileReader("configure.txt")); String s; int iterate=0; // first line for four parameters of PInternalTime, PBIntervalTime // TInternalTime and TBIntervalTime // we get them in the parent class of Measurement s = ifile.readLine(); // skip the first line // second line for five number: how many Router, Link and Road, // the fourth number is the number of the bottleneck Link // the fifth number is the number of how many probing message in one probing route s = ifile.readLine(); t = new StringTokenizer(s,"|"); numOfRouter = Integer.parseInt(t.nextToken()); numOfLink = Integer.parseInt(t.nextToken()); numOfRoad = Integer.parseInt(t.nextToken()); Routers = new Router[numOfRouter+1]; Links = new Link[numOfLink+1]; RoadTable = new RouterTable[numOfRoad]; // generate all the routers: range starts from 1 for(int i=1; i<= numOfRouter; i++) Routers[i] = new Router(this,i); // generate all the links: range starts from 1 for(int i=1; i<= numOfLink; i++) { //int distance = rnd.nextInt(1000)+3; // a random link distance; Links[i] = new Link(this,100000,i,LinkBandwidth); } BottleneckLink = Links[Integer.parseInt(t.nextToken())]; BottleneckLink.BottleneckLink = true; // set the field // retrieve how many messages needed in one Cprobing cycle CprobingNum = Integer.parseInt(t.nextToken()); // create the router table, start from 0 // each line after third line(included) is a single road table while (iterate < numOfRoad) { s = ifile.readLine(); t = new StringTokenizer(s,"|"); int RoadNodeNum = t.countTokens(); RoadTable[iterate] = new RouterTable(iterate,RoadNodeNum); int num=0; String tmp; while (num < RoadNodeNum){ tmp = t.nextToken(); if (tmp.charAt(0) == 'L') // this is a link object RoadTable[iterate].append(Links[Integer.parseInt(tmp.substring(1))],num); else RoadTable[iterate].append(Routers[Integer.parseInt(tmp.substring(1))],num); num++; } // end of one single line, inner while iterate ++; } // end of all road table, outer while EQ = new EventsQueue(RoadTable); ifile.close(); } catch (IOException d) { System.out.print("Error" + d); System.exit(1); } // open a log file for the writing of simulator try { LogFile = new PrintWriter(new FileWriter("log.txt")); PFile = new PrintWriter(new FileWriter("probing.txt")); //EventFile = new PrintWriter(new FileWriter("Events.txt")); } catch(IOException k) { System.out.print("Error" + k); System.exit(1); } } public void run() { // there is only one probing agent. // The first router of the first road is the probing agent. // the first router in each of the rest roads is the traffic generation agent. Message M,NewM; double Start_TrafficTime = 0.1; //double Start_TrafficTime = 6.0; // initializing the start event // for the probing agent // generate the initial probing message, size is static value 46 bytes // the first time always the Cprobing method to create the history bandwidth M = new Message(0,0,"Cprobe-start",46*8,Start_MeaTime); // the message nubmer is useless. EQ.insert(M); if (traffic.trafficType.equals("Web")) { // web traffic pattern M = new Message(0,1,"New-WebMess",46*8,Start_TrafficTime); pareto = new Pareto(); weibull = new Weibull(); } else { // for flat/slope traffic pattern // Generate the first "Traffic-start" type message // always the first traffic agent is to use it to set the bottleneck M = new Message(0,1,"Traffic-start",46*8,Start_TrafficTime); } EQ.insert(M); // generate the last "Simulation-end" message // all arguments except the data type are useless. M = new Message(0,0,"Simulation-end",8,end_time); EQ.insert(M); int MessSize = 500*8; // message size is 500 bytes double SendingTime=0.0; // the start sending time of the current Cprobing round // the current probing method is Adaptive or Cprobing // false means the method is Cprobing // true means the method is Adaptive boolean AdaptiveOrCprobe = false; double DeltaB = 1.0e+6; // 1Mbps speed margin double FirstReturnTime=0; // hold the first return message arrival time in Adaptive probing float GapRange = (float) 0.5; // over 15% gap difference can not be tolerated. // start event dispatching while ((M = EQ.nextItem()) != null) { boolean flag = false; String MessageType = M.MessageType; if (MessageType.compareTo("Simulation-end") == 0) { PFile.close(); LogFile.close(); // close all the opened file in Router for(int i=1; i<= numOfRouter; i++) Routers[i].OFILE.close(); // close all the opened file in Link for(int i=1; i<= numOfLink; i++) Links[i].OFILE.close(); //EventFile.close(); return; } if (MessageType.compareTo("Traffic-start") == 0) { // there is only one Traffic-start message, it starts generating general traffic // generate a new traffic message // the message type is "HTTP-request" NewM = new Message(++MaxMessNum,M.RouterTableNum,"HTTP-request",traffic.TrafficMessSize,M.getArrivalTime()); RoadTable[NewM.RouterTableNum].Node(NewM.NextObjectIndex).EventHandler(NewM); EQ.insert(NewM); BottleneckLink.Tstarting_time = M.getArrivalTime(); BottleneckLink.Transfered_bit = 0; // a new measure cycle // BottleneckLink.end_time = M.getArrivalTime()+TBIntervalTime; // change M type to a new traffic generation message: "New-TrafficMess" // wakeup me to generate the next traffic message in one traffic route // message number is useless. M.MessageType = "New-TrafficMess"; M.setTime(M.getArrivalTime()+TInternalTime); EQ.insert(M); flag = true; } if (!flag && (MessageType.compareTo("New-TrafficMess") == 0)) { // traffic agent generates a new traffic message // generate the next traffic message generation message // generate a new traffic message // change the message type to "HTTP-request" //NewM = new Message(++MaxMessNum,M.RouterTableNum,"HTTP-request",(rnd.nextInt(2400)+100)*8,M.getArrivalTime()); ++MaxMessNum; NewM = new Message(MaxMessNum,M.RouterTableNum,"HTTP-request",traffic.TrafficMessSize,M.getArrivalTime()); //NewM = new Message(++MaxMessNum,M.RouterTableNum,RoadTable[M.RouterTableNum].numOfNode, // M.getArrivalTime(),"HTTP-request",(rnd.nextInt(1900)+100)*8,M.getArrivalTime()); RoadTable[NewM.RouterTableNum].Node(NewM.NextObjectIndex).EventHandler(NewM); EQ.insert(NewM); // set next "New-TrafficMess" generation time // wakeup me to generate the next new traffic message M.setTime(M.getArrivalTime()+TInternalTime); EQ.insert(M); flag = true; } if (!flag && (MessageType.compareTo("AdaptiveCprobe-start") == 0)) { // probing agent generates a couple of Cprobing Message // set the next Cprobing Measurement start time // probing message number always from 1 to CprobingNum SendingTime = M.getArrivalTime(); // the start sending time of the current probing round double NextSendingTime = M.getArrivalTime(); // A new probing round starts // set the probing router's local time because the sending speed is // LastMeasuredBandwidth+DeltaB now. double OldSetting = msgProcessingSpeed; msgProcessingSpeed = LastMeasuredBandwidth + DeltaB; // each round contains two probing message, message size is 1500 bytes. // we count on the time gap between two messages to know if the congestion happen. for (int j=1; j<=2;j++) { // generate the probing mess NewM = new Message(j,M.RouterTableNum,RoadTable[M.RouterTableNum].numOfNode, SendingTime,"CP-request",1500*8,NextSendingTime,0,UnitripProbe); RoadTable[NewM.RouterTableNum].Node(NewM.NextObjectIndex).EventHandler(NewM); EQ.insert(NewM); NextSendingTime = NewM.getArrivalTime(); } msgProcessingSpeed = OldSetting; // reset the old setting for other routers AdaptiveOrCprobe = true; // the current method is Adaptive probing if (traffic.trafficType.equals("Slope")) traffic.ArguChange(true); // generate the next "AdaptiveCprobe-start" message M.setTime(M.getArrivalTime()+PBIntervalTime); EQ.insert(M); flag = true; } if (!flag && (MessageType.compareTo("New-WebMess") == 0)) { double AT = M.getArrivalTime(); // generate a new web request message: "HTTP-request" NewM = new Message(++MaxMessNum,M.RouterTableNum,"HTTP-request",46*8,AT); RoadTable[NewM.RouterTableNum].Node(NewM.NextObjectIndex).EventHandler(NewM); EQ.insert(NewM); BottleneckLink.Tstarting_time = M.getArrivalTime(); BottleneckLink.Transfered_bit = 0; // a new measure cycle //BottleneckLink.end_time = M.getArrivalTime()+TBIntervalTime; // reset the next web message generation time // the time is conform to pareto distribution double Fx = rnd.nextDouble(); double lowerBound = 1.0; double alpha = 1.5; double gap = pareto.getX(Fx,lowerBound,alpha); M.setTime(AT+gap); EQ.insert(M); flag = true; } if (!flag && (MessageType.compareTo("HTTP-request") == 0)) { // wakeup the corresponding object to handle this message // set the wakeup time of the message next time. boolean responseMess_GetToDestination = RoadTable[M.RouterTableNum].Node(M.NextObjectIndex).EventHandler(M); if (!responseMess_GetToDestination) EQ.insert(M); flag = true; } // "HTTP-response" message type is only shown up in Web traffic pattern if (!flag && (MessageType.compareTo("HTTP-response") == 0)) { // wakeup the corresponding object to handle this message // set the wakeup time of the message next time. //double old_ArrivalTime = M.getArrivalTime(); boolean responseMess_GetToDestination = RoadTable[M.RouterTableNum].Node(M.NextObjectIndex).EventHandler(M); if (!responseMess_GetToDestination) EQ.insert(M); // The response message does not back to its source if (responseMess_GetToDestination && traffic.trafficType.equals("Web")) { if (M.MessNum == 0) { // the last returned message generated by one request // how many references will be generated based on pareto distribution double Fx = rnd.nextDouble(); double lowerBound = 1.0; double alpha = 2.43; int numberOfReferences = (int) pareto.getX(Fx,lowerBound,alpha); double GenerationTime = M.getArrivalTime(); for(int i=1; i<= numberOfReferences; i++) { NewM = new Message(i,M.RouterTableNum,"HTTP-request",ProbingMessageSize*8,GenerationTime); RoadTable[NewM.RouterTableNum].Node(NewM.NextObjectIndex).EventHandler(NewM); EQ.insert(NewM); // the time gap between references is conform to weibull distribution Fx = rnd.nextDouble(); //lowerBound = 1.0; alpha = 1.46; double beta = 0.382; double gap = weibull.getX(Fx,alpha,beta); GenerationTime += gap; } } } flag = true; } if (!flag && (MessageType.compareTo("CP-request") == 0)) { // wakeup the corresponding object to handle this message // set the wakeup time of the message next time. NewM = new Message(M.MessNum,M.RouterTableNum,RoadTable[M.RouterTableNum].numOfNode, SendingTime,"CP-request",MessSize,M.getArrivalTime(),M.NextObjectIndex,UnitripProbe); RoadTable[NewM.RouterTableNum].Node(NewM.NextObjectIndex).EventHandler(NewM); EQ.insert(NewM); flag = true; } if (!flag && (MessageType.compareTo("CP-response") == 0)) { // wakeup the corresponding object to handle this message // set the wakeup time of the message next time. NewM = new Message(M.MessNum,M.RouterTableNum,RoadTable[M.RouterTableNum].numOfNode, SendingTime,"CP-response",MessSize,M.getArrivalTime(),M.NextObjectIndex,UnitripProbe); boolean responseMess_GetToDestination = RoadTable[NewM.RouterTableNum].Node(NewM.NextObjectIndex).EventHandler(NewM); if (!responseMess_GetToDestination) EQ.insert(NewM); // The response message does not back to its source else { if (AdaptiveOrCprobe) { // Adpative probe lauches the CP-request message if (M.MessNum == 1) FirstReturnTime = M.getArrivalTime(); if (M.MessNum == 2) { // calculate the sending time gap between two message double switchingtime = M.getSize()/ RouterBandwidth; double OriginalGap = switchingtime + ((msgProcessingTime + M.getSize()/(LastMeasuredBandwidth+DeltaB)) / 1.0); // Weight=1.0 here double MeasuredGap = M.getArrivalTime() - FirstReturnTime; if (MeasuredGap > (OriginalGap * (1+GapRange))) { // congestion happend, the results is useful. //double Measured_Band = (MessSize * 2) / (NewM.getArrivalTime() - NewM.Pstarting_time); double Measured_Band = MessSize / (NewM.getArrivalTime() - FirstReturnTime); LogFile.println("AdaptiveProbing start Time: "+ M.Pstarting_time + " End Time: " + M.getArrivalTime() + " Measured BandWidth: "+ Measured_Band); final double time = M.getArrivalTime(); final double band = Measured_Band*10/LinkBandwidth; Runnable updateJPanel = new Runnable() { public void run() { chart.JPanelUpdate(5,time,band); } }; SwingUtilities.invokeLater(updateJPanel); } // end of if else { // maybe no congestion generated, need Cprobing to measure AdaptiveOrCprobe = false; M.MessageType = "Cprobe-start"; } } // end of if } else { // Cprobing lauches the CP-request message if (NewM.MessNum == 1) firstReiceptTime = NewM.getArrivalTime(); if (NewM.MessNum == CprobingNum) { // the last one return //double Measued_Band = (ProbingMessageSize * 8 * CprobingNum) / (NewM.getArrivalTime() - NewM.Pstarting_time); double Measured_Band = (ProbingMessageSize * 8 * (CprobingNum-1)) / (NewM.getArrivalTime() - firstReiceptTime); LogFile.println("CProbing start Time: "+ M.Pstarting_time + " End Time: " + M.getArrivalTime() + " Measured BandWidth: "+ Measured_Band); LastMeasuredBandwidth = Measured_Band; final double time = M.getArrivalTime(); final double band = Measured_Band*10/LinkBandwidth; Runnable updateJPanel = new Runnable() { public void run() { chart.JPanelUpdate(5,time,band); } }; SwingUtilities.invokeLater(updateJPanel); } } } // end of if flag = true; } if (!AdaptiveOrCprobe && (M.MessageType.compareTo("Cprobe-start") == 0)) { // probing agent generates a couple of Cprobing Message // set the next Cprobing Measurement start time // probing message number always from 1 to CprobingNum SendingTime = M.getArrivalTime(); // the start sending time of the current Cprobing cycle double NextSendingTime = M.getArrivalTime(); // A new Cprobing round starts for (int j=1; j<=CprobingNum;j++) { // generate the Cprobing mess NewM = new Message(j,M.RouterTableNum,RoadTable[M.RouterTableNum].numOfNode, SendingTime,"CP-request",MessSize,NextSendingTime,0,UnitripProbe); RoadTable[NewM.RouterTableNum].Node(NewM.NextObjectIndex).EventHandler(NewM); EQ.insert(NewM); NextSendingTime = NewM.getArrivalTime(); } if (!flag) { // generate the next "AdaptiveCprobe-start" message M.MessageType = "AdaptiveCprobe-start"; M.setTime(M.getArrivalTime()+PBIntervalTime); EQ.insert(M); } } EQ.remove(); // remove the first message from the event queue } // end of while } public void UpdateLog (double output_time) { if (output_time >= Start_MeaTime) { // update the chart long QueuingSize =(long)(BottleneckLink.Transfered_bit - (BottleneckLinkBandwidth*TBIntervalTime)); //long QueuingSize = EQ.getQueueSize(BottleneckLink,output_time); if (QueuingSize < 0) QueuingSize = 0; //double Available_BandWidth = LinkBandwidth - (BottleneckLink.Transfered_bit/TBIntervalTime); //if (QueuingSize > 0) double Available_BandWidth = BottleneckLinkBandwidth*((double)(ProbingMessageSize*8)/(ProbingMessageSize*8+QueuingSize)); LogFile.println("Starting Time: "+ BottleneckLink.Tstarting_time + " End Time: " + output_time + " Available BandWidth: "+ Available_BandWidth+" | " + QueuingSize + " | " +traffic.TIntervalTime + " | "+EQ.getNumElements()); //temp_band = Available_BandWidth; if (trafficoutput) { final double time = output_time; final double band = Available_BandWidth*10/LinkBandwidth; Runnable updateJPanel = new Runnable() { public void run() { chart.JPanelUpdate(2,time,band); } }; SwingUtilities.invokeLater(updateJPanel); } } //traffic.ArguChange(output_time > Start_MeaTime); } }