M/M/1 queue#
The classic single-server queue: Poisson arrivals, exponential service, one teller, first-in first-out. It is the smallest model that exhibits the defining discrete-event behaviors, and its steady-state results are known in closed form, which makes it a good correctness check.
Generated from spec/examples/mm1-queue.osdl.json
desparadigmsDiscrete events in OSDL#
A discrete-event model changes state only at event instants: an arrival, a service completion, a transfer. Between events, nothing happens and no time is spent computing.
The des library components react to entity arrivals, timer events, and send results on the shared engine calendar. Entities move between components under the kernel's escrow transfer protocol: an entity in transfer is held by the engine, delivered to the receiver, and either accepted or blocked. A full bounded queue blocks; the entity waits in escrow and is redelivered when the receiver reports readiness. No transfer can lose or duplicate an entity.
The component contracts are in the des library reference.
The document, piece by piece#
Customers enter through a source whose interarrival delay is sampled fresh for every arrival:
{
"id": "arrivals",
"type": "des.source",
"params": {
"interarrival": {
"dist": "exponential",
"rate": 0.9
}
}
}They wait in an unbounded FIFO queue, and a single server samples an exponential service time per customer:
{
"id": "teller",
"type": "des.server",
"params": {
"serviceTime": {
"dist": "exponential",
"rate": 1
}
}
}With an arrival rate of 0.9 and a service rate of 1.0, the traffic intensity is 0.9. Queueing theory gives a mean queue length of 8.1 and a server utilization of 0.9 at steady state, which is what the experiment's summaries converge toward.
The experiment runs 30 replications of 10,000 time units and records time-weighted summaries of both:
[
{
"path": "waiting.length",
"records": [
{
"type": "summary"
}
]
},
{
"path": "teller.utilization",
"records": [
{
"type": "summary"
}
]
}
]Run it#
View the model document
{
"$schema": "https://osdl.dev/schemas/0.1/osdl.schema.json",
"osdl": "0.1",
"model": {
"name": "mm1-queue",
"label": "M/M/1 Queue",
"description": "The classic single-server queue: Poisson arrivals (rate 0.9), exponential service (rate 1.0), one teller, FIFO discipline. Expected steady-state utilization 0.9.",
"components": [
{
"id": "arrivals",
"type": "des.source",
"params": {
"interarrival": {
"dist": "exponential",
"rate": {
"param": "arrivalRate"
}
}
}
},
{
"id": "waiting",
"type": "des.queue",
"params": {
"discipline": "fifo"
}
},
{
"id": "teller",
"type": "des.server",
"params": {
"serviceTime": {
"dist": "exponential",
"rate": {
"param": "serviceRate"
}
}
}
},
{
"id": "done",
"type": "des.sink"
}
],
"connections": [
{
"from": "arrivals.out",
"to": "waiting.in"
},
{
"from": "waiting.out",
"to": "teller.in"
},
{
"from": "teller.out",
"to": "done.in"
}
],
"parameters": [
{
"name": "arrivalRate",
"description": "Poisson arrival rate.",
"default": 0.9,
"min": 0.1,
"max": 1.4,
"unit": "1/t"
},
{
"name": "serviceRate",
"description": "Exponential service rate.",
"default": 1,
"min": 0.5,
"max": 2,
"unit": "1/t"
}
]
},
"experiments": [
{
"name": "baseline",
"duration": 10000,
"replications": 30,
"seed": 7,
"outputs": [
{
"path": "waiting.length",
"records": [
{
"type": "summary"
}
]
},
{
"path": "teller.utilization",
"records": [
{
"type": "summary"
}
]
}
]
},
{
"name": "browser",
"duration": 150,
"replications": 1,
"seed": 7,
"outputs": [
{
"path": "waiting.length",
"records": [
{
"type": "timeseries"
}
]
},
{
"path": "waiting.waitTime",
"records": [
{
"type": "timeseries"
}
]
}
]
}
],
"views": [
{
"id": "main",
"label": "Process flow",
"type": "canvas",
"elements": [
{
"ref": "arrivals",
"x": 0,
"y": 0
},
{
"ref": "waiting",
"x": 220,
"y": 0
},
{
"ref": "teller",
"x": 440,
"y": 0
},
{
"ref": "done",
"x": 660,
"y": 0
}
]
}
]
}The queue length chart is a step series: it changes only at event instants, which is discrete-event execution made visible. The burstiness is real. At a traffic intensity of 0.9, long quiet stretches and long lines are both expected, and only the time-weighted summary over a long run is stable.
Reference#
Components#
| Id | Type | Params |
|---|---|---|
arrivals |
des.source |
{"interarrival":{"dist":"exponential","rate":0.9}} |
waiting |
des.queue |
{"discipline":"fifo"} |
teller |
des.server |
{"serviceTime":{"dist":"exponential","rate":1}} |
done |
des.sink |
{} |
Connections#
arrivals.out→waiting.inwaiting.out→teller.inteller.out→done.in
Experiments#
| Name | Duration | Replications | Sweep | Outputs |
|---|---|---|---|---|
baseline |
10000 | 30 | — | waiting.length, teller.utilization |
Source#
spec/examples/mm1-queue.osdl.json · 2.1 KB
{
"$schema": "https://osdl.dev/schemas/0.1/osdl.schema.json",
"osdl": "0.1",
"model": {
"name": "mm1-queue",
"label": "M/M/1 Queue",
"description": "The classic single-server queue: Poisson arrivals (rate 0.9), exponential service (rate 1.0), one teller, FIFO discipline. Expected steady-state utilization 0.9.",
"components": [
{
"id": "arrivals",
"type": "des.source",
"params": {
"interarrival": {
"dist": "exponential",
"rate": 0.9
}
}
},
{
"id": "waiting",
"type": "des.queue",
"params": {
"discipline": "fifo"
}
},
{
"id": "teller",
"type": "des.server",
"params": {
"serviceTime": {
"dist": "exponential",
"rate": 1
}
}
},
{
"id": "done",
"type": "des.sink"
}
],
"connections": [
{
"from": "arrivals.out",
"to": "waiting.in"
},
{
"from": "waiting.out",
"to": "teller.in"
},
{
"from": "teller.out",
"to": "done.in"
}
]
},
"experiments": [
{
"name": "baseline",
"duration": 10000,
"replications": 30,
"seed": 7,
"outputs": [
{
"path": "waiting.length",
"records": [
{
"type": "summary"
}
]
},
{
"path": "teller.utilization",
"records": [
{
"type": "summary"
}
]
}
]
}
],
"views": [
{
"id": "main",
"label": "Process flow",
"type": "canvas",
"elements": [
{
"ref": "arrivals",
"x": 0,
"y": 0
},
{
"ref": "waiting",
"x": 220,
"y": 0
},
{
"ref": "teller",
"x": 440,
"y": 0
},
{
"ref": "done",
"x": 660,
"y": 0
}
]
}
]
}