-
Notifications
You must be signed in to change notification settings - Fork 30
/
MachineShop.cs
150 lines (139 loc) · 5.72 KB
/
MachineShop.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#region License Information
/*
* This file is part of SimSharp which is licensed under the MIT license.
* See the LICENSE file in the project root for more information.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using static SimSharp.Distributions;
namespace SimSharp.Samples {
public class MachineShop {
/*
* Machine shop example
*
* Covers:
* - Interrupts
* - Resources: PreemptiveResource
*
* Scenario:
* A workshop has *n* identical machines. A stream of jobs (enough to
* keep the machines busy) arrives. Each machine breaks down
* periodically. Repairs are carried out by one repairman. The repairman
* has other, less important tasks to perform, too. Broken machines
* preempt theses tasks. The repairman continues them when he is done
* with the machine repair. The workshop works continuously.
*/
private const int RandomSeed = 42;
private const int NumMachines = 10; // Number of machines in the machine shop
private static readonly NormalTime ProcessingTime = N(TimeSpan.FromMinutes(10.0), TimeSpan.FromMinutes(2.0)); // Processing time distribution
private static readonly ExponentialTime Failure = EXP(TimeSpan.FromMinutes(300.0)); // Failure distribution
private static readonly TimeSpan RepairTime = TimeSpan.FromMinutes(30.0); // Time it takes to repair a machine in minutes
private static readonly TimeSpan JobDuration = TimeSpan.FromMinutes(30.0); // Duration of other jobs in minutes
private static readonly TimeSpan SimTime = TimeSpan.FromDays(28); // Simulation time in minutes
private class Machine : ActiveObject<Simulation> {
/*
* A machine produces parts and my get broken every now and then.
* If it breaks, it requests a *repairman* and continues the production
* after the it is repaired.
*
* A machine has a *name* and a numberof *parts_made* thus far.
*/
public string Name { get; private set; }
public int PartsMade { get; private set; }
public bool Broken { get; private set; }
public Process Process { get; private set; }
public Machine(Simulation env, string name, PreemptiveResource repairman)
: base(env) {
Name = name;
PartsMade = 0;
Broken = false;
// Start "working" and "break_machine" processes for this machine.
Process = env.Process(Working(repairman));
env.Process(BreakMachine());
}
private IEnumerable<Event> Working(PreemptiveResource repairman) {
/*
* Produce parts as long as the simulation runs.
*
* While making a part, the machine may break multiple times.
* Request a repairman when this happens.
*/
while (true) {
// Start making a new part
var doneIn = Environment.Rand(ProcessingTime);
while (doneIn > TimeSpan.Zero) {
// Working on the part
var start = Environment.Now;
yield return Environment.Timeout(doneIn);
if (Environment.ActiveProcess.HandleFault()) {
Broken = true;
doneIn -= Environment.Now - start;
// How much time left?
// Request a repairman. This will preempt its "other_job".
using (var req = repairman.Request(priority: 1, preempt: true)) {
yield return req;
yield return Environment.Timeout(RepairTime);
}
Broken = false;
} else {
doneIn = TimeSpan.Zero; // Set to 0 to exit while loop.
}
}
// Part is done.
PartsMade++;
}
}
private IEnumerable<Event> BreakMachine() {
// Break the machine every now and then.
while (true) {
yield return Environment.Timeout(Failure);
if (!Broken) {
// Only break the machine if it is currently working.
Process.Interrupt();
}
}
}
}
private IEnumerable<Event> OtherJobs(Simulation env, PreemptiveResource repairman) {
// The repairman's other (unimportant) job.
while (true) {
// Start a new job
var doneIn = JobDuration;
while (doneIn > TimeSpan.Zero) {
// Retry the job until it is done.
// It's priority is lower than that of machine repairs.
using (var req = repairman.Request(priority: 2)) {
yield return req;
var start = env.Now;
yield return env.Timeout(doneIn);
if (env.ActiveProcess.HandleFault())
doneIn -= env.Now - start;
else doneIn = TimeSpan.Zero;
}
}
}
}
public void Simulate(int rseed = RandomSeed) {
// Setup and start the simulation
// Create an environment and start the setup process
var start = new DateTime(2014, 2, 1);
var env = new Simulation(start, rseed);
env.Log("== Machine shop ==");
var repairman = new PreemptiveResource(env, 1);
var machines = Enumerable.Range(0, NumMachines).Select(x => new Machine(env, "Machine " + x, repairman)).ToArray();
env.Process(OtherJobs(env, repairman));
var startPerf = DateTime.UtcNow;
// Execute!
env.Run(SimTime);
var perf = DateTime.UtcNow - startPerf;
// Analyis/results
env.Log("Machine shop results after {0} days.", (env.Now - start).TotalDays);
foreach (var machine in machines)
env.Log("{0} made {1} parts.", machine.Name, machine.PartsMade);
env.Log(string.Empty);
env.Log("Processed {0} events in {1} seconds ({2} events/s).", env.ProcessedEvents, perf.TotalSeconds, (env.ProcessedEvents / perf.TotalSeconds));
}
}
}