📄 edsimulator.java
字号:
/* * Copyright (c) 2003-2005 The BISON Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */package peersim.edsim;import java.util.*;import peersim.config.*;import peersim.core.*;/*** Event-driven simulator engine.* It is a fully static singleton class.* For an event driven simulation * the configuration has to describe a set of {@link Protocol}s,* a set of {@link Control}s and their ordering and a set of* initializers and their ordering. See parameters {@value #PAR_INIT},* {@value #PAR_CTRL}.* <p>* One experiment run by {@link #nextExperiment} works as follows.* First the initializers are run in the specified order. Then the first* execution of all specified controls is scheduled in the event queue.* This scheduling is defined by the {@link Scheduler} parameters of each* control component.* After this, the first event is taken from the event queue. If the event* wraps a control, the control is executed, otherwise the event is* delivered to the destination protocol, that must implement* {@link EDProtocol}. This* is iterated while the current time is less than {@value #PAR_ENDTIME} or* the queue becomes empty.* If more control events fall at the same time point, then the order given* in the configuration is respected. If more non-control events fall at the same* time point, they are processed in a random order.* <p>* The engine also provides the interface to add events to the queue.* Note that this engine does not explicitly run the protocols.* In all cases at least one control or initializer has to be defined that* sends event(s) to protocols.* <p>* Controls can be scheduled (using the {@link Scheduler}* parameters in the configuration) to run after the experiment* has finished.* That is, each experiment is finished by running the controls that are* scheduled to be run after the experiment.* <p>* Any control can interrupt an experiment at any time it is* executed by returning true in method {@link Control#execute}.* However, the controls scheduled to run after the experiment are still* executed completely, irrespective of their return value and even if* the experiment was interrupted.* <p>* {@link CDScheduler} has to be mentioned that is a control that* can bridge the gap between {@link peersim.cdsim} and the event driven* engine. It can wrap {@link peersim.cdsim.CDProtocol} appropriately so that the* execution of the cycles are scheduled in configurable ways for each node* individually. In some cases this can add a more fine-grained control* and more realism to {@link peersim.cdsim.CDProtocol} simulations,* at the cost of some* loss in performance.* <p>* When protocols at different nodes send messages to each other, they might* want to use a model of the transport layer so that in the simulation* message delay and message omissions can be modeled in a modular way.* This functionality is implemented in package {@link peersim.transport}.* @see Configuration */public class EDSimulator{//---------------------------------------------------------------------// Parameters//--------------------------------------------------------------------- /** * The ending time for simulation. Only events that have a strictly smaller * value are executed. It must be positive. Although in principle * negative timestamps could be allowed, we assume time will be positive. * @config */public static final String PAR_ENDTIME = "simulation.endtime"; /** * This parameter specifies * how often the simulator should log the current time on the * standard error. The time is logged only if there were events in the * respective interval, and only the time of some actual event is printed. * That is, the actual log is not guaranteed to happen * in identical intervals of time. It is merely a way of seeing whether the * simulation progresses and how fast... * @config */private static final String PAR_LOGTIME = "simulation.logtime"; /** * This parameter specifies the event queue to be used. It must be an * implementation of interface {@link PriorityQ}. If it is not defined, * the internal implementation is used. * @config */ private static final String PAR_PQ = "simulation.eventqueue";/** * This is the prefix for initializers. * These have to be of type * {@link Control}. They are run at the beginning of each experiment, in the * order specified by the configuration. * @see Configuration * @config * @config */private static final String PAR_INIT = "init";/** * This is the prefix for {@link Control} components. * They are run at the time points defined by the * {@link Scheduler} associated to them. If some controls have to be * executed at the same time point, they are executed in the order * specified in the configuration. * @see Configuration * @config */private static final String PAR_CTRL = "control";//---------------------------------------------------------------------//Fields//---------------------------------------------------------------------/** Maximum time for simulation */private static long endtime;/** Log time */private static long logtime;/** holds the modifiers of this simulation */private static Control[] controls=null;/** Holds the control schedulers of this simulation */private static Scheduler[] ctrlSchedules = null;/** Ordered list of events (heap) */private static PriorityQ heap = null;private static long nextlog = 0;// =============== initialization ======================================// =====================================================================/** to prevent construction */private EDSimulator() {}//---------------------------------------------------------------------//Private methods//---------------------------------------------------------------------/** * Load and run initializers. */private static void runInitializers() { Object[] inits = Configuration.getInstanceArray(PAR_INIT); String names[] = Configuration.getNames(PAR_INIT); for(int i=0; i<inits.length; ++i) { System.err.println( "- Running initializer " +names[i]+ ": " + inits[i].getClass()); ((Control)inits[i]).execute(); }}// --------------------------------------------------------------------private static void scheduleControls(){ // load controls String[] names = Configuration.getNames(PAR_CTRL); controls = new Control[names.length]; ctrlSchedules = new Scheduler[names.length]; for(int i=0; i<names.length; ++i) { controls[i]=(Control)Configuration.getInstance(names[i]); ctrlSchedules[i] = new Scheduler(names[i], false); } System.err.println("EDSimulator: loaded controls "+ Arrays.asList(names)); // Schedule controls execution if (controls.length > heap.maxPriority()+1) throw new IllegalArgumentException( "Too many control objects"); for (int i=0; i < controls.length; i++) { new ControlEvent(controls[i], ctrlSchedules[i], i); }}//---------------------------------------------------------------------/** * Adds a new event to be scheduled, specifying the number of time units * of delay, and the execution order parameter. * * @param time * The actual time at which the next event should be scheduled. * @param order * The index used to specify the order in which control events * should be executed, if they happen to be at the same time, which is * typically the case. * @param event * The control event */static void addControlEvent(long time, int order, ControlEvent event){// we don't check whether time is negative or in the past: we trust// the caller, which must be from this package if (time >= endtime) return; heap.add(time, event, null, (byte)0, order);}//---------------------------------------------------------------------/** * This method is used to check whether the current configuration can * be used for event driven simulations. It checks for the existence of * config parameter {@value #PAR_ENDTIME}. */public static final boolean isConfigurationEventDriven(){ return Configuration.contains(PAR_ENDTIME);}//---------------------------------------------------------------------/** * Execute and remove the next event from the ordered event list. * @return true if the execution should be stopped. */private static boolean executeNext() { PriorityQ.Event ev = heap.removeFirst(); if( ev == null ) { System.err.println("EDSimulator: queue is empty, quitting"+ " at time "+CommonState.getTime()); return true; } long time = ev.time; if (time >= nextlog) { System.err.println("Current time: " + time); // seemingly complicated: to prevent overflow while( time-nextlog >= logtime ) nextlog+=logtime; if( endtime-nextlog >= logtime ) nextlog+=logtime; else nextlog=endtime; } if (time >= endtime) { System.err.println("EDSimulator: reached end time, quitting,"+ " leaving "+heap.size()+" unprocessed events in the queue"); return true; } CommonState.setTime(time); int pid = ev.pid; if (ev.node == null) { // might be control event; handled through a special method try { ControlEvent ctrl = (ControlEvent) ev.event; return ctrl.execute(); } catch (ClassCastException e) { throw new RuntimeException( "No destination specified (null) for event "+ ev); } } else if (ev.node != Network.prototype && ev.node.isUp() ) { CommonState.setPid(pid); CommonState.setNode(ev.node); if( ev.event instanceof NextCycleEvent ) { NextCycleEvent nce = (NextCycleEvent) ev.event; nce.execute(); } else { EDProtocol prot = null; try { prot = (EDProtocol) ev.node.getProtocol(pid); } catch (ClassCastException e) { e.printStackTrace(); throw new IllegalArgumentException("Protocol " + Configuration.lookupPid(pid) + " does not implement EDProtocol; " + ev.event.getClass() ); } prot.processEvent(ev.node, pid, ev.event); } } return false;}//---------------------------------------------------------------------//Public methods//---------------------------------------------------------------------/** * Runs an experiment, resetting everything except the random seed. */public static void nextExperiment() { // Reading parameter if( Configuration.contains(PAR_PQ) ) heap = (PriorityQ) Configuration.getInstance(PAR_PQ); else heap = new Heap(); endtime = Configuration.getLong(PAR_ENDTIME); if( CommonState.getEndTime() < 0 ) // not initialized yet CommonState.setEndTime(endtime); if( heap.maxTime() < endtime ) throw new IllegalParameterException(PAR_ENDTIME, "End time is too large: configured event queue only"+ " supports "+heap.maxTime()); logtime = Configuration.getLong(PAR_LOGTIME, Long.MAX_VALUE); // initialization System.err.println("EDSimulator: resetting"); CommonState.setPhase(CommonState.PHASE_UNKNOWN); CommonState.setTime(0); // needed here controls = null; ctrlSchedules = null; nextlog = 0; Network.reset(); System.err.println("EDSimulator: running initializers"); runInitializers(); scheduleControls(); // Perform the actual simulation; executeNext() will tell when to // stop. boolean exit = false; while (!exit) { exit = executeNext(); } // analysis after the simulation CommonState.setPhase(CommonState.POST_SIMULATION); for(int j=0; j<controls.length; ++j) { if( ctrlSchedules[j].fin ) controls[j].execute(); }}//---------------------------------------------------------------------/** * Adds a new event to be scheduled, specifying the number of time units * of delay, and the node and the protocol identifier to which the event * will be delivered. * * @param delay * The number of time units before the event is scheduled. * Has to be non-negative. * @param event * The object associated to this event * @param node * The node associated to the event. * @param pid * The identifier of the protocol to which the event will be delivered */public static void add(long delay, Object event, Node node, int pid){ if (delay < 0) throw new IllegalArgumentException("Protocol "+ node.getProtocol(pid)+" is trying to add event "+ event+" with a negative delay: "+delay); if (pid > Byte.MAX_VALUE) throw new IllegalArgumentException( "This version does not support more than " + Byte.MAX_VALUE + " protocols"); long time = CommonState.getTime(); if( endtime - time > delay ) // check like this to deal with overflow heap.add(time+delay, event, node, (byte) pid);}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -