Exploring Scenarios

Terms defined: transition probability

Smoothing Over Multiple Runs

ages from 1 run
Figure 1: Ages From 1 Run
ages smoothed over 10 runs
Figure 2: Ages Smoothed Over 10 Runs
ages smoothed over 100 runs
Figure 3: Ages Smoothed Over 100 Runs
ages smoothed over 1000 runs
Figure 4: Ages Smoothed Over 1000 Runs

Choosing Jobs

class Params:
    # …as before…
    policy: str = "shortest"

class Job(Recorder):
    # …as before…
    def __lt__(self, other):
        match self.sim.params.policy:
            case "oldest":
                return self.t_create < other.t_create
            case "newest":
                return other.t_create < self.t_create
            case "shortest":
                return self.duration < other.duration
            case "longest":
                return other.duration < self.duration
            case _:
                assert False, f"unknown policy {self.sim.params.policy}"
job backlog over time
Figure 5: Job backlog vs. time
job age over time
Figure 6: Age of jobs in queue vs. time
Table 1: Throughput
policy t_sim num_jobs throughput
longest 1000 485 0.48
newest 1000 457 0.46
oldest 1000 497 0.5
shortest 1000 509 0.51
Table 2: Utilization
policy t_sim total_work utilization
oldest 1000 934.48 0.93
shortest 1000 961.69 0.96
newest 1000 888.03 0.89
longest 1000 974.04 0.97

Multiple Workers Redoing Work

class Params:
    # …as before…
    n_tester: int = 1
    p_rework: float = 0.5

class Simulation(Environment):
    def __init__(self):
        # …as before…
        self.test_queue = None

    def simulate(self):
        # …as before…
        self.test_queue = Store(self)
        for _ in range(self.params.n_tester):
            self.process(Tester(self).run())

class Tester(Recorder):
    def __init__(self, sim):
        super().__init__(sim)
        self.t_work = 0

    def run(self):
        while True:
            job = yield self.sim.test_queue.get()
            yield self.sim.timeout(job.duration)
            if self.sim.rand_rework():
                yield self.sim.code_queue.put(job)
            else:
                job.t_complete = self.sim.now
class Coder(Recorder):
    def __init__(self, sim):
        # …as before…
        self.queue = Store(self.sim)
class Tester(Recorder):
    def run(self):
        while True:
            job = yield self.sim.test_queue.get()
            assert job.coder_id is not None
            yield self.sim.timeout(job.duration)
            if self.sim.rand_rework():
                yield self.sim.coders[job.coder_id].queue.put(job)
            else:
                job.t_complete = self.sim.now
class Coder(Recorder):
    def run(self):
        while True:
            job = yield from self.get()
            yield self.sim.timeout(job.duration)
            yield self.sim.test_queue.put(job)
    def get(self):
        new_req = self.sim.code_queue.get()
        rework_req = self.queue.get()
        result = yield (new_req | rework_req)
        if (len(result.events) == 2) or (rework_req in result):
            new_req.cancel()
            job = result[rework_req]
            assert job.coder_id == self.id
        else:
            rework_req.cancel()
            job = result[new_req]
            assert job.coder_id is None
            job.coder_id = self.id
        return job
transition probability graph
Figure 7: Transition Probability Graph