/* * Server.java * * server data and operations * * Created by: Arthur L. Blais * Visteon/Ford Microelectronics Inc. * Colorado Springs, CO * * Date: Fri Sep 24 08:43:13 MDT 1999 * **************************************************************************** * * Notes and Acknowledgments: * * Request sizes are generated from one of two distributions modeled by * Barford and Crovella at Boston University. The first distribution is a * table of values generated with a curve fitted to a lognormal distribution. * The lognormal distribution represents the distribution body. The * second distribution represents the tail. The The values for alpha and * k (lowerBound) were fitted the pareto distribution to measured data. * Paul A. Barford and Mark Crovella, Generating Representitive Web * Workloads for Network and Server Performance Evaluation, Technical * Paper BU-CS-07-006, Boston University, December 31, 1997 * **************************************************************************** * * Class Methods * * **************************************************************************** */ import java.io.*; import java.util.*; import java.text.*; public class Server { int id; // server id long requestCount = 0; // number of requests received long requestsComplete = 0; // number of requests completed long totalQueueWaitTime = 0; // queue wait time long totalQueueLength = 0; // for calc average queue length long currentQueueLength = 0; // current number of queued requests int connectionCount = 0; // current number of connections int maxConnections; // maximum number of connections long totalBytes = 0; // total bytes transfered Queue requestQueue; // request queue Request connection[]; // requests being processed double processorPower; // relative processing power double clientThroughput = 10. * 1024.; // default 10 kilobytes per second static Random randomNumber; // psuedo random number generator long table [] = { 200,263,312,356,396,433,469,503,537,570, 602,634,666,697,729,760,791,823,854,886, 918,950,982,1014,1047,1080,1114,1148,1182,1217, 1252,1288,1325,1362,1399,1437,1476,1516,1556,1597, 1639,1681,1725,1769,1815,1861,1909,1957,2007,2058, 2110,2164,2219,2276,2334,2394,2456,2519,2585,2652, 2722,2795,2869,2947,3027,3111,3197,3287,3381,3479, 3582,3689,3802,3920,4044,4175,4313,4459,4615,4780, 4957,5147,5350,5571,5810,6071,6357,6674,7028,7426, 7879,8403,9020,0,0,0,0,0,0,0 }; // Statistical Variables long lastStatTime = 0; // time last stats done long lastRequestCount = 0; // last requestCount long lastRequestsComplete = 0; // for last stat interval long lastTotalBytes = 0; // last totalKB long lastTotalQueueLength = 0; long lastTotalQueueWaitTime = 0; long lastTotalQueueUpdate = 0; // last queue totals update /* * Server */ public Server ( int n, double p, int c, long seed ) { id = n; processorPower = p; randomNumber = new Random( seed ); requestQueue = new Queue(); maxConnections = c; connection = new Request[ maxConnections ]; for ( int i = 0; i < maxConnections; i++ ) { connection[i] = null; } } /** * newRequest * */ void newRequest( Request r ) { long requestSize = getRequestSize(); r.setSize( requestSize ); requestQueue.enqueue( r ); updateTotalQueueLength( r.getRequestTime() ); currentQueueLength++; requestCount++; } /** * dequeueRequest * * get the complete time from current request, it's done * dequeue the next request and put it into the current request * update the request wait time * decrement the queue length * update the total queue length (for avg queue len calc) */ Request dequeueRequest() { Request currentRequest = ( Request ) requestQueue.dequeue(); currentQueueLength--; int i = 0; while ( i < maxConnections ) { if ( connection[i] == null ) { connection[i] = currentRequest; connectionCount++; return currentRequest; } i++; } return null; } /** * deleteCurrentRequest */ void deleteCurrentRequest( Request r ) { int i = 0; this.updateStats( r ); while ( i < maxConnections ) { if ( connection[i] == r ) { connection[i] = null; connectionCount--; requestsComplete++; totalQueueWaitTime += r.getWaitTime(); break; } i++; } return; } /** * getId */ int getId() { return id; } /** * getRequestSize * */ private long getRequestSize() { double tailStart = 0.93; double alpha; double lowerBound; double Fx; long x; Fx = randomNumber.nextDouble(); //System.out.println( "F(x): " + Fx ); if ( Fx < tailStart ) { // value in the distribution body use table lookup int numberOfBins = table.length; int i = (int) ( Fx * table.length ); x = table[i]; //System.out.println( "F(x): " + Fx +" Table[" + i + "] " + table[i] ); } else { // value in the distribution tail use Pareto distribution alpha = 1.0; lowerBound = 9020.0; Fx = randomNumber.nextDouble(); x = ( ( long ) Pareto.getX( Fx, lowerBound , alpha ) ); //System.out.println( "size: " + x + " " + F1x + " " + lowerBound + " " + alpha); } return x; } /** * getRequestExecutionTime * * input: size (bytes) * output: time ( milliseconds ) * * Assumed Default Throughput: 10 Kilobytes per second per connection * times the processor power. */ long getRequestExecutionTime( long size ) { double throughput = clientThroughput * processorPower; // bytes per second double time = ( size / throughput ) * 1000; // milliseconds long execTime = ( long ) ( time + .5 ); // round up & truncate return ( execTime ); } /** * getFileAccessTime * * Returns the time it takes for the server to access the requested * file based upon the server load, and disk caching. * * Version 1 assumes no caching */ long getFileAccessTime() { long defaultTime = 100; double accessTime = connectionCount * defaultTime / processorPower; return ( ( long ) accessTime ); } /** * requestQueueNotEmpty * */ boolean requestQueueNotEmpty() { return( requestQueue.notEmpty() ); } /** * serverBusy */ boolean serverBusy() { if ( this.hasConnection() ) { return false; } return true; } /** * hasConnection */ boolean hasConnection() { int i = 0; if ( connectionCount < maxConnections ) { return true; } return false; } /** * isIdle */ boolean isIdle() { return this.hasConnection(); } /** * getRequestCount */ long getRequestCount() { return requestCount; } /** * getRequestsComplete */ long getRequestsComplete() { return requestsComplete; } /** * getTotalQueueWaitTime */ long getTotalQueueWaitTime() { return totalQueueWaitTime; } /** * getQueueLength */ long getCurrentQueueLength() { return currentQueueLength; } /** * updateTotalQueueLength */ void updateTotalQueueLength( long t ) { //System.out.print( id + "\t" + t + "\t" + lastTotalQueueUpdate + "\t" + currentQueueLength + "\t" + totalQueueLength ); long length; long dt = t - lastTotalQueueUpdate; length = dt * currentQueueLength; totalQueueLength += length; lastTotalQueueUpdate = t; //System.out.println( "\t" + totalQueueLength ); } /** * getTotalQueueLength */ long getTotalQueueLength() { return totalQueueLength; } /** * getTotalBytes * */ long getTotalBytes() { return totalBytes; } /** * updateStats * */ void updateStats( Request r ) { if ( r.getStartTime() < lastStatTime ) { // job started before last stat time long ctime = r.getCompleteTime(); double xferRate = clientThroughput * processorPower / 1000.0; // bytes per ms double bytes = ( ctime - lastStatTime ) * xferRate; bytes += 0.5; // rounding totalBytes += ( long ) bytes; } else { // job started and completed during stat interval totalBytes += r.getSize(); } //totalQueueWaitTime += r.queueWaitTime(); long completeTime = r.getCompleteTime(); updateTotalQueueLength( completeTime ); } /** * printStats */ void printStats( long statTime, FileWriter f ) throws IOException { DecimalFormat df1 = new DecimalFormat( "#,###,###,###,###" ); DecimalFormat df2 = new DecimalFormat( "###,##0.0000" ); // get the request totals long currentRequestCount = requestCount - lastRequestCount; long currentRequestsComplete = requestsComplete - lastRequestsComplete; // calculate the max transfer rate ( bytes/ms ) double xferRate = clientThroughput * processorPower * maxConnections / 1000.0; // calculate the utilization this.updateTotalBytes( statTime ); long currentTotalBytes = totalBytes - lastTotalBytes; double utilization = ( double ) totalBytes / ( ( double )( statTime ) * xferRate ); double currentUtilization = ( double ) ( currentTotalBytes ) / ( ( double ) ( statTime - lastStatTime ) * xferRate ); double avgWaitTime = ( double ) totalQueueWaitTime / ( double ) requestsComplete; avgWaitTime = avgWaitTime / 1000; // convert to seconds long currentWaitTime = totalQueueWaitTime - lastTotalQueueWaitTime; double lastAvgWaitTime = 0; if ( currentRequestCount > 0 ) { lastAvgWaitTime = ( double ) currentWaitTime / ( double ) currentRequestCount; } lastAvgWaitTime = lastAvgWaitTime / 1000; // convert to seconds lastTotalQueueLength += currentQueueLength; // format data for output long hour = ( statTime / 3600000 ) % 24; long reportTime = statTime / 1000; long totalKB = totalBytes / 1024; //long currentTotalKB = currentTotalBytes / 1024; double avgQueueLength = ( double ) lastTotalQueueLength / ( double ) ( reportTime / 1000 ); // divide by number of reports String outputStr = id + "\t" + hour + "\t" + reportTime + "\t" + requestCount + "\t" + currentRequestCount + "\t" + printAlignColumn( df1.format( totalKB ), 12 ) + "\t" + currentQueueLength + "\t" + printAlignColumn( df2.format( avgQueueLength ), 8 ) + "\t" + printAlignColumn( df2.format( avgWaitTime ), 8 ) + "\t" + printAlignColumn( df2.format( lastAvgWaitTime ), 8 ) + "\t" + df2.format( utilization ) + "\t" + df2.format( currentUtilization ); if ( f != null ) { f.write( outputStr ); f.write( "\n" ); f.flush(); } else { System.out.println( outputStr ); } lastStatTime = statTime; lastRequestCount = requestCount; lastTotalBytes = totalBytes; lastTotalQueueWaitTime = totalQueueWaitTime; } //printStats /* * updateTotalBytes * * Calculate the total bytes transfered by adding the bytes * transfered of the currently connected requests to the * totalBytes at the current stat time */ void updateTotalBytes( long stattime ) { int i; long starttime; double bytes; double xferRate = clientThroughput * processorPower / 1000.0; // bytes per ms for ( i = 0; i < maxConnections; i++ ) { if ( connection[i] != null ) { starttime = connection[i].getStartTime(); if ( starttime < lastStatTime ) { starttime = lastStatTime; } bytes = ( stattime - starttime ) * xferRate; bytes += 0.5; // rounding totalBytes += ( long ) bytes; } } } /** * printAlignColumn */ static String printAlignColumn( String s, int c ) { String blanks = " "; for ( int p = s.length(); p < c; p++ ) { blanks += " "; } return ( blanks + s ); } } // class Server