Monday, May 23, 2011

May 2011 Guerrilla Classes: Light Bulb Moments

It's impossible to know what will constitute a light bulb moment for someone else. In the recent Guerrilla classes (GBoot and GCaP), we seemed to be having many more than our usual quota of such moments. So much so, that I decided to keep a list.
  1. The first was mine. Asa H. was having trouble setting up PDQ under cygwin on his work-provided Windows laptop. I suddenly realized that it would have been more helpful if I had provided an example .bashrc file in the PDQ distribution. I will do that but, in the meantime, I've now included a copy in the PDQ download notes.
  2. Another problem is using PDQ-R under cygwin because R is not part of the official cygwin distro. A quick search on the web uncovered cygwinports, which provides R separately.
  3. For people new to using PDQ functions in R, explicit name-dependency can be very helpful. Gary L. asked if this could be done in R. The answer is, yes. Instead of just writing say, CreateNode(name, CEN, FCFS) to define a queueing resource in PDQ, you can write pdq::CreateNode(name, CEN, FCFS) in R. A more detailed example is presented in my blog post "Applying PDQ in R to Load Testing".
  4. John McG. pointed out that my grocery store "price check" service-time stretching analogy for coherency delays in the USL model (i.e., the point-to-point β term), doesn't scale with N customers in checkout lane.
  5. My organizing principle of defining Inputs and Outputs for queueing theory calculations, was a big hit with some students. As a trivial example, if you wanted to apply Little's law, Q = λ R, to some performance data, it is important to know what variables you have and which one you want to solve for. If want to solve for the mean queue length Q, then you need both the arrival rate λ and the mean residence time R. Supposing you do indeed have data for λ and R, then they constitute your inputs and Q is the output. More generally, after you rearrange the equation appropriately, whatever is on the right side of the equal sign are the inputs and the left side is the output. The scheme can be (should be) applied to the construction of PDQ models.
  6. When presenting Erlang's famous queueing formulae, I always apply the mnemonic device that the B stands for a "blocked call" (an engaged signal), and C stands for "call waiting' (a very modern concept). However, the Danish telephone system in the early 1900s did not offer call waiting, so what did Erlang mean in his 1917 paper when he uses the term "waiting room" (the waiting line) to define the difference between his B and C formulae? The image of a doctor's clinic comes to mind, but this could not have been implemented in telephone switches at that time. Gary L. provided us with a new insight. Telephones were still a rare resource in those days, and one can imagine that Danes who wanted to place a call did not have their own phone at home. Instead, they probably had to visit a shop or the post office to use a communal phone and it's in that room that they probably had to wait.
  7. In reviewing one of the questions in the homework exercises, Gary L. observed that the response time R2 for an M/M/2 queue is very close to one half R1 for an M/M/1 queue if each server has the same load. We can test this in R. First we create a function to compute the response time (R) for an M/M/m queue
    
    mmmR <- function(m,a,S) {
       R <- S/(1-(a*S)^m)
       return(R)
    }
    
    where the respective arguments are: m the number of servers, a the mean arrival rate into the queue, and S the mean service time at the queue. Note that this is a Guerrilla approximation to the exact Erlang C formula. Now, test it out. We know that R1 should be 2S at ρ = a S = 0.5. Assuming S = 1:
    
    > mmmR(1,0.5,1)
    [1] 2
    
    And R1 should be 4S at ρ = a S = 0.75:
    
    > mmmR(1,0.75,1)
    [1] 4
    
    In the class exercise, we first simply added another cashier to an existing check-out lane, where the original cashier was 75% busy. So, the load is now split in two:
    
    > mmmR(2,0.75/2,1)
    [1] 1.163636
    
    A clear win compared with R1 = 4. The next part of the exercise added another cashier, but make them both as busy as the original lone cashier:
    
    > mmmR(2,0.75,1)
    [1] 2.285714
    
    Also a win when compared with R1 = 4, even though both cashiers are as busy as the M/M/1 case. That result is not obvious. What about the observation that R2 ≅ R1/2? The following R code will generate a table:
    
    r <- 0.0
    cat(sprintf("%4s\t%6s\t%6s\t%6s\n", "load","M/M/1", "M/M/2", "M/M/20"))
    for (i in 1:10) {
     cat(sprintf("%4.2f\t%6.2f\t%6.2f\t%6.2f\n", r, mmmR(1,r,1), mmmR(2,r,1), mmmR(20,r,1)))
     r <- r + 0.1
    }
    
    which allows us to compare both M/M/2 and M/M/20 for ρ > 0.5 (heavy traffic condition):
    
    load  M/M/1  M/M/2 M/M/20
    0.00   1.00   1.00   1.00
    0.10   1.11   1.01   1.00
    0.20   1.25   1.04   1.00
    0.30   1.43   1.10   1.00
    0.40   1.67   1.19   1.00
    0.50   2.00   1.33   1.00
    0.60   2.50   1.56   1.00
    0.70   3.33   1.96   1.00
    0.80   5.00   2.78   1.01
    0.90  10.00   5.26   1.14
    
    It looks like it holds for M/M/2 under heavy traffic, but it doesn't do so well as the number of servers is increased, e.g., m = 20 servers. Clearly, R20 ≠ R1/20, even at very high loads. See this blog post for an explanation.
  8. The concept of iteratively tuning load-test measurements to try and match the theoretical USL curve, was a eureka moment for Asa H.
As you can see, a good time was had by all.

No comments: