A simjava simulation is a collection of entities (Sim_entity class) each of which runs in its own thread. These entities are connected together by ports (Sim_port class) and can communicate with each other by sending and receiving event objects (Sim_event class) through these ports. A static Sim_system class controls all the threads, advances the simulation time, and maintains the event queues. The progress of the simulation is recorded through trace messages produced by the entities, and saved in a file.
A simulation layout
The main file:
import eduni.simjava.*; class Example { public static void main(String args[]) { Sim_system.initialise(); Sim_system.add(new Source("Sender", 1, Source.SRC_OK)); Sim_system.add(new Sink("Receiver", 2, Sink.SINK_OK)); Sim_system.link_ports("Sender", "out", "Receiver", "in"); Sim_system.run(); } }The first line imports all the classes in the simjava package, all source files in the simulation should have it at the top.
The main program is very simple and follows the steps laid out above. First the Sim_system object is initialised with the call Sim_system.initialise(), this should be done at the start of every simulation. The two entities are then added, we will look at their constructors and code in more detail below. Then the entities are linked together by the Sim_system.link_ports() call. It links the port called "out" on the "Sender" entity to the port called "in" on the "Receiver" entity. Finally the simulation is set in motion by calling Sim_system.run(), which will exit when there are no more events to process.
The classes for the two entities are derived from the standard Sim_entity class. The code for the Source is given below, the Sink class is very similar.
class Source extends Sim_entity { private Sim_port out; private int index; private int state; public static final int SRC_OK = 0; public static final int SRC_BLOCKED = 1; public Source(String name, int index, int state) { super(name); this.index = index; this.state = state; out = new Sim_port("out"); add_port(out); } public void body() { Sim_event ev = null; int i; System.out.println("About to do body S"); for (i=index; i<100; i++) { sim_schedule(out,0.0,0); sim_wait(ev); state = SRC_BLOCKED; sim_hold(10.0); state = SRC_OK; sim_trace(1,"C Src loop index is "+i); } System.out.println("Exiting body S"); } }The constructor method first calls Sim_entity's constructor, super(name), all classes derived from Sim_entity should do this. It then initialises its own two data members, state and index. Finally it creates a new port with the name "in" and adds it to its list of ports. This port is linked to a port on the other entity in the main() function shown earlier.
The standard Sim_entity does nothing; to make an entity do anything useful you need to override the body() method. The source's body() function includes all the most important methods of simjava:
export CLASSPATH=/home/rmcn/summ96/simjava/classes/:$CLASSPATHYou can now compile and execute your Java code in the normal way. After running, the simulation will leave a file called "tracefile" in the current directory, this file contains all the trace lines from the simulation.
sim_trace(int level, String msg)
This adds the msg to the trace file. The level can be used to control which traces get printed in a simulation run, without having to manually comment out sim_trace() calls in the code. The global trace level is set using the static function Sim_system.set_trc_level(int flags), the integer parameter flags is interpreted as a series of bit flags, and only sim_trace() calls with one of those bits set in its level parameter will get printed.
sim_schedule()
This method comes in three flavours, depending on how you refer to the destination of the event, (the first argument).
sim_wait(event)
If the parameter event points to a blank Sim_event object, then it is set to the event received and information can be extracted from it. If you don't need the event returned in this way, then use sim_event(null) and it will be discarded. The following example receives an event, then extracts the time it was sent, and its tag value. A list of the other information held in events can be found in the reference documentation on the class Sim_event.
Sim_event ev = new Sim_event(); sim_wait(ev); double time = ev.event_time(); int tag = ev.get_tag();
Sometimes we may want to send more information than just an integer, for these situations a new form of sim_schedule() is provided which attaches a whole Object to the event. So any information can be packaged up in a class and sent with an event. For example, to send a Double value:
sim_schedule(dest, 0.1, tag, new Double(3.14));And to extract it at the other end:
Sim_event ev = new Sim_event(); Double d; sim_wait(ev); Double d = (Double)ev.get_data();
Events can be extracted from the deferred queue using sim_select(Sim_predicate pred, Sim_event ev), predicates are used to select specific events from the queue. The method sim_waiting() will return a count of the number of events waiting in the queue for that entity entity. For example:
// sender sim_schedule(out, 0.5, 0); // receiver Sim_event ev = new Sim_event(); sim_hold(2.0); // sim_wait() here would block indefinitely as event arrived // whilst we were holding System.out.println("Sim_waiting() returns: "+sim_waiting()); if(sim_waiting() > 0) sim_select(Sim_system.SIM_ANY, ev);
Sometimes you need to get the next event which has been or will be sent to an entity -
if(sim_waiting() > 0) sim_select(Sim_system.SIM_ANY, ev); else sim_wait(ev);
There are other runtime methods for selecting events from the deferred
queue detailed in the reference documentation on the
Sim_entity
class.
Statistics functions
There are three random number generator classes for use in simulations,
Sim_normal_obj
for normally distributed numbers,
Sim_uniform_obj
for uniformly distributed numbers, and Sim_negexp_obj
for negative exponential distributed numbers.
Accumulative data about the value of a variable over a period of
time can also be collected using the
Sim_accum
class. The update(double interval, double value) method records
that it held the given value for the given interval of time.
Once all the data has been collected, the average (avg()),
maximum (max()), and minimum (min()) value can
then be calculated, as well as the total interval recorded
(interval_sum()).
The sim_system
The Sim_system class has several static methods
for monitoring the simulation, and altering its global flags:
There are four example simulations distributed with the simjava package. Their source code may help with syntax and usage queries.
Known bugs and problems
If you find any new bugs please send details to the address below,
and they might even be fixed in a future release!