Jobs queue for one machine. Every hour or so the machine fails and someone fixes it. The model counts what the stops cost, and two of its answers can be checked with a pencil.
Jobs arrive every 7 to 13 minutes and need 6 to 10 minutes on the machine, both uniform. Separately, a failure clock runs: the machine fails after an exponential time with a mean of 60 minutes, and a repair takes 3 to 5 minutes. The run is 2,400 minutes, five eight-hour days.
When the machine fails, the job in progress finishes, but no new job can start until the repair is done. The clock keeps running whether the machine is busy or idle, so the machine is available 60 out of every 64 minutes on average.
The first segment is the usual queue in front of a facility. The second is the failure clock: a single transaction that waits, makes the machine unavailable with FUNAVAIL, waits out the repair, makes it available with FAVAIL, and loops back.
FUNAVAIL with no options lets the job in service finish; it only stops the next one from starting.
GENERATE 10,3
QUEUE LINE
SEIZE MACHINE
DEPART LINE
ADVANCE 8,2
RELEASE MACHINE
TERMINATE
GENERATE ,,,1
DOWN ADVANCE RVEXPO(3,60)
FUNAVAIL MACHINE
ADVANCE 4,1
FAVAIL MACHINE
TRANSFER ,DOWN
GENERATE ,,,1 makes exactly one transaction: the failure clock.The failure clock becomes an object with a forever loop, which reads more plainly than a label and a TRANSFER. funavail and favail keep their GPSS names.
import <h4>
module breakdowns_h4
{
facility Machine;
queue Line;
rn_stream Arrivals seed=100000;
rn_stream Service seed=200000;
rn_stream Failures seed=300000;
rn_stream Repairs seed=400000;
float run_length = 2400;
int served, failures;
float waited, busy, down;
object job
{
float arrived, work;
actions
{
arrived = time;
enqueue Line;
seize Machine;
depart Line;
waited += time - arrived;
work = rv_uniform(Service, 6.0, 10.0);
advance work;
release Machine;
busy += work;
served++;
terminate;
}
}
object failure_clock
{
float repair;
actions
{
forever
{
advance rv_expo(Failures, 60.0);
funavail Machine;
failures++;
repair = rv_uniform(Repairs, 3.0, 5.0);
advance repair;
favail Machine;
down += repair;
}
}
}
procedure main
{
arrivals: job iat = rv_uniform(Arrivals, 7.0, 13.0);
activate new failure_clock;
advance run_length;
report(system);
}
}
deck/breakdowns, without its header comment.As written: five days, run 20 times from seed 1.
| Measure | Mean of 20 runs | Lowest to highest run |
|---|---|---|
| Jobs finished | 238.9 ± 1.0 | 234 to 242 |
| Breakdowns | 36.5 ± 2.7 | 27 to 50 |
| Machine available | 93.91% ± 0.47 | 91.74% to 95.58% |
| Machine busy | 79.53% ± 0.41 | 77.53% to 81.00% |
| Mean wait in line | 0.53 min ± 0.06 | 0.36 min to 0.82 min |
With run_length set to 240,000 minutes, beside the arithmetic: available 60/64 of the time, one failure per 64 minutes, and busy 8/10 of the time (8 minutes of work every 10 minutes).
| Measure | Mean of 20 runs | Lowest to highest run | Theory |
|---|---|---|---|
| Machine available | 93.76% ± 0.04 | 93.56% to 93.90% | 93.75% |
| Breakdowns per 2,400 minutes | 37.5 ± 0.2 | 36.7 to 38.6 | 37.5 |
| Machine busy | 79.95% ± 0.07 | 79.75% to 80.20% | 80.00% |
| Mean wait in line | 0.53 min ± 0.01 | 0.50 min to 0.56 min | – |
± is the 95% confidence interval of the mean over 20 runs. Waiting time has no simple formula here, so it has no theory value.
In many plants a failure stops the job on the machine, and the job resumes once the repair is done. The workspace has that version too, gpss/machine-breakdowns, written in plain chiaha-SLX: each job waits for whichever comes first, its finish time or a failure, and saves the work it has left. A shorter version of that idea is on the example models page.
GPSS/H is a trademark of its owner. ChiAha is not affiliated with or endorsed by it.