|
|
|
Developed by BBN
Technologies, D-OMAR is an Air Force Research Laboratory sponsored project. For further information on D-OMAR, you
may contact Dr.
Michael Young at AFRL or Steve Deutsch at
BBNT.
|
| |
|
Understanding the clock and SignalProcessor
interaction
Assume Agent A is sending a signal to itself.
Using the SimulationClock, the following code is
valid, and will not cause a race condition. The agent will receive the
signal every time, and the join will complete. This is because the
clock wont process the signal until this agent's threads are all in a
wait state. The main thread that executes the S.join below wont be in a
wait state until the f1.getValue(), after the waitForSignal thread is
started. The waitForSignal thread wont be in a wait state until the
waitForSignal is ready for processing.
|
Future f1 = S.join (Invocation.call("sendSignalTo","scorej.S", signal), Invocation.call("waitForSignal","scorej.S", signalSubject));
f1.getValue();
|
| Using the
NonSimulationClock, however, the above code is a race condition.
Sometimes the signal may get missed because the signal processing of
the sent signal may happen before the waitForSignal is ready. Here's
how to do this using the NonSimulationClock: |
SignalWaitQueue swq = S.createSignalQueue(signalSubject); Future f1 = S.join (Invocation.call("sendSignalTo","scorej.S", signal), Invocation.call("waitForSignalQueue","scorej.S", swq)); f1.getValue();
|
Performance
- Turn off the ScoreJLog for real The ScorejLog
can eat up a lot of processing time formatting log messages. Simply
stopping console and logfile output isnt enough, since the ScoreJLog
will still go through the process of preparing the log messages. Also,
the Scenario.initializeScenario routine sets up the ScorejLog and turns
it on. So you if you want to shut it off, you need to do so in your
scenarioInit method.
public void scenarioInit() { // Turn all Logging off ScorejLog.setLevel(ScorejLog.DEFAULT, Log.OFF);
/* Stop console and echo to prevent System.out and System.err to be printed */ Log.stopConsole(); Log.stopEcho(); }
- Manage threads In OmarL joins, races, satisfys,
and execute-top-levels didnt actually spawn new Threads, the OmarL core
engine handled the executing procedures sequentially. This allows for
systems with large numbers of "concurrently" executing procedures,
without the cost of thread management. OmarJ, however, does spawn Java
Threads for each race, join, satisfy, spawn, or fork invocation. This
can lead to scalability problems. For example, assume a system of 500
agents, each with a signal handler procedure. The signal handler is a
simple process:
while (true) { Signal inc = S.waitForSignal(...); handleSignal(inc); }
The OmarL version of this system should
work just fine. The overhead for having 500 of these processes isn't
too bad, because they're not real threads. In OmarJ, however, you'd
have 500 java Threads for the VM to manage. A better design might be
having one procedure catch all of the signals for the 500 agents,
either by matching on the subject or writing an appropriate
SignalEvaluator. Then dispatching the signal by locating the agent
defined by the receivers. You'd implement the handleSignal method as a
method on your Agent class.
while (true) { Signal inc = S.waitForSignal(signalEvaluator); ID[] receivers = inc.getReceivers(); for (int i=0; i< receivers.length; ++i) { // User supplied function that returns a // user defined Agent object UserAgent agent = getAgent(receivers[i]); agent.handleSignal(inc); } }
Note that you dont really need to spawn a
Thread to run the handleSignal in, unless handleSignal can enter a wait
state. The next signal wont get processed until handleSignal is done.
If handleSignal is complex and could enter a wait state, then it needs
to be put in a S.spawn.
|
|
|