package nl.tudelft.simulation.examples.dsol.timesharedcomputer; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.djutils.draw.bounds.Bounds3d; import org.djutils.draw.point.OrientedPoint3d; import org.djutils.event.TimedEventType; import org.djutils.metadata.MetaData; import org.djutils.metadata.ObjectDescriptor; import nl.tudelft.simulation.dsol.SimRuntimeException; import nl.tudelft.simulation.dsol.animation.Locatable; import nl.tudelft.simulation.dsol.formalisms.flow.Station; import nl.tudelft.simulation.dsol.simtime.SimTimeDouble; import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface; /** * The CPU example as published in Simulation Modeling and Analysis by A.M. Law & W.D. Kelton section 1.4 and 2.4. . *

* Copyright (c) 2003-2022 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See * for project information https://simulation.tudelft.nl. The DSOL * project is distributed under a three-clause BSD-style license, which can be found at * * https://simulation.tudelft.nl/dsol/3.0/license.html. *

* @author Peter Jacobs */ public class CPU extends Station implements Locatable { /** */ private static final long serialVersionUID = 1L; /** UTILIZATION_EVENT are fired on utilization. */ public static final TimedEventType UTILIZATION_EVENT = new TimedEventType(new MetaData("UTILIZATION_EVENT", "Utilization change", new ObjectDescriptor("utilization", "Current utilization", Double.class))); /** QUEUE_LENGTH_EVENT is fired on changes in the Queue length. */ public static final TimedEventType QUEUE_LENGTH_EVENT = new TimedEventType(new MetaData("QUEUE_LENGTH_EVENT", "Queue length change", new ObjectDescriptor("queueLength", "New queue length", Integer.class))); /** QUANTUM is the QUANTUM of the CPU. */ public static final double QUANTUM = 0.1; /** SWAP is the swap of this cpu. */ public static final double SWAP = 0.015; /** IDLE defines the IDLE state. */ public static final boolean IDLE = true; /** BUSY defines the BUSY state. */ public static final boolean BUSY = false; /** status of the CPU. */ private boolean status = IDLE; /** queue is the queue of waiting jobs. */ private List queue = Collections.synchronizedList(new ArrayList()); /** the location. */ private OrientedPoint3d location = new OrientedPoint3d(-90, 0, 0); /** * constructs a new CPU. * @param simulator DEVSSimulatorInterface.TimeDouble; a devs simulator */ public CPU(final DEVSSimulatorInterface.TimeDouble simulator) { super("CPU", simulator); this.fireTimedEvent(UTILIZATION_EVENT, 0.0, simulator.getSimulatorTime()); } /** * returns the queue. * @return List the queue */ public List getQueue() { return this.queue; } /** {@inheritDoc} */ @Override public void receiveObject(final Object object) { this.queue.add(object); this.fireTimedEvent(QUEUE_LENGTH_EVENT, this.queue.size(), this.simulator.getSimulatorTime()); if (this.status == IDLE) { try { this.next(); } catch (SimRuntimeException exception) { getSimulator().getLogger().always().error(exception); } } } /** {@inheritDoc} */ @Override protected synchronized void releaseObject(final Object object) { this.status = IDLE; this.fireTimedEvent(UTILIZATION_EVENT, 0.0, this.simulator.getSimulatorTime()); ((Job) object).getOwner().receiveObject(object); try { this.next(); } catch (SimRuntimeException exception) { getSimulator().getLogger().always().error(exception); } } /** * services the next job. * @throws SimRuntimeException on simulation failure */ private void next() throws SimRuntimeException { if (this.queue.size() > 0) { this.status = BUSY; this.fireTimedEvent(UTILIZATION_EVENT, 1.0, this.simulator.getSimulatorTime()); Job job = (Job) this.queue.remove(0); this.fireTimedEvent(QUEUE_LENGTH_EVENT, this.queue.size(), this.simulator.getSimulatorTime()); if (job.getServiceTime() > QUANTUM) { job.setServiceTime(job.getServiceTime() - QUANTUM); Object[] args = {job}; this.simulator.scheduleEventAbs(this.simulator.getSimulatorTime() + QUANTUM + SWAP, this, this, "receiveObject", args); this.simulator.scheduleEventAbs(this.simulator.getSimulatorTime() + QUANTUM + SWAP, this, this, "next", null); } else { Object[] args = {job}; this.simulator.scheduleEventAbs(this.simulator.getSimulatorTime() + job.getServiceTime() + SWAP, this, this, "releaseObject", args); } } else { this.status = IDLE; this.fireTimedEvent(UTILIZATION_EVENT, 0.0, this.simulator.getSimulatorTime()); } } /** {@inheritDoc} */ @Override public OrientedPoint3d getLocation() { return this.location; } /** {@inheritDoc} */ @Override public Bounds3d getBounds() { return new Bounds3d(0, 0, 0); } }