PDQ Manual

= PDQ User Manual =

Updated: Dec 23, 2004
This online edition of the PDQ User Manual is intended to accompany the C language version of PDQ as presented in the book Practical Performance Analyst and corrects several typos found in the original printing.

Overview
PDQ ( Pretty Damn Quick ) is a queueing model solver, not a simulator. The queueing theory models discussed in Chapters 2 and 3 of The Practical Performance Analyst. are incorporated into the solution methods used by PDQ. This saves you the labor of implementing thos codes each times you construct a queueing model and allows you to concentrate on the accuracy of your model rather than the accuracy of the solutions. PDQ guarantees that for you.

Because PDQ uses algorithmic techniques, rather than an event-based simulation (such as that used by C++SIM, NS, and REAL) it is extremely fast at calculating solutions. It is not too far fetched to say that, the result than it takes to calculate it!

Moreover, PDQ is a flexible library of functions rather than a hard-wired binary application. This flexibility requires that you express your performance model in the C language, and then compile it. Therefore, some programming is required. The good news is, you do not need to learn yet another strange modeling language. The bad news is, you have to learn the programming language called C.

In the spirit of the open-source development model (in fact, before it was even fashionable), PDQ is provided as multiple C source files to enable it to be compiled and used in the environment of your choice - from micros to mainframes.

This philosophy imposes two significant requirements.

System Requirements
You will need access to a C compiler e,g, gcc. Almost by definition, C compilers are available in every UNIX and Linux environment and C packages are now provided with most mainframes. There are also a great many C compiler products available for personal computer operating systems such Linux, DOS, Windows, and MacOS. with a mainframe background) this may appear as a burden. In fact, it greatly enhances the portability of your PDQ models.

Human Requirements
Since the source code provided with the book really constitutes a library of functions for solving performance models, all PDQ models must be written in C. into the C code for your performance model. the constructs of a modern procedural programming language such as: extensible data structures, block coding design, procedure calls, and recursion, to create and solve potentially very elaborate performance models.

All the examples in this book are constructed using this paradigm. Setting up a PDQ model is really quite straightforward. To help you gain familiarity with PDQ, you should first read the section on constructing a [#Simple Example simple example] in this manual. (especially those in Chapters 2 and 3) to get a better idea of some of the variations on coding structure useful for creating and solving a PDQ model.

For those readers not yet familiar with the C language (or C++), PDQ offers another motivation to learn. ANSI standard C programming is authored by Kernighan and Ritchie. Many other excellent introductory texts on the C language are also available.

Remember, serious performance modeling is mostly serious programming.

The PDQ Library
In this section we describe the global variables, public data types, and public procedure calls available in the PDQ_Lib.h file.

Data Types
The following data types (implemented as #defines in the C language) are used in conjunction with PDQ library functions. the synopses of procedures for actual syntax.

  PDQ Node Types 

 CEN: Generic queueing center. Used with PDQ_CreateNode  DLY: Generic delay center. Used with PDQ_CreateNode 

 Service Disciplines 

 FCFS: First-come first-served. Used with PDQ_CreateNode  ISRV: Infinite server. Used with PDQ_CreateNode  LCFS: Last-come first-served. Used with PDQ_CreateNode <li> PSHR: Processor sharing. Used with PDQ_CreateNode</tt> </UL>

<li> Workload Streams 

<li> BATCH: A batch class workload which is defined to be one with zero thinktime. Only consistent in the context of a closed queueing circuit to distinguish from TERM. Used with PDQ_CreateClosed</tt> <li> TERM: A terminal class workload which is defined to be one with non-zero thinktime. closed queueing circuit to distinguish from BATCH. Used with PDQ_CreateClosed</tt> <li> TRANS: A transaction class workload which is defined by an arrival rate rather than a thinktime. of a open queueing circuit. Used with PDQ_CreateOpen</tt> </UL>

<li> Solution Methods 

<li> APPROX: Uses the approximate MVA solution technique. for details. Only consistent in the context of solving a	closed queueing circuit. An approximation to the EXACT or iterative MVA solution method. Usedwith PDQ_Solve</tt> <li> CANON: Uses the canonical solution technique. See Chapter 2 (and the online PDQ	User Manual) for more details. Only consistent in the context of a open queueing circuit. Used as an argument for the PDQ_Solve</tt> function. <li> EXACT: This solution technique uses the iterative MVA (Mean Value Analysis) method for up to three workload classes in versions of PDQ later than the original release 1.0. Only consistent in the context of a closed queueing circuit. Used as an argument for the PDQ_Solve</tt> function. </UL>

</OL>

Global Variables
The following global variables are mandatory for every PDQ model.

int nodes;

Cumulative counter for the number of nodes returned by PDQ_CreateNode</tt>

int streams;

Cumulative counter for the number of workload streams returned by P DQ_CreateClosed and PDQ_CreateOpen</tt>

The following global variables may also be useful in PDQ models.

int DEBUG; Flag to toggle PDQ debug facility. argument to PDQ_SetDebug

char model[MAXBUF]; Character array containing the model name. Initialized via PDQ_Init

MAXBUF = 50 double

Controls the number of iterations used in the APPROXimate MVA solution method.

In addition, the following types (which are actually C structures) retain information about queueing nodes and workloads. See PDQ_Lib.h to see how to de-reference specific fields.

batch_type *bt;

Contains the name and number in this batch class workload together with system statistics.

job_type *job;

Describes the workload type either Terminal, Batch, or Transaction and the queueing circuit type, open or closed.

node_type *node;

Describes the queueing node attributes such as: queue length, utilization, and residence time.

systat_type *sys;

Describes system attributes such as: throughput, and response time.

terminal_type *tm;

Similar to batch_type</tt> but includes thinktime.

transaction_type *tx;

Contains the name of the open circuit workload together with system statistics.

For example, to determine the response time for the third stream of a transaction class workload, the appropriate C construct would be:

job[3].trans-&#62;sys-&#62;response;</tt>

Functions
All PDQ library functions have a PDQ_ prefix. The following list groups together the PDQ library procedures in the order of their typical invocation:

<OL type="1">

<li> [#Init PDQ_Init]

<li> [#CreateOpen">PD_CreateOpen] or	[#CreateClosed">PDQ_CreateClosed]

<li> [#CreateNode">PDQ_CreateNode]

<li> [#SetDemand">PDQ_SetDemand] or	[#SetVisits">PDQ_SetVisits]

<li> [#SetWUnit">PDQ_SetWUnit] 	[#SetTUnit">PDQ_SetTUnit]

<li> [#SetDebug">PDQ_SetDebug]

<li> [#Solve">PDQ_Solve]

<li> [#GetResponse">PDQ_GetResponse] and/or	[#GetThruput">PDQ_GetThruput]

<li> [#GetThruMax">PDQ_GetThruMax]

<li> [#GetLoadOpt">PDQ_GetLoadOpt]

<li> [#GetUtilization">PDQ_GetUtilization]	[#GetResidenceTime">PDQ_GetResidenceTime] and/or [#GetQueueLength">PDQ_GetQueueLength]

<li> [#Report">PDQ_Report] </OL>

An alphabetically ordered synopsis for each of these functions now follows.

PDQ_CreateClosed
<font size="+1">NAME 

PDQ_CreateClosed - define the workload for a closed circuit queueing circuit

<font size="+1">SYNOPSIS 

int PDQ_CreateClosed(char *name, int class, float pop, float think);

<font size="+1">DESCRIPTION 

Used to define a workload for a closed circuit queueing model. separate call is required for workload streams having different characteristics.

<font size="+1">OPTIONS 

name: The string used to identify the workload in reports or debug logs

class: Either TERM, or BATCH type

pop: The number of active user processes in the closed circuit. This argument is a float to accommodate 57.4 average active users

think: The user delay or "thinktime" before a request re-enters the queueing system}

RETURNS: the cumulative number of workload streams created.

<font size="+1">EXAMPLE 

main {

}

<font size="+1">SEE ALSO 

PDQ_CreateOpen, PDQ_Init

PDQ_CreateNode
<font size="+1">NAME 

PDQ_CreateNode - define a queueing service center

<font size="+1">SYNOPSIS 

int PDQ_CreateNode(char *name, int device, int sched);

<font size="+1">DESCRIPTION 

Defines a queueing service node for either a closed or open circuit model. queueing node.

name: A string used to identify the service node in reports or debug logs.

device: Type of device.

sched: The queueing discipline.

RETURNS: the the cumulative number of queueing nodes created.

<font size="+1">EXAMPLE 

main {

}

<font size="+1">SEE ALSO 

PDQ_CreateOpen, PDQ_Init

PDQ_CreateOpen
<font size="+1">NAME 

PDQ_CreateOpen - define an open circuit queueing workload

<font size="+1">SYNOPSIS 

int PDQ_CreateOpen(char *name, float lambda);

<font size="+1">DESCRIPTION 

Define a workload in an open circuit queueing model. call is required for workload streams having different characteristics.

name: A string used to identify the workload in reports or debug logs.

lambda: The arrival rate per unit time into the queueing circuit.

RETURNS: the cumulative number of open workloads created.

<font size="+1">EXAMPLE 

main {

}

<font size="+1">SEE ALSO 

PDQ_CreateClosed, PDQ_Init

PDQ_GetLoadOpt
<font size="+1">NAME 

PDQ_GetLoadOpt - determine the optimal user load

<font size="+1">SYNOPSIS 

double PDQ_GetLoadOpt(int class, char *wname);

<font size="+1">DESCRIPTION 

PDQ_GetLoadOpt is used to determine the system throughput for the specified workload.

class: TERM, or BATCH type.

wname: A string containing the name of the workload.

RETURNS: returns the optimal user load as a decimal number.

<font size="+1">EXAMPLE 

main {

}

<font size="+1">SEE ALSO 

PDQ_GetThruput, PDQ_GetResponse

PDQ_GetQueueLength
<font size="+1">NAME 

PDQ_GetQueueLength - determine the queue length at a particular device or node.

<font size="+1">SYNOPSIS 

double PDQ_GetQueueLength(char *device, char *work, int class);

<font size="+1">DESCRIPTION 

PDQ_GetQueueLength is used to determine the queue length of the designated service node by the specified workload. be called after the PDQ model has been solved.

device: A string containing the name of the queueing service node.

work: A string containing the name of the workload.

class: TRANS, TERM, or BATCH type.

RETURNS: returns the queue length as a decimal number.

<font size="+1">EXAMPLE 

main {

}

<font size="+1">SEE ALSO 

PDQ_GetResidenceTime, PDQ_GetUtilization

PDQ_GetResidenceTime
<font size="+1">NAME 

PDQ_GetResidenceTime - determine the residence time at a particular device or node.

<font size="+1">SYNOPSIS 

double PDQ_GetResidenceTime(char *device, char *work, int class);

<font size="+1">DESCRIPTION 

PDQ_GetResidenceTime is used to determine the residence time at the designated service node by the specified workload. be called after the PDQ model has been solved.

device: A string containing the name of the queueing service node.

work: A string containing the name of the workload.

class: TRANS, TERM, or BATCH type.

RETURNS: returns the residence time as a decimal number.

<font size="+1">EXAMPLE 

main {

}

<font size="+1">SEE ALSO 

PDQ_GetQueueLength, PDQ_GetUtilization

PDQ_GetResponse
<font size="+1">NAME 

PDQ_GetResponse - get the system response time

<font size="+1">SYNOPSIS 

double PDQ_GetResponse(int class, char *wname);

<font size="+1">DESCRIPTION 

PDQ_GetResponse used to determine the system response time for the specified workload.

class: TRANS, TERM, or BATCH type.

wname: A string containing the name of the workload.

RETURNS: the system response time as a decimal number.

<font size="+1">EXAMPLE 

main {

}

<font size="+1">SEE ALSO 

PDQ_CreateClosed, PDQ_Init, PDQ_CreateOpen

PDQ_GetThruMax
<font size="+1">NAME 

PDQ_GetThruMax - determine the system throughput at saturation

<font size="+1">SYNOPSIS 

double PDQ_GetThruMax(int class, char *wname);

<font size="+1">DESCRIPTION 

PDQ_GetThruMax is used to determine the system throughput for the specified workload.

class: TERM, or BATCH type.

wname: A string containing the name of the workload.

RETURNS: returns the saturation system throughput as a decimal number.

<font size="+1">EXAMPLE 

main {

}

<font size="+1">SEE ALSO 

PDQ_GetThruput

PDQ_GetThruput
<font size="+1">NAME 

PDQ_GetThruput - determine the system throughput

<font size="+1">SYNOPSIS 

double PDQ_GetThruput(int class, char *wname);

<font size="+1">DESCRIPTION 

PDQ_GetThruput is used to determine the system throughput for the specified workload.

class: TRANS, TERM, or BATCH type.

wname: A string containing the name of the workload.

RETURNS: returns the system throughput as a decimal number.

<font size="+1">EXAMPLE 

main {

}

<font size="+1">SEE ALSO 

PDQ_GetResponse

PDQ_GetUtilization
<font size="+1">NAME 

PDQ_GetUtilization - determine the utilization of a particular device or node.

<font size="+1">SYNOPSIS 

double PDQ_GetUtilization(char *device, char *work, int class);

<font size="+1">DESCRIPTION 

PDQ_GetUtilization is used to determine the utilization of the designated service node by the specified workload. be called after the PDQ model has been solved.

device: A string containing the name of the queueing service node.

work: A string containing the name of the workload.

class: TRANS, TERM, or BATCH type.

RETURNS: returns the utilization as a decimal fraction in the range 0.0 to 1.0.

<font size="+1">EXAMPLE 

main {

}

<font size="+1">SEE ALSO 

PDQ_GetResponse, PDQ_GetThruput, PDQ_Solve

PDQ_Init
<font size="+1">NAME 

PDQ_Init - initializes all internal PDQ variables

<font size="+1">SYNOPSIS 

void PDQ_Init(char *name);

<font size="+1">DESCRIPTION 

Initializes all internal PDQ variables. any other PDQ function. It also resets all internal PDQ variables so that no separate cleanup function call required. be called an arbitrary number of times in the same model.

name: A string containing the name of the performance model that will appear in the PDQ report banner. appearances, the model name should not exceed 24 characters (including spaces).

RETURNS: None.

<font size="+1">EXAMPLE 

main {

}

<font size="+1">SEE ALSO 

PDQ_Solve, PDQ_Report

PDQ_Report
<font size="+1">NAME 

PDQ_Report - generates a formatted report

<font size="+1">SYNOPSIS 

void PDQ_Report;

<font size="+1">DESCRIPTION 

PDQ_Report generates a formatted report that includes the total number of nodes and workloads created in the model, system level performance measures such as throughput and response time for each workload, and service node performance measures such as node utilization and queue lengths. A comment field is available to audit input parameter variations across multiple runs of the same model. file named comments.pdq. Sample reports produced by PDQ Reporter appear throughput this book.

RETURNS: None.

<font size="+1">EXAMPLE 

main {

}

<font size="+1">SEE ALSO 

PDQ_Init, PDQ_Solve

PDQ_SetDebug
<font size="+1">NAME 

PDQ_SetDebug - enable diagnostic printout

<font size="+1">SYNOPSIS 

void PDQ_SetDebug(int flag);

<font size="+1">DESCRIPTION 

Enables diagnostic printout of internal variables and procedures used in solving a PDQ model.

flag: Set either TRUE or FALSE to toggle the debug facility.

RETURNS: None.

<font size="+1">EXAMPLE 

main {

}

Produces the following output.

DEBUG: PDQ_CreateNode

DEBUG: PDQ_SetDemand

DEBUG: getnode_index

<font size="+1">SEE ALSO 

PDQ_Init

PDQ_SetDemand
<font size="+1">NAME 

PDQ_SetDemand - define the service demand (or service time)

<font size="+1">SYNOPSIS 

void PDQ_SetDemand(char *nodename, char *workname, float time);

<font size="+1">DESCRIPTION 

Define the service demand of a specific workload. previously. A separate call is required for each workload stream that accesses the same node.

nodename: the string name of the queueing node.

workname: the string name of the workload.

time: service demand (in units of time) required by the workload at that node.

RETURNS: None.

<font size="+1">EXAMPLE 

main {

}

<font size="+1">SEE ALSO 

PDQ_CreateClosed, PDQ_CreateNode, PDQ_CreateOpen, PDQ_SetVisits

PDQ_SetTUnit
<font size="+1">NAME 

PDQ_SetTUnit - change the timebase unit

<font size="+1">SYNOPSIS 

void PDQ_SetTUnit(char *unitname);

<font size="+1">DESCRIPTION 

Change the name of the time unit that appears in the PDQ report.

unitname: a string name of the unit

RETURNS: None.

<font size="+1">EXAMPLE 

main {

}

<font size="+1">SEE ALSO 

PDQ_Report

PDQ_SetVisits
<font size="+1">NAME 

PDQ_SetVisits - define the visit count

<font size="+1">SYNOPSIS 

void PDQ_SetVisits(char *nodename, char *workname,

<font size="+1">DESCRIPTION 

Used to define the service demand of a specific workload in terms of the explicit service time and visit count. workload must exist. A separate call is required for each workload stream that accesses the same node. from PDQ_SetDemand in the way node-level performance metrics are formatted in the PDQ_Report output. The number of visits shows up in the PDQ_Report INPUTS section. The throughput in the RESOURCE Performance section shows up as counts per unit time.

nodename: name of the queueing node.

workname: name of the workload.

visits: number of visits to that node. Dimensionless.

service: service time the workload requires at that node (in time units).

RETURNS: None.

<font size="+1">EXAMPLE 

main {

}

<font size="+1">SEE ALSO 

PDQ_CreateClosed, PDQ_CreateNode, PDQ_CreateOpen, PDQ_SetDemand

PDQ_SetWUnit
<font size="+1">NAME 

PDQ_SetWUnit - change the name of the workload unit

<font size="+1">SYNOPSIS 

void PDQ_SetWUnit(char *unitname);

<font size="+1">DESCRIPTION 

PDQ_SetWUnit changes the name of the work unit that appears in the PDQ report. The default work unit is Job.

unitname: The name of the work unit.

RETURNS: None.

<font size="+1">EXAMPLE 

main {

}

<font size="+1">SEE ALSO 

PDQ_Report

PDQ_Solve
<font size="+1">NAME 

PDQ_Solve - solve the PDQ model

<font size="+1">SYNOPSIS 

int PDQ_Solve(int method);

<font size="+1">DESCRIPTION 

PDQ_Solve is called after the PDQ model has been created. appropriate solution method must be passed as an argument or an error will reported at runtime.

method: APPROX or CANON. Note: The EXACT method is highly complex and has not been included in this version of the PDQ library. See Chapter 3 for more details.

RETURNS: None.

<font size="+1">EXAMPLE 

main {

}

<font size="+1">SEE ALSO 

PDQ_Report

Simple Example
The following annotated C source code is intended to provide a simple boiler-plate for creating a PDQ performance model. entire model is defined, and solved within the main function. more sophisticated models, it may be preferable to write separate functions to handle different aspects of the model.

Creating the Model
It is a good idea to start the PDQ model off with a unique filename and a description of its purpose. All this goes in a C comment field commencing with /*</tt> and ending with  */</tt>.

/*	Illustrate use of PDQ using a single open workload server.

The filename for our model is min_mod.c</tt>.

It is good practice to include the following header files in any PDQ model source code.


 * 1) include &lt;stdio.h&#62;
 * 2) include &lt;math.h&#62;
 * 3) include "PDQ_Lib.h"

main {

It is necessary to declare the PDQ global variables: nodes and streams. They enable other internal PDQ procedures to keep track of the global state of the queueing circuit created in PDQ.

extern int	nodes, streams;

Variables that are specific to the model are declared next. In this case, we declare the interarrival time and the service time for the workload.

float inter_arriv_time = 0.5; float service_time = 1.0;

The model is initialized by a call to

PDQ_Init

with the name of the model that will appear in the PDQ report.

The actual PDQ model name that will appear in the PDQ report is Minimal Model</tt> and need not be the same as the PDQ filename, although it is a good idea to keep them as similar as possible. We also assign time and work units that are different from the defaults.

The next step is define the queueing centers or nodes that comprise the queueing circuit and the workload that will place service demands on those nodes.

There is only one node and its name is server. circuit model by calling

and passing the workload name work and its interarrival time. This model is an open circuit type.

The service demand placed in the node server by the workload work is defined in the call to

At this point, the PDQ model is now defined and created in memory. All that remains is to solve it and examine the performance data predicted by the PDQ model. the appropriate solution technique is the canonical method.

} /* main */

The report generated by the call to

PDQ_Report

is annotated in the next section. The C source code for more elaborate PDQ models appear throughout the book.

PDQ Report
This is an annotated version of the report generated for the Minimal Model described in the previous section. includes the PDQ model name, Minimal Model, that was passed as an argument to

PDQ_Init.

The banner is followed by the comment field (if any has been supplied).

***************************************			****** Pretty Damn Quick REPORT ******* ***************************************			***			***			***			***************************************			***************************************

******

I couldn't think of anything to say.

The following section of the report headed: summarizes the number and types of nodes and workloads. case there is only one node and one workload in an open circuit model. Second.

***************************************			******			***************************************

Node Sched Resource - CEN

Queueing Circuit Totals:

There are no generators because this an open queueing circuit, not a closed circuit with a finite population generating work. workload and their demands are summarized.

WORKLOAD Parameters

Arrivals

work

The next section, entitled: level and node level performance measures.

***************************************			******			***************************************

Solution Method: CANON

The PDQ report reminds us which of the solution techniques was used in solving the model. In this case, it's the canonical solution.

Each workload component is identified and the system level performance measures are reported that workload component. Minimal Model, there is only one component which was named "work." There is no bounds analysis performed since this is an open circuit model.

******

Metric - Workload: "work" Mean Throughput Response Time Bounds Analysis: Max Throughput

Finally, node level attribites such as, node utilization and queue length at the node are reported. there is only one node which was named &#223erver" demands placed on it by the single workload component called work.

******

Metric - Throughput Utilization Queue Length Residence Time

This is the end of the PDQ Report.

Summary
All the examples used throughout the book, are constructed using the PDQ library described in this manual. Minimal Model discussed in this manual, you should turn some of the examples in the text, especially those in Chapters 2 and 3, to get a better idea of how to apply PDQ to the creation and solution of queueing performance model.