References

Birtwhistle 73
G.M. Birtwhistle, O-J Dahl, B. Myhrhaug, K. Nygaard : Simula Begin, Academic Press 1973.
Eliëns 94
A. Eliëns : Hush - a C++ API for Tcl/Tk
Gross 85
D. Gross, C.M. Harris : Fundamentals of queuing theory, John Wiley \& Sons 1985.
Kalvelagen 90
E. Kalvelagen, H.C. Tijms : Exploring Operations Research \& Statistics in the Micro Lab, Prentice Hall 1990.
Kiviat 69
P.J. Kiviat, R. Villanueva, H.M. Markowitz : The Simscript II, Prentice Hall 1969.
Stroustrup 91
B. Stroustrup : The C++ Programming Language, Addison Wesley 1991.
Watkins 93
K. Watkins : Discrete Event Simulation in C, McGraw-Hill 1993.

Appendix

Contents -- [-<--%--^-->-]

Probability distributions

[-<--%--^-->-] The generator class provides the following probability distributions as described in [Watkins 93] and [Kalvelagen 90] for transforming a random number stream. Some use the \Gamma function, which is defined as :
\Gamma(\alpha) = \int_{0}^{\infty}z^{\alpha}e^{-z}dz
The distributions are :

The generator and some tests

[-<--%--^-->-] In this section we present the generator and some tests. The generator uses the linear congruential method as described in [Watkins 93] to produce its random numbers (section B.1.). The tests cover the randomness of the random number stream (section B.2.), the quality of the distributions that transform the stream (section B.3.) and the quality of the event scheduling routine (section B.4.).

The linear congruential generator

The linear congruential generator consists of the following four numbers : from which a sequence of random numbers , n \geq 0 can be generated by setting
X_{n} = (aX_{n-1} + c) mod m
These numbers should be chosen in such a way, that the random number stream provides a long cycle time and has good statistical properties. The parameter values, that the library sim uses, are
a = 663608941, c = 0 and m = 2^{32}, yielding the following sequence :
X_{n} = 663608941X_{n-1} mod $2^{32}
This generator has a period of $10^{9}, which is plenty for most computer models and has due to computer representation 16.7 million different values equally spaced in the interval [0,1). Furthermore, it has passed several statistical tests.

Tests on the random number stream

We wrote the following tests for the random number stream :

Empirical tests

  • the Uniformity Test. The interval is split up into 10 intervals. For randomness we would expect the counts in each interval to be equal. A \chi^{2} test is performed with each member of the expected array equal to the number of random fractions divided by 10. We also wrote two variations of this test. The first one groups the random numbers into pairs, the second one into triples. The expected values of each pair and triple are then the number of random fractions divided by 2*100 and by 3*1000 respectively.
  • The Poker Test. In this test we multiply the random fractions with 10 and cast them to integers. Furthermore we group the sequence of integers into sequences of five consecutive integers. The frequency of the following categories is recorded :
    • {1} - All of the same or two different integers in a group.
    • {2} - Three different integers in a group.
    • {3} - Four different integers in a group.
    • {4} - Five different integers in a group.
    A \chi^{2} test is performed with the following expected values for each category (n is the number of fractions):
    • {1} - 0.0136 n.
    • {2} - 0.1800 n.
    • {3} - 0.5040 n.
    • {4} - 0.3024 n.
  • the Gap Test. An interval between a and b is defined $(0 < a < b < 1). Each random number is replaced with 0 if outside and with 1 if inside the interval. We are interested in the lengths of the gaps. The expected value of a gap of length k is :
    $(b-a) (1-(b-a))^{k} n
  • the Coupon Collector Test. In this test we divide the interval [0,1) into five intervals [0,0.2),..,[0.8,1). The number of random fractions to get at least a count of 1 in each interval is counted. We define 16 categories as follows :
    • {1} - sequence of 5.
    • {2} - sequence of 6.
    • {..}
    • {15} - sequence of 19.
    • {16} - sequence of 20 or more.
    The expected values of each category are calculated as :
    p_{i} n, 1 \leq i \leq 16
    with n the number of fractions and p_{i} from the following sequence of probabilities : 0.03840000, 0.07680000, 0.09984000, 0.10752000, 0.10450944, 0.09547776, 0.08381645, 0.07163904, 0.06011299, 0.04979157, 0.04086200, 0.03331007, 0.02702163, 0.02184196, 0.01760857, 0.07144851
In all cases we fill an array with the expected values for the taken test and perform a
\chi^{2} test with the observed values with the method from the analysis class. The hypothesis of randomness is rejected if the probability is less then 0.05 (no randomness) or more then 0.95 (fabricated) in 95% or more of the experiments.

The serial correlation test

The statistical correlation between two consecutive numbers from a linear congruential generator is given by
Corr(x_{i},x_{i+1}) = \frac{1}{a}[1 - \frac{6c}{m} + 6(\frac{c}{m})^{2} + \epsilon]
with
|\epsilon| \leq \frac{a+6}{m}
A generator can be treated as correlated if the correlation is greater than 0.01. In our generator we have
Corr(x_{i},x_{i+1}) \leq \frac{1}{663608941}[1 + 0.16] = 1.75 10^{-9}
So it exhibits adequately low autocorrelation.

A test on the distributions

The distributions that transform the random number stream are tested with the methods from the analysis class. We fill a histogram with values taken from the specified probability distribution with the given parameters and fit the theoretical values on the histogram with these parameters. The hypothesis of randomness is rejected if the
\chi^{2} probability is less then 0.05 or more then 0.95 in 95% or more of the experiments .

A test on the event scheduling strategy

The event scheduling strategy is tested by running a general queuing simulation. The arrival and service pattern (M or D), the number of service points and the arrival and service rate are the input for the simulation. The results are compared with the analytical values with the methods of the analysis class. If these values lie within the 95% interval of the simulation results on 95% or more of the experiments the event scheduling strategy passed the test. For example, if we look at the analytical values of the M/M/1 queue, with an arrival rate of 3 and a service rate of 4, the mean of the queue size, according to [Gross 85], is equal to
\frac{\lambda^{2}}{\mu^{2}-\lambda\mu}
where
\lambda is the number of arriving customers per time unit and \mu is the service rate per time unit. So the queue size in our M/M/1 queue is equal to \frac{9}{4}. The mean time spent queuing is
\frac{\lambda}{\mu^{2}-\lambda\mu}
or in our M/M/1 queue
\frac{3}{4}. These values do indeed agree with the results of the simulation program of the M/M/1 queue, taking the confidence intervals into account.

The analysis class

[-<--%--^-->-] The complete interface of the analysis class :

   typedef enum {PERCENT90,PERCENT95,PERCENT99} level;

   interface analysis 
   {
     analysis(histogram* h); // taking histogram to analyze
     virtual ~analysis();    // destructor
   
     void reset();  // reset output structures

     double confidence(level cl); // confidence interval of mean
     double confidence(level cl,histogram* h); // difference

     double covariance(histogram* h2);  // covariance h and h2
     double correlation(histogram* h2); // correlation h and h2
   
     double chisquaretest(double* expected); // chi-square test
   
     double linear();                    // linear fit, return chi-square
     double linear(double a,double b);   
     double quadratic();                 // quadratic fit, return chi-square
     double quadratic(double a,double b,double c);
   
     double uniform();            // uniform fit, return chi-square
     double uniform(double a,double b);     
     double exponential();        // exponential fit, return chi-square
     double exponential(double a);  
     double hyperexponential(double p);  // hyperexponential fit, return chi-square
     double hyperexponential(double p,double a,double b);  
     double gamma();              // gamma fit, return chi-square
     double gamma(double a,double b); 
     double erlang();             // erlang fit, return chi-square
     double erlang(unsigned int n,double a); 
     double binomial();           // binomial fit, return chi-square
     double binomial(double p,unsigned int n);
     double geometric();          // geometric fit, return chi-square
     double geometric(double p);   
     double hypergeometric(unsigned int n); // hypergeometric, return chi-square
     double hypergeometric(unsigned int m,unsigned int n,double p);   
     double negativebinomial();   // neg. binomial fit, return chi-square
     double negativebinomial(double p,unsigned int n);
     double poisson();            // poisson fit, return chi-square
     double poisson(double a);      
     double normal();             // normal fit, return chi-square
     double normal(double a,double b);
     double lognormal();          // lognormal fit, return chi-square
     double lognormal(double a,double b); 
     double chisquare();          // chisquare fit, return chi-square
     double chisquare(unsigned int n);   
     double student();            // students' t fit, return chi-square
     double student(unsigned int n);    
     double fdistribution();      // F distribution fit, return chi-square
     double fdistribution(unsigned int n,unsigned int m); 
     double beta();               // beta fit, return chi-square
     double beta(double a,double b);   
     double weibull();            // weibull fit, return chi-square
     double weibull(double a,double b);
     double triangular();         // triangular fit, return chi-square
     double triangular(double a);  
     double laplace();            // laplace fit, return chi-square
     double laplace(double a); 
   
     int behavior(histogram* h,int n);  // report behavior

     // compare sizes and waiting times for various queues
     int MM1size(double lb,double mu);   
     int MM1waitingtime(double lb,double mu);
     int MMcsize(double lb,double mu,unsigned int c);
     int MMcwaitingtime(double lb,double mu,unsigned int c);
     int MD1size(double lb,double mu);
     int MD1waitingtime(double lb,double mu);

     void postscript(char* fn);   // generate postscript
   
     friend ostream& operator<<(ostream& os,analysis& a);
   };
   

fig C.1. The interface of the class analysis
Notice that the hypergeometric fit in both cases requires the n value. This value represents the number of items drawn from the population and therefore should be known. The hyperexponential fit always takes the chance of the first exponential distribution.

A case study of a job shop

[-<--%--^-->-] This example illustrates the use of priority queues in a simulation of a jobshop. A jobshop is a system where a central resource is shared by customers that submit complete jobs for processing and receive some form of output. You can think of a batch computer system with a single cpu. Typically the cost to the customer in using this service is based on the amount of time required to process the particular job.

The problem

In our example the customers are served in priority order with highest priority first. Furthermore a job with the highest priority preempts the job that is currently served, if the current job does not have the highest priority. The job, that is preempted is appended to the queue and is served later for the remaining service time. If a customer is not served after some maximal period the customer is discarded. In our example the jobshop offers four grades of service and a premium is paid for a higher grade of service because higher priority jobs always go in front of lower priority jobs when queuing for service time. Each grade of service has an associated job priority. They are defined as 0,1,2 or 3 with 3 being the highest and 0 the lowest. Based on the existing job load we are interested in the waiting times and the number of interrupts for customers taking the priority into account. Furthermore we are interested in the number of customers, that depart without being served. Existing measurements of the traffic load have indicated that job submissions basically fall into three classes of service usage which are independent of the grade of service. Job submissions follow a normal distribution with the parameters shown in the next table.



slide: Submissions

A job has a maximal waiting time of 50 time units. For the inter-arrival time of jobs we choose an exponential distribution with parameters shown in the next table.



slide: Parameters for inter-arrival times

Furthermore, redundancy has been built-in for the server, because it is subject to stochastic failures. If the server goes down, an identical server is switched on and the broken server is replaced. The system as a whole goes down when the operating server goes down while the standby is not yet replaced. In this kind of problem it is convenient to work with the Weibull distribution, according to [Kalvelagen 90]. Closer examination has revealed as parameters for the weibull distribution of the lifetime of the server
\alpha = 1 and \lambda = 1.4. Finally, the replacement time is uniformly distributed between 0.1 and 0.12. We are interested in statistics of the lifetime of the system as a whole.

The program

We wrote the following program. It consists of the entities job, server and breakdown, the priority queue q, the resource shop and the various generator, histogram and analysis objects.

#include <sim/sim.h>

// phases job
enum {ARRIVAL,DEPARTURE,INTERRUPTED};

// phases server
enum {RUNNING,BROKEN};

// phases breakdown
enum {BOTH_SERVERS_OK,ONE_SERVER_DOWN,BOTH_SERVERS_DOWN};

// number of job types,number of grades of service and number of runs
enum {JOBTYPES=3,PRIORITIES=4,RUNS=10000};

// define highest queuingpriority and maximal waiting time
enum {HIGHEST=3,MAXWAITED=50};

class server;

simulation* sim;
histogram* waited[PRIORITIES];
histogram* total[PRIORITIES];
histogram* interrupted[PRIORITIES];
histogram* lost;
histogram* lifetime;
histogram* prob;
generator* g1, *g2;
resource* shop;
queue* q;
server* s;
double mean[JOBTYPES] = {0.76,2.14,13.65};
double stddev[JOBTYPES] = {0.16,0.22,1.83};
double probability[JOBTYPES] = {0.21,0.57,0.22};
double arrivalrate[PRIORITIES] = {19.8,13.6,11.2,27.5};


class job : public entity
{
  public :
    job(int ph,int qp,int sp=0);
    virtual int operator()();
    int arrival();
    int departure();
    double servicetime();
    double startingtime;
    double timeleft;
    int interrupts;
};


class server : public entity
{
  public :
    server(int ph);
    virtual int operator()();
    int serve();
    int preempt();
    int discard();
    void breakdown(double t);
    void fixed();
    job* current;
};


class breakdown : public entity
{
  private :
    int runs;
    double last;

  public :
    breakdown(int ph,int sp);
    virtual int operator()();
    int bothok();
    int onedown();
    int bothdown();
};


// constructor, taking phase, scheduling priority and queuing
// priority of the job

job::job(int ph,int qp,int sp) : entity(ph,qp,sp)
{
  startingtime = 0;
  timeleft = 0;
  interrupts = 0;
}

// behavior of a job

int job::operator()()
{
  switch (phase())
  {
    case ARRIVAL :
      return arrival();
    case DEPARTURE :
      return departure();
  }
  return FALSE;
}

// arrival event

int job::arrival()
{
  job* j;

  // add time stamp (for check on waiting time)
  stamp();

  // schedule next job
  j = new job(ARRIVAL,queuingpriority());
  sim -> schedule(j,(g1 -> exponential(arrivalrate[queuingpriority()])));

  // append and report.
  report(total[queuingpriority()]);
  q -> append(this);
  return OK;
}

// departure event

int job::departure()
{
  // add sample, release shop and leave it
  interrupted[queuingpriority()] -> sample(interrupts);
  shop -> release();
  sim -> terminate(this);
  s -> current = NULL;
  return OK;
}

// if interrupted return time left, else determine service time

double job::servicetime()
{
  double p;

  if (phase() == INTERRUPTED)
    return timeleft;
  else
  {
    p = g1 -> uniform(0,1);
    if (p < probability[0])
      return (g1 -> normal(mean[0],stddev[0]));
    else if (p < (probability[0] + probability[1]))
      return (g1 -> normal(mean[1],stddev[1]));
    else
      return (g1 -> normal(mean[2],stddev[2]));
  }
}
  

server::server(int ph) : entity(ph)
{
  current = NULL;
}

// if possible serve or preempt

int server::operator()()
{
  job* j;

  // check if broken
  if (phase() == BROKEN)
    return FALSE;

  // check if empty
  if (!(q -> empty()))
  {  
    j = (job *)q -> front();
    // if waited too long don't serve it
    if ((j -> timespent()) > MAXWAITED)
      return discard();

    // shop available
    else if (shop -> available())
      return serve();

    // current has not highest priority and the front has
    else if ( (j -> queuingpriority() == HIGHEST) && 
              (current -> queuingpriority() != HIGHEST) )
        return preempt();
  }
  return FALSE;
}
    
// serve the front

int server::serve()
{
  double t;
  job* j;

  j = (job *)q -> removefront();

  // determine service time, before adjusting the phase
  t = j -> servicetime();

  // acquire shop and schedule departure
  shop -> acquire();
  j -> phase(DEPARTURE);

  // set starting time and time left.
  j -> startingtime = sim -> clock();
  j -> timeleft = t;

  // set current
  current = j;
  sim -> schedule(j,t);
  return OK;
}

// preempt current job and serve the front

int server::preempt()
{
  double t;
  job* j;

  j = (job *)q -> removefront();

  // update current job, (it always exists)
  current -> timeleft -= sim -> clock() - current -> startingtime;
  current -> startingtime = sim -> clock();

  // remove as departing entity and append as interrupted entity
  sim -> passivate(current);
  current -> phase(INTERRUPTED);
  (current -> interrupts)++;
  q -> append(current);

  // update current job, (it always exists)
  // serve new job
  j -> phase(DEPARTURE);
  t = j -> servicetime();

  // set starting time and time left.
  j -> startingtime = sim -> clock();
  j -> timeleft = t;

  current = j;
  sim -> schedule(j,t);
  return OK;
}

// discard front

int server::discard()
{
  job* j;

  j = (job *)q -> front();

  // add sample
  lost -> sample(j -> queuingpriority());
  interrupted[queuingpriority()] -> sample(j -> interrupts);

  // terminate without recording the waiting time
  q -> terminatefront();
  return FALSE;
}

// model a breakdown of the server

void server::breakdown(double t)
{
  if (current)
  {
    // extract departure
    sim -> passivate(current);

    // update current job
    current -> timeleft -= sim -> clock() - current -> startingtime;
    current -> startingtime = sim -> clock() + t;

    // schedule departure
    sim -> schedule(current,(current -> timeleft + t));
  }
  phase(BROKEN);
}

// the server is fixed

void server::fixed()
{
  phase(RUNNING);
}


breakdown::breakdown(int ph,int sp) : entity(ph,0,sp)
{
  last = 0;
  runs = 0;
}

// behavior of a breakdown

int breakdown::operator()()
{
  switch (phase())
  {
    case BOTH_SERVERS_OK :
      return bothok();
    case ONE_SERVER_DOWN : 
      return onedown();
    case BOTH_SERVERS_DOWN :
      return bothdown();
  }
  return FALSE;
}
  
// both servers OK

int breakdown::bothok()
{  
  double life;

  // if total number of runs is reached, quit
  if (runs == RUNS)
    sim -> quit();
  else
    runs++;
  // schedule one part down
  s -> fixed();
  life = g2 -> weibull(1,1.4);
  phase(ONE_SERVER_DOWN);
  sim -> wait(life);
  return OK;
}

// one server DOWN

int breakdown::onedown()
{
  double life,replacementtime;

  // schedule both parts down, if not replaced on time
  life = g2 -> weibull(1,1.4);
  replacementtime = g2 -> uniform(0.1,0.12);
  if (life < replacementtime)
    phase(BOTH_SERVERS_DOWN);
  sim -> wait(life);
  return OK;
}

// both servers DOWN

int breakdown::bothdown()
{
  double replacementtime,t;
  int j=0;

  // replace both servers and adjust server process
  replacementtime = g2 -> uniform(0.1,0.12);
  phase(BOTH_SERVERS_OK);
  sim -> wait(replacementtime);
  s -> breakdown(replacementtime);

  // sample time server was up, and the probability of the lifetime
  t = sim -> clock() - last;
  last = sim -> clock() + replacementtime;
  lifetime -> sample(t);
  while (j < t)
  {
    prob -> sample(j,1.0/RUNS);
    j += 5;
  }
  return OK;
}


// initialize and run the simulation

void main()
{
  analysis* alifetime;
  analysis* aprob;
  int i;
  job* j;
  breakdown* b;

  sim = new simulation();
  sim -> scan();

  g1 = new generator(821); // inter-arrival and service times
  g2 = new generator(18);  // life and replacement times of the server

  waited[0]= new histogram(0,1,20,FREQUENCY,STATISTICS,"waiting times for a 
                   customer with queuingpriority 0");
  waited[1]= new histogram(0,1,20,FREQUENCY,STATISTICS,"waiting times for a 
                   customer with queuingpriority 1");
  waited[2]= new histogram(0,1,20,FREQUENCY,STATISTICS,"waiting times for a 
                   customer with queuingpriority 2");
  waited[3]= new histogram(0,1,20,FREQUENCY,STATISTICS,"waiting times for a 
                   customer with queuingpriority 3");
  total[0]= new histogram(0,1,20,FREQUENCY,STATISTICS,"total time spent for a 
                   customer with queuingpriority 0");
  total[1]= new histogram(0,1,20,FREQUENCY,STATISTICS,"total time spent for a 
                   customer with queuingpriority 1");
  total[2]= new histogram(0,1,20,FREQUENCY,STATISTICS,"total time spent for a 
                   customer with queuingpriority 2");
  total[3]= new histogram(0,1,20,FREQUENCY,STATISTICS,"total time spent for a 
                   customer with queuingpriority 3");
  interrupted[0]= new histogram(0,1,20,FREQUENCY,STATISTICS,"number of 
                   interrupts for a customer with queuingpriority 0");
  interrupted[1]= new histogram(0,1,20,FREQUENCY,STATISTICS,"number of 
                   interrupts for a customer with queuingpriority 1");
  interrupted[2]= new histogram(0,1,20,FREQUENCY,STATISTICS,"number of 
                   interrupts for a customer with queuingpriority 2");
  interrupted[3]= new histogram(0,1,20,FREQUENCY,STATISTICS,"number of 
                   interrupts for a customer with queuingpriority 3");

  lost = new histogram(0,1,4,FREQUENCY,BARSGRAPH,"lost jobs");
  lifetime = new histogram(0,10,20,FREQUENCY,GRAPH,"life time");
  prob = new histogram(0,5,20,FREQUENCY,BARSGRAPH,"P(X > t)");

  q = new queue();

  shop = new resource(1);

  // add reports on the waiting times
  for (i=0;i reportwaiting(waited[i],0,i);

  // initially the jobs are submitted and the server is conditional
  // the first ones are scheduled in priority order to generate
  // the reports in queuing priority order
  for (i=0;i schedule(j,0);
  }

  s = new server(RUNNING);
  sim -> hold(s);

  // schedule a breakdown, it has the lowest scheduling priority so a
  // customer first departs, if a breakdown occurs at the same time
  b = new breakdown(BOTH_SERVERS_OK,-1);
  sim -> schedule(b,0);

  // run for RUNS lifetimes of the server
  sim -> run();

  // print results
  for (i=0;i confidence(PERCENT95);
  cout << (*alifetime);
  cout << (*prob);
  aprob = new analysis(prob);
  aprob -> exponential();
  cout << (*aprob);

  delete lost;
  delete lifetime;
  delete prob;
  delete alifetime;
  delete aprob;
  delete q;
  delete sim;
}

fig D.3. The listing of the jobshop program

The results

The following ASCII output was obtained :

Simulation started at 0.000000

Simulation stopped - quit called at 213640.080344

Created - 53385 events
Activated - 681816 events
Terminated - 53359 events

Actual time taken - 82 seconds

-------------------------------------------------------------------
waiting times for a customer with queuingpriority 0

mean    =     17.511, variance =    246.715, std dev =     15.707
sum of frequencies             =  6183
min val =      0.000,   max val =     49.995

-------------------------------------------------------------------
waiting times for a customer with queuingpriority 1

mean    =     15.372, variance =    204.220, std dev =     14.291
sum of frequencies             = 14317
min val =      0.000,   max val =     49.991

-------------------------------------------------------------------
waiting times for a customer with queuingpriority 2

mean    =      8.782, variance =     82.108, std dev =      9.061
sum of frequencies             = 21769
min val =      0.000,   max val =     49.997

-------------------------------------------------------------------
waiting times for a customer with queuingpriority 3

mean    =      0.928, variance =      9.208, std dev =      3.034
sum of frequencies             =  7978
min val =      0.000,   max val =     37.472

-------------------------------------------------------------------
total time spent for a customer with queuingpriority 0

mean    =     22.350, variance =    270.269, std dev =     16.440
sum of frequencies             =  5323
min val =      0.221,   max val =     65.139

-------------------------------------------------------------------
total time spent for a customer with queuingpriority 1

mean    =     20.383, variance =    234.780, std dev =     15.323
sum of frequencies             = 12283
min val =      0.217,   max val =     66.079

-------------------------------------------------------------------
total time spent for a customer with queuingpriority 2

mean    =     13.929, variance =    129.825, std dev =     11.394
sum of frequencies             = 18727
min val =      0.325,   max val =     63.692

-------------------------------------------------------------------
total time spent for a customer with queuingpriority 3

mean    =      5.183, variance =     33.611, std dev =      5.798
sum of frequencies             =  7979
min val =      0.174,   max val =     48.609

-------------------------------------------------------------------
number of interrupts for a customer with queuingpriority 0

mean    =      0.147, variance =      0.170, std dev =      0.413
sum of frequencies             = 14370
min val =      0.000,   max val =      5.000
-------------------------------------------------------------------
number of interrupts for a customer with queuingpriority 1

mean    =      0.101, variance =      0.114, std dev =      0.338
sum of frequencies             = 12283
min val =      0.000,   max val =      3.000
-------------------------------------------------------------------
number of interrupts for a customer with queuingpriority 2

mean    =      0.138, variance =      0.155, std dev =      0.394
sum of frequencies             = 18727
min val =      0.000,   max val =      5.000
-------------------------------------------------------------------
number of interrupts for a customer with queuingpriority 3

mean    =      0.000, variance =      0.000, std dev =      0.000
sum of frequencies             =  7979
min val =      0.000,   max val =      0.000
-------------------------------------------------------------------
lost jobs

   0.00 5352.00
#######################################################

1.00 3288.00
###############################

2.00 407.00


3.00 0.00
fig D.4 The results(1)
As you can see, jobs having a higher priority have less waiting times. The first three priorities have the same maximal waiting time, since they are removed from the system when their waiting time is too long. Furthermore, a job having the highest priority can't be interrupted and it can't get lost.

-------------------------------------------------------------------
life time

mean    =     21.254, variance =    451.600, std dev =     21.251
sum of frequencies             = 10000
min val =      0.033,   max val =    224.805

   0.00 3777.00
#######################################################

10.00 2353.00
################################

20.00 1434.00
#################

30.00 903.00
########

40.00 588.00
###

50.00 363.00

60.00 220.00


70.00 149.00## 80.00 81.00# 90.00 40.00 100.00 32.00 110.00 21.00 120.00 13.00 130.00 7.00 140.00 8.00 150.00 3.00 160.00 2.00 170.00 2.00 180.00 2.00 190.00 1.00 over 1.00 ------------------------------------------------------------------- CONFIDENCE : life time level : 95 estimated mean : 21.25 interval : +/-0.42 ------------------------------------------------------------------- P(X > t) (%) 0.00 100.00
#######################################################

5.00 79.64
###########################################

10.00 62.23
################################

15.00 49.34
########################

20.00 38.70
#################

25.00 30.44
############

30.00 24.36
#########

35.00 19.30
#####

40.00 15.33
###

45.00 12.04
#

50.00 9.45

55.00 7.37


60.00 5.82


65.00 4.65## 70.00 3.62## 75.00 2.72# 80.00 2.13# 85.00 1.65# 90.00 1.32 95.00 1.15 over 4.96


------------------------------------------------------------------- EXPONENTIAL FIT : P(X > t) (%) a : 18.87 chi-square : 5.01 degree of freedom : 11 P(chi-square > 5.01) = 0.93

fig D.5 The results(2)
The statistics of the life time of the server and the chances that this life time is greater then 0,5,10.. are given. The exponential distribution has been fitted on the probability histogram of the life times. A
\chi^{2} statistic of 5.01 suggests a very good fit. The chance that the statistic was greater is equal to 0.93. If you want to be sure that the probability indeed follows an exponential distribution, you have to perform this test several times and make sure that it was no lucky fit. \end{document}