Skip to content

Instantly share code, notes, and snippets.

@ruslander
Created September 7, 2019 16:41
Show Gist options
  • Save ruslander/6c62423f4c11f3a93d244575dd0bd4a9 to your computer and use it in GitHub Desktop.
Save ruslander/6c62423f4c11f3a93d244575dd0bd4a9 to your computer and use it in GitHub Desktop.
multiple wrongs don't make it right
Parallel queues model with PDQ
Took as an example the "Internet Provider" from "The practical Performance Analyst".
#!/usr/bin/perl
use pdq;
# Globals
$arrivRate = 3;
$servTime = 2;
$engs = 10;
# Initialize PDQ and add a comment about the model
pdq::Init("Internet Service Provilder");
# Define the workload and circuit type
pdq::CreateOpen("Support", $arrivRate);
# Define the queueing center
#pdq::CreateNode("Server", $pdq::CEN, $pdq::FCFS);
pdq::CreateMultiNode($engs, "Eng", $pdq::MSO, $pdq::FCFS);
# Define service demand due to workload on the queueing center
pdq::SetDemand("Eng", "Support", $servTime);
# Change units labels to suit
pdq::SetWUnit("Cust");
pdq::SetTUnit("Min");
# Solve the model
# Must use the Canonical method for an open network
pdq::Solve($pdq::CANON);
# Generate a generic performance report
pdq::Report();
And I know it is wrong beacuse should give R=5min.
Changing $engs to 18 should change to R=3min. Glanced through
PDQ docs but cannot figure out what I'm doing wrong :)
If it is a quick answer then would appreciate your help. Otherwise
it is not worth ir :D
As always thank you very much!
@ruslander
Copy link
Author

ruslander commented Sep 7, 2019

`

                         PRETTY DAMN QUICK REPORT
                ==========================================
                ***  on   Sat Sep  7 12:35:41 2019     ***
                ***  for  Internet Service Provilder   ***
                ***  PDQ  Version 6.2.0 Build 082015   ***
                ==========================================

                ==========================================
                ********    PDQ Model INPUTS      ********
                ==========================================

 WORKLOAD Parameters:

 Node Sched Resource   Workload   Class     Demand
 ---- ----- --------   --------   -----     ------
  10  MSQ   Eng        Support    Open      2.0000

 Queueing Circuit Totals
 Streams:   1
 Nodes:     1

 Arrivals       per Min       Demand
 --------       --------     -------
 Support        3.0000        2.0000


                ==========================================
                ********   PDQ Model OUTPUTS      ********
                ==========================================

 Solution Method: CANON

                ********   SYSTEM Performance     ********

 Metric                     Value    Unit
 ------                     -----    ----
 Workload: "Support"
 Number in system          6.1519    Cust
 Mean throughput           3.0000    Cust/Min
 Response time             2.0506    Min
 Stretch factor            1.0253

 Bounds Analysis:
 Max throughput            5.0000    Cust/Min
 Min response              2.0000    Min


                ********   RESOURCE Performance   ********

 Metric          Resource     Work              Value   Unit
 ------          --------     ----              -----   ----
 Capacity        Eng          Support              10   Servers
 Throughput      Eng          Support          3.0000   Cust/Min
 In service      Eng          Support          6.0000   Cust
 Utilization     Eng          Support         60.0000   Percent
 Queue length    Eng          Support          6.1519   Cust
 Waiting line    Eng          Support          0.1519   Cust
 Waiting time    Eng          Support          0.0506   Min
 Residence time  Eng          Support          2.0506   Min

`

@ruslander
Copy link
Author

tried this as mentioned in dbc
`

use pdq;

$arrivRate = 3;
$servTime  = 2;

$engs = 10;


pdq::Init("Internet Service Provilder");

# Create parallel centers
for ($k = 0; $k < $engs; $k++) {
      $name = sprintf "Eng%d", $k;
      pdq::CreateNode($name, $pdq::CEN, $pdq::FCFS);
}

# Create the workload
pdq::CreateOpen("query", $arrivRate);

# Set service demands using visits to parallel nodes
for ($k = 0; $k < $engs; $k++) {
      $name = sprintf "Eng%d", $k;
      pdq::SetDemand($name, "query", $servTime);
}

pdq::Solve($pdq::CANON);
pdq::Report();`

it fails with

ERROR in procedure 'canonical()': Arrival rate 3.000 for stream 'query' exceeds saturation thruput 0.500 of node 'Eng0' with demand 2.000
one thing o observed in dbc is that it uses PDQ_CreateClosed not sure what else i miss

@DrQz
Copy link

DrQz commented Sep 7, 2019

#!/usr/bin/perl
#
# Modified Ruslan code 
# Let's just try to reproduce first Table on p.60.
#
# Created by NJG on Saturday, September 07, 2019

use pdq;

$arrivRate = 3; # calls per minute
$servTime  = 2; # minutes per call
$engs = 10;     # thingies

pdq::Init("Internet Service Provider");

# Create the workload for ONE parallel queue
# since ALL others must be the same as that one.
# However, each center only sees 1/10th of the total arrival stream

pdq::CreateOpen("query", $arrivRate / $engs);

$name = "Eng";
pdq::CreateNode($name, $pdq::CEN, $pdq::FCFS);
pdq::SetDemand($name, "query", $servTime);

pdq::SetTUnit("Mins");
pdq::SetWUnit("Calls");

pdq::Solve($pdq::CANON);
pdq::Report();

@DrQz
Copy link

DrQz commented Sep 7, 2019

               ********   RESOURCE Performance   ********

Metric          Resource     Work              Value   Unit
------          --------     ----              -----   ----
Capacity        Eng          query                 1   Servers
Throughput      Eng          query            0.3000   Calls/Mins
In service      Eng          query            0.6000   Calls
Utilization     Eng          query           60.0000   Percent
Queue length    Eng          query            1.5000   Calls
Waiting line    Eng          query            0.9000   Calls
Waiting time    Eng          query            3.0000   Mins
Residence time  Eng          query            5.0000   Mins

@DrQz
Copy link

DrQz commented Sep 8, 2019

# parafast.r
#
# Gunther's theorem (1996): Parallel processing is just fast sequential processing.
#
# Show equivalence of: 
# 	1) k-parallel queues each with service time S
# 	2) k-tandem queues each with speed S/k
#
# Created by NJG on Wednesday, October 7, 2009
 
library(pdq)

workname  <- "AllWork"
arrivrate <- 0.5
servtime  <- 1.0
paraQMax  <- 2

paraname  <- 1:paraQMax

Init("Fast Serial Queues")
CreateOpen(workname, arrivrate)
CreateNode("FastQ", CEN, FCFS)
SetDemand("FastQ", workname, servtime/paraQMax)
Solve(CANON)

# Compare with analytic formula: Rk = (S/k) / (1 - (S/k))
cat(sprintf("Fast serial queues: %d\n", paraQMax))
rtimeFast <- (servtime/paraQMax) / (1 - (arrivrate * (servtime / paraQMax)))
cat(sprintf("FastQ Eqn: R = %6.4f\n", rtimeFast))
cat(sprintf("FastQ PDQ: R = %6.4f\n", GetResidenceTime("FastQ", workname, TRANS)))

cat("---\n")

Init("Parallel Queues")
CreateOpen(workname, arrivrate)

for (k in 1:paraQMax) {
	paraname[k] <- sprintf("ParaQ%d", k)
	CreateNode(paraname[k], CEN, FCFS)
	SetDemand(paraname[k], workname, servtime / paraQMax)
}

Solve(CANON)

# Compare with analytic formula: Rpara = S / (1 - (S/k))
rtimePara <- servtime/(1-((arrivrate/paraQMax)*servtime))
cat(sprintf("Parallel queues: %d\n", paraQMax))
cat(sprintf("ParaQ Eqn: R = %6.4f\n", rtimePara))
cat(sprintf("ParaQ PDQ: R = %6.4f (Residence Time)\n", 
            GetResidenceTime(paraname[1], workname, TRANS)))
cat(sprintf("ParaQ PDQ: R = %6.4f (Residence Time x %d)\n", 
            GetResidenceTime(paraname[1], workname, TRANS) * paraQMax, paraQMax))
cat(sprintf("ParaQ PDQ: R = %6.4f (Response Time sum)\n", 
            GetResponse(TRANS, workname)))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment