Published
Edited
Jan 20, 2021
Insert cell
md`# Performance Analysis With PDQ
This is a WIP of every listing the book translated from Perl to Javascript.

- [x] - Listing 2.1 is in [this notebook](https://observablehq.com/d/8c5c68ea2d029b80)
- ~~Chapter 3 Listings are not done~~
- [x] Chapter 4
- [x] Chapter 5

I am translating PDQ to javascript and will also add the PDQ models here
`
Insert cell
md`# Chapter 4 - Getting the Jump on Queuing

This observable notebook is editable: you can tweak the input variables (busyData, time periods) and all the
values will be recomputed
`
Insert cell
Insert cell
Insert cell
busyData = [1.23, 2.01, 3.11, 1.02, 1.54, 2.69, 3.41, 2.87, 2.22, 2.83];

Insert cell
Insert cell
arrivalCount = busyData.length;
Insert cell
arrivalRate = arrivalCount / timePeriod;
Insert cell
Insert cell
completionCount = busyData.length
Insert cell
throughput = completionCount/ timePeriod
Insert cell
normalizedThroughput = `1 Customer every ${1/throughput} minutes`
Insert cell
Insert cell
Insert cell
busyServer = busyData.reduce((a,b) => a+b)
Insert cell
completionsServer = busyData.length
Insert cell
serviceTime = busyServer / completionsServer // in minutes
Insert cell
md`### Listing 4.4 - Calculate the utilization`
Insert cell
utilization = busyServer / timePeriod
Insert cell
md`The utilization is ${d3.format('0.2%')(utilization)}`
Insert cell
Insert cell
residenceTime = serviceTime / (1 - utilization) //minutes
Insert cell
queueLength = utilization / (1 - utilization)
Insert cell
waitingTime = queueLength * serviceTime // minutes
Insert cell
md`### Listing 4.6 - Calculate the Erlang B and C functions`
Insert cell
servers = 8
Insert cell
erlangs = 4
Insert cell
rho = erlangs / servers
Insert cell
erlangB = {
let erlangB = erlangs / (1 + erlangs);
for (let m = 2; m <= servers; m++) {
erlangB = erlangB * erlangs / (m + (erlangB * erlangs))
}
return erlangB
}
Insert cell
erlangC = erlangB / ( 1 - rho + (rho * erlangB))
Insert cell
normalizedWaitingTime = erlangC / (servers * (1 - rho))
Insert cell
normalizedResponseTime = 1 + normalizedWaitingTime //Exact solution
Insert cell
Insert cell
approximateNormalizedResponseTime = 1 / (1 - Math.pow(rho, servers))
Insert cell
Insert cell
N = 230
Insert cell
Z = 300
Insert cell
m = 1
Insert cell
S = 0.63
Insert cell
L = {
let p0 = 1;
let p = 1;
let L = 0;
for (let k = 1; k <= N; k++) {
p *= (N - k + 1) * S / Z;
p /= Math.min(k, m);
p0 += p;
if (k > m) {
L += p * (k - m);
}
}
L *= 1/p0;
return L
}
Insert cell
W = L * ( S + Z) / (N - L) // Waiting time
Insert cell
R = W + S // Residence time
Insert cell
X = N / (R + Z) //throughput
Insert cell
U = X * S // Number in service (Little's law)
Insert cell
rho_ = U / m // Utilization (from 0 to 1)
Insert cell
md`### Listing 5.1 - Passport Renewal Model`
Insert cell
appsPerHour = 15;
Insert cell
lambda = appsPerHour / 3600
Insert cell
passportResults = {
let p12 = 0.3;
let p13 = 0.7;
let p23 = 0.2;
let p32 = 0.1;
let L2 = lambda * (p12 + (p32*p13)) / ( 1 - (p32 * p23));
let L3 = p13 * lambda + p23 * L2;
let rho1 = lambda * 20;
let rho2 = L2 * 600;
let rho3 = L3 * 300;
let rho4 = lambda * 60;
let Q1 = rho1 / ( 1 - rho1);
let Q2 = rho2 / ( 1 - rho2);
let Q3 = rho3 / ( 1 - rho3);
let Q4 = rho4 / ( 1 - rho4);
let R = (Q1 + Q2 + Q3 + Q4)/ lambda;
return [ L2/ lambda, L3/ lambda, rho1, rho2, rho3, rho4]
}
Insert cell
md`### Listing 5.2 - MVA Algorithm`
Insert cell
mva = (N, D, Z) => { // D is service demand at each queue
const K = D.length;
let Q = Array(K).fill(0);
let R = Array(K).fill(0);
for (let n = 1; n <= N; n++) {
//1. Calculate the residence time at k
for (let k = 0; k < K; k++) {
R[k] = D[k] * (Q[k] + 1);
}
//2. Calculate system response time
let rtt = Z;
for (let k=0; k <K; k++) {
rtt += R[k];
}
//3. Calculate system throughput
const X = n / rtt;
//4. Calculate new queue length at k
for(let k=0; k < K; k++) {
Q[k] = X * R[k];
}
}
return [Q, R, X]
}
Insert cell
mva(230, [0.63], 300) //these numbers match up with the repairman model
Insert cell
md`### Listing 5.3 Approximate MVA algorithm`
Insert cell
approxMva = (N, D, Z) => {
const K = D.length;
const threshold = 0.001;
let Q = Array(K).fill(N / K);
let Qprev = Array(K).fill();
let R = Array(K).fill();

do {
for (let k = 0; k < K; k++) {
Qprev[k] = Q[k];
R[k] = D[k] * (1 + Q[k] * (N - 1) / N);
}
let rtt = Z;
for (let k = 0; k < K; k++) {
rtt += R[k];
}
const X = N / rtt;
for(let k = 0; k < K; k++) {
Q[k] = X * R[k];
}
} while(Q.some((q, idx) => (Math.abs(q - Qprev[idx]) / q) > threshold))
return [Q, R, X]
}
Insert cell
approxMva(230, [0.63], 300) //these are very close to the exact solution
Insert cell
approxMva(1, [0.63], 8) //these are very close to the exact solution
Insert cell
import { chart} from '@joshdata/simple-line-chart'
Insert cell
md`Note, the throughput numbers never change, I'm not sure why. I copied the book's implementation.`
Insert cell
chart({
xAxis: {
title: "Users(N)",
min: 1,
max: 50
},
yAxis: {
title: "Response Time R(N)",
min: 0,
max: 18,
},
series: [
{ title: "Exact", points: n => mva(n, [0.5] ,8)[1][0] },
{ title: "approximate", points: n => approxMva(n, [0.5] ,8)[1][0] }
]
})
Insert cell
md`### Listing 5.4 - Time-share queuing model`
Insert cell
{
const m = 2;
const N = 4;
const D = 5;
const Z = 0.001;
let p = 1;
let p0 =1;
let L = 0;
for (let k=1; k <=N; k++) {
p *= ( N -k + 1) * D / Z;
p /= Math.min(k, m);
p0 += p;
if (k > m) {
L += p * (k - m);
}
}
L *= 1/p0;
return [m, N, ,D, Z, L])
}ie
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more