Thread Links Date Links
Thread Prev Thread Next Thread Index Date Prev Date Next Date Index

[RPRWG] Simula-RPR Shaper error and simulation results.




1. 
I have corrected a major error in my shaper class. It did not wake 
up a client waiting for the shaper value to reach the lowLimit. Now 
it does so (indirectly via the mac data path)
For those of you interested in simulation I have implemented the 
shaper so that it is correct down to the byte/one credit level.
Whenever it is used it remembers the current credit value and the 
current time. The next time it is used ut is first updated by using 
the previous credit value, the time this value was correct and the 
add/increment rate. In this way it is always correct and at the samme 
time consums less simulation resources.  

The new code is at the end of this message. 

2.
 I have re-run the scenario by DVJ and Harry Peng , now with fewer active 
 stations (because this is easier on my laptop), and a class A1 access 
delay timer set to 20 microsec.
 The results can be found at
www.ifi.uio.no/~steing/rpr/sim_res3.pdf
as soon as I can transfer it over this tiny line that is my current Internet 
connection.  
In the scenario I have 8 greedy C stations (1 thru 8), 8 stations sending A1 
  traffic (53 thru 60) at 3% and one station (61) sending A0 traffic at 1%.
 a) the A0 traffic goes perfectly.
 b) the A1 traffic goes as expected:  Because it is shaped by shaper D, 
it stops  when D goes below loLimit, and the A1 traffic stops until the 
access delay timer sense a congestion and fairness message has time to 
take effect (10 ms to send the message upstream and a little mor to stop the 
C traffic.  The graphs show packets from stations 1 thru 8 and 53 thru 60 
as they enter station 62. They also show the value of the shaper in 
station 60 and the size of the STQ in station 60.

Stein

===============================
import java.io.*;
import java.util.*;

/**
 * Shaper class
   SG 22/7/03:  Made as a process in order to wake up the Mac client 
  (indirectly through the Mac data path) that wants to send a packet when 
    the shaper value allows.  
   New methods used internally: act() and shaperSchedule()
 */
public class Shaper extends Unit{
    
    public long startTime;
    
    public long credit=0;

    /**
     * The shapers incremental-rate in bytes/second 
     */
    public long addRate;


    public int serviceClass;
    
    public long incSize;
    public long hiLimit, loLimit;
    public Kernel sim;
    public Datapath dp;

    // mostly for debug purposes:
    public long nextWakeTime = 0;

    public boolean running;
    
    /**
     * Creates a shaper
     * @param s The simulator engine
     * @param d The datapath this shaper belongs to
     * @param start The initial credit value for the shaper
     * @param low This low limit on this shaper
     * @param high The high limit on this shaper
     */
    public Shaper(Kernel s, Datapath d, long start, long low, long high) {
	sim = s; dp = d;
	running = false;
	loLimit = low;
	hiLimit = high;
	credit = start;
	Reporter.reportShaper(this);
	
	
    }
    

    /**
     * Used by the implementation to make this shaper know wich shaper it
     * handles frames for. shaperD shaperM etc..
     */
    public void setClass(int serviceClass) {
	this.serviceClass = serviceClass;
	
    }
    

    /*
     * newRate is of unit Bytes (or credits) / (ageCoef * aginInterval).
       Completely new method July 21. 2003
     */
    public void setRateInit(long newRate) {

       //SG 21/7/03
       	double temp = (double)newRate;
     // one second is 1000000000. nanosec
     // remember addRate is in credits per second
	addRate = (long)(temp / (Const.AGING_INTERVAL * Const.AGE_COEF / 1000000000. ));
     //SG 21/7/03
	update();
    }



    /*
     * newRate is of unit Bytes (or credits) / (ageCoef * aginInterval).
     */
    public void setRate(long newRate) {

       //SG 21/7/03
       update();   // moved from 7 lines below
	double temp = (double)newRate;
     // one second is 1000000000. nanosec
     // remember addRate is in credits per second
	addRate = (long)(1000000000. * temp / (Const.AGING_INTERVAL * Const.AGE_COEF));
     //SG 21/7/03
	shaperSchedule();
	// update();
    }
    
    


    public boolean pass() {
	update();

	return credit >= loLimit;
    }
    
    /**
     * Returns the send value for all other shapers than FE shaper. This is because
     * FE shaper returns an integer while the others return a boolean value
     */
    public boolean send() {
	if (serviceClass == Const.CLASS_C)
	    Const.error("Should not be here. Use passC() instead");
	
	update();
	if (serviceClass == Const.CLASS_A0) dp.shaperA1.update(); 
	if (serviceClass == Const.CLASS_A1) dp.shaperA0.update();
	
	boolean send = true;
	
	switch(serviceClass) {
	case Const.MAC:
	    send = credit >= loLimit;
	    break;
	case Const.CLASS_A0:
	case Const.CLASS_A1:
	    
	    send = (dp.shaperA0.credit >= dp.shaperA0.loLimit) || 
		((dp.shaperA1.credit >= dp.shaperA1.loLimit) && dp.shaperD.pass());
	    break;
	case Const.CLASS_B:
	    send = ((credit >= loLimit) && dp.shaperD.pass());
	    break;
	case Const.DOWN:
	    send = credit >= loLimit;
	    break;
	default:
	    Const.error("Shaper.send()");
	}
	
	return send;
    }

    /**
     * Returns the correct value for the FE shaper. This is the only shaper
     * that is supposed to use this method because it is the only one returning
     * an integer.
     */
    public int sendC() {
	update();

	if (serviceClass != Const.CLASS_C)
	    Const.error("Should not be here. Use pass() instead");

	if (dp.fair.addRateOK() && dp.fair.addRateCongestedOK( ) && dp.shaperD.pass()) { 
	   
	    return Const.MAX_STATIONS;
	}
	if (dp.fair.addRateOK( ) && dp.shaperD.pass()){
	    
	    return dp.fair.hopsToCongestion;
	}
	else {
	    
	    return 0;
	}
    }
    
    public void decreaseCredits(int cred) {
	update();
	credit -= cred;
	running = true;
	Reporter.reportShaper(this);
      shaperSchedule();
    }

	
    
    boolean entryAvailable() {
	
	switch(serviceClass) {
	case Const.IDLE:
	    return false;
	case Const.MAC:
	    return !dp.addMac.empty();
	case Const.CLASS_A0:
	case Const.CLASS_A1:
	    return dp.clnt.classAEntryAvailable(dp.myRingletID);
	case Const.CLASS_B:
	    return (dp.clnt.classBEntryAvailable(dp.myRingletID) != null);
	case Const.CLASS_C:
	    return (dp.clnt.classCEntryAvailable(dp.myRingletID) != null);
	case Const.DOWN:
	    return (dp.clnt.classAEntryAvailable(dp.myRingletID) || 
		    (dp.clnt.classBEntryAvailable(dp.myRingletID) != null) ||
		    (dp.clnt.classCEntryAvailable(dp.myRingletID) != null) ||
		    (Const.shapeStq && dp.EntryInSTQ())
		    );
	default:
	    Const.error("Shaper.running(): Unknown shaper class: "+ serviceClass);
	}

	return true;
		    
    }
  
    public void update() {
	if (!entryAvailable() && credit > loLimit) {
	    credit = loLimit;
	    running = false;
	}
	
	if (running) {
	    long raise = (long)(((sim.time-startTime)*addRate)/1000000000.+1);
	    
	    switch (serviceClass) {
	    case Const.IDLE:
		break;
	    case Const.MAC:
		credit = Math.min(hiLimit, credit+raise);
		break;
	    case Const.CLASS_A0:
		credit = Math.min(hiLimit, credit+raise);
		dp.shaperA1.credit =
		    Math.min(dp.shaperA1.hiLimit,
			     dp.shaperA1.credit+raise);
		break;
	    case Const.CLASS_A1:
		credit = Math.min(hiLimit, credit+raise);
		dp.shaperA0.credit =
		    Math.min(dp.shaperA0.hiLimit,
			     dp.shaperA0.credit+raise);
		break;
	    case Const.CLASS_B:
		credit = Math.min(hiLimit, credit+raise);
		break;
	    case Const.CLASS_C:
		credit = Math.min(hiLimit, credit+raise);
		
		break;
	    case Const.DOWN:

		credit = Math.min(hiLimit, credit+raise);
		break;
	    default:
		Const.error("Should not be here");
	    }
	    
	}

	startTime = sim.time;
     
	Reporter.reportShaper(this);
    }

//SG 21/7/03
public void shaperSchedule() 
{   long  timeToLim;   long length  = 0;
   // update();
  if (credit < loLimit)
       length = loLimit - credit;
  else if ((credit < hiLimit) && entryAvailable())
       length = hiLimit - credit;
  else {length = 0; running = false;}
  // Const.report("Shaper scheduled for time: " +length + " time units" +
  //                        ".  Credits left: " + credit );
  // if (addRate <= 0) System.out.println(" WARNING. Shaper rate zero "); 
  if (length != 0 && addRate > 0)
   {  running = true;
        // timeToLim =  Math.round(length/(addRate/400000));
         //SG 21/7/03 :  Is this correct ???? . BETTER NOW:
           timeToLim =  Math.round(length * 1000000000./addRate +1);
           if (sim.time + timeToLim + 1 < 0) System.out.println(
               "Time to lim: " + timeToLim + " " + length + " " + addRate + " " + credit);
        nextWakeTime = sim.time + timeToLim ;
     //   System.out.println("Shaper Sched " + sim.time + " " + sim.time + timeToLim );
        sim.reschedule (this, sim.time + timeToLim  );
   }
}

//SG 21/7/03
public void act()
{ if (running)
  {  // Const.report(" Shaper activated at time "+ sim.time);
   update();
   
   shaperSchedule();

   dp.canISend();
  }
 }    


} // end class